ELF format standardized AOT file

Signed-off-by: wuzhangda <wuzhangda@huawei.com>
Change-Id: Ibfb512c6b86ac1ab103339c6e1043b56e9c6b612
This commit is contained in:
wuzhangda 2023-04-04 15:53:07 +08:00
parent f12a7e338f
commit c05de1f0a0
17 changed files with 976 additions and 284 deletions

View File

@ -559,6 +559,8 @@ ecma_source = [
"ecmascript/builtins/builtins_weak_ref.cpp",
"ecmascript/builtins/builtins_weak_set.cpp",
"ecmascript/byte_array.cpp",
"ecmascript/compiler/aot_file/elf_builder.cpp",
"ecmascript/compiler/aot_file/elf_reader.cpp",
"ecmascript/containers/containers_arraylist.cpp",
"ecmascript/containers/containers_deque.cpp",
"ecmascript/containers/containers_errors.cpp",
@ -799,9 +801,49 @@ ecma_profiler_source += [
ecma_platform_source = []
ecma_platform_source += [ "ecmascript/platform/common/map.cpp" ]
config("include_llvm") {
if (compile_llvm_online) {
include_dirs = [
"//third_party/third_party_llvm-project/build/include",
"//third_party/third_party_llvm-project/llvm/include/",
]
} else {
if (is_mingw) {
include_dirs = [
"//prebuilts/ark_tools/ark_js_prebuilts/llvm_prebuilts_windows/llvm/include",
"//prebuilts/ark_tools/ark_js_prebuilts/llvm_prebuilts_windows/build/include",
]
} else if (is_mac) {
if (host_cpu == "arm64") {
include_dirs = [
"//prebuilts/ark_tools/ark_js_prebuilts/llvm_prebuilts_darwin_arm64/llvm/include",
"//prebuilts/ark_tools/ark_js_prebuilts/llvm_prebuilts_darwin_arm64/build/include",
]
} else {
include_dirs = [
"//prebuilts/ark_tools/ark_js_prebuilts/llvm_prebuilts_darwin_x64/llvm/include",
"//prebuilts/ark_tools/ark_js_prebuilts/llvm_prebuilts_darwin_x64/build/include",
]
}
} else {
if (current_cpu == "arm64") {
include_dirs = [
"//prebuilts/ark_tools/ark_js_prebuilts/llvm_prebuilts_aarch64/llvm/include",
"//prebuilts/ark_tools/ark_js_prebuilts/llvm_prebuilts_aarch64/build/include",
]
} else {
include_dirs = [
"//prebuilts/ark_tools/ark_js_prebuilts/llvm_prebuilts/llvm/include",
"//prebuilts/ark_tools/ark_js_prebuilts/llvm_prebuilts/build/include",
]
}
}
}
}
if (is_mingw) {
ecma_platform_source += [
"ecmascript/platform/common/elf.cpp",
"ecmascript/platform/windows/backtrace.cpp",
"ecmascript/platform/windows/map.cpp",
"ecmascript/platform/windows/file.cpp",
@ -816,7 +858,6 @@ if (is_mingw) {
]
if (is_mac || target_os == "ios") {
ecma_platform_source += [
"ecmascript/platform/common/elf.cpp",
"ecmascript/platform/unix/mac/os.cpp",
"ecmascript/platform/unix/mac/backtrace.cpp",
]
@ -824,13 +865,11 @@ if (is_mingw) {
ecma_platform_source += [
"ecmascript/platform/unix/linux/os.cpp",
"ecmascript/platform/unix/ohos/backtrace.cpp",
"ecmascript/platform/unix/elf.cpp",
]
} else if (is_linux) {
ecma_platform_source += [
"ecmascript/platform/unix/linux/os.cpp",
"ecmascript/platform/unix/linux/backtrace.cpp",
"ecmascript/platform/unix/elf.cpp",
]
} else {
print("Invalid os!")
@ -846,6 +885,7 @@ ohos_source_set("libark_jsruntime_set") {
sources += ecma_platform_source
public_configs = [ "$js_root:ark_jsruntime_public_config" ]
public_configs += [ ":include_llvm" ]
configs = [
"$js_root:ark_jsruntime_common_config",
@ -920,6 +960,7 @@ ohos_source_set("libark_jsruntime_test_set") {
}
public_configs = [ "$js_root:ark_jsruntime_public_config" ]
public_configs += [ ":include_llvm" ]
configs = [
"$js_root:ark_jsruntime_common_config",
@ -1007,6 +1048,9 @@ ohos_shared_library("libark_jsruntime_test") {
"$ark_root/libpandafile:libarkfile_static",
]
public_configs = [ "$js_root:ark_jsruntime_public_config" ]
public_configs += [ ":include_llvm" ]
ldflags = []
if (enable_coverage) {
ldflags += [ "--coverage" ]

View File

@ -13,8 +13,9 @@
* limitations under the License.
*/
#include "ecmascript/aot_file_manager.h"
#include "ecmascript/base/config.h"
#include "ecmascript/compiler/aot_file/elf_builder.h"
#include "ecmascript/compiler/aot_file/elf_reader.h"
#include "ecmascript/compiler/bc_call_signature.h"
#include "ecmascript/compiler/common_stubs.h"
#include "ecmascript/compiler/compiler_log.h"
@ -31,9 +32,6 @@
#include "ecmascript/stackmap/ark_stackmap_parser.h"
#include "ecmascript/stackmap/llvm_stackmap_parser.h"
#include "ecmascript/mem/region.h"
#include "ecmascript/platform/elf.h"
#include "ecmascript/platform/file.h"
#include "ecmascript/platform/map.h"
extern const uint8_t _binary_stub_an_start[];
@ -199,8 +197,8 @@ bool StubFileInfo::Load()
return false;
}
ExecutedMemoryAllocator::AllocateBuf(totalCodeSize_, exeMem_);
uint64_t codeAddress = reinterpret_cast<uint64_t>(exeMem_.addr_);
ExecutedMemoryAllocator::AllocateBuf(totalCodeSize_, stubsMem_);
uint64_t codeAddress = reinterpret_cast<uint64_t>(stubsMem_.addr_);
uint32_t curUnitOffset = 0;
uint32_t asmStubSize = 0;
binBufparser.ParseBuffer(&asmStubSize, sizeof(asmStubSize));
@ -223,7 +221,7 @@ bool StubFileInfo::Load()
}
}
LOG_COMPILER(INFO) << "loaded stub file successfully";
PageProtect(exeMem_.addr_, exeMem_.size_, PAGE_PROT_EXEC_READ);
PageProtect(stubsMem_.addr_, stubsMem_.size_, PAGE_PROT_EXEC_READ);
return true;
}
@ -246,7 +244,7 @@ void StubFileInfo::Dump() const
}
}
void AnFileInfo::Save(const std::string &filename, kungfu::Triple triple)
void AnFileInfo::Save(const std::string &filename, Triple triple)
{
std::string realPath;
if (!RealPath(filename, realPath, false)) {
@ -260,20 +258,21 @@ void AnFileInfo::Save(const std::string &filename, kungfu::Triple triple)
}
std::ofstream file(realPath.c_str(), std::ofstream::binary);
SetStubNum(entries_.size());
ASSERT(GetCodeUnitsNum() == 1);
ModuleSectionDes &des = des_[0];
// add section
uint64_t addr = reinterpret_cast<uint64_t>(entries_.data());
entryNum_ = entries_.size();
uint32_t size = sizeof(FuncEntryDes) * entryNum_;
des.SetSecAddr(addr, ElfSecName::ARK_FUNCENTRY);
des.SetSecSize(size, ElfSecName::ARK_FUNCENTRY);
Elf64_Ehdr header;
PackELFHeader(header, AOTFileManager::AOT_VERSION, triple);
file.write(reinterpret_cast<char *>(&header), sizeof(Elf64_Ehdr));
file.write(reinterpret_cast<char *>(&entryNum_), sizeof(entryNum_));
file.write(reinterpret_cast<char *>(entries_.data()), sizeof(FuncEntryDes) * entryNum_);
uint32_t moduleNum = GetCodeUnitsNum();
file.write(reinterpret_cast<char *>(&moduleNum), sizeof(moduleNum_));
file.write(reinterpret_cast<char *>(&totalCodeSize_), sizeof(totalCodeSize_));
LOG_COMPILER(DEBUG) << "total code size = " << (totalCodeSize_ / 1_KB) << "KB";
for (size_t i = 0; i < moduleNum; i++) {
des_[i].SaveSectionsInfo(file);
}
ElfBuilder builder(des);
llvm::ELF::Elf64_Ehdr header;
builder.PackELFHeader(header, AOTFileManager::AOT_VERSION, triple);
file.write(reinterpret_cast<char *>(&header), sizeof(llvm::ELF::Elf64_Shdr));
builder.PackELFSections(file);
builder.PackELFSegment(file);
file.close();
}
@ -287,39 +286,37 @@ bool AnFileInfo::Load(const std::string &filename)
return false;
}
std::ifstream file(realPath.c_str(), std::ofstream::binary);
if (!file.good()) {
LOG_COMPILER(INFO) << "Fail to load an file: " << realPath.c_str();
file.close();
fileMapMem_ = FileMap(realPath.c_str(), FILE_RDONLY, PAGE_PROT_READ);
if (fileMapMem_.GetOriginAddr() == nullptr) {
LOG_ECMA(ERROR) << "File mmap failed";
return false;
}
PagePreRead(fileMapMem_.GetOriginAddr(), fileMapMem_.GetSize());
Elf64_Ehdr header;
file.read(reinterpret_cast<char *>(&header), sizeof(Elf64_Ehdr));
if (!VerifyELFHeader(header, AOTFileManager::AOT_VERSION)) {
file.close();
return false;
}
file.read(reinterpret_cast<char *>(&entryNum_), sizeof(entryNum_));
entries_.resize(entryNum_);
file.read(reinterpret_cast<char *>(entries_.data()), sizeof(FuncEntryDes) * entryNum_);
file.read(reinterpret_cast<char *>(&moduleNum_), sizeof(moduleNum_));
moduleNum_ = 1;
des_.resize(moduleNum_);
file.read(reinterpret_cast<char *>(&totalCodeSize_), sizeof(totalCodeSize_));
ModuleSectionDes &des = des_[0];
if (totalCodeSize_ == 0) {
file.close();
LOG_COMPILER(ERROR) << "error: code in the an file is empty!";
ElfReader reader(fileMapMem_);
std::vector<ElfSecName> secs = GetDumpSectionNames();
if (!reader.VerifyELFHeader(AOTFileManager::AOT_VERSION)) {
return false;
}
ExecutedMemoryAllocator::AllocateBuf(totalCodeSize_, exeMem_);
uint64_t codeAddress = reinterpret_cast<uint64_t>(exeMem_.addr_);
uint32_t curUnitOffset = 0;
for (size_t i = 0; i < moduleNum_; i++) {
des_[i].LoadSectionsInfo(file, curUnitOffset, codeAddress);
reader.ParseELFSections(des, secs);
if (!reader.ParseELFSegment()) {
LOG_ECMA(ERROR) << "modify mmap area permission failed";
return false;
}
uint64_t secAddr = des.GetSecAddr(ElfSecName::ARK_FUNCENTRY);
uint32_t secSize = des.GetSecSize(ElfSecName::ARK_FUNCENTRY);
FuncEntryDes *entryDes = reinterpret_cast<FuncEntryDes *>(secAddr);
entryNum_ = secSize / sizeof(FuncEntryDes);
entries_.assign(entryDes, entryDes + entryNum_);
des.SetStartIndex(0);
des.SetFuncCount(entryNum_);
size_t len = entries_.size();
for (size_t i = 0; i < len; i++) {
FuncEntryDes& funcDes = entries_[i];
@ -336,10 +333,16 @@ bool AnFileInfo::Load(const std::string &filename)
LOG_COMPILER(INFO) << "loaded an file: " << filename.c_str();
isLoad_ = true;
PageProtect(exeMem_.addr_, exeMem_.size_, PAGE_PROT_EXEC_READ);
return true;
}
const std::vector<ElfSecName> & AnFileInfo::GetDumpSectionNames()
{
static const std::vector<ElfSecName> secNames = {ElfSecName::RODATA_CST8, ElfSecName::TEXT, ElfSecName::STRTAB,
ElfSecName::SYMTAB, ElfSecName::ARK_STACKMAP, ElfSecName::ARK_FUNCENTRY};
return secNames;
}
void AnFileInfo::Dump() const
{
LOG_COMPILER(ERROR) << "An file loading: ";
@ -819,16 +822,24 @@ AnFileDataManager::~AnFileDataManager()
SafeDestoryAllData();
}
void AnFileDataManager::DestoryFileMapMem(MemMap &fileMapMem)
{
if (fileMapMem.GetOriginAddr() != nullptr && fileMapMem.GetSize() > 0) {
FileUnMap(fileMapMem);
fileMapMem.Reset();
}
}
void AnFileDataManager::SafeDestoryAllData()
{
os::memory::WriteLockHolder lock(lock_);
if (loadedStub_ != nullptr) {
ExecutedMemoryAllocator::DestoryBuf(loadedStub_->GetExeMem());
ExecutedMemoryAllocator::DestoryBuf(loadedStub_->GetStubsMem());
loadedStub_ = nullptr;
}
for (auto &iter : loadedAn_) {
ExecutedMemoryAllocator::DestoryBuf(iter->GetExeMem());
DestoryFileMapMem(iter->GetFileMapMem());
}
loadedAn_.clear();
}

View File

@ -15,11 +15,14 @@
#ifndef ECMASCRIPT_AOT_FILE_MANAGER_H
#define ECMASCRIPT_AOT_FILE_MANAGER_H
#include <string>
#include "ecmascript/compiler/binary_section.h"
#include "ecmascript/deoptimizer/calleeReg.h"
#include "ecmascript/js_function.h"
#include "ecmascript/js_runtime_options.h"
#include "ecmascript/stackmap/ark_stackmap.h"
#include "ecmascript/platform/file.h"
#include "ecmascript/platform/map.h"
namespace panda::ecmascript {
class JSpandafile;
@ -66,33 +69,37 @@ struct ModuleSectionDes {
uint32_t arkStackMapSize_ {0};
uint8_t *arkStackMapRawPtr_ {nullptr};
std::string GetSecName(const ElfSecName idx) const
static std::string GetSecName(const ElfSecName idx)
{
switch (idx) {
case ElfSecName::RODATA:
return "rodata";
return ".rodata";
case ElfSecName::RODATA_CST4:
return "rodata.cst4";
return ".rodata.cst4";
case ElfSecName::RODATA_CST8:
return "rodata.cst8";
return ".rodata.cst8";
case ElfSecName::RODATA_CST16:
return "rodata.cst16";
return ".rodata.cst16";
case ElfSecName::RODATA_CST32:
return "rodata.cst32";
return ".rodata.cst32";
case ElfSecName::TEXT:
return "text";
return ".text";
case ElfSecName::DATA:
return "data";
return ".data";
case ElfSecName::GOT:
return "got";
return ".got";
case ElfSecName::RELATEXT:
return "rela.text";
return ".rela.text";
case ElfSecName::STRTAB:
return "strtab";
return ".strtab";
case ElfSecName::SYMTAB:
return "symtab";
return ".symtab";
case ElfSecName::LLVM_STACKMAP:
return "llvm_stackmaps";
return ".llvm_stackmaps";
case ElfSecName::ARK_STACKMAP:
return ".ark_stackmaps";
case ElfSecName::ARK_FUNCENTRY:
return ".ark_funcentry";
default: {
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
@ -110,6 +117,11 @@ struct ModuleSectionDes {
return std::move(arkStackMapPtr_);
}
std::shared_ptr<uint8_t> GetArkStackMapSharePtr() const
{
return std::move(arkStackMapPtr_);
}
void SetArkStackMapPtr(uint8_t *ptr)
{
arkStackMapRawPtr_ = ptr;
@ -331,8 +343,12 @@ public:
bool CalCallSiteInfo(uintptr_t retAddr, CallSiteInfo& ret) const;
protected:
ExecutedMemoryAllocator::ExeMem& GetExeMem() {
return exeMem_;
ExecutedMemoryAllocator::ExeMem& GetStubsMem() {
return stubsMem_;
}
MemMap& GetFileMapMem() {
return fileMapMem_;
}
uint32_t entryNum_ {0};
@ -340,14 +356,15 @@ protected:
uint32_t totalCodeSize_ {0};
std::vector<FuncEntryDes> entries_ {};
std::vector<ModuleSectionDes> des_ {};
ExecutedMemoryAllocator::ExeMem exeMem_ {};
ExecutedMemoryAllocator::ExeMem stubsMem_ {};
MemMap fileMapMem_ {};
};
class PUBLIC_API AnFileInfo : public AOTFileInfo {
public:
AnFileInfo() = default;
~AnFileInfo() override = default;
void Save(const std::string &filename, kungfu::Triple triple);
void Save(const std::string &filename, Triple triple);
void AddModuleDes(ModuleSectionDes &moduleDes)
{
des_.emplace_back(moduleDes);
@ -380,7 +397,7 @@ public:
private:
bool Load(const std::string &filename);
void RewriteRelcateTextSection(const char* symbol, uintptr_t patchAddr);
const std::vector<ElfSecName> & GetDumpSectionNames();
std::unordered_map<uint32_t, uint64_t> mainEntryMap_ {};
bool isLoad_ {false};
@ -479,6 +496,7 @@ public:
bool SafeInsideStub(uintptr_t pc);
bool SafeInsideAOT(uintptr_t pc);
AOTFileInfo::CallSiteInfo SafeCalCallSiteInfo(uintptr_t retAddr);
void DestoryFileMapMem(MemMap &fileMapMem);
void SafeDestoryAllData();
const std::string& GetDir() const
{
@ -524,7 +542,7 @@ public:
explicit AOTFileManager(EcmaVM *vm);
virtual ~AOTFileManager();
static constexpr uint32_t AOT_VERSION = 1;
static constexpr uint32_t AOT_VERSION = 2;
static constexpr char FILE_EXTENSION_AN[] = ".an";
static constexpr char FILE_EXTENSION_AI[] = ".ai";
static constexpr uint8_t DESERI_CP_ITEM_SIZE = 2;

View File

@ -0,0 +1,496 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/compiler/aot_file/elf_builder.h"
#include "ecmascript/ecma_macros.h"
#include "securec.h"
namespace panda::ecmascript {
void ElfBuilder::ModifyStrTabSection()
{
bool existedStrTab = false;
uint64_t strTabAddr = 0;
uint32_t strTabSize = 0;
std::vector<std::string> sectionNames;
std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = sectionDes_.sectionsInfo_;
// modify strtab
for (auto &s : sections) {
if (s.first == ElfSecName::STRTAB) {
existedStrTab = true;
strTabAddr = s.second.first;
strTabSize = s.second.second;
break;
}
}
for (auto &s : sections) {
ElfSection section = ElfSection(s.first);
if (!section.ShouldDumpToAOTFile()) {
continue;
}
auto str = sectionDes_.GetSecName(s.first);
llvm::ELF::Elf64_Word id = FindShName(str, strTabAddr, strTabSize);
if (id == static_cast<llvm::ELF::Elf64_Word>(-1)) {
sectionNames.emplace_back(str);
}
}
uint32_t size = 0;
if (existedStrTab) {
size += strTabSize;
}
for (auto &str: sectionNames) {
size = size + str.size() + 1;
}
strTabPtr_ = std::make_unique<char []>(size);
char *dst = strTabPtr_.get();
if (strTabSize > 0) {
if ((memcpy_s(dst, size, reinterpret_cast<char *>(strTabAddr), strTabSize)) != EOK) {
UNREACHABLE();
}
}
uint32_t i = strTabSize;
for (auto &str: sectionNames) {
uint32_t copySize = str.size();
if (copySize == 0) {
UNREACHABLE();
}
if ((copySize != 0) && ((memcpy_s(dst + i, size - i + 1, str.data(), copySize)) != EOK)) {
UNREACHABLE();
}
dst[i + copySize] = 0x0;
i = i + copySize + 1;
}
if (existedStrTab) {
sections.erase(ElfSecName::STRTAB);
}
sections[ElfSecName::STRTAB] = std::make_pair(reinterpret_cast<uint64_t>(strTabPtr_.get()), size);
[[maybe_unused]] uint32_t symtabSize = sections[ElfSecName::SYMTAB].second;
ASSERT(symtabSize % sizeof(llvm::ELF::Elf64_Sym) == 0);
if (enableSecDump_) {
DumpSection();
}
}
void ElfBuilder::DumpSection() const
{
const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = sectionDes_.sectionsInfo_;
// dump
for (auto &s : sections) {
ElfSection section = ElfSection(s.first);
if (!section.ShouldDumpToAOTFile()) {
continue;
}
LOG_COMPILER(INFO) << "secname :" << std::dec << static_cast<int>(s.first)
<< " addr:0x" << std::hex << s.second.first << " size:0x" << s.second.second << std::endl;
}
}
void ElfBuilder::AddArkStackMapSection()
{
// add arkstackmap
std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = sectionDes_.sectionsInfo_;
std::shared_ptr<uint8_t> ptr = sectionDes_.GetArkStackMapSharePtr();
uint64_t arkStackMapAddr = reinterpret_cast<uint64_t>(ptr.get());
uint32_t arkStackMapSize = sectionDes_.arkStackMapSize_;
if (arkStackMapSize > 0) {
sections[ElfSecName::ARK_STACKMAP] = std::pair(arkStackMapAddr, arkStackMapSize);
}
}
ElfBuilder::ElfBuilder(ModuleSectionDes sectionDes): sectionDes_(sectionDes)
{
AddArkStackMapSection();
ModifyStrTabSection();
sectionToAlign_ = {
{ElfSecName::RODATA, 8},
{ElfSecName::RODATA_CST4, 8},
{ElfSecName::RODATA_CST8, 8},
{ElfSecName::RODATA_CST16, 8},
{ElfSecName::RODATA_CST32, 8},
{ElfSecName::TEXT, 16},
{ElfSecName::STRTAB, 1},
{ElfSecName::SYMTAB, 8},
{ElfSecName::ARK_STACKMAP, 8},
{ElfSecName::ARK_FUNCENTRY, 8},
};
sectionToSegment_ = {
{ElfSecName::RODATA, ElfSecName::TEXT},
{ElfSecName::RODATA_CST4, ElfSecName::TEXT},
{ElfSecName::RODATA_CST8, ElfSecName::TEXT},
{ElfSecName::RODATA_CST16, ElfSecName::TEXT},
{ElfSecName::RODATA_CST32, ElfSecName::TEXT},
{ElfSecName::TEXT, ElfSecName::TEXT},
{ElfSecName::STRTAB, ElfSecName::DATA},
{ElfSecName::SYMTAB, ElfSecName::DATA},
{ElfSecName::ARK_STACKMAP, ElfSecName::DATA},
{ElfSecName::ARK_FUNCENTRY, ElfSecName::DATA},
};
segmentToFlag_ = {
{ElfSecName::TEXT, llvm::ELF::PF_X | llvm::ELF::PF_R},
{ElfSecName::DATA, llvm::ELF::PF_R},
};
}
ElfBuilder::~ElfBuilder()
{
strTabPtr_ = nullptr;
}
llvm::ELF::Elf64_Half ElfBuilder::GetShStrNdx(std::map<ElfSecName, std::pair<uint64_t, uint32_t>>& sections) const
{
llvm::ELF::Elf64_Half shstrndx = 1; // skip null section
for (auto &s : sections) {
ElfSection section = ElfSection(s.first);
if (!section.ShouldDumpToAOTFile()) {
continue;
}
if (s.first == ElfSecName::STRTAB) {
return shstrndx;
}
shstrndx++;
}
UNREACHABLE();
}
llvm::ELF::Elf64_Half ElfBuilder::GetSecSize() const
{
llvm::ELF::Elf64_Half secsSize = 0;
const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = sectionDes_.sectionsInfo_;
for (auto &s : sections) {
ElfSection section = ElfSection(s.first);
if (!section.ShouldDumpToAOTFile()) {
continue;
}
uint32_t curSecSize = sectionDes_.GetSecSize(s.first);
secsSize += curSecSize;
}
return secsSize;
}
int ElfBuilder::GetSecNum() const
{
int secNum = 0;
const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = sectionDes_.sectionsInfo_;
for (auto &s : sections) {
ElfSection section = ElfSection(s.first);
if (!section.ShouldDumpToAOTFile()) {
continue;
}
++secNum;
}
return secNum;
}
/*
ELF Header as follow:
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x2
Entry point address: 0x0
Start of program headers: 20480 (bytes into file)
Start of section headers: 64 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 2
Size of section headers: 64 (bytes)
Number of section headers: 7
Section header string table index: 3
There are 7 section headers, starting at offset 0x40:
*/
void ElfBuilder::PackELFHeader(llvm::ELF::Elf64_Ehdr &header, uint32_t version, Triple triple)
{
if (memset_s(reinterpret_cast<void *>(&header), sizeof(llvm::ELF::Elf64_Ehdr), 0, sizeof(llvm::ELF::Elf64_Ehdr)) != EOK) {
UNREACHABLE();
}
header.e_ident[llvm::ELF::EI_MAG0] = llvm::ELF::ElfMagic[llvm::ELF::EI_MAG0];
header.e_ident[llvm::ELF::EI_MAG1] = llvm::ELF::ElfMagic[llvm::ELF::EI_MAG1];
header.e_ident[llvm::ELF::EI_MAG2] = llvm::ELF::ElfMagic[llvm::ELF::EI_MAG2];
header.e_ident[llvm::ELF::EI_MAG3] = llvm::ELF::ElfMagic[llvm::ELF::EI_MAG3];
header.e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64;
header.e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB;
header.e_ident[llvm::ELF::EI_VERSION] = 1;
header.e_type = llvm::ELF::ET_DYN;
switch (triple) {
case Triple::TRIPLE_AMD64:
header.e_machine = llvm::ELF::EM_X86_64;
break;
case Triple::TRIPLE_ARM32:
header.e_machine = llvm::ELF::EM_ARM;
break;
case Triple::TRIPLE_AARCH64:
header.e_machine = llvm::ELF::EM_AARCH64;
break;
default:
UNREACHABLE();
break;
}
header.e_version = version;
std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = sectionDes_.sectionsInfo_;
// start of section headers
header.e_shoff = sizeof(llvm::ELF::Elf64_Ehdr);
// size of ehdr
header.e_ehsize = sizeof(llvm::ELF::Elf64_Ehdr);
// size of section headers
header.e_shentsize = sizeof(llvm::ELF::Elf64_Shdr);
// number of section headers
header.e_shnum = GetSecNum() + 1; // 1: skip null section and ark stackmap
// section header string table index
header.e_shstrndx = GetShStrNdx(sections);
// phr
header.e_phentsize = sizeof(llvm::ELF::Elf64_Phdr);
header.e_phnum = GetSegmentNum();
}
int ElfBuilder::GetSegmentNum() const
{
const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = sectionDes_.sectionsInfo_;
std::set<ElfSecName> segments;
for (auto &s: sections) {
ElfSection section = ElfSection(s.first);
if (!section.ShouldDumpToAOTFile()) {
continue;
}
auto it = sectionToSegment_.find(s.first);
ASSERT(it != sectionToSegment_.end());
ElfSecName name = it->second;
segments.insert(name);
}
return segments.size();
}
ElfSecName ElfBuilder::FindLastSection(ElfSecName segment) const
{
ElfSecName ans = ElfSecName::NONE;
const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = sectionDes_.sectionsInfo_;
for (auto &s: sections) {
ElfSection section = ElfSection(s.first);
if (!section.ShouldDumpToAOTFile()) {
continue;
}
auto it = sectionToSegment_.find(s.first);
ASSERT(it != sectionToSegment_.end());
ElfSecName name = it->second;
if (name != segment) {
continue;
}
ans = std::max(ans, s.first);
}
return ans;
}
llvm::ELF::Elf64_Word ElfBuilder::FindShName(std::string name, uintptr_t strTabPtr, int strTabSize)
{
llvm::ELF::Elf64_Word ans = -1;
int len = name.size();
if (strTabSize < len + 1) {
return ans;
}
LOG_ECMA(DEBUG) << " FindShName name:" << name.c_str() << std::endl;
for (int i = 0; i < strTabSize - len + 1; ++i) {
char *dst = reinterpret_cast<char *>(strTabPtr) + i;
if (name.compare(dst) == 0) {
return i;
}
}
return ans;
}
std::pair<uint64_t, uint32_t> ElfBuilder::FindStrTab() const
{
const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = sectionDes_.sectionsInfo_;
uint64_t strTabAddr = 0;
uint32_t strTabSize = 0;
for (auto &s: sections) {
uint32_t curSecSize = sectionDes_.GetSecSize(s.first);
uint64_t curSecAddr = sectionDes_.GetSecAddr(s.first);
if (s.first == ElfSecName::STRTAB) {
strTabSize = curSecSize;
strTabAddr = curSecAddr;
break;
}
}
return std::make_pair(strTabAddr, strTabSize);
}
/*
section layout as follows:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .rodata.cst8 PROGBITS 0000000000001000 001000 000020 00 AM 0 0 8
[ 2] .text PROGBITS 0000000000001020 001020 001130 00 AX 0 0 16
[ 3] .strtab STRTAB 0000000000003000 003000 0001a5 00 A 0 0 1
[ 4] .symtab SYMTAB 00000000000031a8 0031a8 0001c8 18 A 1 0 8
[ 5] .ark_funcentry PROGBITS 0000000000003370 003370 0006c0 00 A 0 0 8
[ 6] .ark_stackmaps PROGBITS 0000000000003a30 003a30 0010f5 00 A 0 0 8
*/
void ElfBuilder::PackELFSections(std::ofstream &file)
{
std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = sectionDes_.sectionsInfo_;
uint32_t secNum = sections.size() + 1; // 1 : section id = 0 is null section
std::unique_ptr<llvm::ELF::Elf64_Shdr []> shdr = std::make_unique<llvm::ELF::Elf64_Shdr []>(secNum);
if (memset_s(reinterpret_cast<void *>(&shdr[0]), sizeof(llvm::ELF::Elf64_Shdr), 0, sizeof(llvm::ELF::Elf64_Shdr)) != EOK) {
UNREACHABLE();
}
llvm::ELF::Elf64_Off curSecOffset = sizeof(llvm::ELF::Elf64_Ehdr) + secNum * sizeof(llvm::ELF::Elf64_Shdr);
curSecOffset = AlignUp(curSecOffset, PageSize()); // not pagesize align will cause performance degradation
file.seekp(curSecOffset);
int i = 1; // 1: skip null section
auto strTab = FindStrTab();
for (auto &s: sections) {
ElfSection section = ElfSection(s.first);
if (!section.ShouldDumpToAOTFile()) {
continue;
}
shdr[i].sh_addralign = sectionToAlign_[s.first];
if (curSecOffset % shdr[i].sh_addralign != 0) {
curSecOffset = AlignUp(curSecOffset, shdr[i].sh_addralign);
file.seekp(curSecOffset);
}
auto it = sectionToSegment_.find(s.first);
ASSERT(it != sectionToSegment_.end());
ElfSecName segName = it->second;
segments_.insert(segName);
uint32_t curSecSize = sectionDes_.GetSecSize(s.first);
uint64_t curSecAddr = sectionDes_.GetSecAddr(s.first);
std::string secName = sectionDes_.GetSecName(s.first);
// text section address needs 16 bytes alignment
if ((ElfSecName::RODATA <= s.first && s.first <= ElfSecName::RODATA_CST8) || s.first == ElfSecName::TEXT) {
curSecOffset = AlignUp(curSecOffset, TEXT_SEC_ALIGN);
file.seekp(curSecOffset);
}
sectionToFileOffset_[s.first] = file.tellp();
file.write(reinterpret_cast<char *>(curSecAddr), curSecSize);
llvm::ELF::Elf64_Word shName = FindShName(secName, strTab.first, strTab.second);
ASSERT(shName != static_cast<llvm::ELF::Elf64_Word>(-1));
shdr[i].sh_name = shName;
shdr[i].sh_type = section.Type();
shdr[i].sh_flags = section.Flag();
shdr[i].sh_addr = curSecOffset;
shdr[i].sh_offset = curSecOffset;
LOG_COMPILER(DEBUG) << "curSecOffset: 0x" << std::hex << curSecOffset << " curSecSize:0x" << curSecSize;
curSecOffset += curSecSize;
ElfSecName lastSecName = FindLastSection(segName);
if (s.first == lastSecName) {
curSecOffset = AlignUp(curSecOffset, PageSize());
file.seekp(curSecOffset);
}
shdr[i].sh_size = curSecSize;
shdr[i].sh_link = section.Link();
shdr[i].sh_info = 0;
shdr[i].sh_entsize = section.Entsize();
sectionToShdr_[s.first] = shdr[i];
LOG_COMPILER(DEBUG) << " shdr[i].sh_entsize " << std::hex << shdr[i].sh_entsize << std::endl;
++i;
}
uint32_t secEnd = file.tellp();
file.seekp(sizeof(llvm::ELF::Elf64_Ehdr));
file.write(reinterpret_cast<char *>(shdr.get()), secNum * sizeof(llvm::ELF::Elf64_Shdr));
file.seekp(secEnd);
}
unsigned ElfBuilder::GetPFlag(ElfSecName segment) const
{
return segmentToFlag_.at(segment);
}
/*
segment layout as follows:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x001150 0x002000 R E 0x1000
LOAD 0x003000 0x0000000000003000 0x0000000000003000 0x001b25 0x002000 R 0x1000
Section to Segment mapping:
Segment Sections...
00 .rodata.cst8 .text
01 .strtab .symtab .ark_funcentry .ark_stackmaps
None
*/
void ElfBuilder::PackELFSegment(std::ofstream &file)
{
llvm::ELF::Elf64_Off e_phoff = file.tellp();
long phoff = (long)offsetof(struct llvm::ELF::Elf64_Ehdr, e_phoff);
// write Elf32_Off e_phoff;
file.seekp(phoff);
file.write(reinterpret_cast<char *>(&e_phoff), sizeof(e_phoff));
file.seekp(e_phoff);
int segNum = GetSegmentNum();
auto phdrs = std::make_unique<llvm::ELF::Elf64_Phdr []>(segNum);
std::map<ElfSecName, llvm::ELF::Elf64_Off> segmentToMaxOffset;
std::map<ElfSecName, llvm::ELF::Elf64_Off> segmentToMaxAddress;
std::set<ElfSecName> segments;
// SecName -> addr & size
std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = sectionDes_.sectionsInfo_;
llvm::ELF::Elf64_Off offset = e_phoff;
for (auto &s: sections) {
ElfSection section = ElfSection(s.first);
if (!section.ShouldDumpToAOTFile()) {
continue;
}
auto it = sectionToSegment_.find(s.first);
ASSERT(it != sectionToSegment_.end());
ElfSecName segName = it->second;
segments.insert(segName);
if (segmentToMaxOffset.find(segName) == segmentToMaxOffset.end()) {
segmentToMaxOffset[segName] = 0;
}
segmentToMaxOffset[segName] =
std::max(segmentToMaxOffset[segName], sectionToShdr_[s.first].sh_offset + sectionToShdr_[s.first].sh_size);
segmentToMaxAddress[segName] =
std::max(segmentToMaxAddress[segName], sectionToShdr_[s.first].sh_addr + sectionToShdr_[s.first].sh_size);
offset = std::min(offset, sectionToShdr_[s.first].sh_offset);
}
int phdrIndex = 0;
llvm::ELF::Elf64_Addr addr = offset;
for (auto &it: segments) {
ElfSecName name = it;
phdrs[phdrIndex].p_align = PageSize();
phdrs[phdrIndex].p_type = llvm::ELF::PT_LOAD;
phdrs[phdrIndex].p_flags = GetPFlag(name);
offset = AlignUp(offset, PageSize());
phdrs[phdrIndex].p_offset = offset;
phdrs[phdrIndex].p_vaddr = addr % phdrs[phdrIndex].p_align == 0 ?
addr : (addr / phdrs[phdrIndex].p_align + 1) * phdrs[phdrIndex].p_align;
phdrs[phdrIndex].p_paddr = phdrs[phdrIndex].p_vaddr;
phdrs[phdrIndex].p_filesz = segmentToMaxOffset[name] - phdrs[phdrIndex].p_offset;
phdrs[phdrIndex].p_memsz = segmentToMaxAddress[name] - phdrs[phdrIndex].p_vaddr;
phdrs[phdrIndex].p_memsz = AlignUp(phdrs[phdrIndex].p_memsz, PageSize());
addr = phdrs[phdrIndex].p_vaddr + phdrs[phdrIndex].p_memsz;
offset += phdrs[phdrIndex].p_filesz;
++phdrIndex;
}
file.write(reinterpret_cast<char *>(phdrs.get()), sizeof(llvm::ELF::Elf64_Phdr) * segNum);
}
} // namespace panda::ecmascript

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_COMPILER_AOT_FILE_ELF_BUILDER_H
#define ECMASCRIPT_COMPILER_AOT_FILE_ELF_BUILDER_H
#include <map>
#include <set>
#include <utility>
#include <stdint.h>
#include <string>
#include "ecmascript/aot_file_manager.h"
#include "ecmascript/compiler/binary_section.h"
namespace panda::ecmascript {
struct ModuleSectionDes;
class ElfBuilder {
public:
ElfBuilder(ModuleSectionDes sectionDes);
~ElfBuilder();
void PackELFHeader(llvm::ELF::Elf64_Ehdr &header, uint32_t version, Triple triple);
void PackELFSections(std::ofstream &elfFile);
void PackELFSegment(std::ofstream &elfFile);
static bool VerifyELFHeader(const llvm::ELF::Elf64_Ehdr &header, uint32_t version);
static llvm::ELF::Elf64_Word FindShName(std::string name, uintptr_t strTabPtr, int strTabSize);
void SetEnableSecDump(bool flag)
{
enableSecDump_ = flag;
}
private:
llvm::ELF::Elf64_Half GetShStrNdx(std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections) const;
llvm::ELF::Elf64_Half GetSecSize() const;
ElfSecName FindLastSection(ElfSecName segment) const;
int GetSegmentNum() const;
int GetSecNum() const;
unsigned GetPFlag(ElfSecName segment) const;
std::pair<uint64_t, uint32_t> FindStrTab() const;
bool SupportELF();
void AddArkStackMapSection();
void DumpSection() const;
void ModifyStrTabSection();
static constexpr uint32_t TEXT_SEC_ALIGN = 16;
ModuleSectionDes sectionDes_;
std::unique_ptr<char []> strTabPtr_ {nullptr};
std::map<ElfSecName, llvm::ELF::Elf64_Shdr> sectionToShdr_;
std::map<ElfSecName, llvm::ELF::Elf64_Xword> sectionToAlign_;
std::map<ElfSecName, ElfSecName> sectionToSegment_;
std::map<ElfSecName, uintptr_t> sectionToFileOffset_;
std::map<ElfSecName, unsigned> segmentToFlag_;
std::set<ElfSecName> segments_;
bool enableSecDump_ {false};
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_COMPILER_AOT_FILE_ELF_BUILDER_H

View File

@ -0,0 +1,110 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/compiler/aot_file/elf_reader.h"
#include "ecmascript/ecma_macros.h"
#include "securec.h"
namespace panda::ecmascript {
bool ElfReader::VerifyELFHeader(uint32_t version)
{
llvm::ELF::Elf64_Ehdr header = *(reinterpret_cast<llvm::ELF::Elf64_Ehdr *>(fileMapMem_.GetOriginAddr()));
if (header.e_ident[llvm::ELF::EI_MAG0] != llvm::ELF::ElfMagic[llvm::ELF::EI_MAG0]
|| header.e_ident[llvm::ELF::EI_MAG1] != llvm::ELF::ElfMagic[llvm::ELF::EI_MAG1]
|| header.e_ident[llvm::ELF::EI_MAG2] != llvm::ELF::ElfMagic[llvm::ELF::EI_MAG2]
|| header.e_ident[llvm::ELF::EI_MAG3] != llvm::ELF::ElfMagic[llvm::ELF::EI_MAG3]) {
LOG_ECMA(ERROR) << "ELF format error, expected magic is " << llvm::ELF::ElfMagic
<< ", but got " << header.e_ident[llvm::ELF::EI_MAG0] << header.e_ident[llvm::ELF::EI_MAG1]
<< header.e_ident[llvm::ELF::EI_MAG2] << header.e_ident[llvm::ELF::EI_MAG3];
return false;
}
if (header.e_version > version) {
LOG_ECMA(ERROR) << "Elf format error, expected version should be less or equal than "
<< version << ", but got " << header.e_version;
return false;
}
return true;
}
void ElfReader::ParseELFSections(ModuleSectionDes &des, std::vector<ElfSecName> &secs)
{
llvm::ELF::Elf64_Ehdr *ehdr = reinterpret_cast<llvm::ELF::Elf64_Ehdr *>(fileMapMem_.GetOriginAddr());
char *addr = reinterpret_cast<char *>(ehdr);
llvm::ELF::Elf64_Shdr *shdr = reinterpret_cast<llvm::ELF::Elf64_Shdr *>(addr + ehdr->e_shoff);
llvm::ELF::Elf64_Shdr strdr = shdr[ehdr->e_shstrndx];
for (size_t j = 0; j < secs.size(); ++j) {
int secId = -1;
ElfSecName sec = secs[j];
std::string sectionName = ModuleSectionDes::GetSecName(sec);
for (size_t i = 0; i < ehdr->e_shnum; ++i) {
llvm::ELF::Elf64_Word shName = shdr[i].sh_name;
char *curShName = reinterpret_cast<char *>(addr) + shName + strdr.sh_offset;
if (sectionName.compare(curShName) == 0) {
secId = i;
break;
}
}
if (secId == -1) {
LOG_COMPILER(DEBUG) << "sectionName: " << sectionName << " not found in strtab";
continue;
}
ASSERT(secId > 0 && secId < ehdr->e_shnum);
llvm::ELF::Elf64_Shdr secShdr = shdr[secId];
uintptr_t secAddr = reinterpret_cast<uintptr_t>(addr + secShdr.sh_offset);
uint32_t secSize = secShdr.sh_size;
if (sec == ElfSecName::ARK_FUNCENTRY) {
ASSERT((secSize > 0) && (secSize % sizeof(AOTFileInfo::FuncEntryDes) == 0));
}
if (sec == ElfSecName::ARK_STACKMAP) {
des.SetArkStackMapPtr(reinterpret_cast<uint8_t *>(secAddr));
des.SetArkStackMapSize(secSize);
} else {
des.SetSecAddr(secAddr, sec);
des.SetSecSize(secSize, sec);
}
}
}
bool ElfReader::ParseELFSegment()
{
if (fileMapMem_.GetOriginAddr() == nullptr) {
return false;
}
char *addr = reinterpret_cast<char *>(fileMapMem_.GetOriginAddr());
llvm::ELF::Elf64_Ehdr *ehdr = reinterpret_cast<llvm::ELF::Elf64_Ehdr *>(fileMapMem_.GetOriginAddr());
llvm::ELF::Elf64_Phdr *phdr = reinterpret_cast<llvm::ELF::Elf64_Phdr *>(addr + ehdr->e_phoff);
for (int i = 0; i < ehdr->e_phnum; ++i) {
if (phdr[i].p_type != llvm::ELF::PT_LOAD) {
continue;
}
if (phdr[i].p_filesz > phdr[i].p_memsz) {
LOG_COMPILER(ERROR) << " p_filesz:0x" << std::hex << phdr[i].p_filesz << " > p_memsz:0x"
<< phdr[i].p_memsz;
return false;
}
if (!phdr[i].p_filesz) {
continue;
}
unsigned char *virtualAddr = reinterpret_cast<unsigned char *>(addr + phdr[i].p_vaddr);
ASSERT(phdr[i].p_offset % PageSize() == 0);
if ((phdr[i].p_flags & llvm::ELF::PF_X) != 0) {
ASSERT(reinterpret_cast<uintptr_t>(virtualAddr) % PageSize() == 0);
PageProtect(virtualAddr, phdr[i].p_memsz, PAGE_PROT_EXEC_READ);
}
}
return true;
}
} // namespace panda::ecmascript

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_COMPILER_AOT_FILE_ELF_READER_H
#define ECMASCRIPT_COMPILER_AOT_FILE_ELF_READER_H
#include <utility>
#include <stdint.h>
#include <string>
#include "ecmascript/aot_file_manager.h"
#include "ecmascript/compiler/binary_section.h"
namespace panda::ecmascript {
struct ModuleSectionDes;
class ElfReader {
public:
ElfReader(MemMap fileMapMem) : fileMapMem_(fileMapMem) {};
~ElfReader() = default;
bool VerifyELFHeader(uint32_t version);
void ParseELFSections(ModuleSectionDes &des, std::vector<ElfSecName> &secs);
bool ParseELFSegment();
private:
MemMap fileMapMem_ {};
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_COMPILER_AOT_FILE_ELF_READER_H

View File

@ -18,6 +18,12 @@
#include "ecmascript/mem/dyn_chunk.h"
namespace panda::ecmascript {
enum class Triple {
TRIPLE_AMD64,
TRIPLE_AARCH64,
TRIPLE_ARM32,
};
class GCStackMapRegisters {
public:
#if defined(PANDA_TARGET_AMD64)

View File

@ -17,7 +17,9 @@
#define ECMASCRIPT_COMPILER_BINARY_SECTION_H
#include <string>
#include <map>
#include "ecmascript/common.h"
#include "llvm/BinaryFormat/ELF.h"
namespace panda::ecmascript {
enum class ElfSecName : uint8_t {
@ -34,6 +36,8 @@ enum class ElfSecName : uint8_t {
STRTAB,
SYMTAB,
LLVM_STACKMAP,
ARK_FUNCENTRY,
ARK_STACKMAP,
SIZE
};
@ -53,10 +57,12 @@ public:
explicit ElfSection(ElfSecName idx)
{
value_ = idx;
InitShTypeAndFlag();
}
explicit ElfSection(size_t idx)
{
value_ = static_cast<ElfSecName>(idx);
InitShTypeAndFlag();
}
explicit ElfSection(std::string str)
{
@ -84,7 +90,92 @@ public:
value_ = ElfSecName::SYMTAB;
} else if (str.compare(".llvm_stackmaps") == 0) {
value_ = ElfSecName::LLVM_STACKMAP;
} else if (str.compare(".ark_stackmaps") == 0) {
value_ = ElfSecName::ARK_STACKMAP;
} else if (str.compare(".ark_funcentry") == 0) {
value_ = ElfSecName::ARK_FUNCENTRY;
}
InitShTypeAndFlag();
}
bool ShouldDumpToAOTFile() const
{
bool saveForAot = false;
switch (value_) {
case ElfSecName::RODATA:
case ElfSecName::RODATA_CST4:
case ElfSecName::RODATA_CST8:
case ElfSecName::RODATA_CST16:
case ElfSecName::RODATA_CST32:
case ElfSecName::TEXT:
case ElfSecName::DATA:
case ElfSecName::SYMTAB:
case ElfSecName::STRTAB:
case ElfSecName::ARK_FUNCENTRY:
case ElfSecName::ARK_STACKMAP: {
saveForAot = true;
break;
}
default: {
break;
}
}
return saveForAot;
}
ElfSecName Value() const
{
return value_;
}
int Entsize() const
{
if (value_ == ElfSecName::RELATEXT || value_ == ElfSecName::SYMTAB) {
return FIX_SIZE;
}
return 0;
}
int Link() const
{
return value_ == ElfSecName::SYMTAB ? 1 : 0;
}
void InitShTypeAndFlag()
{
std::map<ElfSecName, std::pair<unsigned, unsigned>> nameToTypeAndFlag = {
{ElfSecName::RODATA, std::pair<unsigned, unsigned>(llvm::ELF::SHT_PROGBITS, llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_MERGE)},
{ElfSecName::RODATA_CST4, std::pair<unsigned, unsigned>(llvm::ELF::SHT_PROGBITS, llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_MERGE)},
{ElfSecName::RODATA_CST8, std::pair<unsigned, unsigned>(llvm::ELF::SHT_PROGBITS, llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_MERGE)},
{ElfSecName::RODATA_CST16, std::pair<unsigned, unsigned>(llvm::ELF::SHT_PROGBITS, llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_MERGE)},
{ElfSecName::RODATA_CST32, std::pair<unsigned, unsigned>(llvm::ELF::SHT_PROGBITS, llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_MERGE)},
{ElfSecName::TEXT, std::pair<unsigned, unsigned>(llvm::ELF::SHT_PROGBITS, llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR)},
{ElfSecName::DATA, std::pair<unsigned, unsigned>(llvm::ELF::SHT_PROGBITS, llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE)},
{ElfSecName::GOT, std::pair<unsigned, unsigned>(llvm::ELF::SHT_PROGBITS, llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE)},
{ElfSecName::RELATEXT, std::pair<unsigned, unsigned>(llvm::ELF::SHT_RELA, llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE)},
{ElfSecName::STRTAB, std::pair<unsigned, unsigned>(llvm::ELF::SHT_STRTAB, llvm::ELF::SHF_ALLOC)},
{ElfSecName::SYMTAB, std::pair<unsigned, unsigned>(llvm::ELF::SHT_SYMTAB, llvm::ELF::SHF_ALLOC)},
{ElfSecName::LLVM_STACKMAP, std::pair<unsigned, unsigned>(llvm::ELF::SHT_RELA, llvm::ELF::SHF_ALLOC)},
{ElfSecName::ARK_FUNCENTRY, std::pair<unsigned, unsigned>(llvm::ELF::SHF_WRITE, llvm::ELF::SHF_ALLOC)},
{ElfSecName::ARK_STACKMAP, std::pair<unsigned, unsigned>(llvm::ELF::SHF_WRITE, llvm::ELF::SHF_ALLOC)},
};
auto it = nameToTypeAndFlag.find(value_);
if (it == nameToTypeAndFlag.end()) {
return;
}
ASSERT(it != nameToTypeAndFlag.end());
type_ = it->second.first;
flag_ = it->second.second;
}
unsigned Type() const
{
return type_;
}
unsigned Flag() const
{
return flag_;
}
bool isValidAOTSec() const
@ -115,7 +206,11 @@ public:
return ElfSecName::RODATA <= value_ && value_ <= ElfSecName::RODATA_CST8;
}
private:
static int const FIX_SIZE = 24; // 24:Elf_Rel
ElfSecName value_ {ElfSecName::NONE};
unsigned type_ {0};
unsigned flag_ {0};
static constexpr size_t AOTSecFeatureTable_[static_cast<size_t>(ElfSecName::SIZE)] = {
ElfSecFeature::NOT_VALID,
ElfSecFeature::VALID_AND_SEQUENTIAL,
@ -130,6 +225,7 @@ private:
ElfSecFeature::VALID_AND_SEQUENTIAL,
ElfSecFeature::VALID_AND_SEQUENTIAL,
ElfSecFeature::VALID_NOT_SEQUENTIAL,
ElfSecFeature::VALID_NOT_SEQUENTIAL,
};
};
}

View File

@ -17,6 +17,7 @@
#define ECMASCRIPT_COMPILER_CIRCUIT_BUILDER_H
#include "ecmascript/base/number_helper.h"
#include "ecmascript/compiler/assembler/assembler.h"
#include "ecmascript/compiler/builtins/builtins_call_signature.h"
#include "ecmascript/compiler/circuit.h"
#include "ecmascript/compiler/call_signature.h"
@ -27,7 +28,6 @@
#include "ecmascript/jspandafile/constpool_value.h"
#include "ecmascript/js_hclass.h"
#include "ecmascript/js_tagged_value.h"
#include "ecmascript/platform/elf.h"
#include "ecmascript/tagged_array.h"
namespace panda::ecmascript::kungfu {

View File

@ -1,83 +0,0 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/platform/elf.h"
#include "ecmascript/log_wrapper.h"
#include "securec.h"
#define EI_MAG0 0
#define ELFMAG0 0x7f
#define EI_MAG1 1
#define ELFMAG1 'E'
#define EI_MAG2 2
#define ELFMAG2 'L'
#define EI_MAG3 3
#define ELFMAG3 'F'
#define EI_CLASS 4
#define ELFCLASS64 2
#define EI_DATA 5
#define ELFDATA2LSB 1
#define EI_VERSION 6
#define ET_DYN 3
#define EM_X86_64 62
#define EM_ARM 40
#define EM_AARCH64 183
namespace panda::ecmascript {
void PackELFHeader(Elf64_Ehdr &header, uint32_t version, kungfu::Triple triple)
{
if (memset_s(reinterpret_cast<void *>(&header), sizeof(Elf64_Ehdr), 0, sizeof(Elf64_Ehdr)) != EOK) {
UNREACHABLE();
}
header.e_ident[EI_MAG0] = ELFMAG0;
header.e_ident[EI_MAG1] = ELFMAG1;
header.e_ident[EI_MAG2] = ELFMAG2;
header.e_ident[EI_MAG3] = ELFMAG3;
header.e_ident[EI_CLASS] = ELFCLASS64;
header.e_ident[EI_DATA] = ELFDATA2LSB;
header.e_ident[EI_VERSION] = 1;
header.e_type = ET_DYN;
switch (triple) {
case kungfu::Triple::TRIPLE_AMD64:
header.e_machine = EM_X86_64;
break;
case kungfu::Triple::TRIPLE_ARM32:
header.e_machine = EM_ARM;
break;
case kungfu::Triple::TRIPLE_AARCH64:
header.e_machine = EM_AARCH64;
break;
default:
UNREACHABLE();
break;
}
header.e_version = version;
}
bool VerifyELFHeader([[maybe_unused]] const Elf64_Ehdr &header, [[maybe_unused]] uint32_t version)
{
LOG_ECMA(ERROR) << "Elf is not supported on windows platform";
return false;
}
} // namespace panda::ecmascript

View File

@ -1,60 +0,0 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_PLATFORM_ELF_H
#define ECMASCRIPT_PLATFORM_ELF_H
#include <stdint.h>
#if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS) && !defined(PANDA_TARGET_IOS)
#include <elf.h>
#else
typedef uint16_t Elf64_Half;
typedef uint32_t Elf64_Word;
typedef uint64_t Elf64_Addr;
typedef uint64_t Elf64_Off;
#define EI_NIDENT (16)
typedef struct {
unsigned char e_ident[EI_NIDENT];
Elf64_Half e_type;
Elf64_Half e_machine;
Elf64_Word e_version;
Elf64_Addr e_entry;
Elf64_Off e_phoff;
Elf64_Off e_shoff;
Elf64_Word e_flags;
Elf64_Half e_ehsize;
Elf64_Half e_phentsize;
Elf64_Half e_phnum;
Elf64_Half e_shentsize;
Elf64_Half e_shnum;
Elf64_Half e_shstrndx;
} Elf64_Ehdr;
#endif
namespace panda::ecmascript::kungfu {
enum class Triple {
TRIPLE_AMD64,
TRIPLE_AARCH64,
TRIPLE_ARM32,
};
} // namespace panda::ecmascript::kungfu
namespace panda::ecmascript {
void PackELFHeader(Elf64_Ehdr &header, uint32_t version, kungfu::Triple triple);
bool SupportELF();
bool VerifyELFHeader(const Elf64_Ehdr &header, uint32_t version);
} // namespace panda::ecmascript
#endif // ECMASCRIPT_PLATFORM_ELF_H

View File

@ -22,6 +22,7 @@
#include <winnt.h>
#else
#include <fcntl.h>
#include <dlfcn.h>
#endif
#include <string>

View File

@ -79,6 +79,7 @@ void PUBLIC_API PageUnmap(MemMap it);
MemMap PUBLIC_API MachineCodePageMap(size_t size, int prot = PAGE_PROT_NONE, size_t alignment = 0);
void PUBLIC_API MachineCodePageUnmap(MemMap it);
void PageRelease(void *mem, size_t size);
void PagePreRead(void *mem, size_t size);
void PageTag(void *mem, size_t size, PageTagType type);
void PageClearTag(void *mem, size_t size);
const char *GetPageTagString(PageTagType type);

View File

@ -1,69 +0,0 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/platform/elf.h"
#include "ecmascript/ecma_macros.h"
#include "securec.h"
namespace panda::ecmascript {
void PackELFHeader(Elf64_Ehdr &header, uint32_t version, kungfu::Triple triple)
{
if (memset_s(reinterpret_cast<void *>(&header), sizeof(Elf64_Ehdr), 0, sizeof(Elf64_Ehdr)) != EOK) {
UNREACHABLE();
}
header.e_ident[EI_MAG0] = ELFMAG0;
header.e_ident[EI_MAG1] = ELFMAG1;
header.e_ident[EI_MAG2] = ELFMAG2;
header.e_ident[EI_MAG3] = ELFMAG3;
header.e_ident[EI_CLASS] = ELFCLASS64;
header.e_ident[EI_DATA] = ELFDATA2LSB;
header.e_ident[EI_VERSION] = 1;
header.e_type = ET_DYN;
switch (triple) {
case kungfu::Triple::TRIPLE_AMD64:
header.e_machine = EM_X86_64;
break;
case kungfu::Triple::TRIPLE_ARM32:
header.e_machine = EM_ARM;
break;
case kungfu::Triple::TRIPLE_AARCH64:
header.e_machine = EM_AARCH64;
break;
default:
UNREACHABLE();
break;
}
header.e_version = version;
}
bool VerifyELFHeader(const Elf64_Ehdr &header, uint32_t version)
{
if (header.e_ident[EI_MAG0] != ELFMAG0 || header.e_ident[EI_MAG1] != ELFMAG1 ||
header.e_ident[EI_MAG2] != ELFMAG2 || header.e_ident[EI_MAG3] != ELFMAG3) {
LOG_ECMA(ERROR) << "ELF format error, expected magic is " << ELFMAG
<< ", but got " << header.e_ident[EI_MAG0] << header.e_ident[EI_MAG1]
<< header.e_ident[EI_MAG2] << header.e_ident[EI_MAG3];
return false;
}
if (header.e_version > version) {
LOG_ECMA(ERROR) << "Elf format error, expected version should be less or equal than "
<< version << ", but got " << header.e_version;
return false;
}
return true;
}
} // namespace panda::ecmascript

View File

@ -69,6 +69,11 @@ void PageRelease(void *mem, size_t size)
madvise(mem, size, MADV_DONTNEED);
}
void PagePreRead(void *mem, size_t size)
{
madvise(mem, size, MADV_WILLNEED);
}
void PageTag(void *mem, size_t size, PageTagType type)
{
const char *tag = GetPageTagString(type);

View File

@ -83,6 +83,10 @@ void PageRelease([[maybe_unused]] void *mem, [[maybe_unused]] size_t size)
{
}
void PagePreRead([[maybe_unused]] void *mem, [[maybe_unused]] size_t size)
{
}
void PageTag([[maybe_unused]] void *mem, [[maybe_unused]] size_t size, [[maybe_unused]] PageTagType type)
{
}