diff options
Diffstat (limited to 'ELF/SyntheticSections.cpp')
-rw-r--r-- | ELF/SyntheticSections.cpp | 1613 |
1 files changed, 978 insertions, 635 deletions
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index b673a4ece1d2..7009d3d34f66 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -27,6 +27,8 @@ #include "Threads.h" #include "Writer.h" #include "lld/Config/Version.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" +#include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/Endian.h" #include "llvm/Support/MD5.h" @@ -45,6 +47,12 @@ using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; +uint64_t SyntheticSection::getVA() const { + if (this->OutSec) + return this->OutSec->Addr + this->OutSecOff; + return 0; +} + template <class ELFT> static std::vector<DefinedCommon *> getCommonSymbols() { std::vector<DefinedCommon *> V; for (Symbol *S : Symtab<ELFT>::X->getSymbols()) @@ -54,35 +62,24 @@ template <class ELFT> static std::vector<DefinedCommon *> getCommonSymbols() { } // Find all common symbols and allocate space for them. -template <class ELFT> InputSection<ELFT> *elf::createCommonSection() { - auto *Ret = make<InputSection<ELFT>>(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, 1, - ArrayRef<uint8_t>(), "COMMON"); - Ret->Live = true; - +template <class ELFT> InputSection *elf::createCommonSection() { if (!Config->DefineCommon) - return Ret; + return nullptr; // Sort the common symbols by alignment as an heuristic to pack them better. std::vector<DefinedCommon *> Syms = getCommonSymbols<ELFT>(); + if (Syms.empty()) + return nullptr; + std::stable_sort(Syms.begin(), Syms.end(), [](const DefinedCommon *A, const DefinedCommon *B) { return A->Alignment > B->Alignment; }); - // Assign offsets to symbols. - size_t Size = 0; - size_t Alignment = 1; - for (DefinedCommon *Sym : Syms) { - Alignment = std::max<size_t>(Alignment, Sym->Alignment); - Size = alignTo(Size, Sym->Alignment); - - // Compute symbol offset relative to beginning of input section. - Sym->Offset = Size; - Size += Sym->Size; - } - Ret->Alignment = Alignment; - Ret->Data = makeArrayRef<uint8_t>(nullptr, Size); - return Ret; + BssSection *Sec = make<BssSection>("COMMON"); + for (DefinedCommon *Sym : Syms) + Sym->Offset = Sec->reserveSpace(Sym->Size, Sym->Alignment); + return Sec; } // Returns an LLD version string. @@ -102,14 +99,15 @@ static ArrayRef<uint8_t> getVersion() { // With this feature, you can identify LLD-generated binaries easily // by "objdump -s -j .comment <file>". // The returned object is a mergeable string section. -template <class ELFT> MergeInputSection<ELFT> *elf::createCommentSection() { +template <class ELFT> MergeInputSection *elf::createCommentSection() { typename ELFT::Shdr Hdr = {}; Hdr.sh_flags = SHF_MERGE | SHF_STRINGS; Hdr.sh_type = SHT_PROGBITS; Hdr.sh_entsize = 1; Hdr.sh_addralign = 1; - auto *Ret = make<MergeInputSection<ELFT>>(/*file=*/nullptr, &Hdr, ".comment"); + auto *Ret = + make<MergeInputSection>((ObjectFile<ELFT> *)nullptr, &Hdr, ".comment"); Ret->Data = getVersion(); Ret->splitIntoPieces(); return Ret; @@ -118,8 +116,10 @@ template <class ELFT> MergeInputSection<ELFT> *elf::createCommentSection() { // .MIPS.abiflags section. template <class ELFT> MipsAbiFlagsSection<ELFT>::MipsAbiFlagsSection(Elf_Mips_ABIFlags Flags) - : SyntheticSection<ELFT>(SHF_ALLOC, SHT_MIPS_ABIFLAGS, 8, ".MIPS.abiflags"), - Flags(Flags) {} + : SyntheticSection(SHF_ALLOC, SHT_MIPS_ABIFLAGS, 8, ".MIPS.abiflags"), + Flags(Flags) { + this->Entsize = sizeof(Elf_Mips_ABIFlags); +} template <class ELFT> void MipsAbiFlagsSection<ELFT>::writeTo(uint8_t *Buf) { memcpy(Buf, &Flags, sizeof(Flags)); @@ -130,13 +130,13 @@ MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() { Elf_Mips_ABIFlags Flags = {}; bool Create = false; - for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections) { - if (!Sec->Live || Sec->Type != SHT_MIPS_ABIFLAGS) + for (InputSectionBase *Sec : InputSections) { + if (Sec->Type != SHT_MIPS_ABIFLAGS) continue; Sec->Live = false; Create = true; - std::string Filename = toString(Sec->getFile()); + std::string Filename = toString(Sec->getFile<ELFT>()); const size_t Size = Sec->Data.size(); // Older version of BFD (such as the default FreeBSD linker) concatenate // .MIPS.abiflags instead of merging. To allow for this case (or potential @@ -175,8 +175,10 @@ MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() { // .MIPS.options section. template <class ELFT> MipsOptionsSection<ELFT>::MipsOptionsSection(Elf_Mips_RegInfo Reginfo) - : SyntheticSection<ELFT>(SHF_ALLOC, SHT_MIPS_OPTIONS, 8, ".MIPS.options"), - Reginfo(Reginfo) {} + : SyntheticSection(SHF_ALLOC, SHT_MIPS_OPTIONS, 8, ".MIPS.options"), + Reginfo(Reginfo) { + this->Entsize = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo); +} template <class ELFT> void MipsOptionsSection<ELFT>::writeTo(uint8_t *Buf) { auto *Options = reinterpret_cast<Elf_Mips_Options *>(Buf); @@ -197,13 +199,13 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() { Elf_Mips_RegInfo Reginfo = {}; bool Create = false; - for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections) { - if (!Sec->Live || Sec->Type != SHT_MIPS_OPTIONS) + for (InputSectionBase *Sec : InputSections) { + if (Sec->Type != SHT_MIPS_OPTIONS) continue; Sec->Live = false; Create = true; - std::string Filename = toString(Sec->getFile()); + std::string Filename = toString(Sec->getFile<ELFT>()); ArrayRef<uint8_t> D = Sec->Data; while (!D.empty()) { @@ -217,7 +219,7 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() { if (Config->Relocatable && Opt->getRegInfo().ri_gp_value) error(Filename + ": unsupported non-zero ri_gp_value"); Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask; - Sec->getFile()->MipsGp0 = Opt->getRegInfo().ri_gp_value; + Sec->getFile<ELFT>()->MipsGp0 = Opt->getRegInfo().ri_gp_value; break; } @@ -235,8 +237,10 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() { // MIPS .reginfo section. template <class ELFT> MipsReginfoSection<ELFT>::MipsReginfoSection(Elf_Mips_RegInfo Reginfo) - : SyntheticSection<ELFT>(SHF_ALLOC, SHT_MIPS_REGINFO, 4, ".reginfo"), - Reginfo(Reginfo) {} + : SyntheticSection(SHF_ALLOC, SHT_MIPS_REGINFO, 4, ".reginfo"), + Reginfo(Reginfo) { + this->Entsize = sizeof(Elf_Mips_RegInfo); +} template <class ELFT> void MipsReginfoSection<ELFT>::writeTo(uint8_t *Buf) { if (!Config->Relocatable) @@ -253,22 +257,24 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() { Elf_Mips_RegInfo Reginfo = {}; bool Create = false; - for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections) { - if (!Sec->Live || Sec->Type != SHT_MIPS_REGINFO) + for (InputSectionBase *Sec : InputSections) { + if (Sec->Type != SHT_MIPS_REGINFO) continue; Sec->Live = false; Create = true; if (Sec->Data.size() != sizeof(Elf_Mips_RegInfo)) { - error(toString(Sec->getFile()) + ": invalid size of .reginfo section"); + error(toString(Sec->getFile<ELFT>()) + + ": invalid size of .reginfo section"); return nullptr; } auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data()); if (Config->Relocatable && R->ri_gp_value) - error(toString(Sec->getFile()) + ": unsupported non-zero ri_gp_value"); + error(toString(Sec->getFile<ELFT>()) + + ": unsupported non-zero ri_gp_value"); Reginfo.ri_gprmask |= R->ri_gprmask; - Sec->getFile()->MipsGp0 = R->ri_gp_value; + Sec->getFile<ELFT>()->MipsGp0 = R->ri_gp_value; }; if (Create) @@ -276,15 +282,25 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() { return nullptr; } -template <class ELFT> InputSection<ELFT> *elf::createInterpSection() { - auto *Ret = make<InputSection<ELFT>>(SHF_ALLOC, SHT_PROGBITS, 1, - ArrayRef<uint8_t>(), ".interp"); - Ret->Live = true; - +InputSection *elf::createInterpSection() { // StringSaver guarantees that the returned string ends with '\0'. StringRef S = Saver.save(Config->DynamicLinker); - Ret->Data = {(const uint8_t *)S.data(), S.size() + 1}; - return Ret; + ArrayRef<uint8_t> Contents = {(const uint8_t *)S.data(), S.size() + 1}; + + auto *Sec = + make<InputSection>(SHF_ALLOC, SHT_PROGBITS, 1, Contents, ".interp"); + Sec->Live = true; + return Sec; +} + +template <class ELFT> +SymbolBody *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, + uint64_t Size, InputSectionBase *Section) { + auto *S = make<DefinedRegular>(Name, /*IsLocal*/ true, STV_DEFAULT, Type, + Value, Size, Section, nullptr); + if (In<ELFT>::SymTab) + In<ELFT>::SymTab->addSymbol(S); + return S; } static size_t getHashSize() { @@ -303,16 +319,15 @@ static size_t getHashSize() { } } -template <class ELFT> -BuildIdSection<ELFT>::BuildIdSection() - : SyntheticSection<ELFT>(SHF_ALLOC, SHT_NOTE, 1, ".note.gnu.build-id"), +BuildIdSection::BuildIdSection() + : SyntheticSection(SHF_ALLOC, SHT_NOTE, 1, ".note.gnu.build-id"), HashSize(getHashSize()) {} -template <class ELFT> void BuildIdSection<ELFT>::writeTo(uint8_t *Buf) { - const endianness E = ELFT::TargetEndianness; - write32<E>(Buf, 4); // Name size - write32<E>(Buf + 4, HashSize); // Content size - write32<E>(Buf + 8, NT_GNU_BUILD_ID); // Type +void BuildIdSection::writeTo(uint8_t *Buf) { + endianness E = Config->Endianness; + write32(Buf, 4, E); // Name size + write32(Buf + 4, HashSize, E); // Content size + write32(Buf + 8, NT_GNU_BUILD_ID, E); // Type memcpy(Buf + 12, "GNU", 4); // Name string HashBuf = Buf + 16; } @@ -334,23 +349,33 @@ static std::vector<ArrayRef<uint8_t>> split(ArrayRef<uint8_t> Arr, // In order to utilize multiple cores, we first split data into 1MB // chunks, compute a hash for each chunk, and then compute a hash value // of the hash values. -template <class ELFT> -void BuildIdSection<ELFT>::computeHash( +void BuildIdSection::computeHash( llvm::ArrayRef<uint8_t> Data, std::function<void(uint8_t *Dest, ArrayRef<uint8_t> Arr)> HashFn) { std::vector<ArrayRef<uint8_t>> Chunks = split(Data, 1024 * 1024); std::vector<uint8_t> Hashes(Chunks.size() * HashSize); // Compute hash values. - forLoop(0, Chunks.size(), - [&](size_t I) { HashFn(Hashes.data() + I * HashSize, Chunks[I]); }); + parallelFor(0, Chunks.size(), [&](size_t I) { + HashFn(Hashes.data() + I * HashSize, Chunks[I]); + }); // Write to the final output buffer. HashFn(HashBuf, Hashes); } -template <class ELFT> -void BuildIdSection<ELFT>::writeBuildId(ArrayRef<uint8_t> Buf) { +BssSection::BssSection(StringRef Name) + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, 0, Name) {} + +size_t BssSection::reserveSpace(uint64_t Size, uint32_t Alignment) { + if (OutSec) + OutSec->updateAlignment(Alignment); + this->Size = alignTo(this->Size, Alignment) + Size; + this->Alignment = std::max(this->Alignment, Alignment); + return this->Size - Size; +} + +void BuildIdSection::writeBuildId(ArrayRef<uint8_t> Buf) { switch (Config->BuildId) { case BuildIdKind::Fast: computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) { @@ -380,9 +405,216 @@ void BuildIdSection<ELFT>::writeBuildId(ArrayRef<uint8_t> Buf) { } template <class ELFT> +EhFrameSection<ELFT>::EhFrameSection() + : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame") {} + +// Search for an existing CIE record or create a new one. +// CIE records from input object files are uniquified by their contents +// and where their relocations point to. +template <class ELFT> +template <class RelTy> +CieRecord *EhFrameSection<ELFT>::addCie(EhSectionPiece &Piece, + ArrayRef<RelTy> Rels) { + auto *Sec = cast<EhInputSection>(Piece.ID); + const endianness E = ELFT::TargetEndianness; + if (read32<E>(Piece.data().data() + 4) != 0) + fatal(toString(Sec) + ": CIE expected at beginning of .eh_frame"); + + SymbolBody *Personality = nullptr; + unsigned FirstRelI = Piece.FirstRelocation; + if (FirstRelI != (unsigned)-1) + Personality = + &Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]); + + // Search for an existing CIE by CIE contents/relocation target pair. + CieRecord *Cie = &CieMap[{Piece.data(), Personality}]; + + // If not found, create a new one. + if (Cie->Piece == nullptr) { + Cie->Piece = &Piece; + Cies.push_back(Cie); + } + return Cie; +} + +// There is one FDE per function. Returns true if a given FDE +// points to a live function. +template <class ELFT> +template <class RelTy> +bool EhFrameSection<ELFT>::isFdeLive(EhSectionPiece &Piece, + ArrayRef<RelTy> Rels) { + auto *Sec = cast<EhInputSection>(Piece.ID); + unsigned FirstRelI = Piece.FirstRelocation; + if (FirstRelI == (unsigned)-1) + return false; + const RelTy &Rel = Rels[FirstRelI]; + SymbolBody &B = Sec->template getFile<ELFT>()->getRelocTargetSym(Rel); + auto *D = dyn_cast<DefinedRegular>(&B); + if (!D || !D->Section) + return false; + auto *Target = + cast<InputSectionBase>(cast<InputSectionBase>(D->Section)->Repl); + return Target && Target->Live; +} + +// .eh_frame is a sequence of CIE or FDE records. In general, there +// is one CIE record per input object file which is followed by +// a list of FDEs. This function searches an existing CIE or create a new +// one and associates FDEs to the CIE. +template <class ELFT> +template <class RelTy> +void EhFrameSection<ELFT>::addSectionAux(EhInputSection *Sec, + ArrayRef<RelTy> Rels) { + const endianness E = ELFT::TargetEndianness; + + DenseMap<size_t, CieRecord *> OffsetToCie; + for (EhSectionPiece &Piece : Sec->Pieces) { + // The empty record is the end marker. + if (Piece.size() == 4) + return; + + size_t Offset = Piece.InputOff; + uint32_t ID = read32<E>(Piece.data().data() + 4); + if (ID == 0) { + OffsetToCie[Offset] = addCie(Piece, Rels); + continue; + } + + uint32_t CieOffset = Offset + 4 - ID; + CieRecord *Cie = OffsetToCie[CieOffset]; + if (!Cie) + fatal(toString(Sec) + ": invalid CIE reference"); + + if (!isFdeLive(Piece, Rels)) + continue; + Cie->FdePieces.push_back(&Piece); + NumFdes++; + } +} + +template <class ELFT> +void EhFrameSection<ELFT>::addSection(InputSectionBase *C) { + auto *Sec = cast<EhInputSection>(C); + Sec->EHSec = this; + updateAlignment(Sec->Alignment); + Sections.push_back(Sec); + for (auto *DS : Sec->DependentSections) + DependentSections.push_back(DS); + + // .eh_frame is a sequence of CIE or FDE records. This function + // splits it into pieces so that we can call + // SplitInputSection::getSectionPiece on the section. + Sec->split<ELFT>(); + if (Sec->Pieces.empty()) + return; + + if (Sec->NumRelocations) { + if (Sec->AreRelocsRela) + addSectionAux(Sec, Sec->template relas<ELFT>()); + else + addSectionAux(Sec, Sec->template rels<ELFT>()); + return; + } + addSectionAux(Sec, makeArrayRef<Elf_Rela>(nullptr, nullptr)); +} + +template <class ELFT> +static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) { + memcpy(Buf, D.data(), D.size()); + + // Fix the size field. -4 since size does not include the size field itself. + const endianness E = ELFT::TargetEndianness; + write32<E>(Buf, alignTo(D.size(), sizeof(typename ELFT::uint)) - 4); +} + +template <class ELFT> void EhFrameSection<ELFT>::finalizeContents() { + if (this->Size) + return; // Already finalized. + + size_t Off = 0; + for (CieRecord *Cie : Cies) { + Cie->Piece->OutputOff = Off; + Off += alignTo(Cie->Piece->size(), Config->Wordsize); + + for (EhSectionPiece *Fde : Cie->FdePieces) { + Fde->OutputOff = Off; + Off += alignTo(Fde->size(), Config->Wordsize); + } + } + this->Size = Off; +} + +template <class ELFT> static uint64_t readFdeAddr(uint8_t *Buf, int Size) { + const endianness E = ELFT::TargetEndianness; + switch (Size) { + case DW_EH_PE_udata2: + return read16<E>(Buf); + case DW_EH_PE_udata4: + return read32<E>(Buf); + case DW_EH_PE_udata8: + return read64<E>(Buf); + case DW_EH_PE_absptr: + if (ELFT::Is64Bits) + return read64<E>(Buf); + return read32<E>(Buf); + } + fatal("unknown FDE size encoding"); +} + +// Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to. +// We need it to create .eh_frame_hdr section. +template <class ELFT> +uint64_t EhFrameSection<ELFT>::getFdePc(uint8_t *Buf, size_t FdeOff, + uint8_t Enc) { + // The starting address to which this FDE applies is + // stored at FDE + 8 byte. + size_t Off = FdeOff + 8; + uint64_t Addr = readFdeAddr<ELFT>(Buf + Off, Enc & 0x7); + if ((Enc & 0x70) == DW_EH_PE_absptr) + return Addr; + if ((Enc & 0x70) == DW_EH_PE_pcrel) + return Addr + this->OutSec->Addr + Off; + fatal("unknown FDE size relative encoding"); +} + +template <class ELFT> void EhFrameSection<ELFT>::writeTo(uint8_t *Buf) { + const endianness E = ELFT::TargetEndianness; + for (CieRecord *Cie : Cies) { + size_t CieOffset = Cie->Piece->OutputOff; + writeCieFde<ELFT>(Buf + CieOffset, Cie->Piece->data()); + + for (EhSectionPiece *Fde : Cie->FdePieces) { + size_t Off = Fde->OutputOff; + writeCieFde<ELFT>(Buf + Off, Fde->data()); + + // FDE's second word should have the offset to an associated CIE. + // Write it. + write32<E>(Buf + Off + 4, Off + 4 - CieOffset); + } + } + + for (EhInputSection *S : Sections) + S->template relocate<ELFT>(Buf, nullptr); + + // Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table + // to get a FDE from an address to which FDE is applied. So here + // we obtain two addresses and pass them to EhFrameHdr object. + if (In<ELFT>::EhFrameHdr) { + for (CieRecord *Cie : Cies) { + uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece); + for (SectionPiece *Fde : Cie->FdePieces) { + uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc); + uint64_t FdeVA = this->OutSec->Addr + Fde->OutputOff; + In<ELFT>::EhFrameHdr->addFde(Pc, FdeVA); + } + } + } +} + +template <class ELFT> GotSection<ELFT>::GotSection() - : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, - Target->GotEntrySize, ".got") {} + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, + Target->GotEntrySize, ".got") {} template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody &Sym) { Sym.GotIndex = NumEntries; @@ -403,25 +635,23 @@ template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) { template <class ELFT> bool GotSection<ELFT>::addTlsIndex() { if (TlsIndexOff != uint32_t(-1)) return false; - TlsIndexOff = NumEntries * sizeof(uintX_t); + TlsIndexOff = NumEntries * Config->Wordsize; NumEntries += 2; return true; } template <class ELFT> -typename GotSection<ELFT>::uintX_t -GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const { - return this->getVA() + B.GlobalDynIndex * sizeof(uintX_t); +uint64_t GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const { + return this->getVA() + B.GlobalDynIndex * Config->Wordsize; } template <class ELFT> -typename GotSection<ELFT>::uintX_t -GotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const { - return B.GlobalDynIndex * sizeof(uintX_t); +uint64_t GotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const { + return B.GlobalDynIndex * Config->Wordsize; } -template <class ELFT> void GotSection<ELFT>::finalize() { - Size = NumEntries * sizeof(uintX_t); +template <class ELFT> void GotSection<ELFT>::finalizeContents() { + Size = NumEntries * Config->Wordsize; } template <class ELFT> bool GotSection<ELFT>::empty() const { @@ -431,17 +661,14 @@ template <class ELFT> bool GotSection<ELFT>::empty() const { } template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) { - this->relocate(Buf, Buf + Size); + this->template relocate<ELFT>(Buf, Buf + Size); } -template <class ELFT> -MipsGotSection<ELFT>::MipsGotSection() - : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, - SHT_PROGBITS, 16, ".got") {} +MipsGotSection::MipsGotSection() + : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16, + ".got") {} -template <class ELFT> -void MipsGotSection<ELFT>::addEntry(SymbolBody &Sym, uintX_t Addend, - RelExpr Expr) { +void MipsGotSection::addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr) { // For "true" local symbols which can be referenced from the same module // only compiler creates two instructions for address loading: // @@ -472,7 +699,8 @@ void MipsGotSection<ELFT>::addEntry(SymbolBody &Sym, uintX_t Addend, // sections referenced by GOT relocations. Then later in the `finalize` // method calculate number of "pages" required to cover all saved output // section and allocate appropriate number of GOT entries. - PageIndexMap.insert({cast<DefinedRegular<ELFT>>(&Sym)->Section->OutSec, 0}); + auto *DefSym = cast<DefinedRegular>(&Sym); + PageIndexMap.insert({DefSym->Section->getOutputSection(), 0}); return; } if (Sym.isTls()) { @@ -483,7 +711,7 @@ void MipsGotSection<ELFT>::addEntry(SymbolBody &Sym, uintX_t Addend, TlsEntries.push_back(&Sym); return; } - auto AddEntry = [&](SymbolBody &S, uintX_t A, GotEntries &Items) { + auto AddEntry = [&](SymbolBody &S, uint64_t A, GotEntries &Items) { if (S.isInGot() && !A) return; size_t NewIndex = Items.size(); @@ -508,8 +736,7 @@ void MipsGotSection<ELFT>::addEntry(SymbolBody &Sym, uintX_t Addend, } } -template <class ELFT> -bool MipsGotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) { +bool MipsGotSection::addDynTlsEntry(SymbolBody &Sym) { if (Sym.GlobalDynIndex != -1U) return false; Sym.GlobalDynIndex = TlsEntries.size(); @@ -521,10 +748,10 @@ bool MipsGotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) { // Reserves TLS entries for a TLS module ID and a TLS block offset. // In total it takes two GOT slots. -template <class ELFT> bool MipsGotSection<ELFT>::addTlsIndex() { +bool MipsGotSection::addTlsIndex() { if (TlsIndexOff != uint32_t(-1)) return false; - TlsIndexOff = TlsEntries.size() * sizeof(uintX_t); + TlsIndexOff = TlsEntries.size() * Config->Wordsize; TlsEntries.push_back(nullptr); TlsEntries.push_back(nullptr); return true; @@ -538,25 +765,21 @@ static uint64_t getMipsPageCount(uint64_t Size) { return (Size + 0xfffe) / 0xffff + 1; } -template <class ELFT> -typename MipsGotSection<ELFT>::uintX_t -MipsGotSection<ELFT>::getPageEntryOffset(const SymbolBody &B, - uintX_t Addend) const { - const OutputSectionBase *OutSec = - cast<DefinedRegular<ELFT>>(&B)->Section->OutSec; - uintX_t SecAddr = getMipsPageAddr(OutSec->Addr); - uintX_t SymAddr = getMipsPageAddr(B.getVA<ELFT>(Addend)); - uintX_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff; +uint64_t MipsGotSection::getPageEntryOffset(const SymbolBody &B, + int64_t Addend) const { + const OutputSection *OutSec = + cast<DefinedRegular>(&B)->Section->getOutputSection(); + uint64_t SecAddr = getMipsPageAddr(OutSec->Addr); + uint64_t SymAddr = getMipsPageAddr(B.getVA(Addend)); + uint64_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff; assert(Index < PageEntriesNum); - return (HeaderEntriesNum + Index) * sizeof(uintX_t); + return (HeaderEntriesNum + Index) * Config->Wordsize; } -template <class ELFT> -typename MipsGotSection<ELFT>::uintX_t -MipsGotSection<ELFT>::getBodyEntryOffset(const SymbolBody &B, - uintX_t Addend) const { +uint64_t MipsGotSection::getBodyEntryOffset(const SymbolBody &B, + int64_t Addend) const { // Calculate offset of the GOT entries block: TLS, global, local. - uintX_t Index = HeaderEntriesNum + PageEntriesNum; + uint64_t Index = HeaderEntriesNum + PageEntriesNum; if (B.isTls()) Index += LocalEntries.size() + LocalEntries32.size() + GlobalEntries.size(); else if (B.IsInGlobalMipsGot) @@ -571,35 +794,33 @@ MipsGotSection<ELFT>::getBodyEntryOffset(const SymbolBody &B, assert(It != EntryIndexMap.end()); Index += It->second; } - return Index * sizeof(uintX_t); + return Index * Config->Wordsize; } -template <class ELFT> -typename MipsGotSection<ELFT>::uintX_t -MipsGotSection<ELFT>::getTlsOffset() const { - return (getLocalEntriesNum() + GlobalEntries.size()) * sizeof(uintX_t); +uint64_t MipsGotSection::getTlsOffset() const { + return (getLocalEntriesNum() + GlobalEntries.size()) * Config->Wordsize; } -template <class ELFT> -typename MipsGotSection<ELFT>::uintX_t -MipsGotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const { - return B.GlobalDynIndex * sizeof(uintX_t); +uint64_t MipsGotSection::getGlobalDynOffset(const SymbolBody &B) const { + return B.GlobalDynIndex * Config->Wordsize; } -template <class ELFT> -const SymbolBody *MipsGotSection<ELFT>::getFirstGlobalEntry() const { +const SymbolBody *MipsGotSection::getFirstGlobalEntry() const { return GlobalEntries.empty() ? nullptr : GlobalEntries.front().first; } -template <class ELFT> -unsigned MipsGotSection<ELFT>::getLocalEntriesNum() const { +unsigned MipsGotSection::getLocalEntriesNum() const { return HeaderEntriesNum + PageEntriesNum + LocalEntries.size() + LocalEntries32.size(); } -template <class ELFT> void MipsGotSection<ELFT>::finalize() { +void MipsGotSection::finalizeContents() { + updateAllocSize(); +} + +void MipsGotSection::updateAllocSize() { PageEntriesNum = 0; - for (std::pair<const OutputSectionBase *, size_t> &P : PageIndexMap) { + for (std::pair<const OutputSection *, size_t> &P : PageIndexMap) { // For each output section referenced by GOT page relocations calculate // and save into PageIndexMap an upper bound of MIPS GOT entries required // to store page addresses of local symbols. We assume the worst case - @@ -610,27 +831,33 @@ template <class ELFT> void MipsGotSection<ELFT>::finalize() { PageEntriesNum += getMipsPageCount(P.first->Size); } Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) * - sizeof(uintX_t); + Config->Wordsize; } -template <class ELFT> bool MipsGotSection<ELFT>::empty() const { +bool MipsGotSection::empty() const { // We add the .got section to the result for dynamic MIPS target because // its address and properties are mentioned in the .dynamic section. return Config->Relocatable; } -template <class ELFT> -typename MipsGotSection<ELFT>::uintX_t MipsGotSection<ELFT>::getGp() const { - return ElfSym<ELFT>::MipsGp->template getVA<ELFT>(0); +uint64_t MipsGotSection::getGp() const { + return ElfSym::MipsGp->getVA(0); } -template <class ELFT> -static void writeUint(uint8_t *Buf, typename ELFT::uint Val) { - typedef typename ELFT::uint uintX_t; - write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Buf, Val); +static uint64_t readUint(uint8_t *Buf) { + if (Config->Is64) + return read64(Buf, Config->Endianness); + return read32(Buf, Config->Endianness); +} + +static void writeUint(uint8_t *Buf, uint64_t Val) { + if (Config->Is64) + write64(Buf, Val, Config->Endianness); + else + write32(Buf, Val, Config->Endianness); } -template <class ELFT> void MipsGotSection<ELFT>::writeTo(uint8_t *Buf) { +void MipsGotSection::writeTo(uint8_t *Buf) { // Set the MSB of the second GOT slot. This is not required by any // MIPS ABI documentation, though. // @@ -645,25 +872,24 @@ template <class ELFT> void MipsGotSection<ELFT>::writeTo(uint8_t *Buf) { // we've been doing this for years, it is probably a safe bet to // keep doing this for now. We really need to revisit this to see // if we had to do this. - auto *P = reinterpret_cast<typename ELFT::Off *>(Buf); - P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31); - Buf += HeaderEntriesNum * sizeof(uintX_t); + writeUint(Buf + Config->Wordsize, (uint64_t)1 << (Config->Wordsize * 8 - 1)); + Buf += HeaderEntriesNum * Config->Wordsize; // Write 'page address' entries to the local part of the GOT. - for (std::pair<const OutputSectionBase *, size_t> &L : PageIndexMap) { + for (std::pair<const OutputSection *, size_t> &L : PageIndexMap) { size_t PageCount = getMipsPageCount(L.first->Size); - uintX_t FirstPageAddr = getMipsPageAddr(L.first->Addr); + uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr); for (size_t PI = 0; PI < PageCount; ++PI) { - uint8_t *Entry = Buf + (L.second + PI) * sizeof(uintX_t); - writeUint<ELFT>(Entry, FirstPageAddr + PI * 0x10000); + uint8_t *Entry = Buf + (L.second + PI) * Config->Wordsize; + writeUint(Entry, FirstPageAddr + PI * 0x10000); } } - Buf += PageEntriesNum * sizeof(uintX_t); + Buf += PageEntriesNum * Config->Wordsize; auto AddEntry = [&](const GotEntry &SA) { uint8_t *Entry = Buf; - Buf += sizeof(uintX_t); + Buf += Config->Wordsize; const SymbolBody *Body = SA.first; - uintX_t VA = Body->template getVA<ELFT>(SA.second); - writeUint<ELFT>(Entry, VA); + uint64_t VA = Body->getVA(SA.second); + writeUint(Entry, VA); }; std::for_each(std::begin(LocalEntries), std::end(LocalEntries), AddEntry); std::for_each(std::begin(LocalEntries32), std::end(LocalEntries32), AddEntry); @@ -674,86 +900,83 @@ template <class ELFT> void MipsGotSection<ELFT>::writeTo(uint8_t *Buf) { // for thread-local storage. // https://www.linux-mips.org/wiki/NPTL if (TlsIndexOff != -1U && !Config->Pic) - writeUint<ELFT>(Buf + TlsIndexOff, 1); + writeUint(Buf + TlsIndexOff, 1); for (const SymbolBody *B : TlsEntries) { if (!B || B->isPreemptible()) continue; - uintX_t VA = B->getVA<ELFT>(); + uint64_t VA = B->getVA(); if (B->GotIndex != -1U) { - uint8_t *Entry = Buf + B->GotIndex * sizeof(uintX_t); - writeUint<ELFT>(Entry, VA - 0x7000); + uint8_t *Entry = Buf + B->GotIndex * Config->Wordsize; + writeUint(Entry, VA - 0x7000); } if (B->GlobalDynIndex != -1U) { - uint8_t *Entry = Buf + B->GlobalDynIndex * sizeof(uintX_t); - writeUint<ELFT>(Entry, 1); - Entry += sizeof(uintX_t); - writeUint<ELFT>(Entry, VA - 0x8000); + uint8_t *Entry = Buf + B->GlobalDynIndex * Config->Wordsize; + writeUint(Entry, 1); + Entry += Config->Wordsize; + writeUint(Entry, VA - 0x8000); } } } -template <class ELFT> -GotPltSection<ELFT>::GotPltSection() - : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, - Target->GotPltEntrySize, ".got.plt") {} +GotPltSection::GotPltSection() + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, + Target->GotPltEntrySize, ".got.plt") {} -template <class ELFT> void GotPltSection<ELFT>::addEntry(SymbolBody &Sym) { +void GotPltSection::addEntry(SymbolBody &Sym) { Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size(); Entries.push_back(&Sym); } -template <class ELFT> size_t GotPltSection<ELFT>::getSize() const { +size_t GotPltSection::getSize() const { return (Target->GotPltHeaderEntriesNum + Entries.size()) * Target->GotPltEntrySize; } -template <class ELFT> void GotPltSection<ELFT>::writeTo(uint8_t *Buf) { +void GotPltSection::writeTo(uint8_t *Buf) { Target->writeGotPltHeader(Buf); Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize; for (const SymbolBody *B : Entries) { Target->writeGotPlt(Buf, *B); - Buf += sizeof(uintX_t); + Buf += Config->Wordsize; } } // On ARM the IgotPltSection is part of the GotSection, on other Targets it is // part of the .got.plt -template <class ELFT> -IgotPltSection<ELFT>::IgotPltSection() - : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, - Target->GotPltEntrySize, - Config->EMachine == EM_ARM ? ".got" : ".got.plt") { -} +IgotPltSection::IgotPltSection() + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, + Target->GotPltEntrySize, + Config->EMachine == EM_ARM ? ".got" : ".got.plt") {} -template <class ELFT> void IgotPltSection<ELFT>::addEntry(SymbolBody &Sym) { +void IgotPltSection::addEntry(SymbolBody &Sym) { Sym.IsInIgot = true; Sym.GotPltIndex = Entries.size(); Entries.push_back(&Sym); } -template <class ELFT> size_t IgotPltSection<ELFT>::getSize() const { +size_t IgotPltSection::getSize() const { return Entries.size() * Target->GotPltEntrySize; } -template <class ELFT> void IgotPltSection<ELFT>::writeTo(uint8_t *Buf) { +void IgotPltSection::writeTo(uint8_t *Buf) { for (const SymbolBody *B : Entries) { Target->writeIgotPlt(Buf, *B); - Buf += sizeof(uintX_t); + Buf += Config->Wordsize; } } -template <class ELFT> -StringTableSection<ELFT>::StringTableSection(StringRef Name, bool Dynamic) - : SyntheticSection<ELFT>(Dynamic ? (uintX_t)SHF_ALLOC : 0, SHT_STRTAB, 1, - Name), - Dynamic(Dynamic) {} +StringTableSection::StringTableSection(StringRef Name, bool Dynamic) + : SyntheticSection(Dynamic ? (uint64_t)SHF_ALLOC : 0, SHT_STRTAB, 1, Name), + Dynamic(Dynamic) { + // ELF string tables start with a NUL byte. + addString(""); +} // Adds a string to the string table. If HashIt is true we hash and check for // duplicates. It is optional because the name of global symbols are already // uniqued and hashing them again has a big cost for a small value: uniquing // them with some other string that happens to be the same. -template <class ELFT> -unsigned StringTableSection<ELFT>::addString(StringRef S, bool HashIt) { +unsigned StringTableSection::addString(StringRef S, bool HashIt) { if (HashIt) { auto R = StringMap.insert(std::make_pair(S, this->Size)); if (!R.second) @@ -765,9 +988,7 @@ unsigned StringTableSection<ELFT>::addString(StringRef S, bool HashIt) { return Ret; } -template <class ELFT> void StringTableSection<ELFT>::writeTo(uint8_t *Buf) { - // ELF string tables start with NUL byte, so advance the pointer by one. - ++Buf; +void StringTableSection::writeTo(uint8_t *Buf) { for (StringRef S : Strings) { memcpy(Buf, S.data(), S.size()); Buf += S.size() + 1; @@ -781,9 +1002,10 @@ static unsigned getVerDefNum() { return Config->VersionDefinitions.size() + 1; } template <class ELFT> DynamicSection<ELFT>::DynamicSection() - : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_DYNAMIC, - sizeof(uintX_t), ".dynamic") { + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_DYNAMIC, Config->Wordsize, + ".dynamic") { this->Entsize = ELFT::Is64Bits ? 16 : 8; + // .dynamic section is not writable on MIPS. // See "Special Section" in Chapter 4 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf @@ -816,6 +1038,8 @@ template <class ELFT> void DynamicSection<ELFT>::addEntries() { DtFlags |= DF_SYMBOLIC; if (Config->ZNodelete) DtFlags1 |= DF_1_NODELETE; + if (Config->ZNodlopen) + DtFlags1 |= DF_1_NOOPEN; if (Config->ZNow) { DtFlags |= DF_BIND_NOW; DtFlags1 |= DF_1_NOW; @@ -835,17 +1059,17 @@ template <class ELFT> void DynamicSection<ELFT>::addEntries() { } // Add remaining entries to complete .dynamic contents. -template <class ELFT> void DynamicSection<ELFT>::finalize() { +template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { if (this->Size) return; // Already finalized. this->Link = In<ELFT>::DynStrTab->OutSec->SectionIndex; if (In<ELFT>::RelaDyn->OutSec->Size > 0) { - bool IsRela = Config->Rela; + bool IsRela = Config->IsRela; add({IsRela ? DT_RELA : DT_REL, In<ELFT>::RelaDyn}); add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->OutSec->Size}); add({IsRela ? DT_RELAENT : DT_RELENT, - uintX_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))}); + uint64_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))}); // MIPS dynamic loader does not support RELCOUNT tag. // The problem is in the tight relation between dynamic @@ -861,29 +1085,31 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() { add({DT_PLTRELSZ, In<ELFT>::RelaPlt->OutSec->Size}); add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT, In<ELFT>::GotPlt}); - add({DT_PLTREL, uint64_t(Config->Rela ? DT_RELA : DT_REL)}); + add({DT_PLTREL, uint64_t(Config->IsRela ? DT_RELA : DT_REL)}); } add({DT_SYMTAB, In<ELFT>::DynSymTab}); add({DT_SYMENT, sizeof(Elf_Sym)}); add({DT_STRTAB, In<ELFT>::DynStrTab}); add({DT_STRSZ, In<ELFT>::DynStrTab->getSize()}); + if (!Config->ZText) + add({DT_TEXTREL, (uint64_t)0}); if (In<ELFT>::GnuHashTab) add({DT_GNU_HASH, In<ELFT>::GnuHashTab}); if (In<ELFT>::HashTab) add({DT_HASH, In<ELFT>::HashTab}); - if (Out<ELFT>::PreinitArray) { - add({DT_PREINIT_ARRAY, Out<ELFT>::PreinitArray}); - add({DT_PREINIT_ARRAYSZ, Out<ELFT>::PreinitArray, Entry::SecSize}); + if (Out::PreinitArray) { + add({DT_PREINIT_ARRAY, Out::PreinitArray}); + add({DT_PREINIT_ARRAYSZ, Out::PreinitArray, Entry::SecSize}); } - if (Out<ELFT>::InitArray) { - add({DT_INIT_ARRAY, Out<ELFT>::InitArray}); - add({DT_INIT_ARRAYSZ, Out<ELFT>::InitArray, Entry::SecSize}); + if (Out::InitArray) { + add({DT_INIT_ARRAY, Out::InitArray}); + add({DT_INIT_ARRAYSZ, Out::InitArray, Entry::SecSize}); } - if (Out<ELFT>::FiniArray) { - add({DT_FINI_ARRAY, Out<ELFT>::FiniArray}); - add({DT_FINI_ARRAYSZ, Out<ELFT>::FiniArray, Entry::SecSize}); + if (Out::FiniArray) { + add({DT_FINI_ARRAY, Out::FiniArray}); + add({DT_FINI_ARRAYSZ, Out::FiniArray, Entry::SecSize}); } if (SymbolBody *B = Symtab<ELFT>::X->findInCurrentDSO(Config->Init)) @@ -918,7 +1144,6 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() { add({DT_MIPS_RLD_MAP, In<ELFT>::MipsRldMap}); } - this->OutSec->Entsize = this->Entsize; this->OutSec->Link = this->Link; // +1 for DT_NULL @@ -941,7 +1166,7 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) { P->d_un.d_val = E.OutSec->Size; break; case Entry::SymAddr: - P->d_un.d_ptr = E.Sym->template getVA<ELFT>(); + P->d_un.d_ptr = E.Sym->getVA(); break; case Entry::PlainInt: P->d_un.d_val = E.Val; @@ -951,21 +1176,17 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) { } } -template <class ELFT> -typename ELFT::uint DynamicReloc<ELFT>::getOffset() const { - if (OutputSec) - return OutputSec->Addr + OffsetInSec; +uint64_t DynamicReloc::getOffset() const { return InputSec->OutSec->Addr + InputSec->getOffset(OffsetInSec); } -template <class ELFT> -typename ELFT::uint DynamicReloc<ELFT>::getAddend() const { +int64_t DynamicReloc::getAddend() const { if (UseSymVA) - return Sym->getVA<ELFT>(Addend); + return Sym->getVA(Addend); return Addend; } -template <class ELFT> uint32_t DynamicReloc<ELFT>::getSymIndex() const { +uint32_t DynamicReloc::getSymIndex() const { if (Sym && !UseSymVA) return Sym->DynsymIndex; return 0; @@ -973,14 +1194,14 @@ template <class ELFT> uint32_t DynamicReloc<ELFT>::getSymIndex() const { template <class ELFT> RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort) - : SyntheticSection<ELFT>(SHF_ALLOC, Config->Rela ? SHT_RELA : SHT_REL, - sizeof(uintX_t), Name), + : SyntheticSection(SHF_ALLOC, Config->IsRela ? SHT_RELA : SHT_REL, + Config->Wordsize, Name), Sort(Sort) { - this->Entsize = Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); + this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); } template <class ELFT> -void RelocationSection<ELFT>::addReloc(const DynamicReloc<ELFT> &Reloc) { +void RelocationSection<ELFT>::addReloc(const DynamicReloc &Reloc) { if (Reloc.Type == Target->RelativeRel) ++NumRelativeRelocs; Relocs.push_back(Reloc); @@ -988,21 +1209,21 @@ void RelocationSection<ELFT>::addReloc(const DynamicReloc<ELFT> &Reloc) { template <class ELFT, class RelTy> static bool compRelocations(const RelTy &A, const RelTy &B) { - bool AIsRel = A.getType(Config->Mips64EL) == Target->RelativeRel; - bool BIsRel = B.getType(Config->Mips64EL) == Target->RelativeRel; + bool AIsRel = A.getType(Config->IsMips64EL) == Target->RelativeRel; + bool BIsRel = B.getType(Config->IsMips64EL) == Target->RelativeRel; if (AIsRel != BIsRel) return AIsRel; - return A.getSymbol(Config->Mips64EL) < B.getSymbol(Config->Mips64EL); + return A.getSymbol(Config->IsMips64EL) < B.getSymbol(Config->IsMips64EL); } template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) { uint8_t *BufBegin = Buf; - for (const DynamicReloc<ELFT> &Rel : Relocs) { + for (const DynamicReloc &Rel : Relocs) { auto *P = reinterpret_cast<Elf_Rela *>(Buf); - Buf += Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); + Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); - if (Config->Rela) + if (Config->IsRela) P->r_addend = Rel.getAddend(); P->r_offset = Rel.getOffset(); if (Config->EMachine == EM_MIPS && Rel.getInputSec() == In<ELFT>::MipsGot) @@ -1010,11 +1231,11 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) { // allocated in the end of the GOT. We need to adjust the offset to take // in account 'local' and 'global' GOT entries. P->r_offset += In<ELFT>::MipsGot->getTlsOffset(); - P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->Mips64EL); + P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL); } if (Sort) { - if (Config->Rela) + if (Config->IsRela) std::stable_sort((Elf_Rela *)BufBegin, (Elf_Rela *)BufBegin + Relocs.size(), compRelocations<ELFT, Elf_Rela>); @@ -1028,22 +1249,20 @@ template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() { return this->Entsize * Relocs.size(); } -template <class ELFT> void RelocationSection<ELFT>::finalize() { +template <class ELFT> void RelocationSection<ELFT>::finalizeContents() { this->Link = In<ELFT>::DynSymTab ? In<ELFT>::DynSymTab->OutSec->SectionIndex : In<ELFT>::SymTab->OutSec->SectionIndex; // Set required output section properties. this->OutSec->Link = this->Link; - this->OutSec->Entsize = this->Entsize; } template <class ELFT> -SymbolTableSection<ELFT>::SymbolTableSection( - StringTableSection<ELFT> &StrTabSec) - : SyntheticSection<ELFT>(StrTabSec.isDynamic() ? (uintX_t)SHF_ALLOC : 0, - StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB, - sizeof(uintX_t), - StrTabSec.isDynamic() ? ".dynsym" : ".symtab"), +SymbolTableSection<ELFT>::SymbolTableSection(StringTableSection &StrTabSec) + : SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0, + StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB, + Config->Wordsize, + StrTabSec.isDynamic() ? ".dynsym" : ".symtab"), StrTabSec(StrTabSec) { this->Entsize = sizeof(Elf_Sym); } @@ -1053,289 +1272,257 @@ SymbolTableSection<ELFT>::SymbolTableSection( // See "Global Offset Table" in Chapter 5 in the following document // for detailed description: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf -static bool sortMipsSymbols(const SymbolBody *L, const SymbolBody *R) { +static bool sortMipsSymbols(const SymbolTableEntry &L, + const SymbolTableEntry &R) { // Sort entries related to non-local preemptible symbols by GOT indexes. // All other entries go to the first part of GOT in arbitrary order. - bool LIsInLocalGot = !L->IsInGlobalMipsGot; - bool RIsInLocalGot = !R->IsInGlobalMipsGot; + bool LIsInLocalGot = !L.Symbol->IsInGlobalMipsGot; + bool RIsInLocalGot = !R.Symbol->IsInGlobalMipsGot; if (LIsInLocalGot || RIsInLocalGot) return !RIsInLocalGot; - return L->GotIndex < R->GotIndex; -} - -template <class ELFT> void SymbolTableSection<ELFT>::finalize() { - this->OutSec->Link = this->Link = StrTabSec.OutSec->SectionIndex; - this->OutSec->Info = this->Info = NumLocals + 1; - this->OutSec->Entsize = this->Entsize; - - if (Config->Relocatable) - return; + return L.Symbol->GotIndex < R.Symbol->GotIndex; +} + +// Finalize a symbol table. The ELF spec requires that all local +// symbols precede global symbols, so we sort symbol entries in this +// function. (For .dynsym, we don't do that because symbols for +// dynamic linking are inherently all globals.) +template <class ELFT> void SymbolTableSection<ELFT>::finalizeContents() { + this->OutSec->Link = StrTabSec.OutSec->SectionIndex; + + // If it is a .dynsym, there should be no local symbols, but we need + // to do a few things for the dynamic linker. + if (this->Type == SHT_DYNSYM) { + // Section's Info field has the index of the first non-local symbol. + // Because the first symbol entry is a null entry, 1 is the first. + this->OutSec->Info = 1; + + if (In<ELFT>::GnuHashTab) { + // NB: It also sorts Symbols to meet the GNU hash table requirements. + In<ELFT>::GnuHashTab->addSymbols(Symbols); + } else if (Config->EMachine == EM_MIPS) { + std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols); + } - if (!StrTabSec.isDynamic()) { - auto GlobBegin = Symbols.begin() + NumLocals; - auto It = std::stable_partition( - GlobBegin, Symbols.end(), [](const SymbolTableEntry &S) { - return S.Symbol->symbol()->computeBinding() == STB_LOCAL; - }); - // update sh_info with number of Global symbols output with computed - // binding of STB_LOCAL - this->OutSec->Info = this->Info = 1 + It - Symbols.begin(); + size_t I = 0; + for (const SymbolTableEntry &S : Symbols) + S.Symbol->DynsymIndex = ++I; return; } - - if (In<ELFT>::GnuHashTab) - // NB: It also sorts Symbols to meet the GNU hash table requirements. - In<ELFT>::GnuHashTab->addSymbols(Symbols); - else if (Config->EMachine == EM_MIPS) - std::stable_sort(Symbols.begin(), Symbols.end(), - [](const SymbolTableEntry &L, const SymbolTableEntry &R) { - return sortMipsSymbols(L.Symbol, R.Symbol); - }); - size_t I = 0; - for (const SymbolTableEntry &S : Symbols) - S.Symbol->DynsymIndex = ++I; } -template <class ELFT> void SymbolTableSection<ELFT>::addGlobal(SymbolBody *B) { - Symbols.push_back({B, StrTabSec.addString(B->getName(), false)}); +template <class ELFT> void SymbolTableSection<ELFT>::postThunkContents() { + if (this->Type == SHT_DYNSYM) + return; + // move all local symbols before global symbols. + auto It = std::stable_partition( + Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) { + return S.Symbol->isLocal() || + S.Symbol->symbol()->computeBinding() == STB_LOCAL; + }); + size_t NumLocals = It - Symbols.begin(); + this->OutSec->Info = NumLocals + 1; } -template <class ELFT> void SymbolTableSection<ELFT>::addLocal(SymbolBody *B) { - assert(!StrTabSec.isDynamic()); - ++NumLocals; - Symbols.push_back({B, StrTabSec.addString(B->getName())}); +template <class ELFT> void SymbolTableSection<ELFT>::addSymbol(SymbolBody *B) { + // Adding a local symbol to a .dynsym is a bug. + assert(this->Type != SHT_DYNSYM || !B->isLocal()); + + bool HashIt = B->isLocal(); + Symbols.push_back({B, StrTabSec.addString(B->getName(), HashIt)}); } template <class ELFT> size_t SymbolTableSection<ELFT>::getSymbolIndex(SymbolBody *Body) { - auto I = llvm::find_if( - Symbols, [&](const SymbolTableEntry &E) { return E.Symbol == Body; }); + auto I = llvm::find_if(Symbols, [&](const SymbolTableEntry &E) { + if (E.Symbol == Body) + return true; + // This is used for -r, so we have to handle multiple section + // symbols being combined. + if (Body->Type == STT_SECTION && E.Symbol->Type == STT_SECTION) + return cast<DefinedRegular>(Body)->Section->getOutputSection() == + cast<DefinedRegular>(E.Symbol)->Section->getOutputSection(); + return false; + }); if (I == Symbols.end()) return 0; return I - Symbols.begin() + 1; } +// Write the internal symbol table contents to the output symbol table. template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) { + // The first entry is a null entry as per the ELF spec. Buf += sizeof(Elf_Sym); - // All symbols with STB_LOCAL binding precede the weak and global symbols. - // .dynsym only contains global symbols. - if (Config->Discard != DiscardPolicy::All && !StrTabSec.isDynamic()) - writeLocalSymbols(Buf); - - writeGlobalSymbols(Buf); -} - -template <class ELFT> -void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) { - // Iterate over all input object files to copy their local symbols - // to the output symbol table pointed by Buf. + auto *ESym = reinterpret_cast<Elf_Sym *>(Buf); - for (auto I = Symbols.begin(); I != Symbols.begin() + NumLocals; ++I) { - const DefinedRegular<ELFT> &Body = *cast<DefinedRegular<ELFT>>(I->Symbol); - InputSectionBase<ELFT> *Section = Body.Section; - auto *ESym = reinterpret_cast<Elf_Sym *>(Buf); + for (SymbolTableEntry &Ent : Symbols) { + SymbolBody *Body = Ent.Symbol; - if (!Section) { - ESym->st_shndx = SHN_ABS; - ESym->st_value = Body.Value; + // Set st_info and st_other. + if (Body->isLocal()) { + ESym->setBindingAndType(STB_LOCAL, Body->Type); } else { - const OutputSectionBase *OutSec = Section->OutSec; - ESym->st_shndx = OutSec->SectionIndex; - ESym->st_value = OutSec->Addr + Section->getOffset(Body); + ESym->setBindingAndType(Body->symbol()->computeBinding(), Body->Type); + ESym->setVisibility(Body->symbol()->Visibility); } - ESym->st_name = I->StrTabOffset; - ESym->st_size = Body.template getSize<ELFT>(); - ESym->setBindingAndType(STB_LOCAL, Body.Type); - Buf += sizeof(*ESym); - } -} -template <class ELFT> -void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) { - // Write the internal symbol table contents to the output symbol table - // pointed by Buf. - auto *ESym = reinterpret_cast<Elf_Sym *>(Buf); + ESym->st_name = Ent.StrTabOffset; + ESym->st_size = Body->getSize<ELFT>(); - for (auto I = Symbols.begin() + NumLocals; I != Symbols.end(); ++I) { - const SymbolTableEntry &S = *I; - SymbolBody *Body = S.Symbol; - size_t StrOff = S.StrTabOffset; - - uint8_t Type = Body->Type; - uintX_t Size = Body->getSize<ELFT>(); - - ESym->setBindingAndType(Body->symbol()->computeBinding(), Type); - ESym->st_size = Size; - ESym->st_name = StrOff; - ESym->setVisibility(Body->symbol()->Visibility); - ESym->st_value = Body->getVA<ELFT>(); - - if (const OutputSectionBase *OutSec = getOutputSection(Body)) { + // Set a section index. + if (const OutputSection *OutSec = Body->getOutputSection()) ESym->st_shndx = OutSec->SectionIndex; - } else if (isa<DefinedRegular<ELFT>>(Body)) { + else if (isa<DefinedRegular>(Body)) ESym->st_shndx = SHN_ABS; - } else if (isa<DefinedCommon>(Body)) { + else if (isa<DefinedCommon>(Body)) ESym->st_shndx = SHN_COMMON; + + // st_value is usually an address of a symbol, but that has a + // special meaining for uninstantiated common symbols (this can + // occur if -r is given). + if (!Config->DefineCommon && isa<DefinedCommon>(Body)) ESym->st_value = cast<DefinedCommon>(Body)->Alignment; - } + else + ESym->st_value = Body->getVA(); - if (Config->EMachine == EM_MIPS) { - // On MIPS we need to mark symbol which has a PLT entry and requires - // pointer equality by STO_MIPS_PLT flag. That is necessary to help - // dynamic linker distinguish such symbols and MIPS lazy-binding stubs. - // https://sourceware.org/ml/binutils/2008-07/txt00000.txt - if (Body->isInPlt() && Body->NeedsCopyOrPltAddr) - ESym->st_other |= STO_MIPS_PLT; - if (Config->Relocatable) { - auto *D = dyn_cast<DefinedRegular<ELFT>>(Body); - if (D && D->isMipsPIC()) - ESym->st_other |= STO_MIPS_PIC; - } - } ++ESym; } -} -template <class ELFT> -const OutputSectionBase * -SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) { - switch (Sym->kind()) { - case SymbolBody::DefinedSyntheticKind: - return cast<DefinedSynthetic>(Sym)->Section; - case SymbolBody::DefinedRegularKind: { - auto &D = cast<DefinedRegular<ELFT>>(*Sym); - if (D.Section) - return D.Section->OutSec; - break; - } - case SymbolBody::DefinedCommonKind: - if (!Config->DefineCommon) - return nullptr; - return In<ELFT>::Common->OutSec; - case SymbolBody::SharedKind: { - auto &SS = cast<SharedSymbol<ELFT>>(*Sym); - if (SS.needsCopy()) - return SS.getBssSectionForCopy(); - break; - } - case SymbolBody::UndefinedKind: - case SymbolBody::LazyArchiveKind: - case SymbolBody::LazyObjectKind: - break; + // On MIPS we need to mark symbol which has a PLT entry and requires + // pointer equality by STO_MIPS_PLT flag. That is necessary to help + // dynamic linker distinguish such symbols and MIPS lazy-binding stubs. + // https://sourceware.org/ml/binutils/2008-07/txt00000.txt + if (Config->EMachine == EM_MIPS) { + auto *ESym = reinterpret_cast<Elf_Sym *>(Buf); + + for (SymbolTableEntry &Ent : Symbols) { + SymbolBody *Body = Ent.Symbol; + if (Body->isInPlt() && Body->NeedsPltAddr) + ESym->st_other |= STO_MIPS_PLT; + + if (Config->Relocatable) + if (auto *D = dyn_cast<DefinedRegular>(Body)) + if (D->isMipsPIC<ELFT>()) + ESym->st_other |= STO_MIPS_PIC; + ++ESym; + } } - return nullptr; } +// .hash and .gnu.hash sections contain on-disk hash tables that map +// symbol names to their dynamic symbol table indices. Their purpose +// is to help the dynamic linker resolve symbols quickly. If ELF files +// don't have them, the dynamic linker has to do linear search on all +// dynamic symbols, which makes programs slower. Therefore, a .hash +// section is added to a DSO by default. A .gnu.hash is added if you +// give the -hash-style=gnu or -hash-style=both option. +// +// The Unix semantics of resolving dynamic symbols is somewhat expensive. +// Each ELF file has a list of DSOs that the ELF file depends on and a +// list of dynamic symbols that need to be resolved from any of the +// DSOs. That means resolving all dynamic symbols takes O(m)*O(n) +// where m is the number of DSOs and n is the number of dynamic +// symbols. For modern large programs, both m and n are large. So +// making each step faster by using hash tables substiantially +// improves time to load programs. +// +// (Note that this is not the only way to design the shared library. +// For instance, the Windows DLL takes a different approach. On +// Windows, each dynamic symbol has a name of DLL from which the symbol +// has to be resolved. That makes the cost of symbol resolution O(n). +// This disables some hacky techniques you can use on Unix such as +// LD_PRELOAD, but this is arguably better semantics than the Unix ones.) +// +// Due to historical reasons, we have two different hash tables, .hash +// and .gnu.hash. They are for the same purpose, and .gnu.hash is a new +// and better version of .hash. .hash is just an on-disk hash table, but +// .gnu.hash has a bloom filter in addition to a hash table to skip +// DSOs very quickly. If you are sure that your dynamic linker knows +// about .gnu.hash, you want to specify -hash-style=gnu. Otherwise, a +// safe bet is to specify -hash-style=both for backward compatibilty. template <class ELFT> GnuHashTableSection<ELFT>::GnuHashTableSection() - : SyntheticSection<ELFT>(SHF_ALLOC, SHT_GNU_HASH, sizeof(uintX_t), - ".gnu.hash") { - this->Entsize = ELFT::Is64Bits ? 0 : 4; + : SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, Config->Wordsize, ".gnu.hash") { } -template <class ELFT> -unsigned GnuHashTableSection<ELFT>::calcNBuckets(unsigned NumHashed) { - if (!NumHashed) - return 0; - - // These values are prime numbers which are not greater than 2^(N-1) + 1. - // In result, for any particular NumHashed we return a prime number - // which is not greater than NumHashed. - static const unsigned Primes[] = { - 1, 1, 3, 3, 7, 13, 31, 61, 127, 251, - 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071}; - - return Primes[std::min<unsigned>(Log2_32_Ceil(NumHashed), - array_lengthof(Primes) - 1)]; -} - -// Bloom filter estimation: at least 8 bits for each hashed symbol. -// GNU Hash table requirement: it should be a power of 2, -// the minimum value is 1, even for an empty table. -// Expected results for a 32-bit target: -// calcMaskWords(0..4) = 1 -// calcMaskWords(5..8) = 2 -// calcMaskWords(9..16) = 4 -// For a 64-bit target: -// calcMaskWords(0..8) = 1 -// calcMaskWords(9..16) = 2 -// calcMaskWords(17..32) = 4 -template <class ELFT> -unsigned GnuHashTableSection<ELFT>::calcMaskWords(unsigned NumHashed) { - if (!NumHashed) - return 1; - return NextPowerOf2((NumHashed - 1) / sizeof(Elf_Off)); -} +template <class ELFT> void GnuHashTableSection<ELFT>::finalizeContents() { + this->OutSec->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex; -template <class ELFT> void GnuHashTableSection<ELFT>::finalize() { - unsigned NumHashed = Symbols.size(); - NBuckets = calcNBuckets(NumHashed); - MaskWords = calcMaskWords(NumHashed); - // Second hash shift estimation: just predefined values. - Shift2 = ELFT::Is64Bits ? 6 : 5; + // Computes bloom filter size in word size. We want to allocate 8 + // bits for each symbol. It must be a power of two. + if (Symbols.empty()) + MaskWords = 1; + else + MaskWords = NextPowerOf2((Symbols.size() - 1) / Config->Wordsize); - this->OutSec->Entsize = this->Entsize; - this->OutSec->Link = this->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex; - this->Size = sizeof(Elf_Word) * 4 // Header - + sizeof(Elf_Off) * MaskWords // Bloom Filter - + sizeof(Elf_Word) * NBuckets // Hash Buckets - + sizeof(Elf_Word) * NumHashed; // Hash Values + Size = 16; // Header + Size += Config->Wordsize * MaskWords; // Bloom filter + Size += NBuckets * 4; // Hash buckets + Size += Symbols.size() * 4; // Hash values } -template <class ELFT> void GnuHashTableSection<ELFT>::writeTo(uint8_t *Buf) { - writeHeader(Buf); - if (Symbols.empty()) - return; +template <class ELFT> +void GnuHashTableSection<ELFT>::writeTo(uint8_t *Buf) { + // Write a header. + write32(Buf, NBuckets, Config->Endianness); + write32(Buf + 4, In<ELFT>::DynSymTab->getNumSymbols() - Symbols.size(), + Config->Endianness); + write32(Buf + 8, MaskWords, Config->Endianness); + write32(Buf + 12, getShift2(), Config->Endianness); + Buf += 16; + + // Write a bloom filter and a hash table. writeBloomFilter(Buf); + Buf += Config->Wordsize * MaskWords; writeHashTable(Buf); } +// This function writes a 2-bit bloom filter. This bloom filter alone +// usually filters out 80% or more of all symbol lookups [1]. +// The dynamic linker uses the hash table only when a symbol is not +// filtered out by a bloom filter. +// +// [1] Ulrich Drepper (2011), "How To Write Shared Libraries" (Ver. 4.1.2), +// p.9, https://www.akkadia.org/drepper/dsohowto.pdf template <class ELFT> -void GnuHashTableSection<ELFT>::writeHeader(uint8_t *&Buf) { - auto *P = reinterpret_cast<Elf_Word *>(Buf); - *P++ = NBuckets; - *P++ = In<ELFT>::DynSymTab->getNumSymbols() - Symbols.size(); - *P++ = MaskWords; - *P++ = Shift2; - Buf = reinterpret_cast<uint8_t *>(P); -} - -template <class ELFT> -void GnuHashTableSection<ELFT>::writeBloomFilter(uint8_t *&Buf) { - unsigned C = sizeof(Elf_Off) * 8; - - auto *Masks = reinterpret_cast<Elf_Off *>(Buf); - for (const SymbolData &Sym : Symbols) { - size_t Pos = (Sym.Hash / C) & (MaskWords - 1); - uintX_t V = (uintX_t(1) << (Sym.Hash % C)) | - (uintX_t(1) << ((Sym.Hash >> Shift2) % C)); - Masks[Pos] |= V; +void GnuHashTableSection<ELFT>::writeBloomFilter(uint8_t *Buf) { + const unsigned C = Config->Wordsize * 8; + for (const Entry &Sym : Symbols) { + size_t I = (Sym.Hash / C) & (MaskWords - 1); + uint64_t Val = readUint(Buf + I * Config->Wordsize); + Val |= uint64_t(1) << (Sym.Hash % C); + Val |= uint64_t(1) << ((Sym.Hash >> getShift2()) % C); + writeUint(Buf + I * Config->Wordsize, Val); } - Buf += sizeof(Elf_Off) * MaskWords; } template <class ELFT> void GnuHashTableSection<ELFT>::writeHashTable(uint8_t *Buf) { - Elf_Word *Buckets = reinterpret_cast<Elf_Word *>(Buf); - Elf_Word *Values = Buckets + NBuckets; - - int PrevBucket = -1; - int I = 0; - for (const SymbolData &Sym : Symbols) { - int Bucket = Sym.Hash % NBuckets; - assert(PrevBucket <= Bucket); - if (Bucket != PrevBucket) { - Buckets[Bucket] = Sym.Body->DynsymIndex; - PrevBucket = Bucket; - if (I > 0) - Values[I - 1] |= 1; - } - Values[I] = Sym.Hash & ~1; - ++I; + // Group symbols by hash value. + std::vector<std::vector<Entry>> Syms(NBuckets); + for (const Entry &Ent : Symbols) + Syms[Ent.Hash % NBuckets].push_back(Ent); + + // Write hash buckets. Hash buckets contain indices in the following + // hash value table. + uint32_t *Buckets = reinterpret_cast<uint32_t *>(Buf); + for (size_t I = 0; I < NBuckets; ++I) + if (!Syms[I].empty()) + write32(Buckets + I, Syms[I][0].Body->DynsymIndex, Config->Endianness); + + // Write a hash value table. It represents a sequence of chains that + // share the same hash modulo value. The last element of each chain + // is terminated by LSB 1. + uint32_t *Values = Buckets + NBuckets; + size_t I = 0; + for (std::vector<Entry> &Vec : Syms) { + if (Vec.empty()) + continue; + for (const Entry &Ent : makeArrayRef(Vec).drop_back()) + write32(Values + I++, Ent.Hash & ~1, Config->Endianness); + write32(Values + I++, Vec.back().Hash | 1, Config->Endianness); } - if (I > 0) - Values[I - 1] |= 1; } static uint32_t hashGnu(StringRef Name) { @@ -1345,45 +1532,60 @@ static uint32_t hashGnu(StringRef Name) { return H; } +// Returns a number of hash buckets to accomodate given number of elements. +// We want to choose a moderate number that is not too small (which +// causes too many hash collisions) and not too large (which wastes +// disk space.) +// +// We return a prime number because it (is believed to) achieve good +// hash distribution. +static size_t getBucketSize(size_t NumSymbols) { + // List of largest prime numbers that are not greater than 2^n + 1. + for (size_t N : {131071, 65521, 32749, 16381, 8191, 4093, 2039, 1021, 509, + 251, 127, 61, 31, 13, 7, 3, 1}) + if (N <= NumSymbols) + return N; + return 0; +} + // Add symbols to this symbol hash table. Note that this function // destructively sort a given vector -- which is needed because // GNU-style hash table places some sorting requirements. template <class ELFT> void GnuHashTableSection<ELFT>::addSymbols(std::vector<SymbolTableEntry> &V) { - // Ideally this will just be 'auto' but GCC 6.1 is not able - // to deduce it correctly. + // We cannot use 'auto' for Mid because GCC 6.1 cannot deduce + // its type correctly. std::vector<SymbolTableEntry>::iterator Mid = std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) { return S.Symbol->isUndefined(); }); if (Mid == V.end()) return; - for (auto I = Mid, E = V.end(); I != E; ++I) { - SymbolBody *B = I->Symbol; - size_t StrOff = I->StrTabOffset; - Symbols.push_back({B, StrOff, hashGnu(B->getName())}); + + for (SymbolTableEntry &Ent : llvm::make_range(Mid, V.end())) { + SymbolBody *B = Ent.Symbol; + Symbols.push_back({B, Ent.StrTabOffset, hashGnu(B->getName())}); } - unsigned NBuckets = calcNBuckets(Symbols.size()); + NBuckets = getBucketSize(Symbols.size()); std::stable_sort(Symbols.begin(), Symbols.end(), - [&](const SymbolData &L, const SymbolData &R) { + [&](const Entry &L, const Entry &R) { return L.Hash % NBuckets < R.Hash % NBuckets; }); V.erase(Mid, V.end()); - for (const SymbolData &Sym : Symbols) - V.push_back({Sym.Body, Sym.STName}); + for (const Entry &Ent : Symbols) + V.push_back({Ent.Body, Ent.StrTabOffset}); } template <class ELFT> HashTableSection<ELFT>::HashTableSection() - : SyntheticSection<ELFT>(SHF_ALLOC, SHT_HASH, sizeof(Elf_Word), ".hash") { - this->Entsize = sizeof(Elf_Word); + : SyntheticSection(SHF_ALLOC, SHT_HASH, 4, ".hash") { + this->Entsize = 4; } -template <class ELFT> void HashTableSection<ELFT>::finalize() { - this->OutSec->Link = this->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex; - this->OutSec->Entsize = this->Entsize; +template <class ELFT> void HashTableSection<ELFT>::finalizeContents() { + this->OutSec->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex; unsigned NumEntries = 2; // nbucket and nchain. NumEntries += In<ELFT>::DynSymTab->getNumSymbols(); // The chain entries. @@ -1392,11 +1594,15 @@ template <class ELFT> void HashTableSection<ELFT>::finalize() { // FIXME: This is simplistic. We can try to optimize it, but implementing // support for SHT_GNU_HASH is probably even more profitable. NumEntries += In<ELFT>::DynSymTab->getNumSymbols(); - this->Size = NumEntries * sizeof(Elf_Word); + this->Size = NumEntries * 4; } template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) { + // A 32-bit integer type in the target endianness. + typedef typename ELFT::Word Elf_Word; + unsigned NumSymbols = In<ELFT>::DynSymTab->getNumSymbols(); + auto *P = reinterpret_cast<Elf_Word *>(Buf); *P++ = NumSymbols; // nbucket *P++ = NumSymbols; // nchain @@ -1414,79 +1620,65 @@ template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) { } } -template <class ELFT> -PltSection<ELFT>::PltSection() - : SyntheticSection<ELFT>(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, - ".plt") {} +PltSection::PltSection(size_t S) + : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt"), + HeaderSize(S) {} -template <class ELFT> void PltSection<ELFT>::writeTo(uint8_t *Buf) { - // At beginning of PLT, we have code to call the dynamic linker - // to resolve dynsyms at runtime. Write such code. - Target->writePltHeader(Buf); - size_t Off = Target->PltHeaderSize; +void PltSection::writeTo(uint8_t *Buf) { + // At beginning of PLT but not the IPLT, we have code to call the dynamic + // linker to resolve dynsyms at runtime. Write such code. + if (HeaderSize != 0) + Target->writePltHeader(Buf); + size_t Off = HeaderSize; + // The IPlt is immediately after the Plt, account for this in RelOff + unsigned PltOff = getPltRelocOff(); for (auto &I : Entries) { const SymbolBody *B = I.first; - unsigned RelOff = I.second; - uint64_t Got = B->getGotPltVA<ELFT>(); + unsigned RelOff = I.second + PltOff; + uint64_t Got = B->getGotPltVA(); uint64_t Plt = this->getVA() + Off; Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff); Off += Target->PltEntrySize; } } -template <class ELFT> void PltSection<ELFT>::addEntry(SymbolBody &Sym) { +template <class ELFT> void PltSection::addEntry(SymbolBody &Sym) { Sym.PltIndex = Entries.size(); - unsigned RelOff = In<ELFT>::RelaPlt->getRelocOffset(); + RelocationSection<ELFT> *PltRelocSection = In<ELFT>::RelaPlt; + if (HeaderSize == 0) { + PltRelocSection = In<ELFT>::RelaIplt; + Sym.IsInIplt = true; + } + unsigned RelOff = PltRelocSection->getRelocOffset(); Entries.push_back(std::make_pair(&Sym, RelOff)); } -template <class ELFT> size_t PltSection<ELFT>::getSize() const { - return Target->PltHeaderSize + Entries.size() * Target->PltEntrySize; +size_t PltSection::getSize() const { + return HeaderSize + Entries.size() * Target->PltEntrySize; } -template <class ELFT> -IpltSection<ELFT>::IpltSection() - : SyntheticSection<ELFT>(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, - ".plt") {} - -template <class ELFT> void IpltSection<ELFT>::writeTo(uint8_t *Buf) { - // The IRelative relocations do not support lazy binding so no header is - // needed - size_t Off = 0; - for (auto &I : Entries) { - const SymbolBody *B = I.first; - unsigned RelOff = I.second + In<ELFT>::Plt->getSize(); - uint64_t Got = B->getGotPltVA<ELFT>(); - uint64_t Plt = this->getVA() + Off; - Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff); +// Some architectures such as additional symbols in the PLT section. For +// example ARM uses mapping symbols to aid disassembly +void PltSection::addSymbols() { + // The PLT may have symbols defined for the Header, the IPLT has no header + if (HeaderSize != 0) + Target->addPltHeaderSymbols(this); + size_t Off = HeaderSize; + for (size_t I = 0; I < Entries.size(); ++I) { + Target->addPltSymbols(this, Off); Off += Target->PltEntrySize; } } -template <class ELFT> void IpltSection<ELFT>::addEntry(SymbolBody &Sym) { - Sym.PltIndex = Entries.size(); - Sym.IsInIplt = true; - unsigned RelOff = In<ELFT>::RelaIplt->getRelocOffset(); - Entries.push_back(std::make_pair(&Sym, RelOff)); -} - -template <class ELFT> size_t IpltSection<ELFT>::getSize() const { - return Entries.size() * Target->PltEntrySize; +unsigned PltSection::getPltRelocOff() const { + return (HeaderSize == 0) ? InX::Plt->getSize() : 0; } -template <class ELFT> -GdbIndexSection<ELFT>::GdbIndexSection() - : SyntheticSection<ELFT>(0, SHT_PROGBITS, 1, ".gdb_index"), +GdbIndexSection::GdbIndexSection() + : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"), StringPool(llvm::StringTableBuilder::ELF) {} -template <class ELFT> void GdbIndexSection<ELFT>::parseDebugSections() { - for (InputSectionBase<ELFT> *S : Symtab<ELFT>::X->Sections) - if (InputSection<ELFT> *IS = dyn_cast<InputSection<ELFT>>(S)) - if (IS->OutSec && IS->Name == ".debug_info") - readDwarf(IS); -} - // Iterative hash function for symbol's name is described in .gdb_index format // specification. Note that we use one for version 5 to 7 here, it is different // for version 4. @@ -1497,21 +1689,88 @@ static uint32_t hash(StringRef Str) { return R; } -template <class ELFT> -void GdbIndexSection<ELFT>::readDwarf(InputSection<ELFT> *I) { - GdbIndexBuilder<ELFT> Builder(I); - if (ErrorCount) +static std::vector<std::pair<uint64_t, uint64_t>> +readCuList(DWARFContext &Dwarf, InputSection *Sec) { + std::vector<std::pair<uint64_t, uint64_t>> Ret; + for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units()) + Ret.push_back({Sec->OutSecOff + CU->getOffset(), CU->getLength() + 4}); + return Ret; +} + +static InputSectionBase *findSection(ArrayRef<InputSectionBase *> Arr, + uint64_t Offset) { + for (InputSectionBase *S : Arr) + if (S && S != &InputSection::Discarded) + if (Offset >= S->getOffsetInFile() && + Offset < S->getOffsetInFile() + S->getSize()) + return S; + return nullptr; +} + +static std::vector<AddressEntry> +readAddressArea(DWARFContext &Dwarf, InputSection *Sec, size_t CurrentCU) { + std::vector<AddressEntry> Ret; + + for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units()) { + DWARFAddressRangesVector Ranges; + CU->collectAddressRanges(Ranges); + + ArrayRef<InputSectionBase *> Sections = Sec->File->getSections(); + for (std::pair<uint64_t, uint64_t> &R : Ranges) + if (InputSectionBase *S = findSection(Sections, R.first)) + Ret.push_back({S, R.first - S->getOffsetInFile(), + R.second - S->getOffsetInFile(), CurrentCU}); + ++CurrentCU; + } + return Ret; +} + +static std::vector<std::pair<StringRef, uint8_t>> +readPubNamesAndTypes(DWARFContext &Dwarf, bool IsLE) { + StringRef Data[] = {Dwarf.getGnuPubNamesSection(), + Dwarf.getGnuPubTypesSection()}; + + std::vector<std::pair<StringRef, uint8_t>> Ret; + for (StringRef D : Data) { + DWARFDebugPubTable PubTable(D, IsLE, true); + for (const DWARFDebugPubTable::Set &Set : PubTable.getData()) + for (const DWARFDebugPubTable::Entry &Ent : Set.Entries) + Ret.push_back({Ent.Name, Ent.Descriptor.toBits()}); + } + return Ret; +} + +class ObjInfoTy : public llvm::LoadedObjectInfo { + uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override { + auto &S = static_cast<const object::ELFSectionRef &>(Sec); + if (S.getFlags() & ELF::SHF_ALLOC) + return S.getOffset(); + return 0; + } + + std::unique_ptr<llvm::LoadedObjectInfo> clone() const override { return {}; } +}; + +void GdbIndexSection::readDwarf(InputSection *Sec) { + Expected<std::unique_ptr<object::ObjectFile>> Obj = + object::ObjectFile::createObjectFile(Sec->File->MB); + if (!Obj) { + error(toString(Sec->File) + ": error creating DWARF context"); return; + } + + ObjInfoTy ObjInfo; + DWARFContextInMemory Dwarf(*Obj.get(), &ObjInfo); size_t CuId = CompilationUnits.size(); - std::vector<std::pair<uintX_t, uintX_t>> CuList = Builder.readCUList(); - CompilationUnits.insert(CompilationUnits.end(), CuList.begin(), CuList.end()); + for (std::pair<uint64_t, uint64_t> &P : readCuList(Dwarf, Sec)) + CompilationUnits.push_back(P); - std::vector<AddressEntry<ELFT>> AddrArea = Builder.readAddressArea(CuId); - AddressArea.insert(AddressArea.end(), AddrArea.begin(), AddrArea.end()); + for (AddressEntry &Ent : readAddressArea(Dwarf, Sec, CuId)) + AddressArea.push_back(Ent); std::vector<std::pair<StringRef, uint8_t>> NamesAndTypes = - Builder.readPubNamesAndTypes(); + readPubNamesAndTypes(Dwarf, Config->IsLE); for (std::pair<StringRef, uint8_t> &Pair : NamesAndTypes) { uint32_t Hash = hash(Pair.first); @@ -1526,18 +1785,21 @@ void GdbIndexSection<ELFT>::readDwarf(InputSection<ELFT> *I) { continue; } - std::vector<std::pair<uint32_t, uint8_t>> &CuVec = - CuVectors[Sym->CuVectorIndex]; - CuVec.push_back({CuId, Pair.second}); + CuVectors[Sym->CuVectorIndex].push_back({CuId, Pair.second}); } } -template <class ELFT> void GdbIndexSection<ELFT>::finalize() { +void GdbIndexSection::finalizeContents() { if (Finalized) return; Finalized = true; - parseDebugSections(); + for (InputSectionBase *S : InputSections) + if (InputSection *IS = dyn_cast<InputSection>(S)) + if (IS->OutSec && IS->Name == ".debug_info") + readDwarf(IS); + + SymbolTable.finalizeContents(); // GdbIndex header consist from version fields // and 5 more fields with different kinds of offsets. @@ -1556,12 +1818,12 @@ template <class ELFT> void GdbIndexSection<ELFT>::finalize() { StringPool.finalizeInOrder(); } -template <class ELFT> size_t GdbIndexSection<ELFT>::getSize() const { - const_cast<GdbIndexSection<ELFT> *>(this)->finalize(); +size_t GdbIndexSection::getSize() const { + const_cast<GdbIndexSection *>(this)->finalizeContents(); return StringPoolOffset + StringPool.getSize(); } -template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) { +void GdbIndexSection::writeTo(uint8_t *Buf) { write32le(Buf, 7); // Write version. write32le(Buf + 4, CuListOffset); // CU list offset. write32le(Buf + 8, CuTypesOffset); // Types CU list offset. @@ -1571,15 +1833,15 @@ template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) { Buf += 24; // Write the CU list. - for (std::pair<uintX_t, uintX_t> CU : CompilationUnits) { + for (std::pair<uint64_t, uint64_t> CU : CompilationUnits) { write64le(Buf, CU.first); write64le(Buf + 8, CU.second); Buf += 16; } // Write the address area. - for (AddressEntry<ELFT> &E : AddressArea) { - uintX_t BaseAddr = E.Section->OutSec->Addr + E.Section->getOffset(0); + for (AddressEntry &E : AddressArea) { + uint64_t BaseAddr = E.Section->OutSec->Addr + E.Section->getOffset(0); write64le(Buf, BaseAddr + E.LowAddress); write64le(Buf + 8, BaseAddr + E.HighAddress); write32le(Buf + 16, E.CuIndex); @@ -1615,13 +1877,13 @@ template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) { StringPool.write(Buf); } -template <class ELFT> bool GdbIndexSection<ELFT>::empty() const { - return !Out<ELFT>::DebugInfo; +bool GdbIndexSection::empty() const { + return !Out::DebugInfo; } template <class ELFT> EhFrameHeader<ELFT>::EhFrameHeader() - : SyntheticSection<ELFT>(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame_hdr") {} + : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame_hdr") {} // .eh_frame_hdr contains a binary search table of pointers to FDEs. // Each entry of the search table consists of two values, @@ -1642,11 +1904,11 @@ template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) { Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; Buf[2] = DW_EH_PE_udata4; Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; - write32<E>(Buf + 4, Out<ELFT>::EhFrame->Addr - this->getVA() - 4); + write32<E>(Buf + 4, In<ELFT>::EhFrame->OutSec->Addr - this->getVA() - 4); write32<E>(Buf + 8, Fdes.size()); Buf += 12; - uintX_t VA = this->getVA(); + uint64_t VA = this->getVA(); for (FdeData &Fde : Fdes) { write32<E>(Buf, Fde.Pc - VA); write32<E>(Buf + 4, Fde.FdeVA - VA); @@ -1656,7 +1918,7 @@ template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) { template <class ELFT> size_t EhFrameHeader<ELFT>::getSize() const { // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs. - return 12 + Out<ELFT>::EhFrame->NumFdes * 8; + return 12 + In<ELFT>::EhFrame->NumFdes * 8; } template <class ELFT> @@ -1665,13 +1927,13 @@ void EhFrameHeader<ELFT>::addFde(uint32_t Pc, uint32_t FdeVA) { } template <class ELFT> bool EhFrameHeader<ELFT>::empty() const { - return Out<ELFT>::EhFrame->empty(); + return In<ELFT>::EhFrame->empty(); } template <class ELFT> VersionDefinitionSection<ELFT>::VersionDefinitionSection() - : SyntheticSection<ELFT>(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t), - ".gnu.version_d") {} + : SyntheticSection(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t), + ".gnu.version_d") {} static StringRef getFileDefName() { if (!Config->SoName.empty()) @@ -1679,17 +1941,17 @@ static StringRef getFileDefName() { return Config->OutputFile; } -template <class ELFT> void VersionDefinitionSection<ELFT>::finalize() { +template <class ELFT> void VersionDefinitionSection<ELFT>::finalizeContents() { FileDefNameOff = In<ELFT>::DynStrTab->addString(getFileDefName()); for (VersionDefinition &V : Config->VersionDefinitions) V.NameOff = In<ELFT>::DynStrTab->addString(V.Name); - this->OutSec->Link = this->Link = In<ELFT>::DynStrTab->OutSec->SectionIndex; + this->OutSec->Link = In<ELFT>::DynStrTab->OutSec->SectionIndex; // sh_info should be set to the number of definitions. This fact is missed in // documentation, but confirmed by binutils community: // https://sourceware.org/ml/binutils/2014-11/msg00355.html - this->OutSec->Info = this->Info = getVerDefNum(); + this->OutSec->Info = getVerDefNum(); } template <class ELFT> @@ -1729,14 +1991,15 @@ template <class ELFT> size_t VersionDefinitionSection<ELFT>::getSize() const { template <class ELFT> VersionTableSection<ELFT>::VersionTableSection() - : SyntheticSection<ELFT>(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t), - ".gnu.version") {} + : SyntheticSection(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t), + ".gnu.version") { + this->Entsize = sizeof(Elf_Versym); +} -template <class ELFT> void VersionTableSection<ELFT>::finalize() { - this->OutSec->Entsize = this->Entsize = sizeof(Elf_Versym); +template <class ELFT> void VersionTableSection<ELFT>::finalizeContents() { // At the moment of june 2016 GNU docs does not mention that sh_link field // should be set, but Sun docs do. Also readelf relies on this field. - this->OutSec->Link = this->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex; + this->OutSec->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex; } template <class ELFT> size_t VersionTableSection<ELFT>::getSize() const { @@ -1757,8 +2020,8 @@ template <class ELFT> bool VersionTableSection<ELFT>::empty() const { template <class ELFT> VersionNeedSection<ELFT>::VersionNeedSection() - : SyntheticSection<ELFT>(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t), - ".gnu.version_r") { + : SyntheticSection(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t), + ".gnu.version_r") { // Identifiers in verneed section start at 2 because 0 and 1 are reserved // for VER_NDX_LOCAL and VER_NDX_GLOBAL. // First identifiers are reserved by verdef section if it exist. @@ -1766,24 +2029,27 @@ VersionNeedSection<ELFT>::VersionNeedSection() } template <class ELFT> -void VersionNeedSection<ELFT>::addSymbol(SharedSymbol<ELFT> *SS) { - if (!SS->Verdef) { +void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) { + auto *Ver = reinterpret_cast<const typename ELFT::Verdef *>(SS->Verdef); + if (!Ver) { SS->symbol()->VersionId = VER_NDX_GLOBAL; return; } - SharedFile<ELFT> *F = SS->file(); + + auto *File = cast<SharedFile<ELFT>>(SS->File); + // If we don't already know that we need an Elf_Verneed for this DSO, prepare // to create one by adding it to our needed list and creating a dynstr entry // for the soname. - if (F->VerdefMap.empty()) - Needed.push_back({F, In<ELFT>::DynStrTab->addString(F->getSoName())}); - typename SharedFile<ELFT>::NeededVer &NV = F->VerdefMap[SS->Verdef]; + if (File->VerdefMap.empty()) + Needed.push_back({File, In<ELFT>::DynStrTab->addString(File->getSoName())}); + typename SharedFile<ELFT>::NeededVer &NV = File->VerdefMap[Ver]; // If we don't already know that we need an Elf_Vernaux for this Elf_Verdef, // prepare to create one by allocating a version identifier and creating a // dynstr entry for the version name. if (NV.Index == 0) { - NV.StrTab = In<ELFT>::DynStrTab->addString( - SS->file()->getStringTable().data() + SS->Verdef->getAux()->vda_name); + NV.StrTab = In<ELFT>::DynStrTab->addString(File->getStringTable().data() + + Ver->getAux()->vda_name); NV.Index = NextIndex++; } SS->symbol()->VersionId = NV.Index; @@ -1824,9 +2090,9 @@ template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) { Verneed[-1].vn_next = 0; } -template <class ELFT> void VersionNeedSection<ELFT>::finalize() { - this->OutSec->Link = this->Link = In<ELFT>::DynStrTab->OutSec->SectionIndex; - this->OutSec->Info = this->Info = Needed.size(); +template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() { + this->OutSec->Link = In<ELFT>::DynStrTab->OutSec->SectionIndex; + this->OutSec->Info = Needed.size(); } template <class ELFT> size_t VersionNeedSection<ELFT>::getSize() const { @@ -1840,53 +2106,175 @@ template <class ELFT> bool VersionNeedSection<ELFT>::empty() const { return getNeedNum() == 0; } -template <class ELFT> -MipsRldMapSection<ELFT>::MipsRldMapSection() - : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, - sizeof(typename ELFT::uint), ".rld_map") {} +MergeSyntheticSection::MergeSyntheticSection(StringRef Name, uint32_t Type, + uint64_t Flags, uint32_t Alignment) + : SyntheticSection(Flags, Type, Alignment, Name), + Builder(StringTableBuilder::RAW, Alignment) {} + +void MergeSyntheticSection::addSection(MergeInputSection *MS) { + assert(!Finalized); + MS->MergeSec = this; + Sections.push_back(MS); +} + +void MergeSyntheticSection::writeTo(uint8_t *Buf) { Builder.write(Buf); } + +bool MergeSyntheticSection::shouldTailMerge() const { + return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2; +} + +void MergeSyntheticSection::finalizeTailMerge() { + // Add all string pieces to the string table builder to create section + // contents. + for (MergeInputSection *Sec : Sections) + for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) + if (Sec->Pieces[I].Live) + Builder.add(Sec->getData(I)); + + // Fix the string table content. After this, the contents will never change. + Builder.finalize(); + + // finalize() fixed tail-optimized strings, so we can now get + // offsets of strings. Get an offset for each string and save it + // to a corresponding StringPiece for easy access. + for (MergeInputSection *Sec : Sections) + for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) + if (Sec->Pieces[I].Live) + Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I)); +} + +void MergeSyntheticSection::finalizeNoTailMerge() { + // Add all string pieces to the string table builder to create section + // contents. Because we are not tail-optimizing, offsets of strings are + // fixed when they are added to the builder (string table builder contains + // a hash table from strings to offsets). + for (MergeInputSection *Sec : Sections) + for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) + if (Sec->Pieces[I].Live) + Sec->Pieces[I].OutputOff = Builder.add(Sec->getData(I)); + + Builder.finalizeInOrder(); +} + +void MergeSyntheticSection::finalizeContents() { + if (Finalized) + return; + Finalized = true; + if (shouldTailMerge()) + finalizeTailMerge(); + else + finalizeNoTailMerge(); +} + +size_t MergeSyntheticSection::getSize() const { + // We should finalize string builder to know the size. + const_cast<MergeSyntheticSection *>(this)->finalizeContents(); + return Builder.getSize(); +} + +MipsRldMapSection::MipsRldMapSection() + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize, + ".rld_map") {} -template <class ELFT> void MipsRldMapSection<ELFT>::writeTo(uint8_t *Buf) { +void MipsRldMapSection::writeTo(uint8_t *Buf) { // Apply filler from linker script. - uint64_t Filler = Script<ELFT>::X->getFiller(this->Name); + Optional<uint32_t> Fill = Script->getFiller(this->Name); + if (!Fill || *Fill == 0) + return; + + uint64_t Filler = *Fill; Filler = (Filler << 32) | Filler; memcpy(Buf, &Filler, getSize()); } -template <class ELFT> -ARMExidxSentinelSection<ELFT>::ARMExidxSentinelSection() - : SyntheticSection<ELFT>(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX, - sizeof(typename ELFT::uint), ".ARM.exidx") {} +ARMExidxSentinelSection::ARMExidxSentinelSection() + : SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX, + Config->Wordsize, ".ARM.exidx") {} // Write a terminating sentinel entry to the end of the .ARM.exidx table. // This section will have been sorted last in the .ARM.exidx table. // This table entry will have the form: // | PREL31 upper bound of code that has exception tables | EXIDX_CANTUNWIND | -template <class ELFT> -void ARMExidxSentinelSection<ELFT>::writeTo(uint8_t *Buf) { +void ARMExidxSentinelSection::writeTo(uint8_t *Buf) { // Get the InputSection before us, we are by definition last - auto RI = cast<OutputSection<ELFT>>(this->OutSec)->Sections.rbegin(); - InputSection<ELFT> *LE = *(++RI); - InputSection<ELFT> *LC = cast<InputSection<ELFT>>(LE->getLinkOrderDep()); + auto RI = cast<OutputSection>(this->OutSec)->Sections.rbegin(); + InputSection *LE = *(++RI); + InputSection *LC = cast<InputSection>(LE->getLinkOrderDep()); uint64_t S = LC->OutSec->Addr + LC->getOffset(LC->getSize()); uint64_t P = this->getVA(); Target->relocateOne(Buf, R_ARM_PREL31, S - P); write32le(Buf + 4, 0x1); } -template InputSection<ELF32LE> *elf::createCommonSection(); -template InputSection<ELF32BE> *elf::createCommonSection(); -template InputSection<ELF64LE> *elf::createCommonSection(); -template InputSection<ELF64BE> *elf::createCommonSection(); - -template InputSection<ELF32LE> *elf::createInterpSection(); -template InputSection<ELF32BE> *elf::createInterpSection(); -template InputSection<ELF64LE> *elf::createInterpSection(); -template InputSection<ELF64BE> *elf::createInterpSection(); - -template MergeInputSection<ELF32LE> *elf::createCommentSection(); -template MergeInputSection<ELF32BE> *elf::createCommentSection(); -template MergeInputSection<ELF64LE> *elf::createCommentSection(); -template MergeInputSection<ELF64BE> *elf::createCommentSection(); +ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off) + : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, + Config->Wordsize, ".text.thunk") { + this->OutSec = OS; + this->OutSecOff = Off; +} + +void ThunkSection::addThunk(Thunk *T) { + uint64_t Off = alignTo(Size, T->alignment); + T->Offset = Off; + Thunks.push_back(T); + T->addSymbols(*this); + Size = Off + T->size(); +} + +void ThunkSection::writeTo(uint8_t *Buf) { + for (const Thunk *T : Thunks) + T->writeTo(Buf + T->Offset, *this); +} + +InputSection *ThunkSection::getTargetInputSection() const { + const Thunk *T = Thunks.front(); + return T->getTargetInputSection(); +} + +InputSection *InX::ARMAttributes; +BssSection *InX::Bss; +BssSection *InX::BssRelRo; +BuildIdSection *InX::BuildId; +InputSection *InX::Common; +StringTableSection *InX::DynStrTab; +InputSection *InX::Interp; +GdbIndexSection *InX::GdbIndex; +GotPltSection *InX::GotPlt; +IgotPltSection *InX::IgotPlt; +MipsGotSection *InX::MipsGot; +MipsRldMapSection *InX::MipsRldMap; +PltSection *InX::Plt; +PltSection *InX::Iplt; +StringTableSection *InX::ShStrTab; +StringTableSection *InX::StrTab; + +template void PltSection::addEntry<ELF32LE>(SymbolBody &Sym); +template void PltSection::addEntry<ELF32BE>(SymbolBody &Sym); +template void PltSection::addEntry<ELF64LE>(SymbolBody &Sym); +template void PltSection::addEntry<ELF64BE>(SymbolBody &Sym); + +template InputSection *elf::createCommonSection<ELF32LE>(); +template InputSection *elf::createCommonSection<ELF32BE>(); +template InputSection *elf::createCommonSection<ELF64LE>(); +template InputSection *elf::createCommonSection<ELF64BE>(); + +template MergeInputSection *elf::createCommentSection<ELF32LE>(); +template MergeInputSection *elf::createCommentSection<ELF32BE>(); +template MergeInputSection *elf::createCommentSection<ELF64LE>(); +template MergeInputSection *elf::createCommentSection<ELF64BE>(); + +template SymbolBody *elf::addSyntheticLocal<ELF32LE>(StringRef, uint8_t, + uint64_t, uint64_t, + InputSectionBase *); +template SymbolBody *elf::addSyntheticLocal<ELF32BE>(StringRef, uint8_t, + uint64_t, uint64_t, + InputSectionBase *); +template SymbolBody *elf::addSyntheticLocal<ELF64LE>(StringRef, uint8_t, + uint64_t, uint64_t, + InputSectionBase *); +template SymbolBody *elf::addSyntheticLocal<ELF64BE>(StringRef, uint8_t, + uint64_t, uint64_t, + InputSectionBase *); template class elf::MipsAbiFlagsSection<ELF32LE>; template class elf::MipsAbiFlagsSection<ELF32BE>; @@ -1903,36 +2291,11 @@ template class elf::MipsReginfoSection<ELF32BE>; template class elf::MipsReginfoSection<ELF64LE>; template class elf::MipsReginfoSection<ELF64BE>; -template class elf::BuildIdSection<ELF32LE>; -template class elf::BuildIdSection<ELF32BE>; -template class elf::BuildIdSection<ELF64LE>; -template class elf::BuildIdSection<ELF64BE>; - template class elf::GotSection<ELF32LE>; template class elf::GotSection<ELF32BE>; template class elf::GotSection<ELF64LE>; template class elf::GotSection<ELF64BE>; -template class elf::MipsGotSection<ELF32LE>; -template class elf::MipsGotSection<ELF32BE>; -template class elf::MipsGotSection<ELF64LE>; -template class elf::MipsGotSection<ELF64BE>; - -template class elf::GotPltSection<ELF32LE>; -template class elf::GotPltSection<ELF32BE>; -template class elf::GotPltSection<ELF64LE>; -template class elf::GotPltSection<ELF64BE>; - -template class elf::IgotPltSection<ELF32LE>; -template class elf::IgotPltSection<ELF32BE>; -template class elf::IgotPltSection<ELF64LE>; -template class elf::IgotPltSection<ELF64BE>; - -template class elf::StringTableSection<ELF32LE>; -template class elf::StringTableSection<ELF32BE>; -template class elf::StringTableSection<ELF64LE>; -template class elf::StringTableSection<ELF64BE>; - template class elf::DynamicSection<ELF32LE>; template class elf::DynamicSection<ELF32BE>; template class elf::DynamicSection<ELF64LE>; @@ -1958,21 +2321,6 @@ template class elf::HashTableSection<ELF32BE>; template class elf::HashTableSection<ELF64LE>; template class elf::HashTableSection<ELF64BE>; -template class elf::PltSection<ELF32LE>; -template class elf::PltSection<ELF32BE>; -template class elf::PltSection<ELF64LE>; -template class elf::PltSection<ELF64BE>; - -template class elf::IpltSection<ELF32LE>; -template class elf::IpltSection<ELF32BE>; -template class elf::IpltSection<ELF64LE>; -template class elf::IpltSection<ELF64BE>; - -template class elf::GdbIndexSection<ELF32LE>; -template class elf::GdbIndexSection<ELF32BE>; -template class elf::GdbIndexSection<ELF64LE>; -template class elf::GdbIndexSection<ELF64BE>; - template class elf::EhFrameHeader<ELF32LE>; template class elf::EhFrameHeader<ELF32BE>; template class elf::EhFrameHeader<ELF64LE>; @@ -1993,12 +2341,7 @@ template class elf::VersionDefinitionSection<ELF32BE>; template class elf::VersionDefinitionSection<ELF64LE>; template class elf::VersionDefinitionSection<ELF64BE>; -template class elf::MipsRldMapSection<ELF32LE>; -template class elf::MipsRldMapSection<ELF32BE>; -template class elf::MipsRldMapSection<ELF64LE>; -template class elf::MipsRldMapSection<ELF64BE>; - -template class elf::ARMExidxSentinelSection<ELF32LE>; -template class elf::ARMExidxSentinelSection<ELF32BE>; -template class elf::ARMExidxSentinelSection<ELF64LE>; -template class elf::ARMExidxSentinelSection<ELF64BE>; +template class elf::EhFrameSection<ELF32LE>; +template class elf::EhFrameSection<ELF32BE>; +template class elf::EhFrameSection<ELF64LE>; +template class elf::EhFrameSection<ELF64BE>; |