diff --git a/lld/ELF/Adlt/Arch/AArch64.cpp b/lld/ELF/Adlt/Arch/AArch64.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c88a1e25a9be63bd7e2959e3c41409f72208a177 --- /dev/null +++ b/lld/ELF/Adlt/Arch/AArch64.cpp @@ -0,0 +1,67 @@ +//===- Adlt/Arch/AArch64.h --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// OHOS_LOCAL begin +#include "Adlt/Arch/AArch64.h" +#include "llvm/Support/Endian.h" + +#include "Target.h" + +using namespace llvm; +using namespace llvm::support::endian; +using namespace llvm::ELF; + +using namespace lld; +using namespace lld::elf; + +void AdltInfoAArch64::deRelocate(uint8_t *loc, const Relocation &rel, + uint64_t *val) const { + switch (rel.type) { + case R_AARCH64_JUMP26: + case R_AARCH64_CALL26: + case R_AARCH64_CONDBR19: + case R_AARCH64_LD_PREL_LO19: + case R_AARCH64_MOVW_UABS_G0_NC: + case R_AARCH64_MOVW_UABS_G1_NC: + case R_AARCH64_MOVW_UABS_G2_NC: + case R_AARCH64_MOVW_UABS_G3: + case R_AARCH64_TSTBR14: + orClear32le(loc); + break; + case R_AARCH64_ADD_ABS_LO12_NC: + case R_AARCH64_LDST8_ABS_LO12_NC: + case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: + case R_AARCH64_LDST16_ABS_LO12_NC: + case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: + case R_AARCH64_LDST32_ABS_LO12_NC: + case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: + case R_AARCH64_LDST64_ABS_LO12_NC: + case R_AARCH64_ADR_GOT_PAGE: + case R_AARCH64_LD64_GOT_LO12_NC: + case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: + case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: + case R_AARCH64_TLSDESC_LD64_LO12: + case R_AARCH64_LDST128_ABS_LO12_NC: + case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC: + case R_AARCH64_LD64_GOTPAGE_LO15: + case R_AARCH64_TLSLE_ADD_TPREL_HI12: + case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12: + orClearAArch64Imm(loc); + break; + } +} + +void AdltInfoAArch64::orClear32le(uint8_t *loc) const { + write32le(loc, read32le(loc) & ~((1 << 26) - 1)); +} +void AdltInfoAArch64::orClearAArch64Imm(uint8_t *loc) const { + write32le(loc, read32le(loc) & ~(0xFFF << 10)); +} + +// OHOS_LOCAL end diff --git a/lld/ELF/Adlt/Arch/AArch64.h b/lld/ELF/Adlt/Arch/AArch64.h new file mode 100644 index 0000000000000000000000000000000000000000..58a7a2dc57e28d2913508135508f0ed094b41c0d --- /dev/null +++ b/lld/ELF/Adlt/Arch/AArch64.h @@ -0,0 +1,33 @@ +//===- Adlt/Arch/AArch64.h --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// OHOS_LOCAL begin +#ifndef LLD_ELF_ADLT_ARCH_AARCH64_H +#define LLD_ELF_ADLT_ARCH_AARCH64_H + +#include + +namespace lld { +namespace elf { + +struct Relocation; + +class AdltInfoAArch64 { +public: + void deRelocate(uint8_t *loc, const Relocation &rel, uint64_t *val) const; + +private: + void orClear32le(uint8_t *loc) const; + void orClearAArch64Imm(uint8_t *loc) const; +}; + +} // namespace elf +} // namespace lld + +#endif // LLD_ELF_ADLT_ARCH_AARCH64_H +// OHOS_LOCAL end diff --git a/lld/ELF/Adlt.cpp b/lld/ELF/Adlt/Context.cpp similarity index 77% rename from lld/ELF/Adlt.cpp rename to lld/ELF/Adlt/Context.cpp index b3d8f4f56e797c0de62b39ddb1d5cb9591330218..fa14bbf7d551baab4a24ea90aa2671a28d839a07 100644 --- a/lld/ELF/Adlt.cpp +++ b/lld/ELF/Adlt/Context.cpp @@ -1,4 +1,4 @@ -//===- Adlt.cpp -------------------------------------------------*- C++ -*-===// +//===- Adlt/Context.cpp -----------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,10 +7,10 @@ //===----------------------------------------------------------------------===// // OHOS_LOCAL begin -#include "Adlt.h" +#include "Adlt/Context.h" #include "llvm/Support/Casting.h" -#include "InputFiles.h" +#include "Adlt/InputFiles.h" using namespace llvm; @@ -30,6 +30,14 @@ SharedFileExtended *AdltCtx::getSoExt(size_t orderId) { return cast>(sharedFilesExtended[orderId]); } +template void AdltCtx::parseFile(InputFile *file) { + auto *f = cast>(file); + assert(f && "ADLT: Failed to parse .so file!"); + f->orderIdx = sharedFilesExtended.size(); + sharedFilesExtended.push_back(f); + f->parse(); +} + template void AdltCtx::buildSymbolsHist(std::vector &files) { for (auto *file : files) @@ -46,12 +54,17 @@ void AdltCtx::scanDuplicatedSymbols() { symNamesHist.clear(); } -// TODO: inherit from SharedFile +// TODO: inherit from SharedFile and remove it template SharedFileExtended *AdltCtx::getSoExt(InputFile *); template SharedFileExtended *AdltCtx::getSoExt(InputFile *); template SharedFileExtended *AdltCtx::getSoExt(InputFile *); template SharedFileExtended *AdltCtx::getSoExt(InputFile *); +template void AdltCtx::parseFile(InputFile *); +template void AdltCtx::parseFile(InputFile *); +template void AdltCtx::parseFile(InputFile *); +template void AdltCtx::parseFile(InputFile *); + template SharedFileExtended *AdltCtx::getSoExt(size_t); template SharedFileExtended *AdltCtx::getSoExt(size_t); template SharedFileExtended *AdltCtx::getSoExt(size_t); diff --git a/lld/ELF/Adlt.h b/lld/ELF/Adlt/Context.h similarity index 84% rename from lld/ELF/Adlt.h rename to lld/ELF/Adlt/Context.h index b6751cf54607edaea0a222f7e3386cff7cfc8487..0d1fbb9b0ad5a4e02b6c9db7083e5b9bd661c537 100644 --- a/lld/ELF/Adlt.h +++ b/lld/ELF/Adlt/Context.h @@ -1,4 +1,4 @@ -//===- Adlt.h -------------------------------------------------*- C++ -*-===// +//===- Adlt/Context.h -------------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// // OHOS_LOCAL begin -#ifndef LLD_ELF_ADLT_H -#define LLD_ELF_ADLT_H +#ifndef LLD_ELF_ADLT_CONTEXT_H +#define LLD_ELF_ADLT_CONTEXT_H #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/SetVector.h" @@ -33,6 +33,8 @@ public: void scanDuplicatedSymbols(); + template void parseFile(InputFile *file); + template void buildSymbolsHist(std::vector &files); template SharedFileExtended *getSoExt(InputFile *file); @@ -41,6 +43,8 @@ public: llvm::SetVector commonProgramHeaders; bool withCfi = false; + bool withRelr = false; + bool withAndroidRela = false; // From input .rela.dyn, .rela.plt: // Keep input library indexes that are needed for got/plt symbol @@ -58,5 +62,5 @@ extern std::unique_ptr adltCtx; } // namespace elf } // namespace lld -#endif // LLD_ELF_ADLT_H +#endif // LLD_ELF_ADLT_CONTEXT_H // OHOS_LOCAL end diff --git a/lld/ELF/Adlt/InputFiles.cpp b/lld/ELF/Adlt/InputFiles.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a931acca121b4ce9df49b0db9213ebfeaed2acfd --- /dev/null +++ b/lld/ELF/Adlt/InputFiles.cpp @@ -0,0 +1,568 @@ +//===- Adlt/InputFiles.cpp ----------------------------------------*- C++ +//-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// OHOS_LOCAL begin +#include "Adlt/InputFiles.h" + +#include "lld/Common/DWARF.h" // TODO remove it from here + +#include "InputSection.h" +#include "SymbolTable.h" +#include "Symbols.h" +#include "SyntheticSections.h" +#include "Target.h" + +using namespace llvm; +using namespace llvm::ELF; +using namespace llvm::object; +using namespace llvm::sys; +using namespace llvm::sys::fs; +using namespace llvm::support::endian; +using namespace lld; +using namespace lld::elf; + +namespace { +// taken from ELF/InputFiles.cpp +// TODO cleanup +template +SmallVector parseVerdefs(const uint8_t *base, + const typename ELFT::Shdr *sec) { + if (!sec) + return {}; + + // Build the Verdefs array by following the chain of Elf_Verdef objects + // from the start of the .gnu.version_d section. + SmallVector verdefs; + const uint8_t *verdef = base + sec->sh_offset; + for (unsigned i = 0, e = sec->sh_info; i != e; ++i) { + auto *curVerdef = reinterpret_cast(verdef); + verdef += curVerdef->vd_next; + unsigned verdefIndex = curVerdef->vd_ndx; + if (verdefIndex >= verdefs.size()) + verdefs.resize(verdefIndex + 1); + verdefs[verdefIndex] = curVerdef; + } + return verdefs; +} +// taken from ELF/InputFiles.cpp +// TODO cleanup +template +const Elf_Shdr *findSection(ArrayRef sections, uint32_t type) { + for (const Elf_Shdr &sec : sections) + if (sec.sh_type == type) + return &sec; + return nullptr; +} + +// taken from ELF/InputFiles.cpp +// TODO cleanup +ELFKind getELFKind(MemoryBufferRef mb, StringRef archiveName) { + unsigned char size; + unsigned char endian; + std::tie(size, endian) = getElfArchType(mb.getBuffer()); + + auto report = [&](StringRef msg) { + StringRef filename = mb.getBufferIdentifier(); + if (archiveName.empty()) + fatal(filename + ": " + msg); + else + fatal(archiveName + "(" + filename + "): " + msg); + }; + + if (!mb.getBuffer().startswith(ElfMagic)) + report("not an ELF file"); + if (endian != ELFDATA2LSB && endian != ELFDATA2MSB) + report("corrupted ELF file: invalid data encoding"); + if (size != ELFCLASS32 && size != ELFCLASS64) + report("corrupted ELF file: invalid file class"); + + size_t bufSize = mb.getBuffer().size(); + if ((size == ELFCLASS32 && bufSize < sizeof(Elf32_Ehdr)) || + (size == ELFCLASS64 && bufSize < sizeof(Elf64_Ehdr))) + report("corrupted ELF file: file is too short"); + + if (size == ELFCLASS32) + return (endian == ELFDATA2LSB) ? ELF32LEKind : ELF32BEKind; + return (endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind; +} + +// taken from ELF/InputFiles.cpp +// TODO cleanup +template +uint64_t getAlignment(ArrayRef sections, + const typename ELFT::Sym &sym) { + uint64_t ret = UINT64_MAX; + if (sym.st_value) + ret = 1ULL << countTrailingZeros((uint64_t)sym.st_value); + if (0 < sym.st_shndx && sym.st_shndx < sections.size()) + ret = std::min(ret, sections[sym.st_shndx].sh_addralign); + return (ret > UINT32_MAX) ? 0 : ret; +} + +} // namespace + +template +SharedFileExtended::SharedFileExtended(MemoryBufferRef mb, + StringRef soName) + : ObjFile(InputFile::SharedKind, mb, soName), soName(soName) {} + +template +bool SharedFileExtended::classof(const InputFile *f) { + return f->kind() == InputFile::SharedKind; +} + +template void SharedFileExtended::buildSymbolsHist() { + ArrayRef eSyms = this->template getELFSyms(); + for (size_t i = this->firstGlobal, end = eSyms.size(); i != end; ++i) { + if (!eSyms[i].isDefined()) + continue; + StringRef name = CHECK(eSyms[i].getName(this->stringTable), this); + adltCtx->symNamesHist[CachedHashStringRef(name)]++; + } +} + +template +bool SharedFileExtended::isValidSection(InputSectionBase *s) const { + if (!s || s == &InputSection::discarded) + return false; + uint32_t type = s->type; + StringRef name = s->name; + + bool isBaseType = type == SHT_NOBITS || type == SHT_NOTE || + type == SHT_INIT_ARRAY || type == SHT_FINI_ARRAY; + // TODO: fix .debug-* sections relocation + // TODO: rename sections at outputStage. + bool isNeededProgBits = + type == SHT_PROGBITS && + !(name.startswith(".got") || name.startswith(".plt") || + name.startswith(".eh_frame_hdr") || name.startswith(".debug_")); + bool ret = isBaseType || isNeededProgBits; + return ret; +} + +template +bool SharedFileExtended::isDynamicSection(InputSectionBase *s) const { + // TODO: rename sections at outputStage. + return s->type == llvm::ELF::SHT_NULL || s->name.startswith(".got.plt"); +} + +template +void SharedFileExtended::parse(bool ignoreComdats) { + ObjFile::parse(ignoreComdats); + parseDynamics(); + parseElfSymTab(); +} + +template void SharedFileExtended::postParse() { + ObjFile::initializeLocalSymbols(); + ObjFile::postParse(); +} + +template +StringRef SharedFileExtended::getUniqueName(StringRef input) const { + if (input.empty()) + return input; + auto suffix = Twine("__") + Twine::utohexstr(this->orderIdx); + return saver().save(input + suffix); +} + +template +Defined &SharedFileExtended::getDefinedLocalSym(uint64_t offset) { + auto getSym = [&](unsigned offs) { + return localSymbols[this->definedSymbolsMap[offs]]; + }; + auto *s = getSym(offset); + if (!s || s == localSymbols[0]) { + auto sec = findSection(offset); + s = getSym(sec->address); + } + assert(s && s->isDefined()); + return cast(*s); +} + +template +InputSectionBase &SharedFileExtended::getSection(uint64_t offset) { + auto *sec = this->sections[this->sectionsMap[offset]]; + if (offset && sec->type == SHT_NULL) + sec = findSection(offset); + return *sec; +} + +template +InputSectionBase &SharedFileExtended::getSectionByOrder(size_t idx) { + auto *sec = this->sections[idx]; + if (!sec) + sec = &InputSection::discarded; + return *sec; +} + +template +InputSectionBase *SharedFileExtended::findSection(uint64_t offset) { + llvm::SmallVector candidates; + for (InputSectionBase *sec : this->sections) { + if (!sec) + continue; + auto low = sec->address; + auto high = low + sec->size; + if (offset >= low && offset < high) + candidates.push_back(sec); + } + if (candidates.empty()) // no suitable items found + return nullptr; + llvm::sort(candidates, + [](auto *a, auto *b) { return a->address < b->address; }); + return *candidates.begin(); +} + +template +Symbol &SharedFileExtended::getDynamicSymbol(size_t symbolIndex) const { + return *this->symbols[symbolIndex]; +} +template +Symbol &SharedFileExtended::getLocalSymbol(size_t symbolIndex) const { + assert(symbolIndex && (symbolIndex < localSymbols.size())); + return *localSymbols[symbolIndex]; +} + +template +Symbol &SharedFileExtended::getSymbol(size_t symbolIndex, + bool fromDynamic) { + if (!symbolIndex) + return *localSymbols[0]; + /* TODO + if (symbolIndex > static_cast(symTabFirstGlobal)) + return getDynamicSymbol(symbolIndex - (symTabFirstGlobal + 1)); + return fromDynamic ? getDynamicSymbol(symbolIndex) + : getLocalSymbol(symbolIndex); */ + + Symbol &sym = + fromDynamic ? getDynamicSymbol(symbolIndex) : getLocalSymbol(symbolIndex); + StringRef name = sym.getName(); + if (name.empty()) + return sym; + // check SymbolTable + auto res = elf::symtab->find(name); + if (res && (res->exportDynamic || res->versionId)) + return *res; + + // check SymbolTableBaseSection + auto found = llvm::find_if(in.symTab->getSymbols(), + [&](const SymbolTableEntry &entry) { + return entry.sym->getName() == name; + }); + // add a local sym if it was not previously added + if (found == in.symTab->getSymbols().end()) + in.symTab->addSymbol(&sym); + return sym; +} + +template +ArrayRef SharedFileExtended::getLocalSymbols() { + assert(!localSymbols.empty()); + return llvm::makeArrayRef(localSymbols).slice(0, symTabFirstGlobal); +} + +template void SharedFileExtended::parseDynamics() { + const ELFFile obj = this->getObj(); + ArrayRef sections = this->template getELFShdrs(); + + ArrayRef dynamicTags; + const Elf_Shdr *versymSec = nullptr; + const Elf_Shdr *verdefSec = nullptr; + const Elf_Shdr *verneedSec = nullptr; + + // parse external lib deps + int secIdx = 0; + for (const Elf_Shdr &sec : sections) { + switch (sec.sh_type) { + case SHT_DYNAMIC: + dynamicTags = + CHECK(obj.template getSectionContentsAsArray(sec), this); + break; + case SHT_DYNSYM: + dynSymSecIdx = secIdx; + break; + case SHT_SYMTAB: + symTabSecIdx = secIdx; + break; + case SHT_SYMTAB_SHNDX: + symTabShndxSecIdx = secIdx; + break; + case SHT_RELR: + if (config->adltTrace && !adltCtx->withRelr) + lld::outs() << "[ADLT] RELR packing mode is ON\n"; + adltCtx->withRelr = true; + relrDynSec = &sec; + break; + case SHT_ANDROID_RELA: + if (config->adltTrace && !adltCtx->withAndroidRela) + lld::outs() << "[ADLT] ANDROID_RELA packing mode is ON\n"; + adltCtx->withAndroidRela = true; + andrPackSec = &sec; + break; + case SHT_GNU_versym: + versymSec = &sec; + break; + case SHT_GNU_verdef: + verdefSec = &sec; + break; + case SHT_GNU_verneed: + verneedSec = &sec; + break; + } + auto secName = check(this->getObj().getSectionName(sec)); + if (secName == ".got.plt") + gotPltSecIdx = secIdx; + secIdx++; + } + + if (versymSec && this->numELFSyms == 0) { + error("SHT_GNU_versym should be associated with symbol table"); + return; + } + + // Search for a DT_SONAME tag to initialize this->soName. + for (const Elf_Dyn &dyn : dynamicTags) { + if (dyn.d_tag == DT_NEEDED) { + uint64_t val = dyn.getVal(); + if (val >= this->stringTable.size()) + fatal(toString(this) + ": invalid DT_NEEDED entry"); + dtNeeded.push_back(this->stringTable.data() + val); + } else if (dyn.d_tag == DT_SONAME) { + uint64_t val = dyn.getVal(); + if (val >= this->stringTable.size()) + fatal(toString(this) + ": invalid DT_SONAME entry"); + soName = this->stringTable.data() + val; + } + } + + verdefs = parseVerdefs(obj.base(), verdefSec); + std::vector verneeds = parseVerneed(obj, verneedSec); + + // Parse ".gnu.version" section which is a parallel array for the symbol + // table. If a given file doesn't have a ".gnu.version" section, we use + // VER_NDX_GLOBAL. + size_t size = this->numELFSyms - this->firstGlobal; + std::vector versyms(size, VER_NDX_GLOBAL); + if (versymSec) { + ArrayRef versym = + CHECK(obj.template getSectionContentsAsArray(*versymSec), + this) + .slice(this->firstGlobal); + for (size_t i = 0; i < size; ++i) + versyms[i] = versym[i].vs_index; + } + + // System libraries can have a lot of symbols with versions. Using a + // fixed buffer for computing the versions name (foo@ver) can save a + // lot of allocations. + SmallString<0> versionedNameBuffer; + + // Add symbols to the symbol table. + SymbolTable &symtab = *elf::symtab; + ArrayRef syms = this->template getGlobalELFSyms(); + for (size_t i = 0, e = syms.size(); i != e; ++i) { + const Elf_Sym &sym = syms[i]; + + // ELF spec requires that all local symbols precede weak or global + // symbols in each symbol table, and the index of first non-local symbol + // is stored to sh_info. If a local symbol appears after some non-local + // symbol, that's a violation of the spec. + StringRef name = CHECK(sym.getName(this->stringTable), this); + // Add postfix for defined duplicates. + if (config->adlt && sym.isDefined() && + adltCtx->duplicatedSymNames.count(CachedHashStringRef(name)) != 0) + name = getUniqueName(name); // TODO: add unique for output only + + if (sym.getBinding() == STB_LOCAL) { + warn("found local symbol '" + name + + "' in global part of symbol table in file " + toString(this)); + continue; + } + + uint16_t idx = versyms[i] & ~VERSYM_HIDDEN; + if (sym.isUndefined()) { + // For unversioned undefined symbols, VER_NDX_GLOBAL makes more sense but + // as of binutils 2.34, GNU ld produces VER_NDX_LOCAL. + if (idx != VER_NDX_LOCAL && idx != VER_NDX_GLOBAL) { + if (idx >= verneeds.size()) { + error("corrupt input file: version need index " + Twine(idx) + + " for symbol " + name + " is out of bounds\n>>> defined in " + + toString(this)); + continue; + } + StringRef verName = this->stringTable.data() + verneeds[idx]; + versionedNameBuffer.clear(); + name = saver().save( + (name + "@" + verName).toStringRef(versionedNameBuffer)); + } + Symbol *s = symtab.addSymbol( + Undefined{this, name, sym.getBinding(), sym.st_other, sym.getType()}); + s->exportDynamic = true; + if (s->isUndefined() && sym.getBinding() != STB_WEAK && + config->unresolvedSymbolsInShlib != UnresolvedPolicy::Ignore) + requiredSymbols.push_back(s); + continue; + } + // MIPS BFD linker puts _gp_disp symbol into DSO files and incorrectly + // assigns VER_NDX_LOCAL to this section global symbol. Here is a + // workaround for this bug. + if (config->emachine == EM_MIPS && idx == VER_NDX_LOCAL && + name == "_gp_disp") + continue; + + uint32_t alignment = getAlignment(sections, sym); + if (!(versyms[i] & VERSYM_HIDDEN)) { + auto *s = symtab.addSymbol( + SharedSymbol{*this, name, sym.getBinding(), sym.st_other, + sym.getType(), sym.st_value, sym.st_size, alignment}); + if (s->file == this) + s->verdefIndex = idx; + } + + // Also add the symbol with the versioned name to handle undefined symbols + // with explicit versions. + if (idx == VER_NDX_GLOBAL) + continue; + + if (idx >= verdefs.size() || idx == VER_NDX_LOCAL) { + error("corrupt input file: version definition index " + Twine(idx) + + " for symbol " + name + " is out of bounds\n>>> defined in " + + toString(this)); + continue; + } + + StringRef verName = + this->stringTable.data() + + reinterpret_cast(verdefs[idx])->getAux()->vda_name; + versionedNameBuffer.clear(); + name = (name + "@" + verName).toStringRef(versionedNameBuffer); + auto *s = symtab.addSymbol( + SharedSymbol{*this, saver().save(name), sym.getBinding(), sym.st_other, + sym.getType(), sym.st_value, sym.st_size, alignment}); + if (s->file == this) + s->verdefIndex = idx; + } +} + +template void SharedFileExtended::parseElfSymTab() { + const ELFFile obj = this->getObj(); + ArrayRef eSections = this->template getELFShdrs(); + + // Find a symbol table. + const Elf_Shdr *eSymtabSec = ::findSection(eSections, SHT_SYMTAB); + if (!eSymtabSec) + return; + + symTabFirstGlobal = eSymtabSec->sh_info; + + ArrayRef eSyms = CHECK(obj.symbols(eSymtabSec), this); + auto numESyms = uint32_t(eSyms.size()); + auto eStringTable = + CHECK(obj.getStringTableForSymtab(*eSymtabSec, eSections), this); + this->localSymbols.resize(numESyms); + + for (size_t i = 0; i < numESyms; i++) { + const Elf_Sym &eSym = eSyms[i]; + StringRef name(eStringTable.data() + eSym.st_name); + auto bind = eSym.getBinding(); + auto type = eSym.getType(); + auto other = eSym.st_other; + if (eSym.isDefined()) { + auto secIdx = eSym.st_shndx; + if (LLVM_UNLIKELY(secIdx == SHN_XINDEX)) + secIdx = check( + getExtendedSymbolTableIndex(eSym, i, this->getShndxTable())); + else if (secIdx >= SHN_LORESERVE) + secIdx = 0; + auto p = obj.getSection(secIdx); + if (p.takeError()) { + fatal("getSection failed: " + llvm::toString(p.takeError())); + } + const Elf_Shdr *eSec = *p; + InputSectionBase *sec = this->sections[secIdx]; + auto val = eSym.st_value; + if (type != STT_TLS) + val -= eSec->sh_addr; + auto dynSym = llvm::find_if(this->symbols, [=](const Symbol *s) { + return s && s->getName() == name; + }); + bool isInDynSym = dynSym != this->symbols.end(); + if (!isInDynSym) + name = getUniqueName(name); // TODO: add unique for output only + /*if (name == "TLS_data1") // debug hint + lld::outs() << name << '\n'; */ + this->localSymbols[i] = + make(this, name, bind, other, type, val, eSym.st_size, sec); + this->definedSymbolsMap[eSym.st_value] = i; + } else { + this->localSymbols[i] = make(this, name, bind, other, type, + /*discardedSecIdx=*/i); + } + } +} + +template +std::vector SharedFileExtended::parseVerneed(const ELFFile &obj, + const typename ELFT::Shdr *sec) { + if (!sec) + return {}; + std::vector verneeds; + ArrayRef data = CHECK(obj.getSectionContents(*sec), this); + const uint8_t *verneedBuf = data.begin(); + for (unsigned i = 0; i != sec->sh_info; ++i) { + if (verneedBuf + sizeof(typename ELFT::Verneed) > data.end()) + fatal(toString(this) + " has an invalid Verneed"); + auto *vn = reinterpret_cast(verneedBuf); + const uint8_t *vernauxBuf = verneedBuf + vn->vn_aux; + for (unsigned j = 0; j != vn->vn_cnt; ++j) { + if (vernauxBuf + sizeof(typename ELFT::Vernaux) > data.end()) + fatal(toString(this) + " has an invalid Vernaux"); + auto *aux = reinterpret_cast(vernauxBuf); + if (aux->vna_name >= this->stringTable.size()) + fatal(toString(this) + " has a Vernaux with an invalid vna_name"); + uint16_t version = aux->vna_other & VERSYM_VERSION; + if (version >= verneeds.size()) + verneeds.resize(version + 1); + verneeds[version] = aux->vna_name; + vernauxBuf += aux->vna_next; + } + verneedBuf += vn->vn_next; + } + return verneeds; +} + +ELFFileBase *elf::createSharedFileExtended(MemoryBufferRef mb, + StringRef soName) { + ELFFileBase *f; + switch (getELFKind(mb, soName)) { + case ELF32LEKind: + f = make>(mb, soName); + break; + case ELF32BEKind: + f = make>(mb, soName); + break; + case ELF64LEKind: + f = make>(mb, soName); + break; + case ELF64BEKind: + f = make>(mb, soName); + break; + default: + llvm_unreachable("getELFKind"); + } + return f; +} + +template class elf::SharedFileExtended; +template class elf::SharedFileExtended; +template class elf::SharedFileExtended; +template class elf::SharedFileExtended; + +// OHOS_LOCAL end diff --git a/lld/ELF/Adlt/InputFiles.h b/lld/ELF/Adlt/InputFiles.h new file mode 100644 index 0000000000000000000000000000000000000000..e360e7b2013182f01f6eb9829b5ef52d9f476cbd --- /dev/null +++ b/lld/ELF/Adlt/InputFiles.h @@ -0,0 +1,124 @@ +//===- Adlt/InputFiles.h ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// OHOS_LOCAL begin +#ifndef LLD_ELF_ADLT_INPUT_FILES_H +#define LLD_ELF_ADLT_INPUT_FILES_H + +// #include "llvm/Object/ELF.h" +// #include "llvm/Support/MemoryBufferRef.h" +#include "../InputFiles.h" // TODO: remove it +// TODO: remove the inheritance from ObjFile and overriding methods + +namespace lld { +namespace elf { + +class InputSectionBase; +struct PhdrEntry; + +// .so file +// TODO: Inherit from SharedFile or keep only unique API here. +template class SharedFileExtended : public ObjFile { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + +public: + SharedFileExtended(llvm::MemoryBufferRef mb, llvm::StringRef soName); + + static bool classof(const InputFile *f); + void buildSymbolsHist() override; + bool isValidSection(InputSectionBase *s) const override; + bool isDynamicSection(InputSectionBase *s) const; + + void parse(bool ignoreComdats = false) override; + void postParse() override; + + Defined &getDefinedLocalSym(uint64_t offset); + + InputSectionBase &getSection(uint64_t offset); + InputSectionBase &getSectionByOrder(size_t idx); + InputSectionBase *findSection(uint64_t offset); + + // TODO move to *.cpp + template Symbol &getRelocTargetSym(const RelT &rel) { + uint32_t symIndex = rel.getSymbol(config->isMips64EL); + return getSymbol(symIndex, false); + } + + Symbol &getDynamicSymbol(size_t symbolIndex) const; + Symbol &getLocalSymbol(size_t symbolIndex) const; + Symbol &getSymbol(size_t symbolIndex, bool fromDynamic); + + llvm::ArrayRef getLocalSymbols() override; + +public: + // the input order of the file as it presented in ADLT image + size_t orderIdx = 0; + int dynSymSecIdx = 0; + int symTabSecIdx = 0; + int symTabShndxSecIdx = 0; + int symTabFirstGlobal = 0; + int gotPltSecIdx = 0; + + // .symtab's start of local symbols owned by library + llvm::Optional sharedLocalSymbolIndex; + // .symtab's start of global symbols owned by library + llvm::Optional sharedGlobalSymbolIndex; + + // related to relr and android_rela sections + const Elf_Shdr *relrDynSec = nullptr; + const Elf_Shdr *andrPackSec = nullptr; + + // Output information data: + llvm::SetVector programHeaders; + + // From input .rela.dyn, .rela.plt: + llvm::SetVector + relrDynIndexes; // only Relative relocs (if .relr.dyn exists) + llvm::SetVector + relaDynIndexes; // If not .relr.dyn exists, contains only Got/Abs/Tls + // relocs. Otherwise contains relative relocs also. + llvm::SetVector relaPltIndexes; // .got.plt relocs + + // SharedFile compability layer: + // This is actually a vector of Elf_Verdef pointers. + llvm::SmallVector verdefs; + // If the output file needs Elf_Verneed data structures for this file, this is + // a vector of Elf_Vernaux version identifiers that map onto the entries in + // Verdefs, otherwise it is empty. + llvm::SmallVector vernauxs; + static unsigned vernauxNum; + llvm::SmallVector dtNeeded; + llvm::StringRef soName; + llvm::StringRef simpleSoName; + // Used for --as-needed + // bool isNeeded; + // Non-weak undefined symbols which are not yet resolved when the SO is + // parsed. Only filled for `--no-allow-shlib-undefined`. + llvm::SmallVector requiredSymbols; + + // TODO: add unique for output only + llvm::StringRef getUniqueName(llvm::StringRef origName) const override; + +private: + llvm::SmallVector localSymbols; + + void parseDynamics(); // SharedFile compability + void parseElfSymTab(); // ObjectFile compability + + std::vector parseVerneed(const llvm::object::ELFFile &obj, + const typename ELFT::Shdr *sec); +}; + +ELFFileBase *createSharedFileExtended(llvm::MemoryBufferRef mb, + llvm::StringRef soName = ""); + +} // namespace elf +} // namespace lld + +#endif // LLD_ELF_ADLT_INPUT_FILES_H +// OHOS_LOCAL end diff --git a/lld/ELF/Adlt/Relocations.cpp b/lld/ELF/Adlt/Relocations.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d2481ba71709a3d1eddcb31e38a7ef9779bfb19 --- /dev/null +++ b/lld/ELF/Adlt/Relocations.cpp @@ -0,0 +1,220 @@ +//===- Adlt/Relocations.cpp -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// OHOS_LOCAL begin + +#include "Adlt/Relocations.h" +#include "Adlt/Context.h" + +#include "InputFiles.h" +#include "InputSection.h" +#include "SyntheticSections.h" +#include "Target.h" + +using namespace llvm; +using namespace llvm::ELF; +using namespace llvm::object; + +using namespace lld; +using namespace lld::elf; + +template +AdltRelocationScanner::AdltRelocationScanner(InputSectionBase &isec, + bool isRelr) + : file(adltCtx->getSoExt(isec.file)), + fromDynamic(file->isDynamicSection(&isec)), sec(isec), isRelr(isRelr) {} + +template +Symbol &AdltRelocationScanner::getSymbol(unsigned idx) { + return file->getSymbol(idx, fromDynamic); +} + +template +void AdltRelocationScanner::trackGotPlt(Symbol *sym) { + adltCtx->gotPltInfo[sym].push_back(file->orderIdx); +} + +template void AdltRelocationScanner::trackRelatives() { + auto count = isRelr ? mainPart->relrDyn->relocs.size() + : mainPart->relaDyn->relocs.size(); + (isRelr ? file->relrDynIndexes : file->relaDynIndexes).insert(count - 1); +} + +template void AdltRelocationScanner::trackDynamics() { + auto count = mainPart->relaDyn->relocs.size(); + file->relaDynIndexes.insert(count - 1); +} + +template bool AdltRelocationScanner::isScanPackedNeeded() { + return sec.type == SHT_NULL && + (adltCtx->withRelr || adltCtx->withAndroidRela); +} + +template +std::vector AdltRelocationScanner::scanRelr() { + auto *shdr = file->relrDynSec; + if (!shdr) + return {}; + auto obj = file->getObj(); + auto raw = cantFail(obj.relrs(*shdr)); + return obj.decode_relrs(raw); +} + +template +std::vector AdltRelocationScanner::scanAndrRela() { + auto *shdr = file->andrPackSec; + if (!shdr) + return {}; + auto obj = file->getObj(); + return cantFail(obj.android_relas(*shdr)); +} + +template +void AdltRelocationScanner::addRelaReloc(InputSectionBase &isec, + Relocation &r) { + Partition &part = isec.getPartition(); + part.relaDyn->addRelativeReloc(target->relativeRel, isec, r.offset, *r.sym, + r.addend, r.type, r.expr); +} + +template +void AdltRelocationScanner::addRelrReloc(InputSectionBase &isec, + uint64_t offsetInSec) { + Partition &part = isec.getPartition(); + assert(part.relrDyn && isec.alignment >= 2 && offsetInSec % 2 == 0); + part.relrDyn->relocs.push_back({&isec, offsetInSec}); +} + +template +void AdltRelocationScanner::addSymbolicReloc(InputSectionBase &isec, + Relocation &r) { + Partition &part = isec.getPartition(); + part.relaDyn->addSymbolReloc(r.type, isec, r.offset, *r.sym, r.addend, + r.type); +} + +template void AdltRelocationScanner::process(Relocation &r) { + /*if (r.offset == 0x21F) // debug hint + isDebug = true; + /*if (r.type == R_AARCH64_ABS64 && + r.sym->getName() == "__emutls_t.TLS_data1") + isDebug = true;*/ + + // parse offset (where) + InputSectionBase &secWhere = + (sec.type != SHT_NULL) ? sec : file->getSection(r.offset); + + // process offset + r.offset -= secWhere.address; + assert(r.type); + + // resolve relocs + switch (r.type) { + // dyn relocs + case R_AARCH64_RELATIVE: { + if (adltCtx->withRelr) { + addRelrReloc(secWhere, r.offset); + } else { + Defined *d = &file->getDefinedLocalSym(r.addend); + assert(d && "R_AARCH64_RELATIVE: r.sym not found by addend!"); + r.sym = d; + r.addend -= d->section->address + d->value; + addRelaReloc(secWhere, r); + } + trackRelatives(); + return; + } + case R_AARCH64_GLOB_DAT: + assert(r.sym->exportDynamic); + if (!r.sym->needsGot) + r.sym->needsGot = 1; + trackGotPlt(r.sym); + return; + case R_AARCH64_JUMP_SLOT: + assert(r.sym->exportDynamic); + if (r.sym->isUndefined() && !r.sym->needsPlt) + r.sym->needsPlt = 1; + trackGotPlt(r.sym); + return; + // abs relocs + case R_AARCH64_ABS32: + sec.relocations.push_back(r); + return; + case R_AARCH64_ABS64: + if (fromDynamic) { + assert(r.sym->exportDynamic); + addSymbolicReloc(secWhere, r); + trackDynamics(); + return; + } + sec.relocations.push_back(r); + return; + case R_AARCH64_LDST8_ABS_LO12_NC: + case R_AARCH64_LDST16_ABS_LO12_NC: + case R_AARCH64_LDST32_ABS_LO12_NC: + case R_AARCH64_LDST64_ABS_LO12_NC: + case R_AARCH64_LDST128_ABS_LO12_NC: + case R_AARCH64_PREL32: + case R_AARCH64_PREL64: + toProcessAux = true; + return; + // plt relocs + case R_AARCH64_CALL26: + case R_AARCH64_JUMP26: + case R_AARCH64_CONDBR19: + case R_AARCH64_TSTBR14: + if (r.sym->isDefined()) + r.expr = R_PC; // prev: R_PLT_PC + sec.relocations.push_back(r); + return; + // got relocs + case R_AARCH64_ADD_ABS_LO12_NC: + case R_AARCH64_ADR_PREL_PG_HI21: + sec.relocations.push_back(r); // TODO: optimize GOT + return; + case R_AARCH64_ADR_GOT_PAGE: + if (r.sym->isDefined() && !r.sym->needsGot) { + // prev: R_AARCH64_GOT_PAGE_PC || R_AARCH64_GOT_PAGE || R_GOT || R_GOT_PC + r.expr = R_PC; + sec.relocations.push_back(r); + return; + } + LLVM_FALLTHROUGH; + case R_AARCH64_LD64_GOT_LO12_NC: + case R_AARCH64_LD64_GOTPAGE_LO15: + toProcessAux = true; + return; + // tls relocs + case R_AARCH64_TLSDESC: + if (fromDynamic && !r.sym->needsTlsDesc) + r.sym->needsTlsDesc = 1; + trackGotPlt(r.sym); + return; + case R_AARCH64_TLSDESC_CALL: + case R_AARCH64_TLS_TPREL64: + case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: + case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: + case R_AARCH64_TLSDESC_ADR_PAGE21: + case R_AARCH64_TLSDESC_LD64_LO12: + case R_AARCH64_TLSDESC_ADD_LO12: + case R_AARCH64_TLSLE_ADD_TPREL_HI12: + case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + toProcessTls = true; + return; + default: + fatal("[ADLT] Unhandled " + toString(fromDynamic ? "dynamic " : "") + + "reloc: " + toString(r.type)); + break; + } +} + +template class elf::AdltRelocationScanner; +template class elf::AdltRelocationScanner; +template class elf::AdltRelocationScanner; +template class elf::AdltRelocationScanner; +// OHOS_LOCAL end diff --git a/lld/ELF/Adlt/Relocations.h b/lld/ELF/Adlt/Relocations.h new file mode 100644 index 0000000000000000000000000000000000000000..c64865b3ab18a33b24a15feb5b585c69a541d10b --- /dev/null +++ b/lld/ELF/Adlt/Relocations.h @@ -0,0 +1,60 @@ +//===- Adlt/Relocations.h -------------------------------------------------*- +// C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// OHOS_LOCAL begin +#ifndef LLD_ELF_ADLT_RELOCATIONS_H +#define LLD_ELF_ADLT_RELOCATIONS_H + +#include + +namespace lld { +namespace elf { + +struct Relocation; +class Symbol; +class InputSectionBase; + +template class SharedFileExtended; + +template class AdltRelocationScanner { +public: + AdltRelocationScanner(InputSectionBase &isec, bool isRelr = false); + + Symbol &getSymbol(unsigned idx); + void process(Relocation &r); + + bool isScanPackedNeeded(); + std::vector scanRelr(); + std::vector scanAndrRela(); + + bool toProcessAux = false; + bool toProcessTls = false; + +private: + SharedFileExtended *file = nullptr; + bool fromDynamic = false; + InputSectionBase &sec; + bool isRelr = false; + + SharedFileExtended *getSoExt() { return file; } + + void trackGotPlt(Symbol *sym); + void trackRelatives(); + void trackDynamics(); + + void addRelaReloc(InputSectionBase &isec, Relocation &rel); + void addRelrReloc(InputSectionBase &isec, uint64_t offsetInSec); + void addSymbolicReloc(InputSectionBase &isec, Relocation &r); +}; + +} // namespace elf +} // namespace lld + +#endif // LLD_ELF_ADLT_RELOCATIONS_H +// OHOS_LOCAL end diff --git a/lld/ELF/Adlt/Writer.cpp b/lld/ELF/Adlt/Writer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e97559fc57cae09e4e813f1ebcdc635c8785f17 --- /dev/null +++ b/lld/ELF/Adlt/Writer.cpp @@ -0,0 +1,249 @@ +//===- Adlt/Writer.cpp ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// OHOS_LOCAL begin +#include "Adlt/Writer.h" +#include "Adlt/Context.h" + +#include "lld/Common/LLVM.h" + +#include "LinkerScript.h" +#include "OutputSections.h" +#include "InputFiles.h" +#include "Target.h" +#include "Symbols.h" +#include "Writer.h" + +using namespace llvm; +using namespace llvm::ELF; +using namespace llvm::object; + +using namespace lld; +using namespace lld::elf; + +void AdltTracePrinter::printRelocsHead(SyntheticSection *relSec, + llvm::SetVector indexes) { + lld::outs() << relSec->name << " relocs (" << indexes.size() << "): "; + printIndexes(indexes); +} + +void AdltTracePrinter::printRelrTable(RelrBaseSection *relSec, + llvm::SetVector indexes) { + SmallVector &relocs = relSec->relocs; + for (auto &it : indexes) // print relocs + if (RelativeReloc *rel = &relocs[it]) + lld::outs() << it << ":\t" << rel->inputSec->name << " + 0x" + << utohexstr(rel->offsetInSec) << "\t" + << toString(R_AARCH64_RELATIVE) << "\t" << "0x" + << utohexstr(rel->getOffset()) << '\n'; +} +void AdltTracePrinter::printRelaTable(RelocationBaseSection *relSec, + llvm::SetVector indexes) { + SmallVector relocs = relSec->relocs; + for (auto &it : indexes) // print relocs + if (DynamicReloc *rel = &relocs[it]) + lld::outs() << it << ":\t" << rel->inputSec->name << " + 0x" + << utohexstr(rel->offsetInSec) << "\t" << toString(rel->type) + << "\t" << getSymbolName(rel->sym) << " + 0x" + << utohexstr(rel->addend) << '\n'; +} + +void AdltTracePrinter::printIndexes(llvm::SetVector indexes) { + for (auto &it : indexes) + lld::outs() << it << ' '; + lld::outs() << "\n"; +} +StringRef AdltTracePrinter::getSymbolName(Symbol *sym) { + if (sym->getName().empty() && sym->isSection()) { + Defined *d = cast(sym); + return d->section->name; + } + return sym->getName(); +} + +InputSection *AdltWriter::getInputSection(OutputSection *sec) { + if (!sec || !sec->hasInputSections || sec->commands.empty()) + return nullptr; + SectionCommand *cmd = sec->commands.front(); + InputSectionDescription *isd = cast(cmd); + return isd->sections.front(); +} + +template void AdltWriter::checkPhdrs() { + assert(!adltCtx->commonProgramHeaders.empty() && + "Common headers can't be empty!"); + for (auto *file : adltCtx->sharedFilesExtended) + if (auto *soFile = adltCtx->getSoExt(file)) + assert(!soFile->programHeaders.empty() && + "ADLT: PHdr indexes can't be empty!"); +} + +template void AdltWriter::checkRelocs() { + if (adltCtx->withRelr) + assert(!mainPart->relrDyn->relocs.empty() && + "ADLT: relrDyn can't be empty!"); + assert(!mainPart->relaDyn->relocs.empty() && "ADLT: relaDyn can't be empty!"); + assert(!in.relaPlt->relocs.empty() && "ADLT: relaPlt can't be empty!"); + + for (auto *file : adltCtx->sharedFilesExtended) + if (auto *soFile = adltCtx->getSoExt(file)) { + if (adltCtx->withRelr) + assert(!soFile->relrDynIndexes.empty() && + "ADLT: .relr.dyn indexes can't be empty!"); + assert(!soFile->relaDynIndexes.empty() && + "ADLT: relaDyn indexes can't be empty!"); + assert(!soFile->relaPltIndexes.empty() && + "ADLT: relaPlt indexes can't be empty!"); + } +} + +template +void AdltWriter::trackPhdr(OutputSection *sec, PhdrEntry *phdr) { + auto *isec = getInputSection(sec); + if (isec && isec->file) { + isec->getSoExt()->programHeaders.insert(phdr); + return; + } + adltCtx->commonProgramHeaders.insert(phdr); +} + +template void AdltWriter::traceRelocs() { + lld::outs() << "[ADLT]\n"; + auto &part = mainPart; + auto dynRelsSize = part->relaDyn->relocs.size(); + if (adltCtx->withRelr) + dynRelsSize += part->relrDyn->relocs.size(); + lld::outs() << "Dyn relocs (" << dynRelsSize << ")\n" + << "Plt relocs (" << in.relaPlt->relocs.size() << ")\n"; + AdltTracePrinter printer; + auto printHeadAndRelaTable = [&](auto *sec, auto indexes) { + printer.printRelocsHead(sec, indexes); + printer.printRelaTable(sec, indexes); + }; + + for (auto *rawFile : adltCtx->sharedFilesExtended) + if (auto *f = adltCtx->getSoExt(rawFile)) { + lld::outs() << f->soName << ":\n"; + // relative, dynamic + if (adltCtx->withRelr) { + printer.printRelocsHead(part->relrDyn.get(), f->relrDynIndexes); + printer.printRelrTable(part->relrDyn.get(), f->relrDynIndexes); + } + printHeadAndRelaTable(part->relaDyn.get(), f->relaDynIndexes); + // plt + printHeadAndRelaTable(in.relaPlt.get(), f->relaPltIndexes); + } +} + +template void AdltWriter::tracePhdrs() { + lld::outs() << "[ADLT]\n"; + lld::outs() << "Program Headers (" << mainPart->phdrs.size() << ")\n"; + + llvm::DenseMap phIndexMap; + for (auto &it : llvm::enumerate(mainPart->phdrs)) + phIndexMap[it.value()] = it.index(); + + + auto printIndexes = [&](auto &vec) { + lld::outs() << ": "; + for (auto &it : vec) + lld::outs() << phIndexMap[it] << ' '; + lld::outs() << "\n"; + }; + + auto printPhTable = [&](auto &vec) { + lld::outs() << "Idx\tType\tOffset\tVirtAddr\tAlign\tFirstSec\n"; + for (const PhdrEntry *p : vec) + lld::outs() << phIndexMap[p] << ":\t" << phdrTypeToStr(p->p_type) + << "\t0x" << utohexstr(p->p_offset) << "\t0x" + << utohexstr(p->p_vaddr) << " \t0x" << utohexstr(p->p_align) + << "\t" << p->firstSec->name << '\n'; + }; + + auto &common = adltCtx->commonProgramHeaders; + lld::outs() << "Common Program Headers (" << common.size() << ")"; + printIndexes(common); + printPhTable(common); + + for (auto *file : adltCtx->sharedFilesExtended) + if (auto *soFile = adltCtx->getSoExt(file)) { + auto &headers = soFile->programHeaders; + lld::outs() << soFile->soName << "\n"; + lld::outs() << "Program headers (" << headers.size() << ")"; + printIndexes(headers); + printPhTable(headers); + } +} + +template +llvm::Optional AdltWriter::getOwnerIndx(OutputSection *sec) { + auto file = getInputSection(sec)->file; + if (!file) + return llvm::None; + return adltCtx->getSoExt(file)->orderIdx; +} + +StringRef AdltWriter::phdrTypeToStr(uint32_t p_type) { + switch (p_type) { + case PT_PHDR: + return "PT_PHDR"; + case PT_ADLT: + return "PT_ADLT"; + case PT_LOAD: + return "PT_LOAD"; + case PT_TLS: + return "PT_TLS"; + case PT_DYNAMIC: + return "PT_DYNAMIC"; + case PT_GNU_RELRO: + return "PT_GNU_RELRO"; + case PT_GNU_STACK: + return "PT_GNU_STACK"; + case PT_NOTE: + return "PT_NOTE"; + } + llvm_unreachable("UNKNOWN TYPE"); + return ""; +} + +// TODO remove +template llvm::Optional +AdltWriter::getOwnerIndx(OutputSection *); +template llvm::Optional +AdltWriter::getOwnerIndx(OutputSection *); +template llvm::Optional +AdltWriter::getOwnerIndx(OutputSection *); +template llvm::Optional +AdltWriter::getOwnerIndx(OutputSection *); + +template void AdltWriter::checkPhdrs(); +template void AdltWriter::checkPhdrs(); +template void AdltWriter::checkPhdrs(); +template void AdltWriter::checkPhdrs(); + +template void AdltWriter::tracePhdrs(); +template void AdltWriter::tracePhdrs(); +template void AdltWriter::tracePhdrs(); +template void AdltWriter::tracePhdrs(); + +template void AdltWriter::checkRelocs(); +template void AdltWriter::checkRelocs(); +template void AdltWriter::checkRelocs(); +template void AdltWriter::checkRelocs(); + +template void AdltWriter::traceRelocs(); +template void AdltWriter::traceRelocs(); +template void AdltWriter::traceRelocs(); +template void AdltWriter::traceRelocs(); + +template void AdltWriter::trackPhdr(OutputSection *, PhdrEntry *); +template void AdltWriter::trackPhdr(OutputSection *, PhdrEntry *); +template void AdltWriter::trackPhdr(OutputSection *, PhdrEntry *); +template void AdltWriter::trackPhdr(OutputSection *, PhdrEntry *); + +// OHOS_LOCAL end diff --git a/lld/ELF/Adlt/Writer.h b/lld/ELF/Adlt/Writer.h new file mode 100644 index 0000000000000000000000000000000000000000..594238385e47282a65e1f76e3729a4570452a425 --- /dev/null +++ b/lld/ELF/Adlt/Writer.h @@ -0,0 +1,54 @@ +//===- Adlt/Writer.h --------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// OHOS_LOCAL begin +#ifndef LLD_ELF_ADLT_WRITER_H +#define LLD_ELF_ADLT_WRITER_H + +#include "llvm/ADT/SetVector.h" +#include "SyntheticSections.h" + +namespace lld { +namespace elf { + +class Symbol; +class SyntheticSection; + +class AdltTracePrinter { +public: + void printRelocsHead(SyntheticSection *relSec, + llvm::SetVector indexes); + void printRelrTable(RelrBaseSection *relSec, + llvm::SetVector indexes); + void printRelaTable(RelocationBaseSection *relSec, + llvm::SetVector indexes); +private: + void printIndexes(llvm::SetVector indexes); + StringRef getSymbolName(Symbol *sym); +}; + +struct AdltWriter { + InputSection *getInputSection(OutputSection *sec); + StringRef phdrTypeToStr(uint32_t p_type); + + // TODO: remove templates + template void checkPhdrs(); + template void checkRelocs(); + + template void trackPhdr(OutputSection *sec, PhdrEntry *phdr); + template void traceRelocs(); + template void tracePhdrs(); + + template llvm::Optional getOwnerIndx(OutputSection *sec); +}; + +} // namespace elf +} // namespace lld + +#endif // LLD_ELF_ADLT_WRITER_H +// OHOS_LOCAL end diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp index 810ff3f5d9d9854c2e505c2aee7217c46119f5ee..c613cf215fb06aec2ecf5be0ef6127a12bcb6371 100644 --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -13,6 +13,10 @@ #include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/Endian.h" +// OHOS_LOCAL begin +#include "Adlt/Arch/AArch64.h" +// OHOS_LOCAL end + using namespace llvm; using namespace llvm::support::endian; using namespace llvm::ELF; @@ -44,8 +48,6 @@ public: uint32_t getThunkSectionSpacing() const override; bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override; bool usesOnlyLowPageBits(RelType type) const override; - void deRelocate(uint8_t *loc, const Relocation &rel, - uint64_t *val) const override; // ADLT void relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const override; RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override; @@ -351,83 +353,14 @@ static void writeSMovWImm(uint8_t *loc, uint32_t imm) { write32le(loc, inst | ((imm & 0xFFFF) << 5)); } -static void adltRelocateDebugMessage(StringRef title, uint8_t *loc, - const Relocation &rel, uint64_t &val) { - lld::outs() << title - << " loc: " << loc /*<< " loc val: " << Twine::utohexstr(*loc)*/ - << " rel expr: " << rel.expr - << " rel type: " << lld::toString(rel.type) << " rel offset: 0x" - << Twine::utohexstr(rel.offset) << " rel addend: 0x" - << Twine::utohexstr(rel.addend) - << " val: 0x" << Twine::utohexstr(val) - << " rel sym: " << (rel.sym ? rel.sym->getName() : "null!"); - - if (rel.sym && rel.sym->isDefined()) { - auto d = cast(rel.sym); - lld::outs() << ": section " << d->section->name - << ", value 0x" << Twine::utohexstr(d->value); - } - lld::outs() << '\n'; -} - -void AArch64::deRelocate(uint8_t *loc, const Relocation &rel, - uint64_t *val) const { - bool isDebug = false; - if (isDebug) - adltRelocateDebugMessage("[AArch64::deRelocate]: ", loc, rel, *val); - - auto orClear32le = [&]() { - write32le(loc, read32le(loc) & ~((1 << 26) -1)); - }; - - auto orClearAArch64Imm = [&]() { - write32le(loc, read32le(loc) & ~(0xFFF << 10)); - }; - - switch (rel.type) { - case R_AARCH64_JUMP26: - case R_AARCH64_CALL26: - case R_AARCH64_CONDBR19: - case R_AARCH64_LD_PREL_LO19: - case R_AARCH64_MOVW_UABS_G0_NC: - case R_AARCH64_MOVW_UABS_G1_NC: - case R_AARCH64_MOVW_UABS_G2_NC: - case R_AARCH64_MOVW_UABS_G3: - case R_AARCH64_TSTBR14: - orClear32le(); - break; - case R_AARCH64_ADD_ABS_LO12_NC: - case R_AARCH64_LDST8_ABS_LO12_NC: - case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: - case R_AARCH64_LDST16_ABS_LO12_NC: - case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: - case R_AARCH64_LDST32_ABS_LO12_NC: - case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: - case R_AARCH64_LDST64_ABS_LO12_NC: - case R_AARCH64_ADR_GOT_PAGE: - case R_AARCH64_LD64_GOT_LO12_NC: - case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: - case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: - case R_AARCH64_TLSDESC_LD64_LO12: - case R_AARCH64_LDST128_ABS_LO12_NC: - case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC: - case R_AARCH64_LD64_GOTPAGE_LO15: - case R_AARCH64_TLSLE_ADD_TPREL_HI12: - case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: - case R_AARCH64_TLSDESC_ADD_LO12: - orClearAArch64Imm(); - break; - } -} - void AArch64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { - bool isDebug = false; + // OHOS_LOCAL begin if (config->adlt) { - deRelocate(loc, rel, &val); + AdltInfoAArch64 adltInfo; + adltInfo.deRelocate(loc, rel, &val); } - if (config->adlt && isDebug) - adltRelocateDebugMessage("[AArch64::relocate]: ", loc, rel, val); + // OHOS_LOCAL end switch (rel.type) { case R_AARCH64_ABS16: diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt index de8b3bf51d5870e7507e7f5836b38bdabf86f57a..635f286c6907ad013eb5229bab73eb6f84e00911 100644 --- a/lld/ELF/CMakeLists.txt +++ b/lld/ELF/CMakeLists.txt @@ -45,7 +45,13 @@ add_lld_library(lldELF Target.cpp Thunks.cpp Writer.cpp - Adlt.cpp + + # ADLT + Adlt/Arch/AArch64.cpp + Adlt/Context.cpp + Adlt/Relocations.cpp + Adlt/InputFiles.cpp + Adlt/Writer.cpp LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 88ef20d590141ee1c13be40cf14865f1a826fdbb..1a681883a22d46d6e0fe6830e19de075c67582ec 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -24,7 +24,6 @@ #include "Driver.h" #include "Config.h" -#include "Adlt.h" #include "ICF.h" #include "InputFiles.h" #include "InputSection.h" @@ -67,6 +66,12 @@ #include #include + +// OHOS_LOCAL begin +#include "Adlt/Context.h" +#include "Adlt/InputFiles.h" +// OHOS_LOCAL end + using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index df9355f3b62573f97a0a18ad1e2e828a2e9df4ee..a9ba4e7e0318f9ddd5bc5d4fb6649a5fcf472aa0 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -8,7 +8,6 @@ #include "InputFiles.h" #include "Config.h" -#include "Adlt.h" #include "DWARF.h" #include "Driver.h" #include "InputSection.h" @@ -32,6 +31,12 @@ #include "llvm/Support/TarWriter.h" #include "llvm/Support/raw_ostream.h" + +// OHOS_LOCAL begin +#include "Adlt/Context.h" +#include "Adlt/InputFiles.h" +// OHOS_LOCAL end + using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; @@ -185,14 +190,6 @@ template static void doParseFile(InputFile *file) { message(toString(file)); // .so file - if (config->adlt) - if (auto *f = dyn_cast>(file)) { - f->orderIdx = adltCtx->sharedFilesExtended.size(); - adltCtx->sharedFilesExtended.push_back(f); - f->parse(); - return; - } - if (auto *f = dyn_cast(file)) { f->parse(); return; @@ -211,7 +208,15 @@ template static void doParseFile(InputFile *file) { } // Add symbols in File to the symbol table. -void elf::parseFile(InputFile *file) { invokeELFT(doParseFile, file); } +void elf::parseFile(InputFile *file) { + // OHOS_LOCAL begin + if (config->adlt) { + invokeELFT(adltCtx->parseFile, file); + return; + } + // OHOS_LOCAL end + invokeELFT(doParseFile, file); +} // Concatenates arguments to construct a string representing an error location. static std::string createFileLineMsg(StringRef path, unsigned line) { @@ -1367,36 +1372,6 @@ std::vector SharedFile::parseVerneed(const ELFFile &obj, return verneeds; } -template -std::vector SharedFileExtended::parseVerneed(const ELFFile &obj, - const typename ELFT::Shdr *sec) { - if (!sec) - return {}; - std::vector verneeds; - ArrayRef data = CHECK(obj.getSectionContents(*sec), this); - const uint8_t *verneedBuf = data.begin(); - for (unsigned i = 0; i != sec->sh_info; ++i) { - if (verneedBuf + sizeof(typename ELFT::Verneed) > data.end()) - fatal(toString(this) + " has an invalid Verneed"); - auto *vn = reinterpret_cast(verneedBuf); - const uint8_t *vernauxBuf = verneedBuf + vn->vn_aux; - for (unsigned j = 0; j != vn->vn_cnt; ++j) { - if (vernauxBuf + sizeof(typename ELFT::Vernaux) > data.end()) - fatal(toString(this) + " has an invalid Vernaux"); - auto *aux = reinterpret_cast(vernauxBuf); - if (aux->vna_name >= this->stringTable.size()) - fatal(toString(this) + " has a Vernaux with an invalid vna_name"); - uint16_t version = aux->vna_other & VERSYM_VERSION; - if (version >= verneeds.size()) - verneeds.resize(version + 1); - verneeds[version] = aux->vna_name; - vernauxBuf += aux->vna_next; - } - verneedBuf += vn->vn_next; - } - return verneeds; -} - // We do not usually care about alignments of data in shared object // files because the loader takes care of it. However, if we promote a // DSO symbol to point to .bss due to copy relocation, we need to keep @@ -1604,387 +1579,6 @@ template void SharedFile::parse() { } } -template -SharedFileExtended::SharedFileExtended(MemoryBufferRef mb, - StringRef soName) - : ObjFile(InputFile::SharedKind, mb, soName), soName(soName) {} - -template void SharedFileExtended::buildSymbolsHist() { - ArrayRef eSyms = this->template getELFSyms(); - for (size_t i = this->firstGlobal, end = eSyms.size(); i != end; ++i) { - if (!eSyms[i].isDefined()) - continue; - StringRef name = CHECK(eSyms[i].getName(this->stringTable), this); - adltCtx->symNamesHist[CachedHashStringRef(name)]++; - } -} - -template -bool SharedFileExtended::isValidSection(InputSectionBase *s) const { - if (!s || s == &InputSection::discarded) - return false; - uint32_t type = s->type; - StringRef name = s->name; - - bool isBaseType = type == SHT_NOBITS || type == SHT_NOTE || - type == SHT_INIT_ARRAY || type == SHT_FINI_ARRAY; - // TODO: fix .debug-* sections relocation - // TODO: rename sections at outputStage. - bool isNeededProgBits = - type == SHT_PROGBITS && - !(name.startswith(".got") || name.startswith(".plt") || - name.startswith(".eh_frame_hdr") || name.startswith(".debug_")); - bool ret = isBaseType || isNeededProgBits; - return ret; -} - -template -bool SharedFileExtended::isDynamicSection(InputSectionBase *s) const { - // TODO: rename sections at outputStage. - return s->type == llvm::ELF::SHT_NULL || s->name.startswith(".got.plt"); -} - -template void SharedFileExtended::parse(bool ignoreComdats) { - ObjFile::parse(ignoreComdats); - parseDynamics(); - parseElfSymTab(); -} - -template void SharedFileExtended::postParse() { - ObjFile::initializeLocalSymbols(); - ObjFile::postParse(); -} - -template -StringRef SharedFileExtended::getUniqueName(StringRef input) const { - if (input.empty()) return input; - auto suffix = Twine("__") + Twine::utohexstr(this->orderIdx); - return saver().save(input + suffix); -} - -template -Defined &SharedFileExtended::getDefinedLocalSym(uint64_t offset) { - auto getSym = [&](unsigned offs) { - return localSymbols[this->definedSymbolsMap[offs]]; - }; - auto *s = getSym(offset); - if (!s || s == localSymbols[0]) { - auto sec = findSection(offset); - s = getSym(sec->address); - } - assert(s && s->isDefined()); - return cast(*s); -} - -template -InputSectionBase &SharedFileExtended::getSection(uint64_t offset) { - auto *sec = this->sections[this->sectionsMap[offset]]; - if (offset && sec->type == SHT_NULL) - sec = findSection(offset); - return *sec; -} - -template -InputSectionBase &SharedFileExtended::getSectionByOrder(size_t idx) { - auto *sec = this->sections[idx]; - if (!sec) - sec = &InputSection::discarded; - return *sec; -} - -template -InputSectionBase *SharedFileExtended::findSection(uint64_t offset) { - llvm::SmallVector candidates; - for (InputSectionBase *sec : this->sections) { - if (!sec) - continue; - auto low = sec->address; - auto high = low + sec->size; - if (offset >= low && offset < high) - candidates.push_back(sec); - } - if (candidates.empty()) // no suitable items found - return nullptr; - llvm::sort(candidates, - [](auto *a, auto *b) { return a->address < b->address; }); - return *candidates.begin(); -} - -template -Symbol &SharedFileExtended::getDynamicSymbol(size_t symbolIndex) const { - return *this->symbols[symbolIndex]; -} -template -Symbol &SharedFileExtended::getLocalSymbol(size_t symbolIndex) const{ - assert(symbolIndex && (symbolIndex < localSymbols.size())); - return *localSymbols[symbolIndex]; -} - -template -Symbol &SharedFileExtended::getSymbol(size_t symbolIndex, - bool fromDynamic) { - if (!symbolIndex) - return *localSymbols[0]; - /* TODO - if (symbolIndex > static_cast(symTabFirstGlobal)) - return getDynamicSymbol(symbolIndex - (symTabFirstGlobal + 1)); - return fromDynamic ? getDynamicSymbol(symbolIndex) - : getLocalSymbol(symbolIndex); */ - - Symbol &sym = fromDynamic ? getDynamicSymbol(symbolIndex) - : getLocalSymbol(symbolIndex); - StringRef name = sym.getName(); - if (name.empty()) - return sym; - // check SymbolTable - auto res = elf::symtab->find(name); - if (res && (res->exportDynamic || res->versionId)) - return *res; - - // check SymbolTableBaseSection - auto found = llvm::find_if( - in.symTab->getSymbols(), [&](const SymbolTableEntry &entry) { - return entry.sym->getName() == name; - }); - // add a local sym if it was not previously added - if (found == in.symTab->getSymbols().end()) - in.symTab->addSymbol(&sym); - return sym; -} - -template -ArrayRef SharedFileExtended::getLocalSymbols() { - assert(!localSymbols.empty()); - return llvm::makeArrayRef(localSymbols).slice(0, symTabFirstGlobal); -} - -template void SharedFileExtended::parseDynamics() { - const ELFFile obj = this->getObj(); - ArrayRef sections = this->template getELFShdrs(); - - ArrayRef dynamicTags; - const Elf_Shdr *versymSec = nullptr; - const Elf_Shdr *verdefSec = nullptr; - const Elf_Shdr *verneedSec = nullptr; - - // parse external lib deps - int secIdx = 0; - for (const Elf_Shdr &sec : sections) { - switch (sec.sh_type) { - case SHT_DYNAMIC: - dynamicTags = - CHECK(obj.template getSectionContentsAsArray(sec), this); - break; - case SHT_DYNSYM: - dynSymSecIdx = secIdx; - break; - case SHT_SYMTAB: - symTabSecIdx = secIdx; - break; - case SHT_SYMTAB_SHNDX: - symTabShndxSecIdx = secIdx; - break; - case SHT_GNU_versym: - versymSec = &sec; - break; - case SHT_GNU_verdef: - verdefSec = &sec; - break; - case SHT_GNU_verneed: - verneedSec = &sec; - break; - } - auto secName = check(this->getObj().getSectionName(sec)); - if (secName == ".got.plt") - gotPltSecIdx = secIdx; - secIdx++; - } - - if (versymSec && this->numELFSyms == 0) { - error("SHT_GNU_versym should be associated with symbol table"); - return; - } - - // Search for a DT_SONAME tag to initialize this->soName. - for (const Elf_Dyn &dyn : dynamicTags) { - if (dyn.d_tag == DT_NEEDED) { - uint64_t val = dyn.getVal(); - if (val >= this->stringTable.size()) - fatal(toString(this) + ": invalid DT_NEEDED entry"); - dtNeeded.push_back(this->stringTable.data() + val); - } else if (dyn.d_tag == DT_SONAME) { - uint64_t val = dyn.getVal(); - if (val >= this->stringTable.size()) - fatal(toString(this) + ": invalid DT_SONAME entry"); - soName = this->stringTable.data() + val; - } - } - - verdefs = parseVerdefs(obj.base(), verdefSec); - std::vector verneeds = parseVerneed(obj, verneedSec); - - // Parse ".gnu.version" section which is a parallel array for the symbol - // table. If a given file doesn't have a ".gnu.version" section, we use - // VER_NDX_GLOBAL. - size_t size = this->numELFSyms - this->firstGlobal; - std::vector versyms(size, VER_NDX_GLOBAL); - if (versymSec) { - ArrayRef versym = - CHECK(obj.template getSectionContentsAsArray(*versymSec), - this) - .slice(this->firstGlobal); - for (size_t i = 0; i < size; ++i) - versyms[i] = versym[i].vs_index; - } - - // System libraries can have a lot of symbols with versions. Using a - // fixed buffer for computing the versions name (foo@ver) can save a - // lot of allocations. - SmallString<0> versionedNameBuffer; - - // Add symbols to the symbol table. - SymbolTable &symtab = *elf::symtab; - ArrayRef syms = this->template getGlobalELFSyms(); - for (size_t i = 0, e = syms.size(); i != e; ++i) { - const Elf_Sym &sym = syms[i]; - - // ELF spec requires that all local symbols precede weak or global - // symbols in each symbol table, and the index of first non-local symbol - // is stored to sh_info. If a local symbol appears after some non-local - // symbol, that's a violation of the spec. - StringRef name = CHECK(sym.getName(this->stringTable), this); - // Add postfix for defined duplicates. - if (config->adlt && sym.isDefined() && - adltCtx->duplicatedSymNames.count(CachedHashStringRef(name)) != 0) - name = getUniqueName(name); // TODO: add unique for output only - - if (sym.getBinding() == STB_LOCAL) { - warn("found local symbol '" + name + - "' in global part of symbol table in file " + toString(this)); - continue; - } - - uint16_t idx = versyms[i] & ~VERSYM_HIDDEN; - if (sym.isUndefined()) { - // For unversioned undefined symbols, VER_NDX_GLOBAL makes more sense but - // as of binutils 2.34, GNU ld produces VER_NDX_LOCAL. - if (idx != VER_NDX_LOCAL && idx != VER_NDX_GLOBAL) { - if (idx >= verneeds.size()) { - error("corrupt input file: version need index " + Twine(idx) + - " for symbol " + name + " is out of bounds\n>>> defined in " + - toString(this)); - continue; - } - StringRef verName = this->stringTable.data() + verneeds[idx]; - versionedNameBuffer.clear(); - name = saver().save( - (name + "@" + verName).toStringRef(versionedNameBuffer)); - } - Symbol *s = symtab.addSymbol( - Undefined{this, name, sym.getBinding(), sym.st_other, sym.getType()}); - s->exportDynamic = true; - if (s->isUndefined() && sym.getBinding() != STB_WEAK && - config->unresolvedSymbolsInShlib != UnresolvedPolicy::Ignore) - requiredSymbols.push_back(s); - continue; - } - // MIPS BFD linker puts _gp_disp symbol into DSO files and incorrectly - // assigns VER_NDX_LOCAL to this section global symbol. Here is a - // workaround for this bug. - if (config->emachine == EM_MIPS && idx == VER_NDX_LOCAL && - name == "_gp_disp") - continue; - - uint32_t alignment = getAlignment(sections, sym); - if (!(versyms[i] & VERSYM_HIDDEN)) { - auto *s = symtab.addSymbol( - SharedSymbol{*this, name, sym.getBinding(), sym.st_other, - sym.getType(), sym.st_value, sym.st_size, alignment}); - if (s->file == this) - s->verdefIndex = idx; - } - - // Also add the symbol with the versioned name to handle undefined symbols - // with explicit versions. - if (idx == VER_NDX_GLOBAL) - continue; - - if (idx >= verdefs.size() || idx == VER_NDX_LOCAL) { - error("corrupt input file: version definition index " + Twine(idx) + - " for symbol " + name + " is out of bounds\n>>> defined in " + - toString(this)); - continue; - } - - StringRef verName = - this->stringTable.data() + - reinterpret_cast(verdefs[idx])->getAux()->vda_name; - versionedNameBuffer.clear(); - name = (name + "@" + verName).toStringRef(versionedNameBuffer); - auto *s = symtab.addSymbol( - SharedSymbol{*this, saver().save(name), sym.getBinding(), sym.st_other, - sym.getType(), sym.st_value, sym.st_size, alignment}); - if (s->file == this) - s->verdefIndex = idx; - } -} - -template void SharedFileExtended::parseElfSymTab() { - const ELFFile obj = this->getObj(); - ArrayRef eSections = this->template getELFShdrs(); - - // Find a symbol table. - const Elf_Shdr *eSymtabSec = ::findSection(eSections, SHT_SYMTAB); - if (!eSymtabSec) - return; - - symTabFirstGlobal = eSymtabSec->sh_info; - - ArrayRef eSyms = CHECK(obj.symbols(eSymtabSec), this); - auto numESyms = uint32_t(eSyms.size()); - auto eStringTable = CHECK(obj.getStringTableForSymtab(*eSymtabSec, eSections), this); - this->localSymbols.resize(numESyms); - - for (size_t i = 0; i < numESyms; i++) { - const Elf_Sym &eSym = eSyms[i]; - StringRef name(eStringTable.data() + eSym.st_name); - auto bind = eSym.getBinding(); - auto type = eSym.getType(); - auto other = eSym.st_other; - if (eSym.isDefined()) { - auto secIdx = eSym.st_shndx; - if (LLVM_UNLIKELY(secIdx == SHN_XINDEX)) - secIdx = check( - getExtendedSymbolTableIndex(eSym, i, this->getShndxTable())); - else if (secIdx >= SHN_LORESERVE) - secIdx = 0; - auto p = obj.getSection(secIdx); - if (p.takeError()) { - fatal("getSection failed: " + llvm::toString(p.takeError())); - } - const Elf_Shdr *eSec = *p; - InputSectionBase *sec = this->sections[secIdx]; - auto val = eSym.st_value; - if (type != STT_TLS) - val -= eSec->sh_addr; - auto dynSym = llvm::find_if(this->symbols, [=](const Symbol *s) { - return s && s->getName() == name; - }); - bool isInDynSym = dynSym != this->symbols.end(); - if (!isInDynSym) - name = getUniqueName(name); // TODO: add unique for output only - /*if (name == "TLS_data1") // debug hint - lld::outs() << name << '\n'; */ - this->localSymbols[i] = - make(this, name, bind, other, type, val, eSym.st_size, sec); - this->definedSymbolsMap[eSym.st_value] = i; - } else { - this->localSymbols[i] = make(this, name, bind, other, type, - /*discardedSecIdx=*/i); - } - } -} - static ELFKind getBitcodeELFKind(const Triple &t) { if (t.isLittleEndian()) return t.isArch64Bit() ? ELF64LEKind : ELF32LEKind; @@ -2225,27 +1819,6 @@ ELFFileBase *elf::createObjFile(MemoryBufferRef mb, StringRef archiveName, return f; } -ELFFileBase *elf::createSharedFileExtended(MemoryBufferRef mb, StringRef soName) { - ELFFileBase *f; - switch (getELFKind(mb, soName)) { - case ELF32LEKind: - f = make>(mb, soName); - break; - case ELF32BEKind: - f = make>(mb, soName); - break; - case ELF64LEKind: - f = make>(mb, soName); - break; - case ELF64BEKind: - f = make>(mb, soName); - break; - default: - llvm_unreachable("getELFKind"); - } - return f; -} - template void ObjFile::parseLazy() { const ArrayRef eSyms = this->getELFSyms(); SymbolTable &symtab = *elf::symtab; @@ -2298,8 +1871,3 @@ template void SharedFile::parse(); template void SharedFile::parse(); template void SharedFile::parse(); template void SharedFile::parse(); - -template class elf::SharedFileExtended; -template class elf::SharedFileExtended; -template class elf::SharedFileExtended; -template class elf::SharedFileExtended; diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h index 41f1561bb54510d5989180469742abf8b4e1178c..dcf67d7f4e7198a967299fe275e66d85818e5717 100644 --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -38,7 +38,6 @@ namespace elf { class InputSection; class Symbol; -struct PhdrEntry; // OHOS_LOCAL // If --reproduce is specified, all input files are written to this tar archive. extern std::unique_ptr tar; @@ -393,96 +392,6 @@ private: const typename ELFT::Shdr *sec); }; - -// ADLT -template -class SharedFileExtended : public ObjFile { - LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) - -public: - SharedFileExtended(MemoryBufferRef mb, StringRef soName); - - static bool classof(const InputFile *f) { - return f->kind() == InputFile::SharedKind; - } - void buildSymbolsHist() override; - bool isValidSection(InputSectionBase *s) const override; - bool isDynamicSection(InputSectionBase *s) const; - - void parse(bool ignoreComdats = false) override; - void postParse() override; - - Defined &getDefinedLocalSym(uint64_t offset); - - InputSectionBase &getSection(uint64_t offset); - InputSectionBase &getSectionByOrder(size_t idx); - InputSectionBase *findSection(uint64_t offset); - - template Symbol &getRelocTargetSym(const RelT &rel) { - uint32_t symIndex = rel.getSymbol(config->isMips64EL); - return getSymbol(symIndex, false); - } - - Symbol &getDynamicSymbol(size_t symbolIndex) const; - Symbol &getLocalSymbol(size_t symbolIndex) const; - Symbol &getSymbol(size_t symbolIndex, bool fromDynamic); - - ArrayRef getLocalSymbols() override; - - -public: - // the input order of the file as it presented in ADLT image - size_t orderIdx = 0; - int dynSymSecIdx = 0; - int symTabSecIdx = 0; - int symTabShndxSecIdx = 0; - int symTabFirstGlobal = 0; - int gotPltSecIdx = 0; - - // .symtab's start of local symbols owned by library - llvm::Optional sharedLocalSymbolIndex; - // .symtab's start of global symbols owned by library - llvm::Optional sharedGlobalSymbolIndex; - - // Output information data: - llvm::SetVector programHeaders; - - // From input .rela.dyn, .rela.plt: - llvm::SetVector - relaDynIndexes; // If not .relr.dyn exists, contains only Got/Abs/Tls - // relocs. Otherwise contains relative relocs also. - llvm::SetVector relaPltIndexes; // .got.plt relocs - - // SharedFile compability layer: - // This is actually a vector of Elf_Verdef pointers. - SmallVector verdefs; - // If the output file needs Elf_Verneed data structures for this file, this is - // a vector of Elf_Vernaux version identifiers that map onto the entries in - // Verdefs, otherwise it is empty. - SmallVector vernauxs; - static unsigned vernauxNum; - SmallVector dtNeeded; - StringRef soName; - StringRef simpleSoName; - // Used for --as-needed - // bool isNeeded; - // Non-weak undefined symbols which are not yet resolved when the SO is - // parsed. Only filled for `--no-allow-shlib-undefined`. - SmallVector requiredSymbols; - - // TODO: add unique for output only - StringRef getUniqueName(StringRef origName) const override; - -private: - SmallVector localSymbols; - - void parseDynamics(); // SharedFile compability - void parseElfSymTab(); // ObjectFile compability - - std::vector parseVerneed(const llvm::object::ELFFile &obj, - const typename ELFT::Shdr *sec); -}; - class BinaryFile : public InputFile { public: explicit BinaryFile(MemoryBufferRef m) : InputFile(BinaryKind, m) {} @@ -493,8 +402,6 @@ public: ELFFileBase *createObjFile(MemoryBufferRef mb, StringRef archiveName = "", bool lazy = false); -ELFFileBase *createSharedFileExtended(MemoryBufferRef mb, StringRef soName = ""); - std::string replaceThinLTOSuffix(StringRef path); } // namespace elf diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index bf2b1d7c5521e15e2d38220c737d7f16e4a28bfc..7e6ffc2e5b0b8b1c088c640efcbee8f1cd4c1709 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -24,6 +24,11 @@ #include #include +// OHOS_LOCAL begin +#include "Adlt/Context.h" +#include "Adlt/InputFiles.h" +// OHOS_LOCAL end + using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h index 1bcf8b4eca2053d6f808ee15c7eb08ec53a7f4e3..aad37032124e07c497569841fce587b38db1bd51 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -17,7 +17,10 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Object/ELF.h" -#include "Adlt.h" + +// OHOS_LOCAL begin +#include "Adlt/Context.h" +// OHOS_LOCAL end namespace lld { namespace elf { diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index c67ec01bf27ae03c119a1821670d080f85b13121..238943799c0be59a50991e7dd4d794ec18173542 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -42,7 +42,6 @@ #include "Relocations.h" #include "Config.h" -#include "Adlt.h" #include "InputFiles.h" #include "LinkerScript.h" #include "OutputSections.h" @@ -58,6 +57,12 @@ #include "llvm/Support/Endian.h" #include +// OHOS_LOCAL begin +#include "Adlt/Context.h" +#include "Adlt/InputFiles.h" +#include "Adlt/Relocations.h" +// OHOS_LOCAL end + using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; @@ -435,45 +440,6 @@ private: }; -// OHOS_LOCAL begin -template class AdltRelocationScanner { -public: - AdltRelocationScanner(InputSectionBase &isec) - : file(adltCtx->getSoExt(isec.file)), - fromDynamic(file->isDynamicSection(&isec)), sec(isec) {} - - SharedFileExtended *getSoExt() { return file; } - - Symbol &getSymbol(unsigned idx) { return file->getSymbol(idx, fromDynamic); } - - void process(Relocation *r); - void trackGotPlt(Symbol *sym); - void trackRelatives(); - void trackDynamics(); - - bool toProcessAux = false; - -private: - SharedFileExtended *file = nullptr; - bool fromDynamic = false; - InputSectionBase &sec; -}; - -template -void AdltRelocationScanner::trackGotPlt(Symbol *sym) { - adltCtx->gotPltInfo[sym].push_back(file->orderIdx); -} - -template void AdltRelocationScanner::trackRelatives() { - auto count = mainPart->relaDyn->relocs.size(); - file->relaDynIndexes.insert(count - 1); -} - -template void AdltRelocationScanner::trackDynamics() { - auto count = mainPart->relaDyn->relocs.size(); - file->relaDynIndexes.insert(count - 1); -} -// OHOS_LOCAL end // This class encapsulates states needed to scan relocations for one // InputSectionBase. @@ -483,6 +449,7 @@ public: : sec(sec), getter(sec), config(elf::config.get()), target(*elf::target) { } template void scan(ArrayRef rels); + bool isRelr = false; // OHOS_LOCAL private: InputSectionBase &sec; @@ -1345,132 +1312,21 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym, return 0; } -// OHOS_LOCAL begin -template -void AdltRelocationScanner::process(Relocation *r) { - /*if (r->offset == 0x21F) // debug hint - isDebug = true; - /*if (r->type == R_AARCH64_ABS64 && - r->sym->getName() == "__emutls_t.TLS_data1") - isDebug = true;*/ - - // parse offset (where) - InputSectionBase &secWhere = - (sec.type != SHT_NULL) ? sec : file->getSection(r->offset); - - // process offset - r->offset -= secWhere.address; - assert(r->type); - - // resolve relocs - switch (r->type) { - // dyn relocs - case R_AARCH64_RELATIVE: { - Defined *d = &file->getDefinedLocalSym(r->addend); - assert(d && "R_AARCH64_RELATIVE: r->sym not found by addend!"); - r->sym = d; - r->addend -= d->section->address + d->value; - addRelativeReloc(secWhere, r->offset, *r->sym, r->addend, r->expr, - r->type); - trackRelatives(); - return; - } - case R_AARCH64_GLOB_DAT: - assert(r->sym->exportDynamic); - if (!r->sym->needsGot) - r->sym->needsGot = 1; - trackGotPlt(r->sym); - return; - case R_AARCH64_JUMP_SLOT: - assert(r->sym->exportDynamic); - if (r->sym->isUndefined() && !r->sym->needsPlt) - r->sym->needsPlt = 1; - trackGotPlt(r->sym); - return; - // abs relocs - case R_AARCH64_ABS32: - sec.relocations.push_back(*r); - return; - case R_AARCH64_ABS64: - if (fromDynamic) { - assert(r->sym->exportDynamic); - sec.getPartition().relaDyn->addSymbolReloc(r->type, secWhere, - r->offset, *r->sym, r->addend, - r->type); - trackDynamics(); - return; - } - sec.relocations.push_back(*r); - return; - case R_AARCH64_LDST8_ABS_LO12_NC: - case R_AARCH64_LDST16_ABS_LO12_NC: - case R_AARCH64_LDST32_ABS_LO12_NC: - case R_AARCH64_LDST64_ABS_LO12_NC: - case R_AARCH64_LDST128_ABS_LO12_NC: - case R_AARCH64_PREL32: - case R_AARCH64_PREL64: - toProcessAux = true; - return; - // plt relocs - case R_AARCH64_CALL26: - case R_AARCH64_JUMP26: - case R_AARCH64_CONDBR19: - case R_AARCH64_TSTBR14: - if (r->sym->isDefined()) - r->expr = R_PC; // prev: R_PLT_PC - sec.relocations.push_back(*r); - return; - // got relocs - case R_AARCH64_ADD_ABS_LO12_NC: - case R_AARCH64_ADR_PREL_PG_HI21: - sec.relocations.push_back(*r); // TODO: optimize GOT - return; - case R_AARCH64_ADR_GOT_PAGE: - if (r->sym->isDefined() && !r->sym->needsGot) { - // prev: R_AARCH64_GOT_PAGE_PC || R_AARCH64_GOT_PAGE || R_GOT || R_GOT_PC - r->expr = R_PC; - sec.relocations.push_back(*r); - return; - } - LLVM_FALLTHROUGH; - case R_AARCH64_LD64_GOT_LO12_NC: - case R_AARCH64_LD64_GOTPAGE_LO15: - toProcessAux = true; - return; - // tls relocs - case R_AARCH64_TLSDESC: - if (fromDynamic && !r->sym->needsTlsDesc) - r->sym->needsTlsDesc = 1; - trackGotPlt(r->sym); - return; - case R_AARCH64_TLSDESC_CALL: - case R_AARCH64_TLS_TPREL64: - case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: - case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: - case R_AARCH64_TLSDESC_ADR_PAGE21: - case R_AARCH64_TLSDESC_LD64_LO12: - case R_AARCH64_TLSDESC_ADD_LO12: - case R_AARCH64_TLSLE_ADD_TPREL_HI12: - case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: - handleTlsRelocation(r->type, *r->sym, sec, r->offset, r->addend, r->expr); - return; - default: - fatal("[ADLT] Unhandled " + toString(fromDynamic ? "dynamic " : "") + - "reloc: " + toString(r->type)); - break; - } +static unsigned handleTlsRelocation(InputSectionBase &isec, Relocation &r) { + return handleTlsRelocation(r.type, *r.sym, isec, r.offset, r.addend, r.expr); } -// ADLT END template void RelocationScanner::scanOne(RelTy *&i) { const RelTy &rel = *i; + // OHOS_LOCAL begin std::unique_ptr> adltScanner = nullptr; if (config->adlt) - adltScanner = std::make_unique>(sec); + adltScanner = std::make_unique>(sec, isRelr); uint32_t symIndex = rel.getSymbol(config->isMips64EL); Symbol &sym = config->adlt ? adltScanner->getSymbol(symIndex) : sec.getFile()->getSymbol(symIndex); + // OHOS_LOCAL end RelType type; // Deal with MIPS oddity. @@ -1500,13 +1356,15 @@ template void RelocationScanner::scanOne(RelTy *&i) { return; // Read an addend. - int64_t addend = computeAddend(rel, expr, sym.isLocal()); + int64_t addend = isRelr ? 0 : computeAddend(rel, expr, sym.isLocal()); if (config->adlt) { Relocation r = {expr, type, offset, addend, &sym}; - adltScanner->process(&r); + adltScanner->process(r); if (adltScanner->toProcessAux) processAux(r); + else if (adltScanner->toProcessTls) + handleTlsRelocation(sec, r); return; } @@ -1720,6 +1578,23 @@ void RelocationScanner::scan(ArrayRef rels) { template void elf::scanRelocations(InputSectionBase &s) { RelocationScanner scanner(s); + // OHOS_LOCAL begin + if (config->adlt) { + auto adltScanner = std::make_unique>(s); + if (adltScanner->isScanPackedNeeded()) { + auto relrs = adltScanner->scanRelr(); + if (!relrs.empty()) { + scanner.isRelr = true; + scanner.template scan(makeArrayRef(relrs)); + scanner.isRelr = false; + } + auto relas = adltScanner->scanAndrRela(); + if (!relas.empty()) + scanner.template scan(makeArrayRef(relas)); + return; + } + } + // OHOS_LOCAL end const RelsOrRelas rels = s.template relsOrRelas(); if (rels.areRelocsRel()) scanner.template scan(rels.rels); diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 491a61dd15da04be1d3469dd45c4c24416b19e33..259334d376e470beefa51e0410dfa845f46aeea8 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -15,7 +15,6 @@ #include "SyntheticSections.h" #include "Config.h" -#include "Adlt.h" #include "DWARF.h" #include "EhFrame.h" #include "InputFiles.h" @@ -42,6 +41,12 @@ #include "llvm/Support/TimeProfiler.h" #include + +// OHOS_LOCAL +#include "Adlt/Context.h" +#include "Adlt/InputFiles.h" + + using namespace llvm; using namespace llvm::dwarf; using namespace llvm::ELF; @@ -4067,7 +4072,7 @@ static_assert(sizeof(adlt_section_header_t) == 56, "please update version if header has been changed" ); -static_assert(sizeof(adlt_psod_t) == 160, +static_assert(sizeof(adlt_psod_t) == 176, "please udpate version if adlt_psod_t layout or content changed" ); @@ -4201,6 +4206,7 @@ AdltSection::makeSoData(const SharedFileExtended* soext) { data.initArrayName = soext->getUniqueName(".init_array"); data.finiArrayName = soext->getUniqueName(".fini_array"); + data.relrDynIndx = soext->relrDynIndexes.getArrayRef(); data.relaDynIndx = soext->relaDynIndexes.getArrayRef(); data.relaPltIndx = soext->relaPltIndexes.getArrayRef(); @@ -4251,6 +4257,7 @@ adlt_psod_t AdltSection::serialize(const SoData& soData) const { soData.sharedGlobalIndex.value_or(0), }, // .sharedGlobalSymbolIndex adlt_blob_u16_array_t {}, // .phIndexes, filled in writeTo + adlt_blob_u32_array_t {}, // .relrDynIndx, filled in writeTo adlt_blob_u32_array_t {}, // .relaDynIndx, filled in writeTo adlt_blob_u32_array_t {}, // .relaPltIndx, filled in writeTo }; @@ -4270,6 +4277,7 @@ size_t AdltSection::estimateBlobSize() const { for (const auto& soData: soInputs) { blobSize += sizeof(adlt_dt_needed_index_t) * soData.dtNeededs.size(); blobSize += sizeof(uint16_t) * soData.programHeadersAllocated; + blobSize += sizeof(uint32_t) * soData.relrDynIndx.size(); blobSize += sizeof(uint32_t) * soData.relaDynIndx.size(); blobSize += sizeof(uint32_t) * soData.relaPltIndx.size(); }; @@ -4427,6 +4435,9 @@ void AdltSection::writeTo(uint8_t* buf) { const auto& soData = it.value(); auto& psod = psods[it.index()]; + psod.relrDynIndx = writeArray(blobBuf, blobOff, soData.relrDynIndx); + blobOff += psod.relrDynIndx.size; + psod.relaDynIndx = writeArray(blobBuf, blobOff, soData.relaDynIndx); blobOff += psod.relaDynIndx.size; diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index b51c85ce2ea810c1eab4d880926a0b39dc16e9a6..eb1e6bd9fa2d5a35fade87544e607f2a684bad5a 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -1263,6 +1263,7 @@ public: ArrayRef programHeaders; SmallVector phIndexes; + ArrayRef relrDynIndx; ArrayRef relaDynIndx; ArrayRef relaPltIndx; }; diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index 4ed885c2edd431369a679516d0c45a60214245b4..5ec2d85f64e83b6e7f25bfa4c6f702657e91a979 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -88,9 +88,6 @@ public: virtual bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const; - virtual void deRelocate(uint8_t *loc, const Relocation &rel, - uint64_t *val) const {}; // ADLT - virtual void relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const = 0; void relocateNoSym(uint8_t *loc, RelType type, uint64_t val) const { diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 93fd33ccb2b9f1cf12d28e30dfa3d9165d0e3286..ea9220112d8dd6857c9314c208dc21e4f84f16a1 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -11,7 +11,6 @@ #include "ARMErrataFix.h" #include "CallGraphSort.h" #include "Config.h" -#include "Adlt.h" #include "InputFiles.h" #include "LinkerScript.h" #include "MapFile.h" @@ -33,6 +32,13 @@ #include "llvm/Support/xxhash.h" #include +// OHOS_LOCAL begin +#include "Adlt/Context.h" +#include "Adlt/Writer.h" +#include "Adlt/InputFiles.h" +// OHOS_LOCAL end + + #define DEBUG_TYPE "lld" using namespace llvm; @@ -381,7 +387,8 @@ template void elf::createSyntheticSections() { add(*part.memtagAndroidNote); } - if (config->androidPackDynRelocs) + if (config->androidPackDynRelocs || + (config->adlt && adltCtx->withAndroidRela)) part.relaDyn = std::make_unique>(relaDynName); else @@ -417,7 +424,7 @@ template void elf::createSyntheticSections() { add(*part.relaDyn); } - if (config->relrPackDynRelocs) { + if (config->relrPackDynRelocs || (config->adlt && adltCtx->withRelr)) { part.relrDyn = std::make_unique>(); add(*part.relrDyn); } @@ -509,9 +516,14 @@ template void elf::createSyntheticSections() { // that would cause a section type mismatch. However, because the Android // dynamic loader reads .rel.plt after .rel.dyn, we can get the desired // behaviour by placing the iplt section in .rel.plt. + + // OHOS_LOCAL begin + bool adltWithAndroidRela = config->adlt && adltCtx->withAndroidRela; + bool androidPackNeeded = config->androidPackDynRelocs || adltWithAndroidRela; in.relaIplt = std::make_unique>( - config->androidPackDynRelocs ? in.relaPlt->name : relaDynName, + androidPackNeeded ? in.relaPlt->name : relaDynName, /*sort=*/false); + // OHOS_LOCAL end add(*in.relaIplt); if ((config->emachine == EM_386 || config->emachine == EM_X86_64) && @@ -548,167 +560,6 @@ template void elf::createSyntheticSections() { add(*in.strTab); } -// OHOS_LOCAL begin -namespace { -static struct AdltWriter { - InputSection *getInputSection(OutputSection *sec); - StringRef phdrTypeToStr(uint32_t p_type); - - template void checkPhdrs(); - template void checkRelocs(); - - template void trackPhdr(OutputSection *sec, PhdrEntry *phdr); - template void traceRelocs(); - template void tracePhdrs(); -} adltWriter; -} // namespace - -InputSection *AdltWriter::getInputSection(OutputSection *sec) { - if (!sec || !sec->hasInputSections || sec->commands.empty()) - return nullptr; - SectionCommand *cmd = sec->commands.front(); - InputSectionDescription *isd = cast(cmd); - return isd->sections.front(); -} - -template void AdltWriter::checkPhdrs() { - assert(!adltCtx->commonProgramHeaders.empty() && - "Common headers can't be empty!"); - for (auto *file : adltCtx->sharedFilesExtended) - if (auto *soFile = adltCtx->getSoExt(file)) - assert(!soFile->programHeaders.empty() && - "ADLT: PHdr indexes can't be empty!"); -} - -template void AdltWriter::checkRelocs() { - assert(!mainPart->relaDyn->relocs.empty() && "ADLT: relaDyn can't be empty!"); - assert(!in.relaPlt->relocs.empty() && "ADLT: relaPlt can't be empty!"); - - for (auto *file : adltCtx->sharedFilesExtended) - if (auto *soFile = adltCtx->getSoExt(file)) { - assert(!soFile->relaDynIndexes.empty() && - "ADLT: relaDyn indexes can't be empty!"); - assert(!soFile->relaPltIndexes.empty() && - "ADLT: relaPlt indexes can't be empty!"); - } -} - -template -void AdltWriter::trackPhdr(OutputSection *sec, PhdrEntry *phdr) { - auto *isec = getInputSection(sec); - if (isec && isec->file) { - isec->getSoExt()->programHeaders.insert(phdr); - return; - } - adltCtx->commonProgramHeaders.insert(phdr); -} - -template void AdltWriter::traceRelocs() { - lld::outs() << "[ADLT]\n"; - auto dynRelsSize = mainPart->relaDyn->relocs.size(); - lld::outs() << "Dyn relocs (" << dynRelsSize << ")\n"; - lld::outs() << "Plt relocs (" << in.relaPlt->relocs.size() << ")\n"; - - auto printIndexes = [&](auto &vec) { - lld::outs() << ": "; - for (auto &it : vec) - lld::outs() << it << ' '; - lld::outs() << "\n"; - }; - - auto printSym = [&](Symbol *sym) { - if (sym->getName().empty() && sym->isSection()) { - Defined *d = cast(sym); - return d->section->name; - } - return sym->getName(); - }; - - auto printRelaTable = [&](auto *relSec, auto &outIndexes) { - for (auto &it : outIndexes) // print relocs - if (DynamicReloc *rel = &relSec->relocs[it]) - lld::outs() << it << ":\t" << rel->inputSec->name << " + 0x" - << utohexstr(rel->offsetInSec) << "\t" - << toString(rel->type) << "\t" << printSym(rel->sym) - << " + 0x" << utohexstr(rel->addend) << '\n'; - }; - - for (auto *file : adltCtx->sharedFilesExtended) - if (auto *soFile = adltCtx->getSoExt(file)) { - lld::outs() << soFile->soName << ":\n"; - lld::outs() << ".rela.dyn relocs (" << soFile->relaDynIndexes.size() << ")"; - printIndexes(soFile->relaDynIndexes); - printRelaTable(mainPart->relaDyn.get(), soFile->relaDynIndexes); - - lld::outs() << ".rela.plt relocs (" << soFile->relaPltIndexes.size() << ")"; - printIndexes(soFile->relaPltIndexes); - printRelaTable(in.relaPlt.get(), soFile->relaPltIndexes); - } -} - -template void AdltWriter::tracePhdrs() { - lld::outs() << "[ADLT]\n"; - lld::outs() << "Program Headers (" << mainPart->phdrs.size() << ")\n"; - - llvm::DenseMap phIndexMap; - for (auto &it : llvm::enumerate(mainPart->phdrs)) - phIndexMap[it.value()] = it.index(); - - - auto printIndexes = [&](auto &vec) { - lld::outs() << ": "; - for (auto &it : vec) - lld::outs() << phIndexMap[it] << ' '; - lld::outs() << "\n"; - }; - - auto printPhTable = [&](auto &vec) { - lld::outs() << "Idx\tType\tOffset\tVirtAddr\tAlign\tFirstSec\n"; - for (const PhdrEntry *p : vec) - lld::outs() << phIndexMap[p] << ":\t" << phdrTypeToStr(p->p_type) - << "\t0x" << utohexstr(p->p_offset) << "\t0x" - << utohexstr(p->p_vaddr) << " \t0x" << utohexstr(p->p_align) - << "\t" << p->firstSec->name << '\n'; - }; - - auto &common = adltCtx->commonProgramHeaders; - lld::outs() << "Common Program Headers (" << common.size() << ")"; - printIndexes(common); - printPhTable(common); - - for (auto *file : adltCtx->sharedFilesExtended) - if (auto *soFile = adltCtx->getSoExt(file)) { - auto &headers = soFile->programHeaders; - lld::outs() << soFile->soName << "\n"; - lld::outs() << "Program headers (" << headers.size() << ")"; - printIndexes(headers); - printPhTable(headers); - } -} - -StringRef AdltWriter::phdrTypeToStr(uint32_t p_type) { - switch (p_type) { - case PT_PHDR: - return "PT_PHDR"; - case PT_ADLT: - return "PT_ADLT"; - case PT_LOAD: - return "PT_LOAD"; - case PT_TLS: - return "PT_TLS"; - case PT_DYNAMIC: - return "PT_DYNAMIC"; - case PT_GNU_RELRO: - return "PT_GNU_RELRO"; - case PT_GNU_STACK: - return "PT_GNU_STACK"; - case PT_NOTE: - return "PT_NOTE"; - } - llvm_unreachable("UNKNOWN TYPE"); - return ""; -} -// OHOS_LOCAL end // The main function of the writer. template void Writer::run() { @@ -1208,6 +1059,7 @@ void PhdrEntry::add(OutputSection *sec) { p_align = kCFILibraryAlignment; } + AdltWriter adltWriter; if (p_type == PT_LOAD || p_type == PT_TLS) invokeELFT(adltWriter.trackPhdr, sec, this); } @@ -2142,7 +1994,7 @@ template void Writer::finalizeSections() { for (auto &it : llvm::enumerate(adltCtx->sharedFilesExtended)) { auto *soFile = cast>(it.value()); auto sections = soFile->getSections(); - // scan .rela.dyn (base: SHT_NULL) + // scan .rela.dyn or/and .relr.dyn (base: SHT_NULL) scanRelocations(*sections[0]); // scan .rela.plt (base: .got.plt) scanRelocations(*sections[soFile->gotPltSecIdx]); @@ -2357,6 +2209,7 @@ template void Writer::finalizeSections() { } // OHOS_LOCAL begin if (config->adlt) { // check ouput entries and indexes + AdltWriter adltWriter; adltWriter.checkPhdrs(); adltWriter.checkRelocs(); if (config->adltTrace) { @@ -2528,15 +2381,6 @@ SmallVector Writer::createPhdrs(Partition &part) { return ret.back(); }; - // OHOS_LOCAL begin - auto getOwnerFileIdx = [](OutputSection* sec) -> llvm::Optional { - auto file = adltWriter.getInputSection(sec)->file; - if (!file) - return llvm::None; - return adltCtx->getSoExt(file)->orderIdx; - }; - // OHOS_LOCAL end - unsigned partNo = part.getNumber(); bool isMain = partNo == 1; @@ -2627,9 +2471,13 @@ SmallVector Writer::createPhdrs(Partition &part) { // ALDT image sections have additional addribute: input file owner. // The ownership contiguousity allows to map only related sections // when processing program headers that - bool sameFileOwner = config->adlt && lastOwnerIdx == getOwnerFileIdx(sec); + std::unique_ptr adltWriter; + if (config->adlt) + adltWriter = std::make_unique(); + bool sameFileOwner = + config->adlt && lastOwnerIdx == adltWriter->getOwnerIndx(sec); if (config->adlt) - lastOwnerIdx = getOwnerFileIdx(sec); + lastOwnerIdx = adltWriter->getOwnerIndx(sec); // OHOS_LOCAL end if (!(load && newFlags == flags && sec != relroEnd && diff --git a/llvm/include/llvm/BinaryFormat/ADLTSection.h b/llvm/include/llvm/BinaryFormat/ADLTSection.h index 6d57903cdd09deae23b0790d0db0237e8b032713..04cc3fba347757c283ddf9a447da8e02d67328de 100644 --- a/llvm/include/llvm/BinaryFormat/ADLTSection.h +++ b/llvm/include/llvm/BinaryFormat/ADLTSection.h @@ -93,7 +93,8 @@ typedef struct { adlt_blob_array_t dtNeeded; // array of adlt_dt_needed_index_t[] elems adlt_cross_section_ref_t sharedLocalSymbolIndex; adlt_cross_section_ref_t sharedGlobalSymbolIndex; - adlt_blob_u16_array_t phIndexes; // program header indexes, typeof(e_phnum) + adlt_blob_u16_array_t phIndexes; // program header indexes, typeof(e_phnum) + adlt_blob_u32_array_t relrDynIndx; // .relr.dyn dependent indexes, raw list adlt_blob_u32_array_t relaDynIndx; // .rela.dyn dependent indexes, raw list adlt_blob_u32_array_t relaPltIndx; // .rela.plt dependent indexes, raw list } adlt_psod_t; @@ -112,7 +113,7 @@ typedef struct { static const char adltBlobStartMark[4] = {0xA, 0xD, 0x1, 0x7}; -static const adlt_semver_t adltSchemaVersion = {1, 1, 0}; +static const adlt_semver_t adltSchemaVersion = {1, 2, 0}; #ifdef __cplusplus } // namespace adlt