diff options
Diffstat (limited to 'ELF/SyntheticSections.cpp')
-rw-r--r-- | ELF/SyntheticSections.cpp | 3698 |
1 files changed, 2046 insertions, 1652 deletions
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index f459c1b6b4792..f6d0f190d84d0 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -1,9 +1,8 @@ //===- SyntheticSections.cpp ----------------------------------------------===// // -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -15,7 +14,6 @@ //===----------------------------------------------------------------------===// #include "SyntheticSections.h" -#include "Bits.h" #include "Config.h" #include "InputFiles.h" #include "LinkerScript.h" @@ -38,9 +36,6 @@ #include "llvm/Support/Endian.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MD5.h" -#include "llvm/Support/RandomNumberGenerator.h" -#include "llvm/Support/SHA1.h" -#include "llvm/Support/xxhash.h" #include <cstdlib> #include <thread> @@ -57,19 +52,30 @@ using llvm::support::endian::read32le; using llvm::support::endian::write32le; using llvm::support::endian::write64le; -constexpr size_t MergeNoTailSection::NumShards; +constexpr size_t MergeNoTailSection::numShards; + +static uint64_t readUint(uint8_t *buf) { + return config->is64 ? read64(buf) : read32(buf); +} + +static void writeUint(uint8_t *buf, uint64_t val) { + if (config->is64) + write64(buf, val); + else + write32(buf, val); +} // Returns an LLD version string. static ArrayRef<uint8_t> getVersion() { // Check LLD_VERSION first for ease of testing. // You can get consistent output by using the environment variable. // This is only for testing. - StringRef S = getenv("LLD_VERSION"); - if (S.empty()) - S = Saver.save(Twine("Linker: ") + getLLDVersion()); + StringRef s = getenv("LLD_VERSION"); + if (s.empty()) + s = saver.save(Twine("Linker: ") + getLLDVersion()); // +1 to include the terminating '\0'. - return {(const uint8_t *)S.data(), S.size() + 1}; + return {(const uint8_t *)s.data(), s.size() + 1}; } // Creates a .comment section containing LLD version info. @@ -83,79 +89,79 @@ MergeInputSection *elf::createCommentSection() { // .MIPS.abiflags section. template <class ELFT> -MipsAbiFlagsSection<ELFT>::MipsAbiFlagsSection(Elf_Mips_ABIFlags Flags) +MipsAbiFlagsSection<ELFT>::MipsAbiFlagsSection(Elf_Mips_ABIFlags flags) : SyntheticSection(SHF_ALLOC, SHT_MIPS_ABIFLAGS, 8, ".MIPS.abiflags"), - Flags(Flags) { - this->Entsize = sizeof(Elf_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)); +template <class ELFT> void MipsAbiFlagsSection<ELFT>::writeTo(uint8_t *buf) { + memcpy(buf, &flags, sizeof(flags)); } template <class ELFT> MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() { - Elf_Mips_ABIFlags Flags = {}; - bool Create = false; + Elf_Mips_ABIFlags flags = {}; + bool create = false; - for (InputSectionBase *Sec : InputSections) { - if (Sec->Type != SHT_MIPS_ABIFLAGS) + for (InputSectionBase *sec : inputSections) { + if (sec->type != SHT_MIPS_ABIFLAGS) continue; - Sec->Live = false; - Create = true; + sec->markDead(); + create = true; - std::string Filename = toString(Sec->File); - const size_t Size = Sec->data().size(); + std::string filename = toString(sec->file); + 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 // zero padding) we ignore everything after the first Elf_Mips_ABIFlags - if (Size < sizeof(Elf_Mips_ABIFlags)) { - error(Filename + ": invalid size of .MIPS.abiflags section: got " + - Twine(Size) + " instead of " + Twine(sizeof(Elf_Mips_ABIFlags))); + if (size < sizeof(Elf_Mips_ABIFlags)) { + error(filename + ": invalid size of .MIPS.abiflags section: got " + + Twine(size) + " instead of " + Twine(sizeof(Elf_Mips_ABIFlags))); return nullptr; } - auto *S = reinterpret_cast<const Elf_Mips_ABIFlags *>(Sec->data().data()); - if (S->version != 0) { - error(Filename + ": unexpected .MIPS.abiflags version " + - Twine(S->version)); + auto *s = reinterpret_cast<const Elf_Mips_ABIFlags *>(sec->data().data()); + if (s->version != 0) { + error(filename + ": unexpected .MIPS.abiflags version " + + Twine(s->version)); return nullptr; } // LLD checks ISA compatibility in calcMipsEFlags(). Here we just // select the highest number of ISA/Rev/Ext. - Flags.isa_level = std::max(Flags.isa_level, S->isa_level); - Flags.isa_rev = std::max(Flags.isa_rev, S->isa_rev); - Flags.isa_ext = std::max(Flags.isa_ext, S->isa_ext); - Flags.gpr_size = std::max(Flags.gpr_size, S->gpr_size); - Flags.cpr1_size = std::max(Flags.cpr1_size, S->cpr1_size); - Flags.cpr2_size = std::max(Flags.cpr2_size, S->cpr2_size); - Flags.ases |= S->ases; - Flags.flags1 |= S->flags1; - Flags.flags2 |= S->flags2; - Flags.fp_abi = elf::getMipsFpAbiFlag(Flags.fp_abi, S->fp_abi, Filename); + flags.isa_level = std::max(flags.isa_level, s->isa_level); + flags.isa_rev = std::max(flags.isa_rev, s->isa_rev); + flags.isa_ext = std::max(flags.isa_ext, s->isa_ext); + flags.gpr_size = std::max(flags.gpr_size, s->gpr_size); + flags.cpr1_size = std::max(flags.cpr1_size, s->cpr1_size); + flags.cpr2_size = std::max(flags.cpr2_size, s->cpr2_size); + flags.ases |= s->ases; + flags.flags1 |= s->flags1; + flags.flags2 |= s->flags2; + flags.fp_abi = elf::getMipsFpAbiFlag(flags.fp_abi, s->fp_abi, filename); }; - if (Create) - return make<MipsAbiFlagsSection<ELFT>>(Flags); + if (create) + return make<MipsAbiFlagsSection<ELFT>>(flags); return nullptr; } // .MIPS.options section. template <class ELFT> -MipsOptionsSection<ELFT>::MipsOptionsSection(Elf_Mips_RegInfo Reginfo) +MipsOptionsSection<ELFT>::MipsOptionsSection(Elf_Mips_RegInfo reginfo) : SyntheticSection(SHF_ALLOC, SHT_MIPS_OPTIONS, 8, ".MIPS.options"), - Reginfo(Reginfo) { - this->Entsize = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo); + 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); - Options->kind = ODK_REGINFO; - Options->size = getSize(); +template <class ELFT> void MipsOptionsSection<ELFT>::writeTo(uint8_t *buf) { + auto *options = reinterpret_cast<Elf_Mips_Options *>(buf); + options->kind = ODK_REGINFO; + options->size = getSize(); - if (!Config->Relocatable) - Reginfo.ri_gp_value = In.MipsGot->getGp(); - memcpy(Buf + sizeof(Elf_Mips_Options), &Reginfo, sizeof(Reginfo)); + if (!config->relocatable) + reginfo.ri_gp_value = in.mipsGot->getGp(); + memcpy(buf + sizeof(Elf_Mips_Options), ®info, sizeof(reginfo)); } template <class ELFT> @@ -164,55 +170,55 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() { if (!ELFT::Is64Bits) return nullptr; - std::vector<InputSectionBase *> Sections; - for (InputSectionBase *Sec : InputSections) - if (Sec->Type == SHT_MIPS_OPTIONS) - Sections.push_back(Sec); + std::vector<InputSectionBase *> sections; + for (InputSectionBase *sec : inputSections) + if (sec->type == SHT_MIPS_OPTIONS) + sections.push_back(sec); - if (Sections.empty()) + if (sections.empty()) return nullptr; - Elf_Mips_RegInfo Reginfo = {}; - for (InputSectionBase *Sec : Sections) { - Sec->Live = false; + Elf_Mips_RegInfo reginfo = {}; + for (InputSectionBase *sec : sections) { + sec->markDead(); - std::string Filename = toString(Sec->File); - ArrayRef<uint8_t> D = Sec->data(); + std::string filename = toString(sec->file); + ArrayRef<uint8_t> d = sec->data(); - while (!D.empty()) { - if (D.size() < sizeof(Elf_Mips_Options)) { - error(Filename + ": invalid size of .MIPS.options section"); + while (!d.empty()) { + if (d.size() < sizeof(Elf_Mips_Options)) { + error(filename + ": invalid size of .MIPS.options section"); break; } - auto *Opt = reinterpret_cast<const Elf_Mips_Options *>(D.data()); - if (Opt->kind == ODK_REGINFO) { - Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask; - Sec->getFile<ELFT>()->MipsGp0 = Opt->getRegInfo().ri_gp_value; + auto *opt = reinterpret_cast<const Elf_Mips_Options *>(d.data()); + if (opt->kind == ODK_REGINFO) { + reginfo.ri_gprmask |= opt->getRegInfo().ri_gprmask; + sec->getFile<ELFT>()->mipsGp0 = opt->getRegInfo().ri_gp_value; break; } - if (!Opt->size) - fatal(Filename + ": zero option descriptor size"); - D = D.slice(Opt->size); + if (!opt->size) + fatal(filename + ": zero option descriptor size"); + d = d.slice(opt->size); } }; - return make<MipsOptionsSection<ELFT>>(Reginfo); + return make<MipsOptionsSection<ELFT>>(reginfo); } // MIPS .reginfo section. template <class ELFT> -MipsReginfoSection<ELFT>::MipsReginfoSection(Elf_Mips_RegInfo Reginfo) +MipsReginfoSection<ELFT>::MipsReginfoSection(Elf_Mips_RegInfo reginfo) : SyntheticSection(SHF_ALLOC, SHT_MIPS_REGINFO, 4, ".reginfo"), - Reginfo(Reginfo) { - this->Entsize = sizeof(Elf_Mips_RegInfo); + reginfo(reginfo) { + this->entsize = sizeof(Elf_Mips_RegInfo); } -template <class ELFT> void MipsReginfoSection<ELFT>::writeTo(uint8_t *Buf) { - if (!Config->Relocatable) - Reginfo.ri_gp_value = In.MipsGot->getGp(); - memcpy(Buf, &Reginfo, sizeof(Reginfo)); +template <class ELFT> void MipsReginfoSection<ELFT>::writeTo(uint8_t *buf) { + if (!config->relocatable) + reginfo.ri_gp_value = in.mipsGot->getGp(); + memcpy(buf, ®info, sizeof(reginfo)); } template <class ELFT> @@ -221,53 +227,53 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() { if (ELFT::Is64Bits) return nullptr; - std::vector<InputSectionBase *> Sections; - for (InputSectionBase *Sec : InputSections) - if (Sec->Type == SHT_MIPS_REGINFO) - Sections.push_back(Sec); + std::vector<InputSectionBase *> sections; + for (InputSectionBase *sec : inputSections) + if (sec->type == SHT_MIPS_REGINFO) + sections.push_back(sec); - if (Sections.empty()) + if (sections.empty()) return nullptr; - Elf_Mips_RegInfo Reginfo = {}; - for (InputSectionBase *Sec : Sections) { - Sec->Live = false; + Elf_Mips_RegInfo reginfo = {}; + for (InputSectionBase *sec : sections) { + sec->markDead(); - if (Sec->data().size() != sizeof(Elf_Mips_RegInfo)) { - error(toString(Sec->File) + ": invalid size of .reginfo section"); + if (sec->data().size() != sizeof(Elf_Mips_RegInfo)) { + error(toString(sec->file) + ": invalid size of .reginfo section"); return nullptr; } - auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->data().data()); - Reginfo.ri_gprmask |= R->ri_gprmask; - Sec->getFile<ELFT>()->MipsGp0 = R->ri_gp_value; + auto *r = reinterpret_cast<const Elf_Mips_RegInfo *>(sec->data().data()); + reginfo.ri_gprmask |= r->ri_gprmask; + sec->getFile<ELFT>()->mipsGp0 = r->ri_gp_value; }; - return make<MipsReginfoSection<ELFT>>(Reginfo); + return make<MipsReginfoSection<ELFT>>(reginfo); } InputSection *elf::createInterpSection() { // StringSaver guarantees that the returned string ends with '\0'. - StringRef S = Saver.save(Config->DynamicLinker); - ArrayRef<uint8_t> Contents = {(const uint8_t *)S.data(), S.size() + 1}; + StringRef s = saver.save(config->dynamicLinker); + ArrayRef<uint8_t> contents = {(const uint8_t *)s.data(), s.size() + 1}; - auto *Sec = make<InputSection>(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, Contents, + auto *sec = make<InputSection>(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, contents, ".interp"); - Sec->Live = true; - return Sec; + sec->markLive(); + return sec; } -Defined *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, - uint64_t Size, InputSectionBase &Section) { - auto *S = make<Defined>(Section.File, Name, STB_LOCAL, STV_DEFAULT, Type, - Value, Size, &Section); - if (In.SymTab) - In.SymTab->addSymbol(S); - return S; +Defined *elf::addSyntheticLocal(StringRef name, uint8_t type, uint64_t value, + uint64_t size, InputSectionBase §ion) { + auto *s = make<Defined>(section.file, name, STB_LOCAL, STV_DEFAULT, type, + value, size, §ion); + if (in.symTab) + in.symTab->addSymbol(s); + return s; } static size_t getHashSize() { - switch (Config->BuildId) { + switch (config->buildId) { case BuildIdKind::Fast: return 8; case BuildIdKind::Md5: @@ -276,89 +282,67 @@ static size_t getHashSize() { case BuildIdKind::Sha1: return 20; case BuildIdKind::Hexstring: - return Config->BuildIdVector.size(); + return config->buildIdVector.size(); default: llvm_unreachable("unknown BuildIdKind"); } } +// This class represents a linker-synthesized .note.gnu.property section. +// +// In x86 and AArch64, object files may contain feature flags indicating the +// features that they have used. The flags are stored in a .note.gnu.property +// section. +// +// lld reads the sections from input files and merges them by computing AND of +// the flags. The result is written as a new .note.gnu.property section. +// +// If the flag is zero (which indicates that the intersection of the feature +// sets is empty, or some input files didn't have .note.gnu.property sections), +// we don't create this section. +GnuPropertySection::GnuPropertySection() + : SyntheticSection(llvm::ELF::SHF_ALLOC, llvm::ELF::SHT_NOTE, 4, + ".note.gnu.property") {} + +void GnuPropertySection::writeTo(uint8_t *buf) { + uint32_t featureAndType = config->emachine == EM_AARCH64 + ? GNU_PROPERTY_AARCH64_FEATURE_1_AND + : GNU_PROPERTY_X86_FEATURE_1_AND; + + write32(buf, 4); // Name size + write32(buf + 4, config->is64 ? 16 : 12); // Content size + write32(buf + 8, NT_GNU_PROPERTY_TYPE_0); // Type + memcpy(buf + 12, "GNU", 4); // Name string + write32(buf + 16, featureAndType); // Feature type + write32(buf + 20, 4); // Feature size + write32(buf + 24, config->andFeatures); // Feature flags + if (config->is64) + write32(buf + 28, 0); // Padding +} + +size_t GnuPropertySection::getSize() const { return config->is64 ? 32 : 28; } + BuildIdSection::BuildIdSection() : SyntheticSection(SHF_ALLOC, SHT_NOTE, 4, ".note.gnu.build-id"), - HashSize(getHashSize()) {} - -void BuildIdSection::writeTo(uint8_t *Buf) { - write32(Buf, 4); // Name size - write32(Buf + 4, HashSize); // Content size - write32(Buf + 8, NT_GNU_BUILD_ID); // Type - memcpy(Buf + 12, "GNU", 4); // Name string - HashBuf = Buf + 16; -} - -// Split one uint8 array into small pieces of uint8 arrays. -static std::vector<ArrayRef<uint8_t>> split(ArrayRef<uint8_t> Arr, - size_t ChunkSize) { - std::vector<ArrayRef<uint8_t>> Ret; - while (Arr.size() > ChunkSize) { - Ret.push_back(Arr.take_front(ChunkSize)); - Arr = Arr.drop_front(ChunkSize); - } - if (!Arr.empty()) - Ret.push_back(Arr); - return Ret; -} - -// Computes a hash value of Data using a given hash function. -// 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. -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. - parallelForEachN(0, Chunks.size(), [&](size_t I) { - HashFn(Hashes.data() + I * HashSize, Chunks[I]); - }); + hashSize(getHashSize()) {} - // Write to the final output buffer. - HashFn(HashBuf, Hashes); +void BuildIdSection::writeTo(uint8_t *buf) { + write32(buf, 4); // Name size + write32(buf + 4, hashSize); // Content size + write32(buf + 8, NT_GNU_BUILD_ID); // Type + memcpy(buf + 12, "GNU", 4); // Name string + hashBuf = buf + 16; } -BssSection::BssSection(StringRef Name, uint64_t Size, uint32_t Alignment) - : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, Alignment, Name) { - this->Bss = true; - this->Size = Size; +void BuildIdSection::writeBuildId(ArrayRef<uint8_t> buf) { + assert(buf.size() == hashSize); + memcpy(hashBuf, buf.data(), hashSize); } -void BuildIdSection::writeBuildId(ArrayRef<uint8_t> Buf) { - switch (Config->BuildId) { - case BuildIdKind::Fast: - computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) { - write64le(Dest, xxHash64(Arr)); - }); - break; - case BuildIdKind::Md5: - computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) { - memcpy(Dest, MD5::hash(Arr).data(), 16); - }); - break; - case BuildIdKind::Sha1: - computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) { - memcpy(Dest, SHA1::hash(Arr).data(), 20); - }); - break; - case BuildIdKind::Uuid: - if (auto EC = getRandomBytes(HashBuf, HashSize)) - error("entropy source failure: " + EC.message()); - break; - case BuildIdKind::Hexstring: - memcpy(HashBuf, Config->BuildIdVector.data(), Config->BuildIdVector.size()); - break; - default: - llvm_unreachable("unknown BuildIdKind"); - } +BssSection::BssSection(StringRef name, uint64_t size, uint32_t alignment) + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, alignment, name) { + this->bss = true; + this->size = size; } EhFrameSection::EhFrameSection() @@ -368,47 +352,48 @@ EhFrameSection::EhFrameSection() // CIE records from input object files are uniquified by their contents // and where their relocations point to. template <class ELFT, class RelTy> -CieRecord *EhFrameSection::addCie(EhSectionPiece &Cie, ArrayRef<RelTy> Rels) { - Symbol *Personality = nullptr; - unsigned FirstRelI = Cie.FirstRelocation; - if (FirstRelI != (unsigned)-1) - Personality = - &Cie.Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]); +CieRecord *EhFrameSection::addCie(EhSectionPiece &cie, ArrayRef<RelTy> rels) { + Symbol *personality = nullptr; + unsigned firstRelI = cie.firstRelocation; + if (firstRelI != (unsigned)-1) + personality = + &cie.sec->template getFile<ELFT>()->getRelocTargetSym(rels[firstRelI]); // Search for an existing CIE by CIE contents/relocation target pair. - CieRecord *&Rec = CieMap[{Cie.data(), Personality}]; + CieRecord *&rec = cieMap[{cie.data(), personality}]; // If not found, create a new one. - if (!Rec) { - Rec = make<CieRecord>(); - Rec->Cie = &Cie; - CieRecords.push_back(Rec); + if (!rec) { + rec = make<CieRecord>(); + rec->cie = &cie; + cieRecords.push_back(rec); } - return Rec; + return rec; } // There is one FDE per function. Returns true if a given FDE // points to a live function. template <class ELFT, class RelTy> -bool EhFrameSection::isFdeLive(EhSectionPiece &Fde, ArrayRef<RelTy> Rels) { - auto *Sec = cast<EhInputSection>(Fde.Sec); - unsigned FirstRelI = Fde.FirstRelocation; +bool EhFrameSection::isFdeLive(EhSectionPiece &fde, ArrayRef<RelTy> rels) { + auto *sec = cast<EhInputSection>(fde.sec); + unsigned firstRelI = fde.firstRelocation; // An FDE should point to some function because FDEs are to describe // functions. That's however not always the case due to an issue of // ld.gold with -r. ld.gold may discard only functions and leave their // corresponding FDEs, which results in creating bad .eh_frame sections. // To deal with that, we ignore such FDEs. - if (FirstRelI == (unsigned)-1) + if (firstRelI == (unsigned)-1) return false; - const RelTy &Rel = Rels[FirstRelI]; - Symbol &B = Sec->template getFile<ELFT>()->getRelocTargetSym(Rel); + const RelTy &rel = rels[firstRelI]; + Symbol &b = sec->template getFile<ELFT>()->getRelocTargetSym(rel); - // FDEs for garbage-collected or merged-by-ICF sections are dead. - if (auto *D = dyn_cast<Defined>(&B)) - if (SectionBase *Sec = D->Section) - return Sec->Live; + // FDEs for garbage-collected or merged-by-ICF sections, or sections in + // another partition, are dead. + if (auto *d = dyn_cast<Defined>(&b)) + if (SectionBase *sec = d->section) + return sec->partition == partition; return false; } @@ -417,73 +402,73 @@ bool EhFrameSection::isFdeLive(EhSectionPiece &Fde, ArrayRef<RelTy> Rels) { // a list of FDEs. This function searches an existing CIE or create a new // one and associates FDEs to the CIE. template <class ELFT, class RelTy> -void EhFrameSection::addSectionAux(EhInputSection *Sec, ArrayRef<RelTy> Rels) { - OffsetToCie.clear(); - for (EhSectionPiece &Piece : Sec->Pieces) { +void EhFrameSection::addSectionAux(EhInputSection *sec, ArrayRef<RelTy> rels) { + offsetToCie.clear(); + for (EhSectionPiece &piece : sec->pieces) { // The empty record is the end marker. - if (Piece.Size == 4) + if (piece.size == 4) return; - size_t Offset = Piece.InputOff; - uint32_t ID = read32(Piece.data().data() + 4); - if (ID == 0) { - OffsetToCie[Offset] = addCie<ELFT>(Piece, Rels); + size_t offset = piece.inputOff; + uint32_t id = read32(piece.data().data() + 4); + if (id == 0) { + offsetToCie[offset] = addCie<ELFT>(piece, rels); continue; } - uint32_t CieOffset = Offset + 4 - ID; - CieRecord *Rec = OffsetToCie[CieOffset]; - if (!Rec) - fatal(toString(Sec) + ": invalid CIE reference"); + uint32_t cieOffset = offset + 4 - id; + CieRecord *rec = offsetToCie[cieOffset]; + if (!rec) + fatal(toString(sec) + ": invalid CIE reference"); - if (!isFdeLive<ELFT>(Piece, Rels)) + if (!isFdeLive<ELFT>(piece, rels)) continue; - Rec->Fdes.push_back(&Piece); - NumFdes++; + rec->fdes.push_back(&piece); + numFdes++; } } -template <class ELFT> void EhFrameSection::addSection(InputSectionBase *C) { - auto *Sec = cast<EhInputSection>(C); - Sec->Parent = this; +template <class ELFT> void EhFrameSection::addSection(InputSectionBase *c) { + auto *sec = cast<EhInputSection>(c); + sec->parent = this; - Alignment = std::max(Alignment, Sec->Alignment); - Sections.push_back(Sec); + alignment = std::max(alignment, sec->alignment); + sections.push_back(sec); - for (auto *DS : Sec->DependentSections) - DependentSections.push_back(DS); + for (auto *ds : sec->dependentSections) + dependentSections.push_back(ds); - if (Sec->Pieces.empty()) + if (sec->pieces.empty()) return; - if (Sec->AreRelocsRela) - addSectionAux<ELFT>(Sec, Sec->template relas<ELFT>()); + if (sec->areRelocsRela) + addSectionAux<ELFT>(sec, sec->template relas<ELFT>()); else - addSectionAux<ELFT>(Sec, Sec->template rels<ELFT>()); + addSectionAux<ELFT>(sec, sec->template rels<ELFT>()); } -static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) { - memcpy(Buf, D.data(), D.size()); +static void writeCieFde(uint8_t *buf, ArrayRef<uint8_t> d) { + memcpy(buf, d.data(), d.size()); - size_t Aligned = alignTo(D.size(), Config->Wordsize); + size_t aligned = alignTo(d.size(), config->wordsize); // Zero-clear trailing padding if it exists. - memset(Buf + D.size(), 0, Aligned - D.size()); + memset(buf + d.size(), 0, aligned - d.size()); // Fix the size field. -4 since size does not include the size field itself. - write32(Buf, Aligned - 4); + write32(buf, aligned - 4); } void EhFrameSection::finalizeContents() { - assert(!this->Size); // Not finalized. - size_t Off = 0; - for (CieRecord *Rec : CieRecords) { - Rec->Cie->OutputOff = Off; - Off += alignTo(Rec->Cie->Size, Config->Wordsize); - - for (EhSectionPiece *Fde : Rec->Fdes) { - Fde->OutputOff = Off; - Off += alignTo(Fde->Size, Config->Wordsize); + assert(!this->size); // Not finalized. + size_t off = 0; + for (CieRecord *rec : cieRecords) { + rec->cie->outputOff = off; + off += alignTo(rec->cie->size, config->wordsize); + + for (EhSectionPiece *fde : rec->fdes) { + fde->outputOff = off; + off += alignTo(fde->size, config->wordsize); } } @@ -491,375 +476,374 @@ void EhFrameSection::finalizeContents() { // Call Frame Information records. glibc unwind-dw2-fde.c // classify_object_over_fdes expects there is a CIE record length 0 as a // terminator. Thus we add one unconditionally. - Off += 4; + off += 4; - this->Size = Off; + this->size = off; } // Returns data for .eh_frame_hdr. .eh_frame_hdr is a binary search table // to get an FDE from an address to which FDE is applied. This function // returns a list of such pairs. std::vector<EhFrameSection::FdeData> EhFrameSection::getFdeData() const { - uint8_t *Buf = getParent()->Loc + OutSecOff; - std::vector<FdeData> Ret; - - uint64_t VA = In.EhFrameHdr->getVA(); - for (CieRecord *Rec : CieRecords) { - uint8_t Enc = getFdeEncoding(Rec->Cie); - for (EhSectionPiece *Fde : Rec->Fdes) { - uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc); - uint64_t FdeVA = getParent()->Addr + Fde->OutputOff; - if (!isInt<32>(Pc - VA)) - fatal(toString(Fde->Sec) + ": PC offset is too large: 0x" + - Twine::utohexstr(Pc - VA)); - Ret.push_back({uint32_t(Pc - VA), uint32_t(FdeVA - VA)}); + uint8_t *buf = Out::bufferStart + getParent()->offset + outSecOff; + std::vector<FdeData> ret; + + uint64_t va = getPartition().ehFrameHdr->getVA(); + for (CieRecord *rec : cieRecords) { + uint8_t enc = getFdeEncoding(rec->cie); + for (EhSectionPiece *fde : rec->fdes) { + uint64_t pc = getFdePc(buf, fde->outputOff, enc); + uint64_t fdeVA = getParent()->addr + fde->outputOff; + if (!isInt<32>(pc - va)) + fatal(toString(fde->sec) + ": PC offset is too large: 0x" + + Twine::utohexstr(pc - va)); + ret.push_back({uint32_t(pc - va), uint32_t(fdeVA - va)}); } } // Sort the FDE list by their PC and uniqueify. Usually there is only // one FDE for a PC (i.e. function), but if ICF merges two functions // into one, there can be more than one FDEs pointing to the address. - auto Less = [](const FdeData &A, const FdeData &B) { - return A.PcRel < B.PcRel; + auto less = [](const FdeData &a, const FdeData &b) { + return a.pcRel < b.pcRel; }; - std::stable_sort(Ret.begin(), Ret.end(), Less); - auto Eq = [](const FdeData &A, const FdeData &B) { - return A.PcRel == B.PcRel; + llvm::stable_sort(ret, less); + auto eq = [](const FdeData &a, const FdeData &b) { + return a.pcRel == b.pcRel; }; - Ret.erase(std::unique(Ret.begin(), Ret.end(), Eq), Ret.end()); + ret.erase(std::unique(ret.begin(), ret.end(), eq), ret.end()); - return Ret; + return ret; } -static uint64_t readFdeAddr(uint8_t *Buf, int Size) { - switch (Size) { +static uint64_t readFdeAddr(uint8_t *buf, int size) { + switch (size) { case DW_EH_PE_udata2: - return read16(Buf); + return read16(buf); case DW_EH_PE_sdata2: - return (int16_t)read16(Buf); + return (int16_t)read16(buf); case DW_EH_PE_udata4: - return read32(Buf); + return read32(buf); case DW_EH_PE_sdata4: - return (int32_t)read32(Buf); + return (int32_t)read32(buf); case DW_EH_PE_udata8: case DW_EH_PE_sdata8: - return read64(Buf); + return read64(buf); case DW_EH_PE_absptr: - return readUint(Buf); + return readUint(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. -uint64_t EhFrameSection::getFdePc(uint8_t *Buf, size_t FdeOff, - uint8_t Enc) const { +uint64_t EhFrameSection::getFdePc(uint8_t *buf, size_t fdeOff, + uint8_t enc) const { // The starting address to which this FDE applies is // stored at FDE + 8 byte. - size_t Off = FdeOff + 8; - uint64_t Addr = readFdeAddr(Buf + Off, Enc & 0xf); - if ((Enc & 0x70) == DW_EH_PE_absptr) - return Addr; - if ((Enc & 0x70) == DW_EH_PE_pcrel) - return Addr + getParent()->Addr + Off; + size_t off = fdeOff + 8; + uint64_t addr = readFdeAddr(buf + off, enc & 0xf); + if ((enc & 0x70) == DW_EH_PE_absptr) + return addr; + if ((enc & 0x70) == DW_EH_PE_pcrel) + return addr + getParent()->addr + off; fatal("unknown FDE size relative encoding"); } -void EhFrameSection::writeTo(uint8_t *Buf) { +void EhFrameSection::writeTo(uint8_t *buf) { // Write CIE and FDE records. - for (CieRecord *Rec : CieRecords) { - size_t CieOffset = Rec->Cie->OutputOff; - writeCieFde(Buf + CieOffset, Rec->Cie->data()); + for (CieRecord *rec : cieRecords) { + size_t cieOffset = rec->cie->outputOff; + writeCieFde(buf + cieOffset, rec->cie->data()); - for (EhSectionPiece *Fde : Rec->Fdes) { - size_t Off = Fde->OutputOff; - writeCieFde(Buf + Off, Fde->data()); + for (EhSectionPiece *fde : rec->fdes) { + size_t off = fde->outputOff; + writeCieFde(buf + off, fde->data()); // FDE's second word should have the offset to an associated CIE. // Write it. - write32(Buf + Off + 4, Off + 4 - CieOffset); + write32(buf + off + 4, off + 4 - cieOffset); } } // Apply relocations. .eh_frame section contents are not contiguous // in the output buffer, but relocateAlloc() still works because // getOffset() takes care of discontiguous section pieces. - for (EhInputSection *S : Sections) - S->relocateAlloc(Buf, nullptr); + for (EhInputSection *s : sections) + s->relocateAlloc(buf, nullptr); + + if (getPartition().ehFrameHdr && getPartition().ehFrameHdr->getParent()) + getPartition().ehFrameHdr->write(); } GotSection::GotSection() - : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, - Target->GotEntrySize, ".got") { - // PPC64 saves the ElfSym::GlobalOffsetTable .TOC. as the first entry in the - // .got. If there are no references to .TOC. in the symbol table, - // ElfSym::GlobalOffsetTable will not be defined and we won't need to save - // .TOC. in the .got. When it is defined, we increase NumEntries by the number - // of entries used to emit ElfSym::GlobalOffsetTable. - if (ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt) - NumEntries += Target->GotHeaderEntriesNum; + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, config->wordsize, + ".got") { + // If ElfSym::globalOffsetTable is relative to .got and is referenced, + // increase numEntries by the number of entries used to emit + // ElfSym::globalOffsetTable. + if (ElfSym::globalOffsetTable && !target->gotBaseSymInGotPlt) + numEntries += target->gotHeaderEntriesNum; } -void GotSection::addEntry(Symbol &Sym) { - Sym.GotIndex = NumEntries; - ++NumEntries; +void GotSection::addEntry(Symbol &sym) { + sym.gotIndex = numEntries; + ++numEntries; } -bool GotSection::addDynTlsEntry(Symbol &Sym) { - if (Sym.GlobalDynIndex != -1U) +bool GotSection::addDynTlsEntry(Symbol &sym) { + if (sym.globalDynIndex != -1U) return false; - Sym.GlobalDynIndex = NumEntries; + sym.globalDynIndex = numEntries; // Global Dynamic TLS entries take two GOT slots. - NumEntries += 2; + numEntries += 2; return true; } // Reserves TLS entries for a TLS module ID and a TLS block offset. // In total it takes two GOT slots. bool GotSection::addTlsIndex() { - if (TlsIndexOff != uint32_t(-1)) + if (tlsIndexOff != uint32_t(-1)) return false; - TlsIndexOff = NumEntries * Config->Wordsize; - NumEntries += 2; + tlsIndexOff = numEntries * config->wordsize; + numEntries += 2; return true; } -uint64_t GotSection::getGlobalDynAddr(const Symbol &B) const { - return this->getVA() + B.GlobalDynIndex * Config->Wordsize; +uint64_t GotSection::getGlobalDynAddr(const Symbol &b) const { + return this->getVA() + b.globalDynIndex * config->wordsize; } -uint64_t GotSection::getGlobalDynOffset(const Symbol &B) const { - return B.GlobalDynIndex * Config->Wordsize; +uint64_t GotSection::getGlobalDynOffset(const Symbol &b) const { + return b.globalDynIndex * config->wordsize; } void GotSection::finalizeContents() { - Size = NumEntries * Config->Wordsize; + size = numEntries * config->wordsize; } -bool GotSection::empty() const { +bool GotSection::isNeeded() const { // We need to emit a GOT even if it's empty if there's a relocation that is - // relative to GOT(such as GOTOFFREL) or there's a symbol that points to a GOT - // (i.e. _GLOBAL_OFFSET_TABLE_) that the target defines relative to the .got. - return NumEntries == 0 && !HasGotOffRel && - !(ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt); + // relative to GOT(such as GOTOFFREL). + return numEntries || hasGotOffRel; } -void GotSection::writeTo(uint8_t *Buf) { +void GotSection::writeTo(uint8_t *buf) { // Buf points to the start of this section's buffer, // whereas InputSectionBase::relocateAlloc() expects its argument // to point to the start of the output section. - Target->writeGotHeader(Buf); - relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + Size); + target->writeGotHeader(buf); + relocateAlloc(buf - outSecOff, buf - outSecOff + size); } -static uint64_t getMipsPageAddr(uint64_t Addr) { - return (Addr + 0x8000) & ~0xffff; +static uint64_t getMipsPageAddr(uint64_t addr) { + return (addr + 0x8000) & ~0xffff; } -static uint64_t getMipsPageCount(uint64_t Size) { - return (Size + 0xfffe) / 0xffff + 1; +static uint64_t getMipsPageCount(uint64_t size) { + return (size + 0xfffe) / 0xffff + 1; } MipsGotSection::MipsGotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16, ".got") {} -void MipsGotSection::addEntry(InputFile &File, Symbol &Sym, int64_t Addend, - RelExpr Expr) { - FileGot &G = getGot(File); - if (Expr == R_MIPS_GOT_LOCAL_PAGE) { - if (const OutputSection *OS = Sym.getOutputSection()) - G.PagesMap.insert({OS, {}}); +void MipsGotSection::addEntry(InputFile &file, Symbol &sym, int64_t addend, + RelExpr expr) { + FileGot &g = getGot(file); + if (expr == R_MIPS_GOT_LOCAL_PAGE) { + if (const OutputSection *os = sym.getOutputSection()) + g.pagesMap.insert({os, {}}); else - G.Local16.insert({{nullptr, getMipsPageAddr(Sym.getVA(Addend))}, 0}); - } else if (Sym.isTls()) - G.Tls.insert({&Sym, 0}); - else if (Sym.IsPreemptible && Expr == R_ABS) - G.Relocs.insert({&Sym, 0}); - else if (Sym.IsPreemptible) - G.Global.insert({&Sym, 0}); - else if (Expr == R_MIPS_GOT_OFF32) - G.Local32.insert({{&Sym, Addend}, 0}); + g.local16.insert({{nullptr, getMipsPageAddr(sym.getVA(addend))}, 0}); + } else if (sym.isTls()) + g.tls.insert({&sym, 0}); + else if (sym.isPreemptible && expr == R_ABS) + g.relocs.insert({&sym, 0}); + else if (sym.isPreemptible) + g.global.insert({&sym, 0}); + else if (expr == R_MIPS_GOT_OFF32) + g.local32.insert({{&sym, addend}, 0}); else - G.Local16.insert({{&Sym, Addend}, 0}); + g.local16.insert({{&sym, addend}, 0}); } -void MipsGotSection::addDynTlsEntry(InputFile &File, Symbol &Sym) { - getGot(File).DynTlsSymbols.insert({&Sym, 0}); +void MipsGotSection::addDynTlsEntry(InputFile &file, Symbol &sym) { + getGot(file).dynTlsSymbols.insert({&sym, 0}); } -void MipsGotSection::addTlsIndex(InputFile &File) { - getGot(File).DynTlsSymbols.insert({nullptr, 0}); +void MipsGotSection::addTlsIndex(InputFile &file) { + getGot(file).dynTlsSymbols.insert({nullptr, 0}); } size_t MipsGotSection::FileGot::getEntriesNum() const { - return getPageEntriesNum() + Local16.size() + Global.size() + Relocs.size() + - Tls.size() + DynTlsSymbols.size() * 2; + return getPageEntriesNum() + local16.size() + global.size() + relocs.size() + + tls.size() + dynTlsSymbols.size() * 2; } size_t MipsGotSection::FileGot::getPageEntriesNum() const { - size_t Num = 0; - for (const std::pair<const OutputSection *, FileGot::PageBlock> &P : PagesMap) - Num += P.second.Count; - return Num; + size_t num = 0; + for (const std::pair<const OutputSection *, FileGot::PageBlock> &p : pagesMap) + num += p.second.count; + return num; } size_t MipsGotSection::FileGot::getIndexedEntriesNum() const { - size_t Count = getPageEntriesNum() + Local16.size() + Global.size(); + size_t count = getPageEntriesNum() + local16.size() + global.size(); // If there are relocation-only entries in the GOT, TLS entries // are allocated after them. TLS entries should be addressable // by 16-bit index so count both reloc-only and TLS entries. - if (!Tls.empty() || !DynTlsSymbols.empty()) - Count += Relocs.size() + Tls.size() + DynTlsSymbols.size() * 2; - return Count; + if (!tls.empty() || !dynTlsSymbols.empty()) + count += relocs.size() + tls.size() + dynTlsSymbols.size() * 2; + return count; } -MipsGotSection::FileGot &MipsGotSection::getGot(InputFile &F) { - if (!F.MipsGotIndex.hasValue()) { - Gots.emplace_back(); - Gots.back().File = &F; - F.MipsGotIndex = Gots.size() - 1; +MipsGotSection::FileGot &MipsGotSection::getGot(InputFile &f) { + if (!f.mipsGotIndex.hasValue()) { + gots.emplace_back(); + gots.back().file = &f; + f.mipsGotIndex = gots.size() - 1; } - return Gots[*F.MipsGotIndex]; + return gots[*f.mipsGotIndex]; } -uint64_t MipsGotSection::getPageEntryOffset(const InputFile *F, - const Symbol &Sym, - int64_t Addend) const { - const FileGot &G = Gots[*F->MipsGotIndex]; - uint64_t Index = 0; - if (const OutputSection *OutSec = Sym.getOutputSection()) { - uint64_t SecAddr = getMipsPageAddr(OutSec->Addr); - uint64_t SymAddr = getMipsPageAddr(Sym.getVA(Addend)); - Index = G.PagesMap.lookup(OutSec).FirstIndex + (SymAddr - SecAddr) / 0xffff; +uint64_t MipsGotSection::getPageEntryOffset(const InputFile *f, + const Symbol &sym, + int64_t addend) const { + const FileGot &g = gots[*f->mipsGotIndex]; + uint64_t index = 0; + if (const OutputSection *outSec = sym.getOutputSection()) { + uint64_t secAddr = getMipsPageAddr(outSec->addr); + uint64_t symAddr = getMipsPageAddr(sym.getVA(addend)); + index = g.pagesMap.lookup(outSec).firstIndex + (symAddr - secAddr) / 0xffff; } else { - Index = G.Local16.lookup({nullptr, getMipsPageAddr(Sym.getVA(Addend))}); + index = g.local16.lookup({nullptr, getMipsPageAddr(sym.getVA(addend))}); } - return Index * Config->Wordsize; + return index * config->wordsize; } -uint64_t MipsGotSection::getSymEntryOffset(const InputFile *F, const Symbol &S, - int64_t Addend) const { - const FileGot &G = Gots[*F->MipsGotIndex]; - Symbol *Sym = const_cast<Symbol *>(&S); - if (Sym->isTls()) - return G.Tls.lookup(Sym) * Config->Wordsize; - if (Sym->IsPreemptible) - return G.Global.lookup(Sym) * Config->Wordsize; - return G.Local16.lookup({Sym, Addend}) * Config->Wordsize; +uint64_t MipsGotSection::getSymEntryOffset(const InputFile *f, const Symbol &s, + int64_t addend) const { + const FileGot &g = gots[*f->mipsGotIndex]; + Symbol *sym = const_cast<Symbol *>(&s); + if (sym->isTls()) + return g.tls.lookup(sym) * config->wordsize; + if (sym->isPreemptible) + return g.global.lookup(sym) * config->wordsize; + return g.local16.lookup({sym, addend}) * config->wordsize; } -uint64_t MipsGotSection::getTlsIndexOffset(const InputFile *F) const { - const FileGot &G = Gots[*F->MipsGotIndex]; - return G.DynTlsSymbols.lookup(nullptr) * Config->Wordsize; +uint64_t MipsGotSection::getTlsIndexOffset(const InputFile *f) const { + const FileGot &g = gots[*f->mipsGotIndex]; + return g.dynTlsSymbols.lookup(nullptr) * config->wordsize; } -uint64_t MipsGotSection::getGlobalDynOffset(const InputFile *F, - const Symbol &S) const { - const FileGot &G = Gots[*F->MipsGotIndex]; - Symbol *Sym = const_cast<Symbol *>(&S); - return G.DynTlsSymbols.lookup(Sym) * Config->Wordsize; +uint64_t MipsGotSection::getGlobalDynOffset(const InputFile *f, + const Symbol &s) const { + const FileGot &g = gots[*f->mipsGotIndex]; + Symbol *sym = const_cast<Symbol *>(&s); + return g.dynTlsSymbols.lookup(sym) * config->wordsize; } const Symbol *MipsGotSection::getFirstGlobalEntry() const { - if (Gots.empty()) + if (gots.empty()) return nullptr; - const FileGot &PrimGot = Gots.front(); - if (!PrimGot.Global.empty()) - return PrimGot.Global.front().first; - if (!PrimGot.Relocs.empty()) - return PrimGot.Relocs.front().first; + const FileGot &primGot = gots.front(); + if (!primGot.global.empty()) + return primGot.global.front().first; + if (!primGot.relocs.empty()) + return primGot.relocs.front().first; return nullptr; } unsigned MipsGotSection::getLocalEntriesNum() const { - if (Gots.empty()) - return HeaderEntriesNum; - return HeaderEntriesNum + Gots.front().getPageEntriesNum() + - Gots.front().Local16.size(); + if (gots.empty()) + return headerEntriesNum; + return headerEntriesNum + gots.front().getPageEntriesNum() + + gots.front().local16.size(); } -bool MipsGotSection::tryMergeGots(FileGot &Dst, FileGot &Src, bool IsPrimary) { - FileGot Tmp = Dst; - set_union(Tmp.PagesMap, Src.PagesMap); - set_union(Tmp.Local16, Src.Local16); - set_union(Tmp.Global, Src.Global); - set_union(Tmp.Relocs, Src.Relocs); - set_union(Tmp.Tls, Src.Tls); - set_union(Tmp.DynTlsSymbols, Src.DynTlsSymbols); +bool MipsGotSection::tryMergeGots(FileGot &dst, FileGot &src, bool isPrimary) { + FileGot tmp = dst; + set_union(tmp.pagesMap, src.pagesMap); + set_union(tmp.local16, src.local16); + set_union(tmp.global, src.global); + set_union(tmp.relocs, src.relocs); + set_union(tmp.tls, src.tls); + set_union(tmp.dynTlsSymbols, src.dynTlsSymbols); - size_t Count = IsPrimary ? HeaderEntriesNum : 0; - Count += Tmp.getIndexedEntriesNum(); + size_t count = isPrimary ? headerEntriesNum : 0; + count += tmp.getIndexedEntriesNum(); - if (Count * Config->Wordsize > Config->MipsGotSize) + if (count * config->wordsize > config->mipsGotSize) return false; - std::swap(Tmp, Dst); + std::swap(tmp, dst); return true; } void MipsGotSection::finalizeContents() { updateAllocSize(); } bool MipsGotSection::updateAllocSize() { - Size = HeaderEntriesNum * Config->Wordsize; - for (const FileGot &G : Gots) - Size += G.getEntriesNum() * Config->Wordsize; + size = headerEntriesNum * config->wordsize; + for (const FileGot &g : gots) + size += g.getEntriesNum() * config->wordsize; return false; } -template <class ELFT> void MipsGotSection::build() { - if (Gots.empty()) +void MipsGotSection::build() { + if (gots.empty()) return; - std::vector<FileGot> MergedGots(1); + std::vector<FileGot> mergedGots(1); // For each GOT move non-preemptible symbols from the `Global` // to `Local16` list. Preemptible symbol might become non-preemptible // one if, for example, it gets a related copy relocation. - for (FileGot &Got : Gots) { - for (auto &P: Got.Global) - if (!P.first->IsPreemptible) - Got.Local16.insert({{P.first, 0}, 0}); - Got.Global.remove_if([&](const std::pair<Symbol *, size_t> &P) { - return !P.first->IsPreemptible; + for (FileGot &got : gots) { + for (auto &p: got.global) + if (!p.first->isPreemptible) + got.local16.insert({{p.first, 0}, 0}); + got.global.remove_if([&](const std::pair<Symbol *, size_t> &p) { + return !p.first->isPreemptible; }); } // For each GOT remove "reloc-only" entry if there is "global" // entry for the same symbol. And add local entries which indexed // using 32-bit value at the end of 16-bit entries. - for (FileGot &Got : Gots) { - Got.Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) { - return Got.Global.count(P.first); + for (FileGot &got : gots) { + got.relocs.remove_if([&](const std::pair<Symbol *, size_t> &p) { + return got.global.count(p.first); }); - set_union(Got.Local16, Got.Local32); - Got.Local32.clear(); + set_union(got.local16, got.local32); + got.local32.clear(); } // Evaluate number of "reloc-only" entries in the resulting GOT. // To do that put all unique "reloc-only" and "global" entries // from all GOTs to the future primary GOT. - FileGot *PrimGot = &MergedGots.front(); - for (FileGot &Got : Gots) { - set_union(PrimGot->Relocs, Got.Global); - set_union(PrimGot->Relocs, Got.Relocs); - Got.Relocs.clear(); + FileGot *primGot = &mergedGots.front(); + for (FileGot &got : gots) { + set_union(primGot->relocs, got.global); + set_union(primGot->relocs, got.relocs); + got.relocs.clear(); } // Evaluate number of "page" entries in each GOT. - for (FileGot &Got : Gots) { - for (std::pair<const OutputSection *, FileGot::PageBlock> &P : - Got.PagesMap) { - const OutputSection *OS = P.first; - uint64_t SecSize = 0; - for (BaseCommand *Cmd : OS->SectionCommands) { - if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd)) - for (InputSection *IS : ISD->Sections) { - uint64_t Off = alignTo(SecSize, IS->Alignment); - SecSize = Off + IS->getSize(); + for (FileGot &got : gots) { + for (std::pair<const OutputSection *, FileGot::PageBlock> &p : + got.pagesMap) { + const OutputSection *os = p.first; + uint64_t secSize = 0; + for (BaseCommand *cmd : os->sectionCommands) { + if (auto *isd = dyn_cast<InputSectionDescription>(cmd)) + for (InputSection *isec : isd->sections) { + uint64_t off = alignTo(secSize, isec->alignment); + secSize = off + isec->getSize(); } } - P.second.Count = getMipsPageCount(SecSize); + p.second.count = getMipsPageCount(secSize); } } @@ -868,149 +852,149 @@ template <class ELFT> void MipsGotSection::build() { // the primary GOT can be accessed in the most effective way. If it // is not possible, try to fill the last GOT in the list, and finally // create a new GOT if both attempts failed. - for (FileGot &SrcGot : Gots) { - InputFile *File = SrcGot.File; - if (tryMergeGots(MergedGots.front(), SrcGot, true)) { - File->MipsGotIndex = 0; + for (FileGot &srcGot : gots) { + InputFile *file = srcGot.file; + if (tryMergeGots(mergedGots.front(), srcGot, true)) { + file->mipsGotIndex = 0; } else { // If this is the first time we failed to merge with the primary GOT, // MergedGots.back() will also be the primary GOT. We must make sure not - // to try to merge again with IsPrimary=false, as otherwise, if the + // to try to merge again with isPrimary=false, as otherwise, if the // inputs are just right, we could allow the primary GOT to become 1 or 2 - // words too big due to ignoring the header size. - if (MergedGots.size() == 1 || - !tryMergeGots(MergedGots.back(), SrcGot, false)) { - MergedGots.emplace_back(); - std::swap(MergedGots.back(), SrcGot); + // words bigger due to ignoring the header size. + if (mergedGots.size() == 1 || + !tryMergeGots(mergedGots.back(), srcGot, false)) { + mergedGots.emplace_back(); + std::swap(mergedGots.back(), srcGot); } - File->MipsGotIndex = MergedGots.size() - 1; + file->mipsGotIndex = mergedGots.size() - 1; } } - std::swap(Gots, MergedGots); + std::swap(gots, mergedGots); // Reduce number of "reloc-only" entries in the primary GOT // by substracting "global" entries exist in the primary GOT. - PrimGot = &Gots.front(); - PrimGot->Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) { - return PrimGot->Global.count(P.first); + primGot = &gots.front(); + primGot->relocs.remove_if([&](const std::pair<Symbol *, size_t> &p) { + return primGot->global.count(p.first); }); // Calculate indexes for each GOT entry. - size_t Index = HeaderEntriesNum; - for (FileGot &Got : Gots) { - Got.StartIndex = &Got == PrimGot ? 0 : Index; - for (std::pair<const OutputSection *, FileGot::PageBlock> &P : - Got.PagesMap) { + size_t index = headerEntriesNum; + for (FileGot &got : gots) { + got.startIndex = &got == primGot ? 0 : index; + for (std::pair<const OutputSection *, FileGot::PageBlock> &p : + got.pagesMap) { // For each output section referenced by GOT page relocations calculate - // and save into PagesMap an upper bound of MIPS GOT entries required + // and save into pagesMap an upper bound of MIPS GOT entries required // to store page addresses of local symbols. We assume the worst case - // each 64kb page of the output section has at least one GOT relocation // against it. And take in account the case when the section intersects // page boundaries. - P.second.FirstIndex = Index; - Index += P.second.Count; + p.second.firstIndex = index; + index += p.second.count; } - for (auto &P: Got.Local16) - P.second = Index++; - for (auto &P: Got.Global) - P.second = Index++; - for (auto &P: Got.Relocs) - P.second = Index++; - for (auto &P: Got.Tls) - P.second = Index++; - for (auto &P: Got.DynTlsSymbols) { - P.second = Index; - Index += 2; + for (auto &p: got.local16) + p.second = index++; + for (auto &p: got.global) + p.second = index++; + for (auto &p: got.relocs) + p.second = index++; + for (auto &p: got.tls) + p.second = index++; + for (auto &p: got.dynTlsSymbols) { + p.second = index; + index += 2; } } - // Update Symbol::GotIndex field to use this + // Update Symbol::gotIndex field to use this // value later in the `sortMipsSymbols` function. - for (auto &P : PrimGot->Global) - P.first->GotIndex = P.second; - for (auto &P : PrimGot->Relocs) - P.first->GotIndex = P.second; + for (auto &p : primGot->global) + p.first->gotIndex = p.second; + for (auto &p : primGot->relocs) + p.first->gotIndex = p.second; // Create dynamic relocations. - for (FileGot &Got : Gots) { + for (FileGot &got : gots) { // Create dynamic relocations for TLS entries. - for (std::pair<Symbol *, size_t> &P : Got.Tls) { - Symbol *S = P.first; - uint64_t Offset = P.second * Config->Wordsize; - if (S->IsPreemptible) - In.RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S); + for (std::pair<Symbol *, size_t> &p : got.tls) { + Symbol *s = p.first; + uint64_t offset = p.second * config->wordsize; + if (s->isPreemptible) + mainPart->relaDyn->addReloc(target->tlsGotRel, this, offset, s); } - for (std::pair<Symbol *, size_t> &P : Got.DynTlsSymbols) { - Symbol *S = P.first; - uint64_t Offset = P.second * Config->Wordsize; - if (S == nullptr) { - if (!Config->Pic) + for (std::pair<Symbol *, size_t> &p : got.dynTlsSymbols) { + Symbol *s = p.first; + uint64_t offset = p.second * config->wordsize; + if (s == nullptr) { + if (!config->isPic) continue; - In.RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S); + mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, this, offset, s); } else { // When building a shared library we still need a dynamic relocation // for the module index. Therefore only checking for - // S->IsPreemptible is not sufficient (this happens e.g. for + // S->isPreemptible is not sufficient (this happens e.g. for // thread-locals that have been marked as local through a linker script) - if (!S->IsPreemptible && !Config->Pic) + if (!s->isPreemptible && !config->isPic) continue; - In.RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S); + mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, this, offset, s); // However, we can skip writing the TLS offset reloc for non-preemptible // symbols since it is known even in shared libraries - if (!S->IsPreemptible) + if (!s->isPreemptible) continue; - Offset += Config->Wordsize; - In.RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S); + offset += config->wordsize; + mainPart->relaDyn->addReloc(target->tlsOffsetRel, this, offset, s); } } // Do not create dynamic relocations for non-TLS // entries in the primary GOT. - if (&Got == PrimGot) + if (&got == primGot) continue; // Dynamic relocations for "global" entries. - for (const std::pair<Symbol *, size_t> &P : Got.Global) { - uint64_t Offset = P.second * Config->Wordsize; - In.RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first); + for (const std::pair<Symbol *, size_t> &p : got.global) { + uint64_t offset = p.second * config->wordsize; + mainPart->relaDyn->addReloc(target->relativeRel, this, offset, p.first); } - if (!Config->Pic) + if (!config->isPic) continue; // Dynamic relocations for "local" entries in case of PIC. - for (const std::pair<const OutputSection *, FileGot::PageBlock> &L : - Got.PagesMap) { - size_t PageCount = L.second.Count; - for (size_t PI = 0; PI < PageCount; ++PI) { - uint64_t Offset = (L.second.FirstIndex + PI) * Config->Wordsize; - In.RelaDyn->addReloc({Target->RelativeRel, this, Offset, L.first, - int64_t(PI * 0x10000)}); + for (const std::pair<const OutputSection *, FileGot::PageBlock> &l : + got.pagesMap) { + size_t pageCount = l.second.count; + for (size_t pi = 0; pi < pageCount; ++pi) { + uint64_t offset = (l.second.firstIndex + pi) * config->wordsize; + mainPart->relaDyn->addReloc({target->relativeRel, this, offset, l.first, + int64_t(pi * 0x10000)}); } } - for (const std::pair<GotEntry, size_t> &P : Got.Local16) { - uint64_t Offset = P.second * Config->Wordsize; - In.RelaDyn->addReloc({Target->RelativeRel, this, Offset, true, - P.first.first, P.first.second}); + for (const std::pair<GotEntry, size_t> &p : got.local16) { + uint64_t offset = p.second * config->wordsize; + mainPart->relaDyn->addReloc({target->relativeRel, this, offset, true, + p.first.first, p.first.second}); } } } -bool MipsGotSection::empty() const { +bool MipsGotSection::isNeeded() 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; + return !config->relocatable; } -uint64_t MipsGotSection::getGp(const InputFile *F) const { +uint64_t MipsGotSection::getGp(const InputFile *f) const { // For files without related GOT or files refer a primary GOT // returns "common" _gp value. For secondary GOTs calculate // individual _gp values. - if (!F || !F->MipsGotIndex.hasValue() || *F->MipsGotIndex == 0) - return ElfSym::MipsGp->getVA(0); - return getVA() + Gots[*F->MipsGotIndex].StartIndex * Config->Wordsize + + if (!f || !f->mipsGotIndex.hasValue() || *f->mipsGotIndex == 0) + return ElfSym::mipsGp->getVA(0); + return getVA() + gots[*f->mipsGotIndex].startIndex * config->wordsize + 0x7ff0; } -void MipsGotSection::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. // @@ -1025,51 +1009,48 @@ void MipsGotSection::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. - writeUint(Buf + Config->Wordsize, (uint64_t)1 << (Config->Wordsize * 8 - 1)); - for (const FileGot &G : Gots) { - auto Write = [&](size_t I, const Symbol *S, int64_t A) { - uint64_t VA = A; - if (S) { - VA = S->getVA(A); - if (S->StOther & STO_MIPS_MICROMIPS) - VA |= 1; - } - writeUint(Buf + I * Config->Wordsize, VA); + writeUint(buf + config->wordsize, (uint64_t)1 << (config->wordsize * 8 - 1)); + for (const FileGot &g : gots) { + auto write = [&](size_t i, const Symbol *s, int64_t a) { + uint64_t va = a; + if (s) + va = s->getVA(a); + writeUint(buf + i * config->wordsize, va); }; // Write 'page address' entries to the local part of the GOT. - for (const std::pair<const OutputSection *, FileGot::PageBlock> &L : - G.PagesMap) { - size_t PageCount = L.second.Count; - uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr); - for (size_t PI = 0; PI < PageCount; ++PI) - Write(L.second.FirstIndex + PI, nullptr, FirstPageAddr + PI * 0x10000); + for (const std::pair<const OutputSection *, FileGot::PageBlock> &l : + g.pagesMap) { + size_t pageCount = l.second.count; + uint64_t firstPageAddr = getMipsPageAddr(l.first->addr); + for (size_t pi = 0; pi < pageCount; ++pi) + write(l.second.firstIndex + pi, nullptr, firstPageAddr + pi * 0x10000); } // Local, global, TLS, reloc-only entries. // If TLS entry has a corresponding dynamic relocations, leave it // initialized by zero. Write down adjusted TLS symbol's values otherwise. // To calculate the adjustments use offsets for thread-local storage. // https://www.linux-mips.org/wiki/NPTL - for (const std::pair<GotEntry, size_t> &P : G.Local16) - Write(P.second, P.first.first, P.first.second); + for (const std::pair<GotEntry, size_t> &p : g.local16) + write(p.second, p.first.first, p.first.second); // Write VA to the primary GOT only. For secondary GOTs that // will be done by REL32 dynamic relocations. - if (&G == &Gots.front()) - for (const std::pair<const Symbol *, size_t> &P : G.Global) - Write(P.second, P.first, 0); - for (const std::pair<Symbol *, size_t> &P : G.Relocs) - Write(P.second, P.first, 0); - for (const std::pair<Symbol *, size_t> &P : G.Tls) - Write(P.second, P.first, P.first->IsPreemptible ? 0 : -0x7000); - for (const std::pair<Symbol *, size_t> &P : G.DynTlsSymbols) { - if (P.first == nullptr && !Config->Pic) - Write(P.second, nullptr, 1); - else if (P.first && !P.first->IsPreemptible) { + if (&g == &gots.front()) + for (const std::pair<const Symbol *, size_t> &p : g.global) + write(p.second, p.first, 0); + for (const std::pair<Symbol *, size_t> &p : g.relocs) + write(p.second, p.first, 0); + for (const std::pair<Symbol *, size_t> &p : g.tls) + write(p.second, p.first, p.first->isPreemptible ? 0 : -0x7000); + for (const std::pair<Symbol *, size_t> &p : g.dynTlsSymbols) { + if (p.first == nullptr && !config->isPic) + write(p.second, nullptr, 1); + else if (p.first && !p.first->isPreemptible) { // If we are emitting PIC code with relocations we mustn't write // anything to the GOT here. When using Elf_Rel relocations the value // one will be treated as an addend and will cause crashes at runtime - if (!Config->Pic) - Write(P.second, nullptr, 1); - Write(P.second + 1, P.first, -0x8000); + if (!config->isPic) + write(p.second, nullptr, 1); + write(p.second + 1, p.first, -0x8000); } } } @@ -1080,46 +1061,48 @@ void MipsGotSection::writeTo(uint8_t *Buf) { // section. I don't know why we have a BSS style type for the section but it is // consitent across both 64-bit PowerPC ABIs as well as the 32-bit PowerPC ABI. GotPltSection::GotPltSection() - : SyntheticSection(SHF_ALLOC | SHF_WRITE, - Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS, - Target->GotPltEntrySize, - Config->EMachine == EM_PPC64 ? ".plt" : ".got.plt") {} + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, config->wordsize, + ".got.plt") { + if (config->emachine == EM_PPC) { + name = ".plt"; + } else if (config->emachine == EM_PPC64) { + type = SHT_NOBITS; + name = ".plt"; + } +} -void GotPltSection::addEntry(Symbol &Sym) { - assert(Sym.PltIndex == Entries.size()); - Entries.push_back(&Sym); +void GotPltSection::addEntry(Symbol &sym) { + assert(sym.pltIndex == entries.size()); + entries.push_back(&sym); } size_t GotPltSection::getSize() const { - return (Target->GotPltHeaderEntriesNum + Entries.size()) * - Target->GotPltEntrySize; + return (target->gotPltHeaderEntriesNum + entries.size()) * config->wordsize; } -void GotPltSection::writeTo(uint8_t *Buf) { - Target->writeGotPltHeader(Buf); - Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize; - for (const Symbol *B : Entries) { - Target->writeGotPlt(Buf, *B); - Buf += Config->Wordsize; +void GotPltSection::writeTo(uint8_t *buf) { + target->writeGotPltHeader(buf); + buf += target->gotPltHeaderEntriesNum * config->wordsize; + for (const Symbol *b : entries) { + target->writeGotPlt(buf, *b); + buf += config->wordsize; } } -bool GotPltSection::empty() const { - // We need to emit a GOT.PLT even if it's empty if there's a symbol that - // references the _GLOBAL_OFFSET_TABLE_ and the Target defines the symbol - // relative to the .got.plt section. - return Entries.empty() && - !(ElfSym::GlobalOffsetTable && Target->GotBaseSymInGotPlt); +bool GotPltSection::isNeeded() const { + // We need to emit GOTPLT even if it's empty if there's a relocation relative + // to it. + return !entries.empty() || hasGotPltOffRel; } static StringRef getIgotPltName() { // On ARM the IgotPltSection is part of the GotSection. - if (Config->EMachine == EM_ARM) + if (config->emachine == EM_ARM) return ".got"; // On PowerPC64 the GotPltSection is renamed to '.plt' so the IgotPltSection // needs to be named the same. - if (Config->EMachine == EM_PPC64) + if (config->emachine == EM_PPC64) return ".plt"; return ".got.plt"; @@ -1129,130 +1112,110 @@ static StringRef getIgotPltName() { // with the IgotPltSection. IgotPltSection::IgotPltSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, - Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS, - Target->GotPltEntrySize, getIgotPltName()) {} + config->emachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS, + config->wordsize, getIgotPltName()) {} -void IgotPltSection::addEntry(Symbol &Sym) { - Sym.IsInIgot = true; - assert(Sym.PltIndex == Entries.size()); - Entries.push_back(&Sym); +void IgotPltSection::addEntry(Symbol &sym) { + assert(sym.pltIndex == entries.size()); + entries.push_back(&sym); } size_t IgotPltSection::getSize() const { - return Entries.size() * Target->GotPltEntrySize; + return entries.size() * config->wordsize; } -void IgotPltSection::writeTo(uint8_t *Buf) { - for (const Symbol *B : Entries) { - Target->writeIgotPlt(Buf, *B); - Buf += Config->Wordsize; +void IgotPltSection::writeTo(uint8_t *buf) { + for (const Symbol *b : entries) { + target->writeIgotPlt(buf, *b); + buf += config->wordsize; } } -StringTableSection::StringTableSection(StringRef Name, bool Dynamic) - : SyntheticSection(Dynamic ? (uint64_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 +// 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. -unsigned StringTableSection::addString(StringRef S, bool HashIt) { - if (HashIt) { - auto R = StringMap.insert(std::make_pair(S, this->Size)); - if (!R.second) - return R.first->second; +unsigned StringTableSection::addString(StringRef s, bool hashIt) { + if (hashIt) { + auto r = stringMap.insert(std::make_pair(s, this->size)); + if (!r.second) + return r.first->second; } - unsigned Ret = this->Size; - this->Size = this->Size + S.size() + 1; - Strings.push_back(S); - return Ret; + unsigned ret = this->size; + this->size = this->size + s.size() + 1; + strings.push_back(s); + return ret; } -void StringTableSection::writeTo(uint8_t *Buf) { - for (StringRef S : Strings) { - memcpy(Buf, S.data(), S.size()); - Buf[S.size()] = '\0'; - Buf += S.size() + 1; +void StringTableSection::writeTo(uint8_t *buf) { + for (StringRef s : strings) { + memcpy(buf, s.data(), s.size()); + buf[s.size()] = '\0'; + buf += s.size() + 1; } } // Returns the number of version definition entries. Because the first entry // is for the version definition itself, it is the number of versioned symbols // plus one. Note that we don't support multiple versions yet. -static unsigned getVerDefNum() { return Config->VersionDefinitions.size() + 1; } +static unsigned getVerDefNum() { return config->versionDefinitions.size() + 1; } template <class ELFT> DynamicSection<ELFT>::DynamicSection() - : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_DYNAMIC, Config->Wordsize, + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_DYNAMIC, config->wordsize, ".dynamic") { - this->Entsize = ELFT::Is64Bits ? 16 : 8; + this->entsize = ELFT::Is64Bits ? 16 : 8; // .dynamic section is not writable on MIPS and on Fuchsia OS // which passes -z rodynamic. // See "Special Section" in Chapter 4 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - if (Config->EMachine == EM_MIPS || Config->ZRodynamic) - this->Flags = SHF_ALLOC; - - // Add strings to .dynstr early so that .dynstr's size will be - // fixed early. - for (StringRef S : Config->FilterList) - addInt(DT_FILTER, In.DynStrTab->addString(S)); - for (StringRef S : Config->AuxiliaryList) - addInt(DT_AUXILIARY, In.DynStrTab->addString(S)); - - if (!Config->Rpath.empty()) - addInt(Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH, - In.DynStrTab->addString(Config->Rpath)); - - for (InputFile *File : SharedFiles) { - SharedFile<ELFT> *F = cast<SharedFile<ELFT>>(File); - if (F->IsNeeded) - addInt(DT_NEEDED, In.DynStrTab->addString(F->SoName)); - } - if (!Config->SoName.empty()) - addInt(DT_SONAME, In.DynStrTab->addString(Config->SoName)); + if (config->emachine == EM_MIPS || config->zRodynamic) + this->flags = SHF_ALLOC; } template <class ELFT> -void DynamicSection<ELFT>::add(int32_t Tag, std::function<uint64_t()> Fn) { - Entries.push_back({Tag, Fn}); +void DynamicSection<ELFT>::add(int32_t tag, std::function<uint64_t()> fn) { + entries.push_back({tag, fn}); } template <class ELFT> -void DynamicSection<ELFT>::addInt(int32_t Tag, uint64_t Val) { - Entries.push_back({Tag, [=] { return Val; }}); +void DynamicSection<ELFT>::addInt(int32_t tag, uint64_t val) { + entries.push_back({tag, [=] { return val; }}); } template <class ELFT> -void DynamicSection<ELFT>::addInSec(int32_t Tag, InputSection *Sec) { - Entries.push_back({Tag, [=] { return Sec->getVA(0); }}); +void DynamicSection<ELFT>::addInSec(int32_t tag, InputSection *sec) { + entries.push_back({tag, [=] { return sec->getVA(0); }}); } template <class ELFT> -void DynamicSection<ELFT>::addInSecRelative(int32_t Tag, InputSection *Sec) { - size_t TagOffset = Entries.size() * Entsize; - Entries.push_back( - {Tag, [=] { return Sec->getVA(0) - (getVA() + TagOffset); }}); +void DynamicSection<ELFT>::addInSecRelative(int32_t tag, InputSection *sec) { + size_t tagOffset = entries.size() * entsize; + entries.push_back( + {tag, [=] { return sec->getVA(0) - (getVA() + tagOffset); }}); } template <class ELFT> -void DynamicSection<ELFT>::addOutSec(int32_t Tag, OutputSection *Sec) { - Entries.push_back({Tag, [=] { return Sec->Addr; }}); +void DynamicSection<ELFT>::addOutSec(int32_t tag, OutputSection *sec) { + entries.push_back({tag, [=] { return sec->addr; }}); } template <class ELFT> -void DynamicSection<ELFT>::addSize(int32_t Tag, OutputSection *Sec) { - Entries.push_back({Tag, [=] { return Sec->Size; }}); +void DynamicSection<ELFT>::addSize(int32_t tag, OutputSection *sec) { + entries.push_back({tag, [=] { return sec->size; }}); } template <class ELFT> -void DynamicSection<ELFT>::addSym(int32_t Tag, Symbol *Sym) { - Entries.push_back({Tag, [=] { return Sym->getVA(); }}); +void DynamicSection<ELFT>::addSym(int32_t tag, Symbol *sym) { + entries.push_back({tag, [=] { return sym->getVA(); }}); } // A Linker script may assign the RELA relocation sections to the same @@ -1260,47 +1223,74 @@ void DynamicSection<ELFT>::addSym(int32_t Tag, Symbol *Sym) { // Size. Moreover the [DT_JMPREL, DT_JMPREL + DT_PLTRELSZ) is permitted to // overlap with the [DT_RELA, DT_RELA + DT_RELASZ). static uint64_t addPltRelSz() { - size_t Size = In.RelaPlt->getSize(); - if (In.RelaIplt->getParent() == In.RelaPlt->getParent() && - In.RelaIplt->Name == In.RelaPlt->Name) - Size += In.RelaIplt->getSize(); - return Size; + size_t size = in.relaPlt->getSize(); + if (in.relaIplt->getParent() == in.relaPlt->getParent() && + in.relaIplt->name == in.relaPlt->name) + size += in.relaIplt->getSize(); + return size; } // Add remaining entries to complete .dynamic contents. template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { + elf::Partition &part = getPartition(); + bool isMain = part.name.empty(); + + for (StringRef s : config->filterList) + addInt(DT_FILTER, part.dynStrTab->addString(s)); + for (StringRef s : config->auxiliaryList) + addInt(DT_AUXILIARY, part.dynStrTab->addString(s)); + + if (!config->rpath.empty()) + addInt(config->enableNewDtags ? DT_RUNPATH : DT_RPATH, + part.dynStrTab->addString(config->rpath)); + + for (SharedFile *file : sharedFiles) + if (file->isNeeded) + addInt(DT_NEEDED, part.dynStrTab->addString(file->soName)); + + if (isMain) { + if (!config->soName.empty()) + addInt(DT_SONAME, part.dynStrTab->addString(config->soName)); + } else { + if (!config->soName.empty()) + addInt(DT_NEEDED, part.dynStrTab->addString(config->soName)); + addInt(DT_SONAME, part.dynStrTab->addString(part.name)); + } + // Set DT_FLAGS and DT_FLAGS_1. - uint32_t DtFlags = 0; - uint32_t DtFlags1 = 0; - if (Config->Bsymbolic) - DtFlags |= DF_SYMBOLIC; - if (Config->ZGlobal) - DtFlags1 |= DF_1_GLOBAL; - if (Config->ZInitfirst) - DtFlags1 |= DF_1_INITFIRST; - if (Config->ZInterpose) - DtFlags1 |= DF_1_INTERPOSE; - if (Config->ZNodefaultlib) - DtFlags1 |= DF_1_NODEFLIB; - 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; - } - if (Config->ZOrigin) { - DtFlags |= DF_ORIGIN; - DtFlags1 |= DF_1_ORIGIN; - } - if (!Config->ZText) - DtFlags |= DF_TEXTREL; - - if (DtFlags) - addInt(DT_FLAGS, DtFlags); - if (DtFlags1) - addInt(DT_FLAGS_1, DtFlags1); + uint32_t dtFlags = 0; + uint32_t dtFlags1 = 0; + if (config->bsymbolic) + dtFlags |= DF_SYMBOLIC; + if (config->zGlobal) + dtFlags1 |= DF_1_GLOBAL; + if (config->zInitfirst) + dtFlags1 |= DF_1_INITFIRST; + if (config->zInterpose) + dtFlags1 |= DF_1_INTERPOSE; + if (config->zNodefaultlib) + dtFlags1 |= DF_1_NODEFLIB; + 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; + } + if (config->zOrigin) { + dtFlags |= DF_ORIGIN; + dtFlags1 |= DF_1_ORIGIN; + } + if (!config->zText) + dtFlags |= DF_TEXTREL; + if (config->hasStaticTlsModel) + dtFlags |= DF_STATIC_TLS; + + if (dtFlags) + addInt(DT_FLAGS, dtFlags); + if (dtFlags1) + addInt(DT_FLAGS_1, dtFlags1); // DT_DEBUG is a pointer to debug informaion used by debuggers at runtime. We // need it for each process, so we don't write it for DSOs. The loader writes @@ -1310,266 +1300,287 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { // systems (currently only Fuchsia OS) provide other means to give the // debugger this information. Such systems may choose make .dynamic read-only. // If the target is such a system (used -z rodynamic) don't write DT_DEBUG. - if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic) + if (!config->shared && !config->relocatable && !config->zRodynamic) addInt(DT_DEBUG, 0); - if (OutputSection *Sec = In.DynStrTab->getParent()) - this->Link = Sec->SectionIndex; + if (OutputSection *sec = part.dynStrTab->getParent()) + this->link = sec->sectionIndex; - if (!In.RelaDyn->empty()) { - addInSec(In.RelaDyn->DynamicTag, In.RelaDyn); - addSize(In.RelaDyn->SizeDynamicTag, In.RelaDyn->getParent()); + if (part.relaDyn->isNeeded()) { + addInSec(part.relaDyn->dynamicTag, part.relaDyn); + addSize(part.relaDyn->sizeDynamicTag, part.relaDyn->getParent()); - bool IsRela = Config->IsRela; - addInt(IsRela ? DT_RELAENT : DT_RELENT, - IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel)); + bool isRela = config->isRela; + addInt(isRela ? DT_RELAENT : DT_RELENT, + isRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel)); // MIPS dynamic loader does not support RELCOUNT tag. // The problem is in the tight relation between dynamic // relocations and GOT. So do not emit this tag on MIPS. - if (Config->EMachine != EM_MIPS) { - size_t NumRelativeRels = In.RelaDyn->getRelativeRelocCount(); - if (Config->ZCombreloc && NumRelativeRels) - addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels); + if (config->emachine != EM_MIPS) { + size_t numRelativeRels = part.relaDyn->getRelativeRelocCount(); + if (config->zCombreloc && numRelativeRels) + addInt(isRela ? DT_RELACOUNT : DT_RELCOUNT, numRelativeRels); } } - if (In.RelrDyn && !In.RelrDyn->Relocs.empty()) { - addInSec(Config->UseAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR, - In.RelrDyn); - addSize(Config->UseAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ, - In.RelrDyn->getParent()); - addInt(Config->UseAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT, + if (part.relrDyn && !part.relrDyn->relocs.empty()) { + addInSec(config->useAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR, + part.relrDyn); + addSize(config->useAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ, + part.relrDyn->getParent()); + addInt(config->useAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT, sizeof(Elf_Relr)); } // .rel[a].plt section usually consists of two parts, containing plt and // iplt relocations. It is possible to have only iplt relocations in the - // output. In that case RelaPlt is empty and have zero offset, the same offset - // as RelaIplt have. And we still want to emit proper dynamic tags for that - // case, so here we always use RelaPlt as marker for the begining of + // output. In that case relaPlt is empty and have zero offset, the same offset + // as relaIplt has. And we still want to emit proper dynamic tags for that + // case, so here we always use relaPlt as marker for the begining of // .rel[a].plt section. - if (In.RelaPlt->getParent()->Live) { - addInSec(DT_JMPREL, In.RelaPlt); - Entries.push_back({DT_PLTRELSZ, addPltRelSz}); - switch (Config->EMachine) { + if (isMain && (in.relaPlt->isNeeded() || in.relaIplt->isNeeded())) { + addInSec(DT_JMPREL, in.relaPlt); + entries.push_back({DT_PLTRELSZ, addPltRelSz}); + switch (config->emachine) { case EM_MIPS: - addInSec(DT_MIPS_PLTGOT, In.GotPlt); + addInSec(DT_MIPS_PLTGOT, in.gotPlt); break; case EM_SPARCV9: - addInSec(DT_PLTGOT, In.Plt); + addInSec(DT_PLTGOT, in.plt); break; default: - addInSec(DT_PLTGOT, In.GotPlt); + addInSec(DT_PLTGOT, in.gotPlt); break; } - addInt(DT_PLTREL, Config->IsRela ? DT_RELA : DT_REL); + addInt(DT_PLTREL, config->isRela ? DT_RELA : DT_REL); + } + + if (config->emachine == EM_AARCH64) { + if (config->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) + addInt(DT_AARCH64_BTI_PLT, 0); + if (config->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_PAC) + addInt(DT_AARCH64_PAC_PLT, 0); } - addInSec(DT_SYMTAB, In.DynSymTab); + addInSec(DT_SYMTAB, part.dynSymTab); addInt(DT_SYMENT, sizeof(Elf_Sym)); - addInSec(DT_STRTAB, In.DynStrTab); - addInt(DT_STRSZ, In.DynStrTab->getSize()); - if (!Config->ZText) + addInSec(DT_STRTAB, part.dynStrTab); + addInt(DT_STRSZ, part.dynStrTab->getSize()); + if (!config->zText) addInt(DT_TEXTREL, 0); - if (In.GnuHashTab) - addInSec(DT_GNU_HASH, In.GnuHashTab); - if (In.HashTab) - addInSec(DT_HASH, In.HashTab); - - if (Out::PreinitArray) { - addOutSec(DT_PREINIT_ARRAY, Out::PreinitArray); - addSize(DT_PREINIT_ARRAYSZ, Out::PreinitArray); - } - if (Out::InitArray) { - addOutSec(DT_INIT_ARRAY, Out::InitArray); - addSize(DT_INIT_ARRAYSZ, Out::InitArray); - } - if (Out::FiniArray) { - addOutSec(DT_FINI_ARRAY, Out::FiniArray); - addSize(DT_FINI_ARRAYSZ, Out::FiniArray); - } - - if (Symbol *B = Symtab->find(Config->Init)) - if (B->isDefined()) - addSym(DT_INIT, B); - if (Symbol *B = Symtab->find(Config->Fini)) - if (B->isDefined()) - addSym(DT_FINI, B); - - bool HasVerNeed = InX<ELFT>::VerNeed->getNeedNum() != 0; - if (HasVerNeed || In.VerDef) - addInSec(DT_VERSYM, InX<ELFT>::VerSym); - if (In.VerDef) { - addInSec(DT_VERDEF, In.VerDef); + if (part.gnuHashTab) + addInSec(DT_GNU_HASH, part.gnuHashTab); + if (part.hashTab) + addInSec(DT_HASH, part.hashTab); + + if (isMain) { + if (Out::preinitArray) { + addOutSec(DT_PREINIT_ARRAY, Out::preinitArray); + addSize(DT_PREINIT_ARRAYSZ, Out::preinitArray); + } + if (Out::initArray) { + addOutSec(DT_INIT_ARRAY, Out::initArray); + addSize(DT_INIT_ARRAYSZ, Out::initArray); + } + if (Out::finiArray) { + addOutSec(DT_FINI_ARRAY, Out::finiArray); + addSize(DT_FINI_ARRAYSZ, Out::finiArray); + } + + if (Symbol *b = symtab->find(config->init)) + if (b->isDefined()) + addSym(DT_INIT, b); + if (Symbol *b = symtab->find(config->fini)) + if (b->isDefined()) + addSym(DT_FINI, b); + } + + bool hasVerNeed = SharedFile::vernauxNum != 0; + if (hasVerNeed || part.verDef) + addInSec(DT_VERSYM, part.verSym); + if (part.verDef) { + addInSec(DT_VERDEF, part.verDef); addInt(DT_VERDEFNUM, getVerDefNum()); } - if (HasVerNeed) { - addInSec(DT_VERNEED, InX<ELFT>::VerNeed); - addInt(DT_VERNEEDNUM, InX<ELFT>::VerNeed->getNeedNum()); + if (hasVerNeed) { + addInSec(DT_VERNEED, part.verNeed); + unsigned needNum = 0; + for (SharedFile *f : sharedFiles) + if (!f->vernauxs.empty()) + ++needNum; + addInt(DT_VERNEEDNUM, needNum); } - if (Config->EMachine == EM_MIPS) { + if (config->emachine == EM_MIPS) { addInt(DT_MIPS_RLD_VERSION, 1); addInt(DT_MIPS_FLAGS, RHF_NOTPOT); - addInt(DT_MIPS_BASE_ADDRESS, Target->getImageBase()); - addInt(DT_MIPS_SYMTABNO, In.DynSymTab->getNumSymbols()); + addInt(DT_MIPS_BASE_ADDRESS, target->getImageBase()); + addInt(DT_MIPS_SYMTABNO, part.dynSymTab->getNumSymbols()); - add(DT_MIPS_LOCAL_GOTNO, [] { return In.MipsGot->getLocalEntriesNum(); }); + add(DT_MIPS_LOCAL_GOTNO, [] { return in.mipsGot->getLocalEntriesNum(); }); - if (const Symbol *B = In.MipsGot->getFirstGlobalEntry()) - addInt(DT_MIPS_GOTSYM, B->DynsymIndex); + if (const Symbol *b = in.mipsGot->getFirstGlobalEntry()) + addInt(DT_MIPS_GOTSYM, b->dynsymIndex); else - addInt(DT_MIPS_GOTSYM, In.DynSymTab->getNumSymbols()); - addInSec(DT_PLTGOT, In.MipsGot); - if (In.MipsRldMap) { - if (!Config->Pie) - addInSec(DT_MIPS_RLD_MAP, In.MipsRldMap); + addInt(DT_MIPS_GOTSYM, part.dynSymTab->getNumSymbols()); + addInSec(DT_PLTGOT, in.mipsGot); + if (in.mipsRldMap) { + if (!config->pie) + addInSec(DT_MIPS_RLD_MAP, in.mipsRldMap); // Store the offset to the .rld_map section // relative to the address of the tag. - addInSecRelative(DT_MIPS_RLD_MAP_REL, In.MipsRldMap); + addInSecRelative(DT_MIPS_RLD_MAP_REL, in.mipsRldMap); } } + // DT_PPC_GOT indicates to glibc Secure PLT is used. If DT_PPC_GOT is absent, + // glibc assumes the old-style BSS PLT layout which we don't support. + if (config->emachine == EM_PPC) + add(DT_PPC_GOT, [] { return in.got->getVA(); }); + // Glink dynamic tag is required by the V2 abi if the plt section isn't empty. - if (Config->EMachine == EM_PPC64 && !In.Plt->empty()) { + if (config->emachine == EM_PPC64 && in.plt->isNeeded()) { // The Glink tag points to 32 bytes before the first lazy symbol resolution // stub, which starts directly after the header. - Entries.push_back({DT_PPC64_GLINK, [=] { - unsigned Offset = Target->PltHeaderSize - 32; - return In.Plt->getVA(0) + Offset; + entries.push_back({DT_PPC64_GLINK, [=] { + unsigned offset = target->pltHeaderSize - 32; + return in.plt->getVA(0) + offset; }}); } addInt(DT_NULL, 0); - getParent()->Link = this->Link; - this->Size = Entries.size() * this->Entsize; + getParent()->link = this->link; + this->size = entries.size() * this->entsize; } -template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) { - auto *P = reinterpret_cast<Elf_Dyn *>(Buf); +template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *buf) { + auto *p = reinterpret_cast<Elf_Dyn *>(buf); - for (std::pair<int32_t, std::function<uint64_t()>> &KV : Entries) { - P->d_tag = KV.first; - P->d_un.d_val = KV.second(); - ++P; + for (std::pair<int32_t, std::function<uint64_t()>> &kv : entries) { + p->d_tag = kv.first; + p->d_un.d_val = kv.second(); + ++p; } } uint64_t DynamicReloc::getOffset() const { - return InputSec->getVA(OffsetInSec); + return inputSec->getVA(offsetInSec); } int64_t DynamicReloc::computeAddend() const { - if (UseSymVA) - return Sym->getVA(Addend); - if (!OutputSec) - return Addend; + if (useSymVA) + return sym->getVA(addend); + if (!outputSec) + return addend; // See the comment in the DynamicReloc ctor. - return getMipsPageAddr(OutputSec->Addr) + Addend; + return getMipsPageAddr(outputSec->addr) + addend; } -uint32_t DynamicReloc::getSymIndex() const { - if (Sym && !UseSymVA) - return Sym->DynsymIndex; +uint32_t DynamicReloc::getSymIndex(SymbolTableBaseSection *symTab) const { + if (sym && !useSymVA) + return symTab->getSymbolIndex(sym); return 0; } -RelocationBaseSection::RelocationBaseSection(StringRef Name, uint32_t Type, - int32_t DynamicTag, - int32_t SizeDynamicTag) - : SyntheticSection(SHF_ALLOC, Type, Config->Wordsize, Name), - DynamicTag(DynamicTag), SizeDynamicTag(SizeDynamicTag) {} +RelocationBaseSection::RelocationBaseSection(StringRef name, uint32_t type, + int32_t dynamicTag, + int32_t sizeDynamicTag) + : SyntheticSection(SHF_ALLOC, type, config->wordsize, name), + dynamicTag(dynamicTag), sizeDynamicTag(sizeDynamicTag) {} -void RelocationBaseSection::addReloc(RelType DynType, InputSectionBase *IS, - uint64_t OffsetInSec, Symbol *Sym) { - addReloc({DynType, IS, OffsetInSec, false, Sym, 0}); +void RelocationBaseSection::addReloc(RelType dynType, InputSectionBase *isec, + uint64_t offsetInSec, Symbol *sym) { + addReloc({dynType, isec, offsetInSec, false, sym, 0}); } -void RelocationBaseSection::addReloc(RelType DynType, - InputSectionBase *InputSec, - uint64_t OffsetInSec, Symbol *Sym, - int64_t Addend, RelExpr Expr, - RelType Type) { +void RelocationBaseSection::addReloc(RelType dynType, + InputSectionBase *inputSec, + uint64_t offsetInSec, Symbol *sym, + int64_t addend, RelExpr expr, + RelType type) { // Write the addends to the relocated address if required. We skip // it if the written value would be zero. - if (Config->WriteAddends && (Expr != R_ADDEND || Addend != 0)) - InputSec->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym}); - addReloc({DynType, InputSec, OffsetInSec, Expr != R_ADDEND, Sym, Addend}); + if (config->writeAddends && (expr != R_ADDEND || addend != 0)) + inputSec->relocations.push_back({expr, type, offsetInSec, addend, sym}); + addReloc({dynType, inputSec, offsetInSec, expr != R_ADDEND, sym, addend}); } -void RelocationBaseSection::addReloc(const DynamicReloc &Reloc) { - if (Reloc.Type == Target->RelativeRel) - ++NumRelativeRelocs; - Relocs.push_back(Reloc); +void RelocationBaseSection::addReloc(const DynamicReloc &reloc) { + if (reloc.type == target->relativeRel) + ++numRelativeRelocs; + relocs.push_back(reloc); } void RelocationBaseSection::finalizeContents() { + SymbolTableBaseSection *symTab = getPartition().dynSymTab; + // When linking glibc statically, .rel{,a}.plt contains R_*_IRELATIVE // relocations due to IFUNC (e.g. strcpy). sh_link will be set to 0 in that // case. - InputSection *SymTab = Config->Relocatable ? In.SymTab : In.DynSymTab; - if (SymTab && SymTab->getParent()) - getParent()->Link = SymTab->getParent()->SectionIndex; + if (symTab && symTab->getParent()) + getParent()->link = symTab->getParent()->sectionIndex; else - getParent()->Link = 0; + getParent()->link = 0; - if (In.RelaIplt == this || In.RelaPlt == this) - getParent()->Info = In.GotPlt->getParent()->SectionIndex; + if (in.relaPlt == this) + getParent()->info = in.gotPlt->getParent()->sectionIndex; + if (in.relaIplt == this) + getParent()->info = in.igotPlt->getParent()->sectionIndex; } RelrBaseSection::RelrBaseSection() : SyntheticSection(SHF_ALLOC, - Config->UseAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR, - Config->Wordsize, ".relr.dyn") {} + config->useAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR, + config->wordsize, ".relr.dyn") {} template <class ELFT> -static void encodeDynamicReloc(typename ELFT::Rela *P, - const DynamicReloc &Rel) { - if (Config->IsRela) - P->r_addend = Rel.computeAddend(); - P->r_offset = Rel.getOffset(); - P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL); +static void encodeDynamicReloc(SymbolTableBaseSection *symTab, + typename ELFT::Rela *p, + const DynamicReloc &rel) { + if (config->isRela) + p->r_addend = rel.computeAddend(); + p->r_offset = rel.getOffset(); + p->setSymbolAndType(rel.getSymIndex(symTab), rel.type, config->isMips64EL); } template <class ELFT> -RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort) - : RelocationBaseSection(Name, Config->IsRela ? SHT_RELA : SHT_REL, - Config->IsRela ? DT_RELA : DT_REL, - Config->IsRela ? DT_RELASZ : DT_RELSZ), - Sort(Sort) { - this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); +RelocationSection<ELFT>::RelocationSection(StringRef name, bool sort) + : RelocationBaseSection(name, config->isRela ? SHT_RELA : SHT_REL, + config->isRela ? DT_RELA : DT_REL, + config->isRela ? DT_RELASZ : DT_RELSZ), + sort(sort) { + this->entsize = config->isRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); } -static bool compRelocations(const DynamicReloc &A, const DynamicReloc &B) { - bool AIsRel = A.Type == Target->RelativeRel; - bool BIsRel = B.Type == Target->RelativeRel; - if (AIsRel != BIsRel) - return AIsRel; - return A.getSymIndex() < B.getSymIndex(); -} +template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *buf) { + SymbolTableBaseSection *symTab = getPartition().dynSymTab; -template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) { - if (Sort) - std::stable_sort(Relocs.begin(), Relocs.end(), compRelocations); + // Sort by (!IsRelative,SymIndex,r_offset). DT_REL[A]COUNT requires us to + // place R_*_RELATIVE first. SymIndex is to improve locality, while r_offset + // is to make results easier to read. + if (sort) + llvm::stable_sort( + relocs, [&](const DynamicReloc &a, const DynamicReloc &b) { + return std::make_tuple(a.type != target->relativeRel, + a.getSymIndex(symTab), a.getOffset()) < + std::make_tuple(b.type != target->relativeRel, + b.getSymIndex(symTab), b.getOffset()); + }); - for (const DynamicReloc &Rel : Relocs) { - encodeDynamicReloc<ELFT>(reinterpret_cast<Elf_Rela *>(Buf), Rel); - Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); + for (const DynamicReloc &rel : relocs) { + encodeDynamicReloc<ELFT>(symTab, reinterpret_cast<Elf_Rela *>(buf), rel); + buf += config->isRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); } } -template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() { - return this->Entsize * Relocs.size(); -} - template <class ELFT> AndroidPackedRelocationSection<ELFT>::AndroidPackedRelocationSection( - StringRef Name) + StringRef name) : RelocationBaseSection( - Name, Config->IsRela ? SHT_ANDROID_RELA : SHT_ANDROID_REL, - Config->IsRela ? DT_ANDROID_RELA : DT_ANDROID_REL, - Config->IsRela ? DT_ANDROID_RELASZ : DT_ANDROID_RELSZ) { - this->Entsize = 1; + name, config->isRela ? SHT_ANDROID_RELA : SHT_ANDROID_REL, + config->isRela ? DT_ANDROID_RELA : DT_ANDROID_REL, + config->isRela ? DT_ANDROID_RELASZ : DT_ANDROID_RELSZ) { + this->entsize = 1; } template <class ELFT> @@ -1619,32 +1630,32 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() { // RELOCATION_GROUPED_BY_ADDEND_FLAG is not set) the r_addend delta for // this relocation. - size_t OldSize = RelocData.size(); + size_t oldSize = relocData.size(); - RelocData = {'A', 'P', 'S', '2'}; - raw_svector_ostream OS(RelocData); - auto Add = [&](int64_t V) { encodeSLEB128(V, OS); }; + relocData = {'A', 'P', 'S', '2'}; + raw_svector_ostream os(relocData); + auto add = [&](int64_t v) { encodeSLEB128(v, os); }; // The format header includes the number of relocations and the initial // offset (we set this to zero because the first relocation group will // perform the initial adjustment). - Add(Relocs.size()); - Add(0); + add(relocs.size()); + add(0); - std::vector<Elf_Rela> Relatives, NonRelatives; + std::vector<Elf_Rela> relatives, nonRelatives; - for (const DynamicReloc &Rel : Relocs) { - Elf_Rela R; - encodeDynamicReloc<ELFT>(&R, Rel); + for (const DynamicReloc &rel : relocs) { + Elf_Rela r; + encodeDynamicReloc<ELFT>(getPartition().dynSymTab, &r, rel); - if (R.getType(Config->IsMips64EL) == Target->RelativeRel) - Relatives.push_back(R); + if (r.getType(config->isMips64EL) == target->relativeRel) + relatives.push_back(r); else - NonRelatives.push_back(R); + nonRelatives.push_back(r); } - llvm::sort(Relatives, [](const Elf_Rel &A, const Elf_Rel &B) { - return A.r_offset < B.r_offset; + llvm::sort(relatives, [](const Elf_Rel &a, const Elf_Rel &b) { + return a.r_offset < b.r_offset; }); // Try to find groups of relative relocations which are spaced one word @@ -1653,108 +1664,108 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() { // encoding, but each group will cost 7 bytes in addition to the offset from // the previous group, so it is only profitable to do this for groups of // size 8 or larger. - std::vector<Elf_Rela> UngroupedRelatives; - std::vector<std::vector<Elf_Rela>> RelativeGroups; - for (auto I = Relatives.begin(), E = Relatives.end(); I != E;) { - std::vector<Elf_Rela> Group; + std::vector<Elf_Rela> ungroupedRelatives; + std::vector<std::vector<Elf_Rela>> relativeGroups; + for (auto i = relatives.begin(), e = relatives.end(); i != e;) { + std::vector<Elf_Rela> group; do { - Group.push_back(*I++); - } while (I != E && (I - 1)->r_offset + Config->Wordsize == I->r_offset); + group.push_back(*i++); + } while (i != e && (i - 1)->r_offset + config->wordsize == i->r_offset); - if (Group.size() < 8) - UngroupedRelatives.insert(UngroupedRelatives.end(), Group.begin(), - Group.end()); + if (group.size() < 8) + ungroupedRelatives.insert(ungroupedRelatives.end(), group.begin(), + group.end()); else - RelativeGroups.emplace_back(std::move(Group)); + relativeGroups.emplace_back(std::move(group)); } - unsigned HasAddendIfRela = - Config->IsRela ? RELOCATION_GROUP_HAS_ADDEND_FLAG : 0; + unsigned hasAddendIfRela = + config->isRela ? RELOCATION_GROUP_HAS_ADDEND_FLAG : 0; - uint64_t Offset = 0; - uint64_t Addend = 0; + uint64_t offset = 0; + uint64_t addend = 0; // Emit the run-length encoding for the groups of adjacent relative // relocations. Each group is represented using two groups in the packed // format. The first is used to set the current offset to the start of the // group (and also encodes the first relocation), and the second encodes the // remaining relocations. - for (std::vector<Elf_Rela> &G : RelativeGroups) { + for (std::vector<Elf_Rela> &g : relativeGroups) { // The first relocation in the group. - Add(1); - Add(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG | - RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela); - Add(G[0].r_offset - Offset); - Add(Target->RelativeRel); - if (Config->IsRela) { - Add(G[0].r_addend - Addend); - Addend = G[0].r_addend; + add(1); + add(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG | + RELOCATION_GROUPED_BY_INFO_FLAG | hasAddendIfRela); + add(g[0].r_offset - offset); + add(target->relativeRel); + if (config->isRela) { + add(g[0].r_addend - addend); + addend = g[0].r_addend; } // The remaining relocations. - Add(G.size() - 1); - Add(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG | - RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela); - Add(Config->Wordsize); - Add(Target->RelativeRel); - if (Config->IsRela) { - for (auto I = G.begin() + 1, E = G.end(); I != E; ++I) { - Add(I->r_addend - Addend); - Addend = I->r_addend; + add(g.size() - 1); + add(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG | + RELOCATION_GROUPED_BY_INFO_FLAG | hasAddendIfRela); + add(config->wordsize); + add(target->relativeRel); + if (config->isRela) { + for (auto i = g.begin() + 1, e = g.end(); i != e; ++i) { + add(i->r_addend - addend); + addend = i->r_addend; } } - Offset = G.back().r_offset; + offset = g.back().r_offset; } // Now the ungrouped relatives. - if (!UngroupedRelatives.empty()) { - Add(UngroupedRelatives.size()); - Add(RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela); - Add(Target->RelativeRel); - for (Elf_Rela &R : UngroupedRelatives) { - Add(R.r_offset - Offset); - Offset = R.r_offset; - if (Config->IsRela) { - Add(R.r_addend - Addend); - Addend = R.r_addend; + if (!ungroupedRelatives.empty()) { + add(ungroupedRelatives.size()); + add(RELOCATION_GROUPED_BY_INFO_FLAG | hasAddendIfRela); + add(target->relativeRel); + for (Elf_Rela &r : ungroupedRelatives) { + add(r.r_offset - offset); + offset = r.r_offset; + if (config->isRela) { + add(r.r_addend - addend); + addend = r.r_addend; } } } // Finally the non-relative relocations. - llvm::sort(NonRelatives, [](const Elf_Rela &A, const Elf_Rela &B) { - return A.r_offset < B.r_offset; + llvm::sort(nonRelatives, [](const Elf_Rela &a, const Elf_Rela &b) { + return a.r_offset < b.r_offset; }); - if (!NonRelatives.empty()) { - Add(NonRelatives.size()); - Add(HasAddendIfRela); - for (Elf_Rela &R : NonRelatives) { - Add(R.r_offset - Offset); - Offset = R.r_offset; - Add(R.r_info); - if (Config->IsRela) { - Add(R.r_addend - Addend); - Addend = R.r_addend; + if (!nonRelatives.empty()) { + add(nonRelatives.size()); + add(hasAddendIfRela); + for (Elf_Rela &r : nonRelatives) { + add(r.r_offset - offset); + offset = r.r_offset; + add(r.r_info); + if (config->isRela) { + add(r.r_addend - addend); + addend = r.r_addend; } } } // Don't allow the section to shrink; otherwise the size of the section can // oscillate infinitely. - if (RelocData.size() < OldSize) - RelocData.append(OldSize - RelocData.size(), 0); + if (relocData.size() < oldSize) + relocData.append(oldSize - relocData.size(), 0); // Returns whether the section size changed. We need to keep recomputing both // section layout and the contents of this section until the size converges // because changing this section's size can affect section layout, which in // turn can affect the sizes of the LEB-encoded integers stored in this // section. - return RelocData.size() != OldSize; + return relocData.size() != oldSize; } template <class ELFT> RelrSection<ELFT>::RelrSection() { - this->Entsize = Config->Wordsize; + this->entsize = config->wordsize; } template <class ELFT> bool RelrSection<ELFT>::updateAllocSize() { @@ -1788,90 +1799,90 @@ template <class ELFT> bool RelrSection<ELFT>::updateAllocSize() { // even means address, odd means bitmap. // 2. Just a simple list of addresses is a valid encoding. - size_t OldSize = RelrRelocs.size(); - RelrRelocs.clear(); + size_t oldSize = relrRelocs.size(); + relrRelocs.clear(); // Same as Config->Wordsize but faster because this is a compile-time // constant. - const size_t Wordsize = sizeof(typename ELFT::uint); + const size_t wordsize = sizeof(typename ELFT::uint); // Number of bits to use for the relocation offsets bitmap. // Must be either 63 or 31. - const size_t NBits = Wordsize * 8 - 1; + const size_t nBits = wordsize * 8 - 1; // Get offsets for all relative relocations and sort them. - std::vector<uint64_t> Offsets; - for (const RelativeReloc &Rel : Relocs) - Offsets.push_back(Rel.getOffset()); - llvm::sort(Offsets.begin(), Offsets.end()); + std::vector<uint64_t> offsets; + for (const RelativeReloc &rel : relocs) + offsets.push_back(rel.getOffset()); + llvm::sort(offsets); // For each leading relocation, find following ones that can be folded // as a bitmap and fold them. - for (size_t I = 0, E = Offsets.size(); I < E;) { + for (size_t i = 0, e = offsets.size(); i < e;) { // Add a leading relocation. - RelrRelocs.push_back(Elf_Relr(Offsets[I])); - uint64_t Base = Offsets[I] + Wordsize; - ++I; + relrRelocs.push_back(Elf_Relr(offsets[i])); + uint64_t base = offsets[i] + wordsize; + ++i; // Find foldable relocations to construct bitmaps. - while (I < E) { - uint64_t Bitmap = 0; + while (i < e) { + uint64_t bitmap = 0; - while (I < E) { - uint64_t Delta = Offsets[I] - Base; + while (i < e) { + uint64_t delta = offsets[i] - base; // If it is too far, it cannot be folded. - if (Delta >= NBits * Wordsize) + if (delta >= nBits * wordsize) break; // If it is not a multiple of wordsize away, it cannot be folded. - if (Delta % Wordsize) + if (delta % wordsize) break; // Fold it. - Bitmap |= 1ULL << (Delta / Wordsize); - ++I; + bitmap |= 1ULL << (delta / wordsize); + ++i; } - if (!Bitmap) + if (!bitmap) break; - RelrRelocs.push_back(Elf_Relr((Bitmap << 1) | 1)); - Base += NBits * Wordsize; + relrRelocs.push_back(Elf_Relr((bitmap << 1) | 1)); + base += nBits * wordsize; } } - return RelrRelocs.size() != OldSize; + return relrRelocs.size() != oldSize; } -SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec) - : SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0, - StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB, - Config->Wordsize, - StrTabSec.isDynamic() ? ".dynsym" : ".symtab"), - StrTabSec(StrTabSec) {} +SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &strTabSec) + : SyntheticSection(strTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0, + strTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB, + config->wordsize, + strTabSec.isDynamic() ? ".dynsym" : ".symtab"), + strTabSec(strTabSec) {} // Orders symbols according to their positions in the GOT, // in compliance with MIPS ABI rules. // 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 SymbolTableEntry &L, - const SymbolTableEntry &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 beginning of a dynsym in arbitrary order. - if (L.Sym->isInGot() && R.Sym->isInGot()) - return L.Sym->GotIndex < R.Sym->GotIndex; - if (!L.Sym->isInGot() && !R.Sym->isInGot()) + if (l.sym->isInGot() && r.sym->isInGot()) + return l.sym->gotIndex < r.sym->gotIndex; + if (!l.sym->isInGot() && !r.sym->isInGot()) return false; - return !L.Sym->isInGot(); + return !l.sym->isInGot(); } void SymbolTableBaseSection::finalizeContents() { - if (OutputSection *Sec = StrTabSec.getParent()) - getParent()->Link = Sec->SectionIndex; + if (OutputSection *sec = strTabSec.getParent()) + getParent()->link = sec->sectionIndex; - if (this->Type != SHT_DYNSYM) { + if (this->type != SHT_DYNSYM) { sortSymTabSymbols(); return; } @@ -1881,18 +1892,22 @@ void SymbolTableBaseSection::finalizeContents() { // 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. - getParent()->Info = 1; + getParent()->info = 1; - if (In.GnuHashTab) { + if (getPartition().gnuHashTab) { // NB: It also sorts Symbols to meet the GNU hash table requirements. - In.GnuHashTab->addSymbols(Symbols); - } else if (Config->EMachine == EM_MIPS) { - std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols); + getPartition().gnuHashTab->addSymbols(symbols); + } else if (config->emachine == EM_MIPS) { + llvm::stable_sort(symbols, sortMipsSymbols); } - size_t I = 0; - for (const SymbolTableEntry &S : Symbols) - S.Sym->DynsymIndex = ++I; + // Only the main partition's dynsym indexes are stored in the symbols + // themselves. All other partitions use a lookup table. + if (this == mainPart->dynSymTab) { + size_t i = 0; + for (const SymbolTableEntry &s : symbols) + s.sym->dynsymIndex = ++i; + } } // The ELF spec requires that all local symbols precede global symbols, so we @@ -1904,193 +1919,210 @@ void SymbolTableBaseSection::finalizeContents() { // coming from. void SymbolTableBaseSection::sortSymTabSymbols() { // Move all local symbols before global symbols. - auto E = std::stable_partition( - Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) { - return S.Sym->isLocal() || S.Sym->computeBinding() == STB_LOCAL; + auto e = std::stable_partition( + symbols.begin(), symbols.end(), [](const SymbolTableEntry &s) { + return s.sym->isLocal() || s.sym->computeBinding() == STB_LOCAL; }); - size_t NumLocals = E - Symbols.begin(); - getParent()->Info = NumLocals + 1; + size_t numLocals = e - symbols.begin(); + getParent()->info = numLocals + 1; // We want to group the local symbols by file. For that we rebuild the local // part of the symbols vector. We do not need to care about the STT_FILE // symbols, they are already naturally placed first in each group. That // happens because STT_FILE is always the first symbol in the object and hence // precede all other local symbols we add for a file. - MapVector<InputFile *, std::vector<SymbolTableEntry>> Arr; - for (const SymbolTableEntry &S : llvm::make_range(Symbols.begin(), E)) - Arr[S.Sym->File].push_back(S); + MapVector<InputFile *, std::vector<SymbolTableEntry>> arr; + for (const SymbolTableEntry &s : llvm::make_range(symbols.begin(), e)) + arr[s.sym->file].push_back(s); - auto I = Symbols.begin(); - for (std::pair<InputFile *, std::vector<SymbolTableEntry>> &P : Arr) - for (SymbolTableEntry &Entry : P.second) - *I++ = Entry; + auto i = symbols.begin(); + for (std::pair<InputFile *, std::vector<SymbolTableEntry>> &p : arr) + for (SymbolTableEntry &entry : p.second) + *i++ = entry; } -void SymbolTableBaseSection::addSymbol(Symbol *B) { +void SymbolTableBaseSection::addSymbol(Symbol *b) { // Adding a local symbol to a .dynsym is a bug. - assert(this->Type != SHT_DYNSYM || !B->isLocal()); + assert(this->type != SHT_DYNSYM || !b->isLocal()); - bool HashIt = B->isLocal(); - Symbols.push_back({B, StrTabSec.addString(B->getName(), HashIt)}); + bool hashIt = b->isLocal(); + symbols.push_back({b, strTabSec.addString(b->getName(), hashIt)}); } -size_t SymbolTableBaseSection::getSymbolIndex(Symbol *Sym) { - // Initializes symbol lookup tables lazily. This is used only - // for -r or -emit-relocs. - llvm::call_once(OnceFlag, [&] { - SymbolIndexMap.reserve(Symbols.size()); - size_t I = 0; - for (const SymbolTableEntry &E : Symbols) { - if (E.Sym->Type == STT_SECTION) - SectionIndexMap[E.Sym->getOutputSection()] = ++I; +size_t SymbolTableBaseSection::getSymbolIndex(Symbol *sym) { + if (this == mainPart->dynSymTab) + return sym->dynsymIndex; + + // Initializes symbol lookup tables lazily. This is used only for -r, + // -emit-relocs and dynsyms in partitions other than the main one. + llvm::call_once(onceFlag, [&] { + symbolIndexMap.reserve(symbols.size()); + size_t i = 0; + for (const SymbolTableEntry &e : symbols) { + if (e.sym->type == STT_SECTION) + sectionIndexMap[e.sym->getOutputSection()] = ++i; else - SymbolIndexMap[E.Sym] = ++I; + symbolIndexMap[e.sym] = ++i; } }); // Section symbols are mapped based on their output sections // to maintain their semantics. - if (Sym->Type == STT_SECTION) - return SectionIndexMap.lookup(Sym->getOutputSection()); - return SymbolIndexMap.lookup(Sym); + if (sym->type == STT_SECTION) + return sectionIndexMap.lookup(sym->getOutputSection()); + return symbolIndexMap.lookup(sym); } template <class ELFT> -SymbolTableSection<ELFT>::SymbolTableSection(StringTableSection &StrTabSec) - : SymbolTableBaseSection(StrTabSec) { - this->Entsize = sizeof(Elf_Sym); +SymbolTableSection<ELFT>::SymbolTableSection(StringTableSection &strTabSec) + : SymbolTableBaseSection(strTabSec) { + this->entsize = sizeof(Elf_Sym); } -static BssSection *getCommonSec(Symbol *Sym) { - if (!Config->DefineCommon) - if (auto *D = dyn_cast<Defined>(Sym)) - return dyn_cast_or_null<BssSection>(D->Section); +static BssSection *getCommonSec(Symbol *sym) { + if (!config->defineCommon) + if (auto *d = dyn_cast<Defined>(sym)) + return dyn_cast_or_null<BssSection>(d->section); return nullptr; } -static uint32_t getSymSectionIndex(Symbol *Sym) { - if (getCommonSec(Sym)) +static uint32_t getSymSectionIndex(Symbol *sym) { + if (getCommonSec(sym)) return SHN_COMMON; - if (!isa<Defined>(Sym) || Sym->NeedsPltAddr) + if (!isa<Defined>(sym) || sym->needsPltAddr) return SHN_UNDEF; - if (const OutputSection *OS = Sym->getOutputSection()) - return OS->SectionIndex >= SHN_LORESERVE ? (uint32_t)SHN_XINDEX - : OS->SectionIndex; + if (const OutputSection *os = sym->getOutputSection()) + return os->sectionIndex >= SHN_LORESERVE ? (uint32_t)SHN_XINDEX + : os->sectionIndex; return SHN_ABS; } // Write the internal symbol table contents to the output symbol table. -template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) { +template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *buf) { // The first entry is a null entry as per the ELF spec. - memset(Buf, 0, sizeof(Elf_Sym)); - Buf += sizeof(Elf_Sym); + memset(buf, 0, sizeof(Elf_Sym)); + buf += sizeof(Elf_Sym); - auto *ESym = reinterpret_cast<Elf_Sym *>(Buf); + auto *eSym = reinterpret_cast<Elf_Sym *>(buf); - for (SymbolTableEntry &Ent : Symbols) { - Symbol *Sym = Ent.Sym; + for (SymbolTableEntry &ent : symbols) { + Symbol *sym = ent.sym; + bool isDefinedHere = type == SHT_SYMTAB || sym->partition == partition; // Set st_info and st_other. - ESym->st_other = 0; - if (Sym->isLocal()) { - ESym->setBindingAndType(STB_LOCAL, Sym->Type); + eSym->st_other = 0; + if (sym->isLocal()) { + eSym->setBindingAndType(STB_LOCAL, sym->type); } else { - ESym->setBindingAndType(Sym->computeBinding(), Sym->Type); - ESym->setVisibility(Sym->Visibility); + eSym->setBindingAndType(sym->computeBinding(), sym->type); + eSym->setVisibility(sym->visibility); } - ESym->st_name = Ent.StrTabOffset; - ESym->st_shndx = getSymSectionIndex(Ent.Sym); + // The 3 most significant bits of st_other are used by OpenPOWER ABI. + // See getPPC64GlobalEntryToLocalEntryOffset() for more details. + if (config->emachine == EM_PPC64) + eSym->st_other |= sym->stOther & 0xe0; + + eSym->st_name = ent.strTabOffset; + if (isDefinedHere) + eSym->st_shndx = getSymSectionIndex(ent.sym); + else + eSym->st_shndx = 0; // Copy symbol size if it is a defined symbol. st_size is not significant // for undefined symbols, so whether copying it or not is up to us if that's // the case. We'll leave it as zero because by not setting a value, we can // get the exact same outputs for two sets of input files that differ only // in undefined symbol size in DSOs. - if (ESym->st_shndx == SHN_UNDEF) - ESym->st_size = 0; + if (eSym->st_shndx == SHN_UNDEF || !isDefinedHere) + eSym->st_size = 0; else - ESym->st_size = Sym->getSize(); + eSym->st_size = sym->getSize(); // 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 (BssSection *CommonSec = getCommonSec(Ent.Sym)) - ESym->st_value = CommonSec->Alignment; + if (BssSection *commonSec = getCommonSec(ent.sym)) + eSym->st_value = commonSec->alignment; + else if (isDefinedHere) + eSym->st_value = sym->getVA(); else - ESym->st_value = Sym->getVA(); + eSym->st_value = 0; - ++ESym; + ++eSym; } // 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); + if (config->emachine == EM_MIPS) { + auto *eSym = reinterpret_cast<Elf_Sym *>(buf); - for (SymbolTableEntry &Ent : Symbols) { - Symbol *Sym = Ent.Sym; - if (Sym->isInPlt() && Sym->NeedsPltAddr) - ESym->st_other |= STO_MIPS_PLT; + for (SymbolTableEntry &ent : symbols) { + Symbol *sym = ent.sym; + if (sym->isInPlt() && sym->needsPltAddr) + eSym->st_other |= STO_MIPS_PLT; if (isMicroMips()) { - // Set STO_MIPS_MICROMIPS flag and less-significant bit for - // a defined microMIPS symbol and symbol should point to its - // PLT entry (in case of microMIPS, PLT entries always contain - // microMIPS code). - if (Sym->isDefined() && - ((Sym->StOther & STO_MIPS_MICROMIPS) || Sym->NeedsPltAddr)) { - if (StrTabSec.isDynamic()) - ESym->st_value |= 1; - ESym->st_other |= STO_MIPS_MICROMIPS; + // We already set the less-significant bit for symbols + // marked by the `STO_MIPS_MICROMIPS` flag and for microMIPS PLT + // records. That allows us to distinguish such symbols in + // the `MIPS<ELFT>::relocateOne()` routine. Now we should + // clear that bit for non-dynamic symbol table, so tools + // like `objdump` will be able to deal with a correct + // symbol position. + if (sym->isDefined() && + ((sym->stOther & STO_MIPS_MICROMIPS) || sym->needsPltAddr)) { + if (!strTabSec.isDynamic()) + eSym->st_value &= ~1; + eSym->st_other |= STO_MIPS_MICROMIPS; } } - if (Config->Relocatable) - if (auto *D = dyn_cast<Defined>(Sym)) - if (isMipsPIC<ELFT>(D)) - ESym->st_other |= STO_MIPS_PIC; - ++ESym; + if (config->relocatable) + if (auto *d = dyn_cast<Defined>(sym)) + if (isMipsPIC<ELFT>(d)) + eSym->st_other |= STO_MIPS_PIC; + ++eSym; } } } SymtabShndxSection::SymtabShndxSection() - : SyntheticSection(0, SHT_SYMTAB_SHNDX, 4, ".symtab_shndxr") { - this->Entsize = 4; + : SyntheticSection(0, SHT_SYMTAB_SHNDX, 4, ".symtab_shndx") { + this->entsize = 4; } -void SymtabShndxSection::writeTo(uint8_t *Buf) { +void SymtabShndxSection::writeTo(uint8_t *buf) { // We write an array of 32 bit values, where each value has 1:1 association // with an entry in .symtab. If the corresponding entry contains SHN_XINDEX, // we need to write actual index, otherwise, we must write SHN_UNDEF(0). - Buf += 4; // Ignore .symtab[0] entry. - for (const SymbolTableEntry &Entry : In.SymTab->getSymbols()) { - if (getSymSectionIndex(Entry.Sym) == SHN_XINDEX) - write32(Buf, Entry.Sym->getOutputSection()->SectionIndex); - Buf += 4; + buf += 4; // Ignore .symtab[0] entry. + for (const SymbolTableEntry &entry : in.symTab->getSymbols()) { + if (getSymSectionIndex(entry.sym) == SHN_XINDEX) + write32(buf, entry.sym->getOutputSection()->sectionIndex); + buf += 4; } } -bool SymtabShndxSection::empty() const { +bool SymtabShndxSection::isNeeded() const { // SHT_SYMTAB can hold symbols with section indices values up to // SHN_LORESERVE. If we need more, we want to use extension SHT_SYMTAB_SHNDX // section. Problem is that we reveal the final section indices a bit too // late, and we do not know them here. For simplicity, we just always create - // a .symtab_shndxr section when the amount of output sections is huge. - size_t Size = 0; - for (BaseCommand *Base : Script->SectionCommands) - if (isa<OutputSection>(Base)) - ++Size; - return Size < SHN_LORESERVE; + // a .symtab_shndx section when the amount of output sections is huge. + size_t size = 0; + for (BaseCommand *base : script->sectionCommands) + if (isa<OutputSection>(base)) + ++size; + return size >= SHN_LORESERVE; } void SymtabShndxSection::finalizeContents() { - getParent()->Link = In.SymTab->getParent()->SectionIndex; + getParent()->link = in.symTab->getParent()->sectionIndex; } size_t SymtabShndxSection::getSize() const { - return In.SymTab->getNumSymbols() * 4; + return in.symTab->getNumSymbols() * 4; } // .hash and .gnu.hash sections contain on-disk hash tables that map @@ -2125,45 +2157,45 @@ size_t SymtabShndxSection::getSize() const { // about .gnu.hash, you want to specify -hash-style=gnu. Otherwise, a // safe bet is to specify -hash-style=both for backward compatibilty. GnuHashTableSection::GnuHashTableSection() - : SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, Config->Wordsize, ".gnu.hash") { + : SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, config->wordsize, ".gnu.hash") { } void GnuHashTableSection::finalizeContents() { - if (OutputSection *Sec = In.DynSymTab->getParent()) - getParent()->Link = Sec->SectionIndex; + if (OutputSection *sec = getPartition().dynSymTab->getParent()) + getParent()->link = sec->sectionIndex; // Computes bloom filter size in word size. We want to allocate 12 // bits for each symbol. It must be a power of two. - if (Symbols.empty()) { - MaskWords = 1; + if (symbols.empty()) { + maskWords = 1; } else { - uint64_t NumBits = Symbols.size() * 12; - MaskWords = NextPowerOf2(NumBits / (Config->Wordsize * 8)); + uint64_t numBits = symbols.size() * 12; + maskWords = NextPowerOf2(numBits / (config->wordsize * 8)); } - Size = 16; // Header - Size += Config->Wordsize * MaskWords; // Bloom filter - Size += NBuckets * 4; // Hash buckets - Size += Symbols.size() * 4; // Hash values + size = 16; // Header + size += config->wordsize * maskWords; // Bloom filter + size += nBuckets * 4; // Hash buckets + size += symbols.size() * 4; // Hash values } -void GnuHashTableSection::writeTo(uint8_t *Buf) { +void GnuHashTableSection::writeTo(uint8_t *buf) { // The output buffer is not guaranteed to be zero-cleared because we pre- // fill executable sections with trap instructions. This is a precaution // for that case, which happens only when -no-rosegment is given. - memset(Buf, 0, Size); + memset(buf, 0, size); // Write a header. - write32(Buf, NBuckets); - write32(Buf + 4, In.DynSymTab->getNumSymbols() - Symbols.size()); - write32(Buf + 8, MaskWords); - write32(Buf + 12, Shift2); - Buf += 16; + write32(buf, nBuckets); + write32(buf + 4, getPartition().dynSymTab->getNumSymbols() - symbols.size()); + write32(buf + 8, maskWords); + write32(buf + 12, Shift2); + buf += 16; // Write a bloom filter and a hash table. - writeBloomFilter(Buf); - Buf += Config->Wordsize * MaskWords; - writeHashTable(Buf); + writeBloomFilter(buf); + buf += config->wordsize * maskWords; + writeHashTable(buf); } // This function writes a 2-bit bloom filter. This bloom filter alone @@ -2173,57 +2205,58 @@ void GnuHashTableSection::writeTo(uint8_t *Buf) { // // [1] Ulrich Drepper (2011), "How To Write Shared Libraries" (Ver. 4.1.2), // p.9, https://www.akkadia.org/drepper/dsohowto.pdf -void GnuHashTableSection::writeBloomFilter(uint8_t *Buf) { - unsigned C = Config->Is64 ? 64 : 32; - for (const Entry &Sym : Symbols) { +void GnuHashTableSection::writeBloomFilter(uint8_t *buf) { + unsigned c = config->is64 ? 64 : 32; + for (const Entry &sym : symbols) { // When C = 64, we choose a word with bits [6:...] and set 1 to two bits in // the word using bits [0:5] and [26:31]. - 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 >> Shift2) % C); - writeUint(Buf + I * Config->Wordsize, Val); + 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 >> Shift2) % c); + writeUint(buf + i * config->wordsize, val); } } -void GnuHashTableSection::writeHashTable(uint8_t *Buf) { - uint32_t *Buckets = reinterpret_cast<uint32_t *>(Buf); - uint32_t OldBucket = -1; - uint32_t *Values = Buckets + NBuckets; - for (auto I = Symbols.begin(), E = Symbols.end(); I != E; ++I) { +void GnuHashTableSection::writeHashTable(uint8_t *buf) { + uint32_t *buckets = reinterpret_cast<uint32_t *>(buf); + uint32_t oldBucket = -1; + uint32_t *values = buckets + nBuckets; + for (auto i = symbols.begin(), e = symbols.end(); i != e; ++i) { // Write a hash value. 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 Hash = I->Hash; - bool IsLastInChain = (I + 1) == E || I->BucketIdx != (I + 1)->BucketIdx; - Hash = IsLastInChain ? Hash | 1 : Hash & ~1; - write32(Values++, Hash); + uint32_t hash = i->hash; + bool isLastInChain = (i + 1) == e || i->bucketIdx != (i + 1)->bucketIdx; + hash = isLastInChain ? hash | 1 : hash & ~1; + write32(values++, hash); - if (I->BucketIdx == OldBucket) + if (i->bucketIdx == oldBucket) continue; // Write a hash bucket. Hash buckets contain indices in the following hash // value table. - write32(Buckets + I->BucketIdx, I->Sym->DynsymIndex); - OldBucket = I->BucketIdx; + write32(buckets + i->bucketIdx, + getPartition().dynSymTab->getSymbolIndex(i->sym)); + oldBucket = i->bucketIdx; } } -static uint32_t hashGnu(StringRef Name) { - uint32_t H = 5381; - for (uint8_t C : Name) - H = (H << 5) + H + C; - return H; +static uint32_t hashGnu(StringRef name) { + uint32_t h = 5381; + for (uint8_t c : name) + h = (h << 5) + h + c; + return h; } // 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. -void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) { +void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &v) { // 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.Sym->isDefined(); + std::vector<SymbolTableEntry>::iterator mid = + std::stable_partition(v.begin(), v.end(), [&](const SymbolTableEntry &s) { + return !s.sym->isDefined() || s.sym->partition != partition; }); // We chose load factor 4 for the on-disk hash table. For each hash @@ -2235,138 +2268,143 @@ void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) { // Android loader as of 2018 doesn't like a .gnu.hash containing such // table. If that's the case, we create a hash table with one unused // dummy slot. - NBuckets = std::max<size_t>((V.end() - Mid) / 4, 1); + nBuckets = std::max<size_t>((v.end() - mid) / 4, 1); - if (Mid == V.end()) + if (mid == v.end()) return; - for (SymbolTableEntry &Ent : llvm::make_range(Mid, V.end())) { - Symbol *B = Ent.Sym; - uint32_t Hash = hashGnu(B->getName()); - uint32_t BucketIdx = Hash % NBuckets; - Symbols.push_back({B, Ent.StrTabOffset, Hash, BucketIdx}); + for (SymbolTableEntry &ent : llvm::make_range(mid, v.end())) { + Symbol *b = ent.sym; + uint32_t hash = hashGnu(b->getName()); + uint32_t bucketIdx = hash % nBuckets; + symbols.push_back({b, ent.strTabOffset, hash, bucketIdx}); } - std::stable_sort( - Symbols.begin(), Symbols.end(), - [](const Entry &L, const Entry &R) { return L.BucketIdx < R.BucketIdx; }); + llvm::stable_sort(symbols, [](const Entry &l, const Entry &r) { + return l.bucketIdx < r.bucketIdx; + }); - V.erase(Mid, V.end()); - for (const Entry &Ent : Symbols) - V.push_back({Ent.Sym, Ent.StrTabOffset}); + v.erase(mid, v.end()); + for (const Entry &ent : symbols) + v.push_back({ent.sym, ent.strTabOffset}); } HashTableSection::HashTableSection() : SyntheticSection(SHF_ALLOC, SHT_HASH, 4, ".hash") { - this->Entsize = 4; + this->entsize = 4; } void HashTableSection::finalizeContents() { - if (OutputSection *Sec = In.DynSymTab->getParent()) - getParent()->Link = Sec->SectionIndex; + SymbolTableBaseSection *symTab = getPartition().dynSymTab; - unsigned NumEntries = 2; // nbucket and nchain. - NumEntries += In.DynSymTab->getNumSymbols(); // The chain entries. + if (OutputSection *sec = symTab->getParent()) + getParent()->link = sec->sectionIndex; + + unsigned numEntries = 2; // nbucket and nchain. + numEntries += symTab->getNumSymbols(); // The chain entries. // Create as many buckets as there are symbols. - NumEntries += In.DynSymTab->getNumSymbols(); - this->Size = NumEntries * 4; + numEntries += symTab->getNumSymbols(); + this->size = numEntries * 4; } -void HashTableSection::writeTo(uint8_t *Buf) { +void HashTableSection::writeTo(uint8_t *buf) { + SymbolTableBaseSection *symTab = getPartition().dynSymTab; + // See comment in GnuHashTableSection::writeTo. - memset(Buf, 0, Size); + memset(buf, 0, size); - unsigned NumSymbols = In.DynSymTab->getNumSymbols(); + unsigned numSymbols = symTab->getNumSymbols(); - uint32_t *P = reinterpret_cast<uint32_t *>(Buf); - write32(P++, NumSymbols); // nbucket - write32(P++, NumSymbols); // nchain + uint32_t *p = reinterpret_cast<uint32_t *>(buf); + write32(p++, numSymbols); // nbucket + write32(p++, numSymbols); // nchain - uint32_t *Buckets = P; - uint32_t *Chains = P + NumSymbols; + uint32_t *buckets = p; + uint32_t *chains = p + numSymbols; - for (const SymbolTableEntry &S : In.DynSymTab->getSymbols()) { - Symbol *Sym = S.Sym; - StringRef Name = Sym->getName(); - unsigned I = Sym->DynsymIndex; - uint32_t Hash = hashSysV(Name) % NumSymbols; - Chains[I] = Buckets[Hash]; - write32(Buckets + Hash, I); + for (const SymbolTableEntry &s : symTab->getSymbols()) { + Symbol *sym = s.sym; + StringRef name = sym->getName(); + unsigned i = sym->dynsymIndex; + uint32_t hash = hashSysV(name) % numSymbols; + chains[i] = buckets[hash]; + write32(buckets + hash, i); } } // On PowerPC64 the lazy symbol resolvers go into the `global linkage table` // in the .glink section, rather then the typical .plt section. -PltSection::PltSection(bool IsIplt) - : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, - Config->EMachine == EM_PPC64 ? ".glink" : ".plt"), - HeaderSize(!IsIplt || Config->ZRetpolineplt ? Target->PltHeaderSize : 0), - IsIplt(IsIplt) { +PltSection::PltSection(bool isIplt) + : SyntheticSection( + SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, + (config->emachine == EM_PPC || config->emachine == EM_PPC64) + ? ".glink" + : ".plt"), + headerSize(!isIplt || config->zRetpolineplt ? target->pltHeaderSize : 0), + isIplt(isIplt) { // The PLT needs to be writable on SPARC as the dynamic linker will // modify the instructions in the PLT entries. - if (Config->EMachine == EM_SPARCV9) - this->Flags |= SHF_WRITE; + if (config->emachine == EM_SPARCV9) + this->flags |= SHF_WRITE; } -void PltSection::writeTo(uint8_t *Buf) { +void PltSection::writeTo(uint8_t *buf) { + if (config->emachine == EM_PPC) { + writePPC32GlinkSection(buf, entries.size()); + return; + } + // At beginning of PLT or retpoline 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(); + if (headerSize) + target->writePltHeader(buf); + size_t off = headerSize; + + RelocationBaseSection *relSec = isIplt ? in.relaIplt : in.relaPlt; - for (auto &I : Entries) { - const Symbol *B = I.first; - 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; + // The IPlt is immediately after the Plt, account for this in relOff + size_t pltOff = isIplt ? in.plt->getSize() : 0; + + for (size_t i = 0, e = entries.size(); i != e; ++i) { + const Symbol *b = entries[i]; + unsigned relOff = relSec->entsize * i + 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::addEntry(Symbol &Sym) { - Sym.PltIndex = Entries.size(); - RelocationBaseSection *PltRelocSection = In.RelaPlt; - if (IsIplt) { - PltRelocSection = In.RelaIplt; - Sym.IsInIplt = true; - } - unsigned RelOff = - static_cast<RelocationSection<ELFT> *>(PltRelocSection)->getRelocOffset(); - Entries.push_back(std::make_pair(&Sym, RelOff)); +template <class ELFT> void PltSection::addEntry(Symbol &sym) { + sym.pltIndex = entries.size(); + entries.push_back(&sym); } size_t PltSection::getSize() const { - return HeaderSize + Entries.size() * Target->PltEntrySize; + return headerSize + entries.size() * target->pltEntrySize; } // 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 (!IsIplt) - Target->addPltHeaderSymbols(*this); - size_t Off = HeaderSize; - for (size_t I = 0; I < Entries.size(); ++I) { - Target->addPltSymbols(*this, Off); - Off += Target->PltEntrySize; - } -} + if (!isIplt) + target->addPltHeaderSymbols(*this); -unsigned PltSection::getPltRelocOff() const { - return IsIplt ? In.Plt->getSize() : 0; + size_t off = headerSize; + for (size_t i = 0; i < entries.size(); ++i) { + target->addPltSymbols(*this, off); + off += target->pltEntrySize; + } } // The string hash function for .gdb_index. -static uint32_t computeGdbHash(StringRef S) { - uint32_t H = 0; - for (uint8_t C : S) - H = H * 67 + toLower(C) - 113; - return H; +static uint32_t computeGdbHash(StringRef s) { + uint32_t h = 0; + for (uint8_t c : s) + h = h * 67 + toLower(c) - 113; + return h; } GdbIndexSection::GdbIndexSection() @@ -2375,367 +2413,384 @@ GdbIndexSection::GdbIndexSection() // Returns the desired size of an on-disk hash table for a .gdb_index section. // There's a tradeoff between size and collision rate. We aim 75% utilization. size_t GdbIndexSection::computeSymtabSize() const { - return std::max<size_t>(NextPowerOf2(Symbols.size() * 4 / 3), 1024); + return std::max<size_t>(NextPowerOf2(symbols.size() * 4 / 3), 1024); } // Compute the output section size. void GdbIndexSection::initOutputSize() { - Size = sizeof(GdbIndexHeader) + computeSymtabSize() * 8; + size = sizeof(GdbIndexHeader) + computeSymtabSize() * 8; - for (GdbChunk &Chunk : Chunks) - Size += Chunk.CompilationUnits.size() * 16 + Chunk.AddressAreas.size() * 20; + for (GdbChunk &chunk : chunks) + size += chunk.compilationUnits.size() * 16 + chunk.addressAreas.size() * 20; // Add the constant pool size if exists. - if (!Symbols.empty()) { - GdbSymbol &Sym = Symbols.back(); - Size += Sym.NameOff + Sym.Name.size() + 1; + if (!symbols.empty()) { + GdbSymbol &sym = symbols.back(); + size += sym.nameOff + sym.name.size() + 1; } } static std::vector<InputSection *> getDebugInfoSections() { - std::vector<InputSection *> Ret; - for (InputSectionBase *S : InputSections) - if (InputSection *IS = dyn_cast<InputSection>(S)) - if (IS->Name == ".debug_info") - Ret.push_back(IS); - return Ret; + std::vector<InputSection *> ret; + for (InputSectionBase *s : inputSections) + if (InputSection *isec = dyn_cast<InputSection>(s)) + if (isec->name == ".debug_info") + ret.push_back(isec); + return ret; } -static std::vector<GdbIndexSection::CuEntry> readCuList(DWARFContext &Dwarf) { - std::vector<GdbIndexSection::CuEntry> Ret; - for (std::unique_ptr<DWARFUnit> &Cu : Dwarf.compile_units()) - Ret.push_back({Cu->getOffset(), Cu->getLength() + 4}); - return Ret; +static std::vector<GdbIndexSection::CuEntry> readCuList(DWARFContext &dwarf) { + std::vector<GdbIndexSection::CuEntry> ret; + for (std::unique_ptr<DWARFUnit> &cu : dwarf.compile_units()) + ret.push_back({cu->getOffset(), cu->getLength() + 4}); + return ret; } static std::vector<GdbIndexSection::AddressEntry> -readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) { - std::vector<GdbIndexSection::AddressEntry> Ret; - - uint32_t CuIdx = 0; - for (std::unique_ptr<DWARFUnit> &Cu : Dwarf.compile_units()) { - Expected<DWARFAddressRangesVector> Ranges = Cu->collectAddressRanges(); - if (!Ranges) { - error(toString(Sec) + ": " + toString(Ranges.takeError())); +readAddressAreas(DWARFContext &dwarf, InputSection *sec) { + std::vector<GdbIndexSection::AddressEntry> ret; + + uint32_t cuIdx = 0; + for (std::unique_ptr<DWARFUnit> &cu : dwarf.compile_units()) { + Expected<DWARFAddressRangesVector> ranges = cu->collectAddressRanges(); + if (!ranges) { + error(toString(sec) + ": " + toString(ranges.takeError())); return {}; } - ArrayRef<InputSectionBase *> Sections = Sec->File->getSections(); - for (DWARFAddressRange &R : *Ranges) { - InputSectionBase *S = Sections[R.SectionIndex]; - if (!S || S == &InputSection::Discarded || !S->Live) + ArrayRef<InputSectionBase *> sections = sec->file->getSections(); + for (DWARFAddressRange &r : *ranges) { + if (r.SectionIndex == -1ULL) + continue; + InputSectionBase *s = sections[r.SectionIndex]; + if (!s || s == &InputSection::discarded || !s->isLive()) continue; // Range list with zero size has no effect. - if (R.LowPC == R.HighPC) + if (r.LowPC == r.HighPC) continue; - auto *IS = cast<InputSection>(S); - uint64_t Offset = IS->getOffsetInFile(); - Ret.push_back({IS, R.LowPC - Offset, R.HighPC - Offset, CuIdx}); + auto *isec = cast<InputSection>(s); + uint64_t offset = isec->getOffsetInFile(); + ret.push_back({isec, r.LowPC - offset, r.HighPC - offset, cuIdx}); } - ++CuIdx; + ++cuIdx; } - return Ret; + return ret; } template <class ELFT> static std::vector<GdbIndexSection::NameAttrEntry> -readPubNamesAndTypes(const LLDDwarfObj<ELFT> &Obj, - const std::vector<GdbIndexSection::CuEntry> &CUs) { - const DWARFSection &PubNames = Obj.getGnuPubNamesSection(); - const DWARFSection &PubTypes = Obj.getGnuPubTypesSection(); - - std::vector<GdbIndexSection::NameAttrEntry> Ret; - for (const DWARFSection *Pub : {&PubNames, &PubTypes}) { - DWARFDebugPubTable Table(Obj, *Pub, Config->IsLE, true); - for (const DWARFDebugPubTable::Set &Set : Table.getData()) { - // The value written into the constant pool is Kind << 24 | CuIndex. As we +readPubNamesAndTypes(const LLDDwarfObj<ELFT> &obj, + const std::vector<GdbIndexSection::CuEntry> &cUs) { + const DWARFSection &pubNames = obj.getGnuPubNamesSection(); + const DWARFSection &pubTypes = obj.getGnuPubTypesSection(); + + std::vector<GdbIndexSection::NameAttrEntry> ret; + for (const DWARFSection *pub : {&pubNames, &pubTypes}) { + DWARFDebugPubTable table(obj, *pub, config->isLE, true); + for (const DWARFDebugPubTable::Set &set : table.getData()) { + // The value written into the constant pool is kind << 24 | cuIndex. As we // don't know how many compilation units precede this object to compute - // CuIndex, we compute (Kind << 24 | CuIndexInThisObject) instead, and add + // cuIndex, we compute (kind << 24 | cuIndexInThisObject) instead, and add // the number of preceding compilation units later. - uint32_t I = - lower_bound(CUs, Set.Offset, - [](GdbIndexSection::CuEntry CU, uint32_t Offset) { - return CU.CuOffset < Offset; + uint32_t i = + lower_bound(cUs, set.Offset, + [](GdbIndexSection::CuEntry cu, uint32_t offset) { + return cu.cuOffset < offset; }) - - CUs.begin(); - for (const DWARFDebugPubTable::Entry &Ent : Set.Entries) - Ret.push_back({{Ent.Name, computeGdbHash(Ent.Name)}, - (Ent.Descriptor.toBits() << 24) | I}); + cUs.begin(); + for (const DWARFDebugPubTable::Entry &ent : set.Entries) + ret.push_back({{ent.Name, computeGdbHash(ent.Name)}, + (ent.Descriptor.toBits() << 24) | i}); } } - return Ret; + return ret; } // Create a list of symbols from a given list of symbol names and types // by uniquifying them by name. static std::vector<GdbIndexSection::GdbSymbol> -createSymbols(ArrayRef<std::vector<GdbIndexSection::NameAttrEntry>> NameAttrs, - const std::vector<GdbIndexSection::GdbChunk> &Chunks) { - typedef GdbIndexSection::GdbSymbol GdbSymbol; - typedef GdbIndexSection::NameAttrEntry NameAttrEntry; +createSymbols(ArrayRef<std::vector<GdbIndexSection::NameAttrEntry>> nameAttrs, + const std::vector<GdbIndexSection::GdbChunk> &chunks) { + using GdbSymbol = GdbIndexSection::GdbSymbol; + using NameAttrEntry = GdbIndexSection::NameAttrEntry; // For each chunk, compute the number of compilation units preceding it. - uint32_t CuIdx = 0; - std::vector<uint32_t> CuIdxs(Chunks.size()); - for (uint32_t I = 0, E = Chunks.size(); I != E; ++I) { - CuIdxs[I] = CuIdx; - CuIdx += Chunks[I].CompilationUnits.size(); + uint32_t cuIdx = 0; + std::vector<uint32_t> cuIdxs(chunks.size()); + for (uint32_t i = 0, e = chunks.size(); i != e; ++i) { + cuIdxs[i] = cuIdx; + cuIdx += chunks[i].compilationUnits.size(); } // The number of symbols we will handle in this function is of the order // of millions for very large executables, so we use multi-threading to // speed it up. - size_t NumShards = 32; - size_t Concurrency = 1; - if (ThreadsEnabled) - Concurrency = - std::min<size_t>(PowerOf2Floor(hardware_concurrency()), NumShards); + size_t numShards = 32; + size_t concurrency = 1; + if (threadsEnabled) + concurrency = + std::min<size_t>(PowerOf2Floor(hardware_concurrency()), numShards); // A sharded map to uniquify symbols by name. - std::vector<DenseMap<CachedHashStringRef, size_t>> Map(NumShards); - size_t Shift = 32 - countTrailingZeros(NumShards); + std::vector<DenseMap<CachedHashStringRef, size_t>> map(numShards); + size_t shift = 32 - countTrailingZeros(numShards); // Instantiate GdbSymbols while uniqufying them by name. - std::vector<std::vector<GdbSymbol>> Symbols(NumShards); - parallelForEachN(0, Concurrency, [&](size_t ThreadId) { - uint32_t I = 0; - for (ArrayRef<NameAttrEntry> Entries : NameAttrs) { - for (const NameAttrEntry &Ent : Entries) { - size_t ShardId = Ent.Name.hash() >> Shift; - if ((ShardId & (Concurrency - 1)) != ThreadId) + std::vector<std::vector<GdbSymbol>> symbols(numShards); + parallelForEachN(0, concurrency, [&](size_t threadId) { + uint32_t i = 0; + for (ArrayRef<NameAttrEntry> entries : nameAttrs) { + for (const NameAttrEntry &ent : entries) { + size_t shardId = ent.name.hash() >> shift; + if ((shardId & (concurrency - 1)) != threadId) continue; - uint32_t V = Ent.CuIndexAndAttrs + CuIdxs[I]; - size_t &Idx = Map[ShardId][Ent.Name]; - if (Idx) { - Symbols[ShardId][Idx - 1].CuVector.push_back(V); + uint32_t v = ent.cuIndexAndAttrs + cuIdxs[i]; + size_t &idx = map[shardId][ent.name]; + if (idx) { + symbols[shardId][idx - 1].cuVector.push_back(v); continue; } - Idx = Symbols[ShardId].size() + 1; - Symbols[ShardId].push_back({Ent.Name, {V}, 0, 0}); + idx = symbols[shardId].size() + 1; + symbols[shardId].push_back({ent.name, {v}, 0, 0}); } - ++I; + ++i; } }); - size_t NumSymbols = 0; - for (ArrayRef<GdbSymbol> V : Symbols) - NumSymbols += V.size(); + size_t numSymbols = 0; + for (ArrayRef<GdbSymbol> v : symbols) + numSymbols += v.size(); // The return type is a flattened vector, so we'll copy each vector // contents to Ret. - std::vector<GdbSymbol> Ret; - Ret.reserve(NumSymbols); - for (std::vector<GdbSymbol> &Vec : Symbols) - for (GdbSymbol &Sym : Vec) - Ret.push_back(std::move(Sym)); + std::vector<GdbSymbol> ret; + ret.reserve(numSymbols); + for (std::vector<GdbSymbol> &vec : symbols) + for (GdbSymbol &sym : vec) + ret.push_back(std::move(sym)); // CU vectors and symbol names are adjacent in the output file. // We can compute their offsets in the output file now. - size_t Off = 0; - for (GdbSymbol &Sym : Ret) { - Sym.CuVectorOff = Off; - Off += (Sym.CuVector.size() + 1) * 4; + size_t off = 0; + for (GdbSymbol &sym : ret) { + sym.cuVectorOff = off; + off += (sym.cuVector.size() + 1) * 4; } - for (GdbSymbol &Sym : Ret) { - Sym.NameOff = Off; - Off += Sym.Name.size() + 1; + for (GdbSymbol &sym : ret) { + sym.nameOff = off; + off += sym.name.size() + 1; } - return Ret; + return ret; } // Returns a newly-created .gdb_index section. template <class ELFT> GdbIndexSection *GdbIndexSection::create() { - std::vector<InputSection *> Sections = getDebugInfoSections(); + std::vector<InputSection *> sections = getDebugInfoSections(); // .debug_gnu_pub{names,types} are useless in executables. // They are present in input object files solely for creating // a .gdb_index. So we can remove them from the output. - for (InputSectionBase *S : InputSections) - if (S->Name == ".debug_gnu_pubnames" || S->Name == ".debug_gnu_pubtypes") - S->Live = false; - - std::vector<GdbChunk> Chunks(Sections.size()); - std::vector<std::vector<NameAttrEntry>> NameAttrs(Sections.size()); - - parallelForEachN(0, Sections.size(), [&](size_t I) { - ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>(); - DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(File)); - - Chunks[I].Sec = Sections[I]; - Chunks[I].CompilationUnits = readCuList(Dwarf); - Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]); - NameAttrs[I] = readPubNamesAndTypes<ELFT>( - static_cast<const LLDDwarfObj<ELFT> &>(Dwarf.getDWARFObj()), - Chunks[I].CompilationUnits); + for (InputSectionBase *s : inputSections) + if (s->name == ".debug_gnu_pubnames" || s->name == ".debug_gnu_pubtypes") + s->markDead(); + + std::vector<GdbChunk> chunks(sections.size()); + std::vector<std::vector<NameAttrEntry>> nameAttrs(sections.size()); + + parallelForEachN(0, sections.size(), [&](size_t i) { + ObjFile<ELFT> *file = sections[i]->getFile<ELFT>(); + DWARFContext dwarf(make_unique<LLDDwarfObj<ELFT>>(file)); + + chunks[i].sec = sections[i]; + chunks[i].compilationUnits = readCuList(dwarf); + chunks[i].addressAreas = readAddressAreas(dwarf, sections[i]); + nameAttrs[i] = readPubNamesAndTypes<ELFT>( + static_cast<const LLDDwarfObj<ELFT> &>(dwarf.getDWARFObj()), + chunks[i].compilationUnits); }); - auto *Ret = make<GdbIndexSection>(); - Ret->Chunks = std::move(Chunks); - Ret->Symbols = createSymbols(NameAttrs, Ret->Chunks); - Ret->initOutputSize(); - return Ret; + auto *ret = make<GdbIndexSection>(); + ret->chunks = std::move(chunks); + ret->symbols = createSymbols(nameAttrs, ret->chunks); + ret->initOutputSize(); + return ret; } -void GdbIndexSection::writeTo(uint8_t *Buf) { +void GdbIndexSection::writeTo(uint8_t *buf) { // Write the header. - auto *Hdr = reinterpret_cast<GdbIndexHeader *>(Buf); - uint8_t *Start = Buf; - Hdr->Version = 7; - Buf += sizeof(*Hdr); + auto *hdr = reinterpret_cast<GdbIndexHeader *>(buf); + uint8_t *start = buf; + hdr->version = 7; + buf += sizeof(*hdr); // Write the CU list. - Hdr->CuListOff = Buf - Start; - for (GdbChunk &Chunk : Chunks) { - for (CuEntry &Cu : Chunk.CompilationUnits) { - write64le(Buf, Chunk.Sec->OutSecOff + Cu.CuOffset); - write64le(Buf + 8, Cu.CuLength); - Buf += 16; + hdr->cuListOff = buf - start; + for (GdbChunk &chunk : chunks) { + for (CuEntry &cu : chunk.compilationUnits) { + write64le(buf, chunk.sec->outSecOff + cu.cuOffset); + write64le(buf + 8, cu.cuLength); + buf += 16; } } // Write the address area. - Hdr->CuTypesOff = Buf - Start; - Hdr->AddressAreaOff = Buf - Start; - uint32_t CuOff = 0; - for (GdbChunk &Chunk : Chunks) { - for (AddressEntry &E : Chunk.AddressAreas) { - uint64_t BaseAddr = E.Section->getVA(0); - write64le(Buf, BaseAddr + E.LowAddress); - write64le(Buf + 8, BaseAddr + E.HighAddress); - write32le(Buf + 16, E.CuIndex + CuOff); - Buf += 20; + hdr->cuTypesOff = buf - start; + hdr->addressAreaOff = buf - start; + uint32_t cuOff = 0; + for (GdbChunk &chunk : chunks) { + for (AddressEntry &e : chunk.addressAreas) { + uint64_t baseAddr = e.section->getVA(0); + write64le(buf, baseAddr + e.lowAddress); + write64le(buf + 8, baseAddr + e.highAddress); + write32le(buf + 16, e.cuIndex + cuOff); + buf += 20; } - CuOff += Chunk.CompilationUnits.size(); + cuOff += chunk.compilationUnits.size(); } // Write the on-disk open-addressing hash table containing symbols. - Hdr->SymtabOff = Buf - Start; - size_t SymtabSize = computeSymtabSize(); - uint32_t Mask = SymtabSize - 1; + hdr->symtabOff = buf - start; + size_t symtabSize = computeSymtabSize(); + uint32_t mask = symtabSize - 1; - for (GdbSymbol &Sym : Symbols) { - uint32_t H = Sym.Name.hash(); - uint32_t I = H & Mask; - uint32_t Step = ((H * 17) & Mask) | 1; + for (GdbSymbol &sym : symbols) { + uint32_t h = sym.name.hash(); + uint32_t i = h & mask; + uint32_t step = ((h * 17) & mask) | 1; - while (read32le(Buf + I * 8)) - I = (I + Step) & Mask; + while (read32le(buf + i * 8)) + i = (i + step) & mask; - write32le(Buf + I * 8, Sym.NameOff); - write32le(Buf + I * 8 + 4, Sym.CuVectorOff); + write32le(buf + i * 8, sym.nameOff); + write32le(buf + i * 8 + 4, sym.cuVectorOff); } - Buf += SymtabSize * 8; + buf += symtabSize * 8; // Write the string pool. - Hdr->ConstantPoolOff = Buf - Start; - parallelForEach(Symbols, [&](GdbSymbol &Sym) { - memcpy(Buf + Sym.NameOff, Sym.Name.data(), Sym.Name.size()); + hdr->constantPoolOff = buf - start; + parallelForEach(symbols, [&](GdbSymbol &sym) { + memcpy(buf + sym.nameOff, sym.name.data(), sym.name.size()); }); // Write the CU vectors. - for (GdbSymbol &Sym : Symbols) { - write32le(Buf, Sym.CuVector.size()); - Buf += 4; - for (uint32_t Val : Sym.CuVector) { - write32le(Buf, Val); - Buf += 4; + for (GdbSymbol &sym : symbols) { + write32le(buf, sym.cuVector.size()); + buf += 4; + for (uint32_t val : sym.cuVector) { + write32le(buf, val); + buf += 4; } } } -bool GdbIndexSection::empty() const { return Chunks.empty(); } +bool GdbIndexSection::isNeeded() const { return !chunks.empty(); } EhFrameHeader::EhFrameHeader() : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".eh_frame_hdr") {} +void EhFrameHeader::writeTo(uint8_t *buf) { + // Unlike most sections, the EhFrameHeader section is written while writing + // another section, namely EhFrameSection, which calls the write() function + // below from its writeTo() function. This is necessary because the contents + // of EhFrameHeader depend on the relocated contents of EhFrameSection and we + // don't know which order the sections will be written in. +} + // .eh_frame_hdr contains a binary search table of pointers to FDEs. // Each entry of the search table consists of two values, // the starting PC from where FDEs covers, and the FDE's address. // It is sorted by PC. -void EhFrameHeader::writeTo(uint8_t *Buf) { - typedef EhFrameSection::FdeData FdeData; +void EhFrameHeader::write() { + uint8_t *buf = Out::bufferStart + getParent()->offset + outSecOff; + using FdeData = EhFrameSection::FdeData; - std::vector<FdeData> Fdes = In.EhFrame->getFdeData(); + std::vector<FdeData> fdes = getPartition().ehFrame->getFdeData(); - Buf[0] = 1; - 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(Buf + 4, In.EhFrame->getParent()->Addr - this->getVA() - 4); - write32(Buf + 8, Fdes.size()); - Buf += 12; + buf[0] = 1; + 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(buf + 4, + getPartition().ehFrame->getParent()->addr - this->getVA() - 4); + write32(buf + 8, fdes.size()); + buf += 12; - for (FdeData &Fde : Fdes) { - write32(Buf, Fde.PcRel); - write32(Buf + 4, Fde.FdeVARel); - Buf += 8; + for (FdeData &fde : fdes) { + write32(buf, fde.pcRel); + write32(buf + 4, fde.fdeVARel); + buf += 8; } } size_t EhFrameHeader::getSize() const { // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs. - return 12 + In.EhFrame->NumFdes * 8; + return 12 + getPartition().ehFrame->numFdes * 8; } -bool EhFrameHeader::empty() const { return In.EhFrame->empty(); } +bool EhFrameHeader::isNeeded() const { + return isLive() && getPartition().ehFrame->isNeeded(); +} VersionDefinitionSection::VersionDefinitionSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t), ".gnu.version_d") {} -static StringRef getFileDefName() { - if (!Config->SoName.empty()) - return Config->SoName; - return Config->OutputFile; +StringRef VersionDefinitionSection::getFileDefName() { + if (!getPartition().name.empty()) + return getPartition().name; + if (!config->soName.empty()) + return config->soName; + return config->outputFile; } void VersionDefinitionSection::finalizeContents() { - FileDefNameOff = In.DynStrTab->addString(getFileDefName()); - for (VersionDefinition &V : Config->VersionDefinitions) - V.NameOff = In.DynStrTab->addString(V.Name); + fileDefNameOff = getPartition().dynStrTab->addString(getFileDefName()); + for (VersionDefinition &v : config->versionDefinitions) + verDefNameOffs.push_back(getPartition().dynStrTab->addString(v.name)); - if (OutputSection *Sec = In.DynStrTab->getParent()) - getParent()->Link = Sec->SectionIndex; + if (OutputSection *sec = getPartition().dynStrTab->getParent()) + getParent()->link = sec->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 - getParent()->Info = getVerDefNum(); + getParent()->info = getVerDefNum(); } -void VersionDefinitionSection::writeOne(uint8_t *Buf, uint32_t Index, - StringRef Name, size_t NameOff) { - uint16_t Flags = Index == 1 ? VER_FLG_BASE : 0; +void VersionDefinitionSection::writeOne(uint8_t *buf, uint32_t index, + StringRef name, size_t nameOff) { + uint16_t flags = index == 1 ? VER_FLG_BASE : 0; // Write a verdef. - write16(Buf, 1); // vd_version - write16(Buf + 2, Flags); // vd_flags - write16(Buf + 4, Index); // vd_ndx - write16(Buf + 6, 1); // vd_cnt - write32(Buf + 8, hashSysV(Name)); // vd_hash - write32(Buf + 12, 20); // vd_aux - write32(Buf + 16, 28); // vd_next + write16(buf, 1); // vd_version + write16(buf + 2, flags); // vd_flags + write16(buf + 4, index); // vd_ndx + write16(buf + 6, 1); // vd_cnt + write32(buf + 8, hashSysV(name)); // vd_hash + write32(buf + 12, 20); // vd_aux + write32(buf + 16, 28); // vd_next // Write a veraux. - write32(Buf + 20, NameOff); // vda_name - write32(Buf + 24, 0); // vda_next + write32(buf + 20, nameOff); // vda_name + write32(buf + 24, 0); // vda_next } -void VersionDefinitionSection::writeTo(uint8_t *Buf) { - writeOne(Buf, 1, getFileDefName(), FileDefNameOff); +void VersionDefinitionSection::writeTo(uint8_t *buf) { + writeOne(buf, 1, getFileDefName(), fileDefNameOff); - for (VersionDefinition &V : Config->VersionDefinitions) { - Buf += EntrySize; - writeOne(Buf, V.Id, V.Name, V.NameOff); + auto nameOffIt = verDefNameOffs.begin(); + for (VersionDefinition &v : config->versionDefinitions) { + buf += EntrySize; + writeOne(buf, v.id, v.name, *nameOffIt++); } // Need to terminate the last version definition. - write32(Buf + 16, 0); // vd_next + write32(buf + 16, 0); // vd_next } size_t VersionDefinitionSection::getSize() const { @@ -2743,160 +2798,161 @@ size_t VersionDefinitionSection::getSize() const { } // .gnu.version is a table where each entry is 2 byte long. -template <class ELFT> -VersionTableSection<ELFT>::VersionTableSection() +VersionTableSection::VersionTableSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t), ".gnu.version") { - this->Entsize = 2; + this->entsize = 2; } -template <class ELFT> void VersionTableSection<ELFT>::finalizeContents() { +void VersionTableSection::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. - getParent()->Link = In.DynSymTab->getParent()->SectionIndex; + getParent()->link = getPartition().dynSymTab->getParent()->sectionIndex; } -template <class ELFT> size_t VersionTableSection<ELFT>::getSize() const { - return (In.DynSymTab->getSymbols().size() + 1) * 2; +size_t VersionTableSection::getSize() const { + return (getPartition().dynSymTab->getSymbols().size() + 1) * 2; } -template <class ELFT> void VersionTableSection<ELFT>::writeTo(uint8_t *Buf) { - Buf += 2; - for (const SymbolTableEntry &S : In.DynSymTab->getSymbols()) { - write16(Buf, S.Sym->VersionId); - Buf += 2; +void VersionTableSection::writeTo(uint8_t *buf) { + buf += 2; + for (const SymbolTableEntry &s : getPartition().dynSymTab->getSymbols()) { + write16(buf, s.sym->versionId); + buf += 2; } } -template <class ELFT> bool VersionTableSection<ELFT>::empty() const { - return !In.VerDef && InX<ELFT>::VerNeed->empty(); +bool VersionTableSection::isNeeded() const { + return getPartition().verDef || getPartition().verNeed->isNeeded(); +} + +void elf::addVerneed(Symbol *ss) { + auto &file = cast<SharedFile>(*ss->file); + if (ss->verdefIndex == VER_NDX_GLOBAL) { + ss->versionId = VER_NDX_GLOBAL; + return; + } + + if (file.vernauxs.empty()) + file.vernauxs.resize(file.verdefs.size()); + + // Select a version identifier for the vernaux data structure, if we haven't + // already allocated one. The verdef identifiers cover the range + // [1..getVerDefNum()]; this causes the vernaux identifiers to start from + // getVerDefNum()+1. + if (file.vernauxs[ss->verdefIndex] == 0) + file.vernauxs[ss->verdefIndex] = ++SharedFile::vernauxNum + getVerDefNum(); + + ss->versionId = file.vernauxs[ss->verdefIndex]; } template <class ELFT> VersionNeedSection<ELFT>::VersionNeedSection() : 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. - NextIndex = getVerDefNum() + 1; -} + ".gnu.version_r") {} -template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(Symbol *SS) { - auto &File = cast<SharedFile<ELFT>>(*SS->File); - if (SS->VerdefIndex == VER_NDX_GLOBAL) { - SS->VersionId = VER_NDX_GLOBAL; - return; +template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() { + for (SharedFile *f : sharedFiles) { + if (f->vernauxs.empty()) + continue; + verneeds.emplace_back(); + Verneed &vn = verneeds.back(); + vn.nameStrTab = getPartition().dynStrTab->addString(f->soName); + for (unsigned i = 0; i != f->vernauxs.size(); ++i) { + if (f->vernauxs[i] == 0) + continue; + auto *verdef = + reinterpret_cast<const typename ELFT::Verdef *>(f->verdefs[i]); + vn.vernauxs.push_back( + {verdef->vd_hash, f->vernauxs[i], + getPartition().dynStrTab->addString(f->getStringTable().data() + + verdef->getAux()->vda_name)}); + } } - // 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 (File.VerdefMap.empty()) - Needed.push_back({&File, In.DynStrTab->addString(File.SoName)}); - const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex]; - 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.DynStrTab->addString(File.getStringTable().data() + - Ver->getAux()->vda_name); - NV.Index = NextIndex++; - } - SS->VersionId = NV.Index; + if (OutputSection *sec = getPartition().dynStrTab->getParent()) + getParent()->link = sec->sectionIndex; + getParent()->info = verneeds.size(); } -template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) { +template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *buf) { // The Elf_Verneeds need to appear first, followed by the Elf_Vernauxs. - auto *Verneed = reinterpret_cast<Elf_Verneed *>(Buf); - auto *Vernaux = reinterpret_cast<Elf_Vernaux *>(Verneed + Needed.size()); + auto *verneed = reinterpret_cast<Elf_Verneed *>(buf); + auto *vernaux = reinterpret_cast<Elf_Vernaux *>(verneed + verneeds.size()); - for (std::pair<SharedFile<ELFT> *, size_t> &P : Needed) { + for (auto &vn : verneeds) { // Create an Elf_Verneed for this DSO. - Verneed->vn_version = 1; - Verneed->vn_cnt = P.first->VerdefMap.size(); - Verneed->vn_file = P.second; - Verneed->vn_aux = - reinterpret_cast<char *>(Vernaux) - reinterpret_cast<char *>(Verneed); - Verneed->vn_next = sizeof(Elf_Verneed); - ++Verneed; - - // Create the Elf_Vernauxs for this Elf_Verneed. The loop iterates over - // VerdefMap, which will only contain references to needed version - // definitions. Each Elf_Vernaux is based on the information contained in - // the Elf_Verdef in the source DSO. This loop iterates over a std::map of - // pointers, but is deterministic because the pointers refer to Elf_Verdef - // data structures within a single input file. - for (auto &NV : P.first->VerdefMap) { - Vernaux->vna_hash = NV.first->vd_hash; - Vernaux->vna_flags = 0; - Vernaux->vna_other = NV.second.Index; - Vernaux->vna_name = NV.second.StrTab; - Vernaux->vna_next = sizeof(Elf_Vernaux); - ++Vernaux; + verneed->vn_version = 1; + verneed->vn_cnt = vn.vernauxs.size(); + verneed->vn_file = vn.nameStrTab; + verneed->vn_aux = + reinterpret_cast<char *>(vernaux) - reinterpret_cast<char *>(verneed); + verneed->vn_next = sizeof(Elf_Verneed); + ++verneed; + + // Create the Elf_Vernauxs for this Elf_Verneed. + for (auto &vna : vn.vernauxs) { + vernaux->vna_hash = vna.hash; + vernaux->vna_flags = 0; + vernaux->vna_other = vna.verneedIndex; + vernaux->vna_name = vna.nameStrTab; + vernaux->vna_next = sizeof(Elf_Vernaux); + ++vernaux; } - Vernaux[-1].vna_next = 0; + vernaux[-1].vna_next = 0; } - Verneed[-1].vn_next = 0; -} - -template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() { - if (OutputSection *Sec = In.DynStrTab->getParent()) - getParent()->Link = Sec->SectionIndex; - getParent()->Info = Needed.size(); + verneed[-1].vn_next = 0; } template <class ELFT> size_t VersionNeedSection<ELFT>::getSize() const { - unsigned Size = Needed.size() * sizeof(Elf_Verneed); - for (const std::pair<SharedFile<ELFT> *, size_t> &P : Needed) - Size += P.first->VerdefMap.size() * sizeof(Elf_Vernaux); - return Size; + return verneeds.size() * sizeof(Elf_Verneed) + + SharedFile::vernauxNum * sizeof(Elf_Vernaux); } -template <class ELFT> bool VersionNeedSection<ELFT>::empty() const { - return getNeedNum() == 0; +template <class ELFT> bool VersionNeedSection<ELFT>::isNeeded() const { + return SharedFile::vernauxNum != 0; } -void MergeSyntheticSection::addSection(MergeInputSection *MS) { - MS->Parent = this; - Sections.push_back(MS); +void MergeSyntheticSection::addSection(MergeInputSection *ms) { + ms->parent = this; + sections.push_back(ms); + assert(alignment == ms->alignment || !(ms->flags & SHF_STRINGS)); + alignment = std::max(alignment, ms->alignment); } -MergeTailSection::MergeTailSection(StringRef Name, uint32_t Type, - uint64_t Flags, uint32_t Alignment) - : MergeSyntheticSection(Name, Type, Flags, Alignment), - Builder(StringTableBuilder::RAW, Alignment) {} +MergeTailSection::MergeTailSection(StringRef name, uint32_t type, + uint64_t flags, uint32_t alignment) + : MergeSyntheticSection(name, type, flags, alignment), + builder(StringTableBuilder::RAW, alignment) {} -size_t MergeTailSection::getSize() const { return Builder.getSize(); } +size_t MergeTailSection::getSize() const { return builder.getSize(); } -void MergeTailSection::writeTo(uint8_t *Buf) { Builder.write(Buf); } +void MergeTailSection::writeTo(uint8_t *buf) { builder.write(buf); } void MergeTailSection::finalizeContents() { // 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)); + 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(); + 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)); + // to a corresponding SectionPiece 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 MergeNoTailSection::writeTo(uint8_t *Buf) { - for (size_t I = 0; I < NumShards; ++I) - Shards[I].write(Buf + ShardOffsets[I]); +void MergeNoTailSection::writeTo(uint8_t *buf) { + for (size_t i = 0; i < numShards; ++i) + shards[i].write(buf + shardOffsets[i]); } // This function is very hot (i.e. it can take several seconds to finish) @@ -2909,66 +2965,68 @@ void MergeNoTailSection::writeTo(uint8_t *Buf) { // We do it in parallel. void MergeNoTailSection::finalizeContents() { // Initializes string table builders. - for (size_t I = 0; I < NumShards; ++I) - Shards.emplace_back(StringTableBuilder::RAW, Alignment); + for (size_t i = 0; i < numShards; ++i) + shards.emplace_back(StringTableBuilder::RAW, alignment); // Concurrency level. Must be a power of 2 to avoid expensive modulo // operations in the following tight loop. - size_t Concurrency = 1; - if (ThreadsEnabled) - Concurrency = - std::min<size_t>(PowerOf2Floor(hardware_concurrency()), NumShards); + size_t concurrency = 1; + if (threadsEnabled) + concurrency = + std::min<size_t>(PowerOf2Floor(hardware_concurrency()), numShards); // Add section pieces to the builders. - parallelForEachN(0, Concurrency, [&](size_t ThreadId) { - for (MergeInputSection *Sec : Sections) { - for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) { - size_t ShardId = getShardId(Sec->Pieces[I].Hash); - if ((ShardId & (Concurrency - 1)) == ThreadId && Sec->Pieces[I].Live) - Sec->Pieces[I].OutputOff = Shards[ShardId].add(Sec->getData(I)); + parallelForEachN(0, concurrency, [&](size_t threadId) { + for (MergeInputSection *sec : sections) { + for (size_t i = 0, e = sec->pieces.size(); i != e; ++i) { + if (!sec->pieces[i].live) + continue; + size_t shardId = getShardId(sec->pieces[i].hash); + if ((shardId & (concurrency - 1)) == threadId) + sec->pieces[i].outputOff = shards[shardId].add(sec->getData(i)); } } }); // Compute an in-section offset for each shard. - size_t Off = 0; - for (size_t I = 0; I < NumShards; ++I) { - Shards[I].finalizeInOrder(); - if (Shards[I].getSize() > 0) - Off = alignTo(Off, Alignment); - ShardOffsets[I] = Off; - Off += Shards[I].getSize(); + size_t off = 0; + for (size_t i = 0; i < numShards; ++i) { + shards[i].finalizeInOrder(); + if (shards[i].getSize() > 0) + off = alignTo(off, alignment); + shardOffsets[i] = off; + off += shards[i].getSize(); } - Size = Off; + size = off; // So far, section pieces have offsets from beginning of shards, but // we want offsets from beginning of the whole section. Fix them. - parallelForEach(Sections, [&](MergeInputSection *Sec) { - for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) - if (Sec->Pieces[I].Live) - Sec->Pieces[I].OutputOff += - ShardOffsets[getShardId(Sec->Pieces[I].Hash)]; + parallelForEach(sections, [&](MergeInputSection *sec) { + for (size_t i = 0, e = sec->pieces.size(); i != e; ++i) + if (sec->pieces[i].live) + sec->pieces[i].outputOff += + shardOffsets[getShardId(sec->pieces[i].hash)]; }); } -static MergeSyntheticSection *createMergeSynthetic(StringRef Name, - uint32_t Type, - uint64_t Flags, - uint32_t Alignment) { - bool ShouldTailMerge = (Flags & SHF_STRINGS) && Config->Optimize >= 2; - if (ShouldTailMerge) - return make<MergeTailSection>(Name, Type, Flags, Alignment); - return make<MergeNoTailSection>(Name, Type, Flags, Alignment); +static MergeSyntheticSection *createMergeSynthetic(StringRef name, + uint32_t type, + uint64_t flags, + uint32_t alignment) { + bool shouldTailMerge = (flags & SHF_STRINGS) && config->optimize >= 2; + if (shouldTailMerge) + return make<MergeTailSection>(name, type, flags, alignment); + return make<MergeNoTailSection>(name, type, flags, alignment); } template <class ELFT> void elf::splitSections() { // splitIntoPieces needs to be called on each MergeInputSection // before calling finalizeContents(). - parallelForEach(InputSections, [](InputSectionBase *Sec) { - if (auto *S = dyn_cast<MergeInputSection>(Sec)) - S->splitIntoPieces(); - else if (auto *Eh = dyn_cast<EhInputSection>(Sec)) - Eh->split<ELFT>(); + parallelForEach(inputSections, [](InputSectionBase *sec) { + if (auto *s = dyn_cast<MergeInputSection>(sec)) + s->splitIntoPieces(); + else if (auto *eh = dyn_cast<EhInputSection>(sec)) + eh->split<ELFT>(); }); } @@ -2980,23 +3038,22 @@ template <class ELFT> void elf::splitSections() { // that it replaces. It then finalizes each synthetic section in order // to compute an output offset for each piece of each input section. void elf::mergeSections() { - std::vector<MergeSyntheticSection *> MergeSections; - for (InputSectionBase *&S : InputSections) { - MergeInputSection *MS = dyn_cast<MergeInputSection>(S); - if (!MS) + std::vector<MergeSyntheticSection *> mergeSections; + for (InputSectionBase *&s : inputSections) { + MergeInputSection *ms = dyn_cast<MergeInputSection>(s); + if (!ms) continue; // We do not want to handle sections that are not alive, so just remove // them instead of trying to merge. - if (!MS->Live) { - S = nullptr; + if (!ms->isLive()) { + s = nullptr; continue; } - StringRef OutsecName = getOutputSectionName(MS); - uint32_t Alignment = std::max<uint32_t>(MS->Alignment, MS->Entsize); + StringRef outsecName = getOutputSectionName(ms); - auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) { + auto i = llvm::find_if(mergeSections, [=](MergeSyntheticSection *sec) { // While we could create a single synthetic section for two different // values of Entsize, it is better to take Entsize into consideration. // @@ -3005,98 +3062,285 @@ void elf::mergeSections() { // // Using Entsize in here also allows us to propagate it to the synthetic // section. - return Sec->Name == OutsecName && Sec->Flags == MS->Flags && - Sec->Entsize == MS->Entsize && Sec->Alignment == Alignment; + // + // SHF_STRINGS section with different alignments should not be merged. + return sec->name == outsecName && sec->flags == ms->flags && + sec->entsize == ms->entsize && + (sec->alignment == ms->alignment || !(sec->flags & SHF_STRINGS)); }); - if (I == MergeSections.end()) { - MergeSyntheticSection *Syn = - createMergeSynthetic(OutsecName, MS->Type, MS->Flags, Alignment); - MergeSections.push_back(Syn); - I = std::prev(MergeSections.end()); - S = Syn; - Syn->Entsize = MS->Entsize; + if (i == mergeSections.end()) { + MergeSyntheticSection *syn = + createMergeSynthetic(outsecName, ms->type, ms->flags, ms->alignment); + mergeSections.push_back(syn); + i = std::prev(mergeSections.end()); + s = syn; + syn->entsize = ms->entsize; } else { - S = nullptr; + s = nullptr; } - (*I)->addSection(MS); + (*i)->addSection(ms); } - for (auto *MS : MergeSections) - MS->finalizeContents(); + for (auto *ms : mergeSections) + ms->finalizeContents(); - std::vector<InputSectionBase *> &V = InputSections; - V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); + std::vector<InputSectionBase *> &v = inputSections; + v.erase(std::remove(v.begin(), v.end(), nullptr), v.end()); } MipsRldMapSection::MipsRldMapSection() - : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize, + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, config->wordsize, ".rld_map") {} -ARMExidxSentinelSection::ARMExidxSentinelSection() +ARMExidxSyntheticSection::ARMExidxSyntheticSection() : 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 | -// The sentinel must have the PREL31 value of an address higher than any -// address described by any other table entry. -void ARMExidxSentinelSection::writeTo(uint8_t *Buf) { - assert(Highest); - uint64_t S = Highest->getVA(Highest->getSize()); - uint64_t P = getVA(); - Target->relocateOne(Buf, R_ARM_PREL31, S - P); - write32le(Buf + 4, 1); -} - -// The sentinel has to be removed if there are no other .ARM.exidx entries. -bool ARMExidxSentinelSection::empty() const { - for (InputSection *IS : getInputSections(getParent())) - if (!isa<ARMExidxSentinelSection>(IS)) + config->wordsize, ".ARM.exidx") {} + +static InputSection *findExidxSection(InputSection *isec) { + for (InputSection *d : isec->dependentSections) + if (d->type == SHT_ARM_EXIDX) + return d; + return nullptr; +} + +bool ARMExidxSyntheticSection::addSection(InputSection *isec) { + if (isec->type == SHT_ARM_EXIDX) { + exidxSections.push_back(isec); + return true; + } + + if ((isec->flags & SHF_ALLOC) && (isec->flags & SHF_EXECINSTR) && + isec->getSize() > 0) { + executableSections.push_back(isec); + if (empty && findExidxSection(isec)) + empty = false; + return false; + } + + // FIXME: we do not output a relocation section when --emit-relocs is used + // as we do not have relocation sections for linker generated table entries + // and we would have to erase at a late stage relocations from merged entries. + // Given that exception tables are already position independent and a binary + // analyzer could derive the relocations we choose to erase the relocations. + if (config->emitRelocs && isec->type == SHT_REL) + if (InputSectionBase *ex = isec->getRelocatedSection()) + if (isa<InputSection>(ex) && ex->type == SHT_ARM_EXIDX) + return true; + + return false; +} + +// References to .ARM.Extab Sections have bit 31 clear and are not the +// special EXIDX_CANTUNWIND bit-pattern. +static bool isExtabRef(uint32_t unwind) { + return (unwind & 0x80000000) == 0 && unwind != 0x1; +} + +// Return true if the .ARM.exidx section Cur can be merged into the .ARM.exidx +// section Prev, where Cur follows Prev in the table. This can be done if the +// unwinding instructions in Cur are identical to Prev. Linker generated +// EXIDX_CANTUNWIND entries are represented by nullptr as they do not have an +// InputSection. +static bool isDuplicateArmExidxSec(InputSection *prev, InputSection *cur) { + + struct ExidxEntry { + ulittle32_t fn; + ulittle32_t unwind; + }; + // Get the last table Entry from the previous .ARM.exidx section. If Prev is + // nullptr then it will be a synthesized EXIDX_CANTUNWIND entry. + ExidxEntry prevEntry = {ulittle32_t(0), ulittle32_t(1)}; + if (prev) + prevEntry = prev->getDataAs<ExidxEntry>().back(); + if (isExtabRef(prevEntry.unwind)) + return false; + + // We consider the unwind instructions of an .ARM.exidx table entry + // a duplicate if the previous unwind instructions if: + // - Both are the special EXIDX_CANTUNWIND. + // - Both are the same inline unwind instructions. + // We do not attempt to follow and check links into .ARM.extab tables as + // consecutive identical entries are rare and the effort to check that they + // are identical is high. + + // If Cur is nullptr then this is synthesized EXIDX_CANTUNWIND entry. + if (cur == nullptr) + return prevEntry.unwind == 1; + + for (const ExidxEntry entry : cur->getDataAs<ExidxEntry>()) + if (isExtabRef(entry.unwind) || entry.unwind != prevEntry.unwind) return false; + + // All table entries in this .ARM.exidx Section can be merged into the + // previous Section. return true; } -bool ARMExidxSentinelSection::classof(const SectionBase *D) { - return D->kind() == InputSectionBase::Synthetic && D->Type == SHT_ARM_EXIDX; +// The .ARM.exidx table must be sorted in ascending order of the address of the +// functions the table describes. Optionally duplicate adjacent table entries +// can be removed. At the end of the function the ExecutableSections must be +// sorted in ascending order of address, Sentinel is set to the InputSection +// with the highest address and any InputSections that have mergeable +// .ARM.exidx table entries are removed from it. +void ARMExidxSyntheticSection::finalizeContents() { + // Sort the executable sections that may or may not have associated + // .ARM.exidx sections by order of ascending address. This requires the + // relative positions of InputSections to be known. + auto compareByFilePosition = [](const InputSection *a, + const InputSection *b) { + OutputSection *aOut = a->getParent(); + OutputSection *bOut = b->getParent(); + + if (aOut != bOut) + return aOut->sectionIndex < bOut->sectionIndex; + return a->outSecOff < b->outSecOff; + }; + llvm::stable_sort(executableSections, compareByFilePosition); + sentinel = executableSections.back(); + // Optionally merge adjacent duplicate entries. + if (config->mergeArmExidx) { + std::vector<InputSection *> selectedSections; + selectedSections.reserve(executableSections.size()); + selectedSections.push_back(executableSections[0]); + size_t prev = 0; + for (size_t i = 1; i < executableSections.size(); ++i) { + InputSection *ex1 = findExidxSection(executableSections[prev]); + InputSection *ex2 = findExidxSection(executableSections[i]); + if (!isDuplicateArmExidxSec(ex1, ex2)) { + selectedSections.push_back(executableSections[i]); + prev = i; + } + } + executableSections = std::move(selectedSections); + } + + size_t offset = 0; + size = 0; + for (InputSection *isec : executableSections) { + if (InputSection *d = findExidxSection(isec)) { + d->outSecOff = offset; + d->parent = getParent(); + offset += d->getSize(); + } else { + offset += 8; + } + } + // Size includes Sentinel. + size = offset + 8; +} + +InputSection *ARMExidxSyntheticSection::getLinkOrderDep() const { + return executableSections.front(); } -ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off) +// To write the .ARM.exidx table from the ExecutableSections we have three cases +// 1.) The InputSection has a .ARM.exidx InputSection in its dependent sections. +// We write the .ARM.exidx section contents and apply its relocations. +// 2.) The InputSection does not have a dependent .ARM.exidx InputSection. We +// must write the contents of an EXIDX_CANTUNWIND directly. We use the +// start of the InputSection as the purpose of the linker generated +// section is to terminate the address range of the previous entry. +// 3.) A trailing EXIDX_CANTUNWIND sentinel section is required at the end of +// the table to terminate the address range of the final entry. +void ARMExidxSyntheticSection::writeTo(uint8_t *buf) { + + const uint8_t cantUnwindData[8] = {0, 0, 0, 0, // PREL31 to target + 1, 0, 0, 0}; // EXIDX_CANTUNWIND + + uint64_t offset = 0; + for (InputSection *isec : executableSections) { + assert(isec->getParent() != nullptr); + if (InputSection *d = findExidxSection(isec)) { + memcpy(buf + offset, d->data().data(), d->data().size()); + d->relocateAlloc(buf, buf + d->getSize()); + offset += d->getSize(); + } else { + // A Linker generated CANTUNWIND section. + memcpy(buf + offset, cantUnwindData, sizeof(cantUnwindData)); + uint64_t s = isec->getVA(); + uint64_t p = getVA() + offset; + target->relocateOne(buf + offset, R_ARM_PREL31, s - p); + offset += 8; + } + } + // Write Sentinel. + memcpy(buf + offset, cantUnwindData, sizeof(cantUnwindData)); + uint64_t s = sentinel->getVA(sentinel->getSize()); + uint64_t p = getVA() + offset; + target->relocateOne(buf + offset, R_ARM_PREL31, s - p); + assert(size == offset + 8); +} + +bool ARMExidxSyntheticSection::classof(const SectionBase *d) { + return d->kind() == InputSectionBase::Synthetic && d->type == SHT_ARM_EXIDX; +} + +ThunkSection::ThunkSection(OutputSection *os, uint64_t off) : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, - Config->Wordsize, ".text.thunk") { - this->Parent = OS; - this->OutSecOff = Off; + config->wordsize, ".text.thunk") { + this->parent = os; + this->outSecOff = off; } -void ThunkSection::addThunk(Thunk *T) { - Thunks.push_back(T); - T->addSymbols(*this); +void ThunkSection::addThunk(Thunk *t) { + thunks.push_back(t); + t->addSymbols(*this); } -void ThunkSection::writeTo(uint8_t *Buf) { - for (Thunk *T : Thunks) - T->writeTo(Buf + T->Offset); +void ThunkSection::writeTo(uint8_t *buf) { + for (Thunk *t : thunks) + t->writeTo(buf + t->offset); } InputSection *ThunkSection::getTargetInputSection() const { - if (Thunks.empty()) + if (thunks.empty()) return nullptr; - const Thunk *T = Thunks.front(); - return T->getTargetInputSection(); + const Thunk *t = thunks.front(); + return t->getTargetInputSection(); } bool ThunkSection::assignOffsets() { - uint64_t Off = 0; - for (Thunk *T : Thunks) { - Off = alignTo(Off, T->Alignment); - T->setOffset(Off); - uint32_t Size = T->size(); - T->getThunkTargetSym()->Size = Size; - Off += Size; - } - bool Changed = Off != Size; - Size = Off; - return Changed; + uint64_t off = 0; + for (Thunk *t : thunks) { + off = alignTo(off, t->alignment); + t->setOffset(off); + uint32_t size = t->size(); + t->getThunkTargetSym()->size = size; + off += size; + } + bool changed = off != size; + size = off; + return changed; +} + +PPC32Got2Section::PPC32Got2Section() + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 4, ".got2") {} + +bool PPC32Got2Section::isNeeded() const { + // See the comment below. This is not needed if there is no other + // InputSection. + for (BaseCommand *base : getParent()->sectionCommands) + if (auto *isd = dyn_cast<InputSectionDescription>(base)) + for (InputSection *isec : isd->sections) + if (isec != this) + return true; + return false; +} + +void PPC32Got2Section::finalizeContents() { + // PPC32 may create multiple GOT sections for -fPIC/-fPIE, one per file in + // .got2 . This function computes outSecOff of each .got2 to be used in + // PPC32PltCallStub::writeTo(). The purpose of this empty synthetic section is + // to collect input sections named ".got2". + uint32_t offset = 0; + for (BaseCommand *base : getParent()->sectionCommands) + if (auto *isd = dyn_cast<InputSectionDescription>(base)) { + for (InputSection *isec : isd->sections) { + if (isec == this) + continue; + isec->file->ppc32Got2OutSecOff = offset; + offset += (uint32_t)isec->getSize(); + } + } } // If linking position-dependent code then the table will store the addresses @@ -3105,48 +3349,188 @@ bool ThunkSection::assignOffsets() { // allocated and filled in by the dynamic linker. PPC64LongBranchTargetSection::PPC64LongBranchTargetSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, - Config->Pic ? SHT_NOBITS : SHT_PROGBITS, 8, + config->isPic ? SHT_NOBITS : SHT_PROGBITS, 8, ".branch_lt") {} -void PPC64LongBranchTargetSection::addEntry(Symbol &Sym) { - assert(Sym.PPC64BranchltIndex == 0xffff); - Sym.PPC64BranchltIndex = Entries.size(); - Entries.push_back(&Sym); +void PPC64LongBranchTargetSection::addEntry(Symbol &sym) { + assert(sym.ppc64BranchltIndex == 0xffff); + sym.ppc64BranchltIndex = entries.size(); + entries.push_back(&sym); } size_t PPC64LongBranchTargetSection::getSize() const { - return Entries.size() * 8; + return entries.size() * 8; } -void PPC64LongBranchTargetSection::writeTo(uint8_t *Buf) { - assert(Target->GotPltEntrySize == 8); +void PPC64LongBranchTargetSection::writeTo(uint8_t *buf) { // If linking non-pic we have the final addresses of the targets and they get // written to the table directly. For pic the dynamic linker will allocate // the section and fill it it. - if (Config->Pic) + if (config->isPic) return; - for (const Symbol *Sym : Entries) { - assert(Sym->getVA()); + for (const Symbol *sym : entries) { + assert(sym->getVA()); // Need calls to branch to the local entry-point since a long-branch // must be a local-call. - write64(Buf, - Sym->getVA() + getPPC64GlobalEntryToLocalEntryOffset(Sym->StOther)); - Buf += Target->GotPltEntrySize; + write64(buf, + sym->getVA() + getPPC64GlobalEntryToLocalEntryOffset(sym->stOther)); + buf += 8; } } -bool PPC64LongBranchTargetSection::empty() const { +bool PPC64LongBranchTargetSection::isNeeded() const { // `removeUnusedSyntheticSections()` is called before thunk allocation which // is too early to determine if this section will be empty or not. We need // Finalized to keep the section alive until after thunk creation. Finalized // only gets set to true once `finalizeSections()` is called after thunk // creation. Becuase of this, if we don't create any long-branch thunks we end // up with an empty .branch_lt section in the binary. - return Finalized && Entries.empty(); + return !finalized || !entries.empty(); } -InStruct elf::In; +RISCVSdataSection::RISCVSdataSection() + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 1, ".sdata") {} + +bool RISCVSdataSection::isNeeded() const { + if (!ElfSym::riscvGlobalPointer) + return false; + + // __global_pointer$ is defined relative to .sdata . If the section does not + // exist, create a dummy one. + for (BaseCommand *base : getParent()->sectionCommands) + if (auto *isd = dyn_cast<InputSectionDescription>(base)) + for (InputSection *isec : isd->sections) + if (isec != this) + return false; + return true; +} + +static uint8_t getAbiVersion() { + // MIPS non-PIC executable gets ABI version 1. + if (config->emachine == EM_MIPS) { + if (!config->isPic && !config->relocatable && + (config->eflags & (EF_MIPS_PIC | EF_MIPS_CPIC)) == EF_MIPS_CPIC) + return 1; + return 0; + } + + if (config->emachine == EM_AMDGPU) { + uint8_t ver = objectFiles[0]->abiVersion; + for (InputFile *file : makeArrayRef(objectFiles).slice(1)) + if (file->abiVersion != ver) + error("incompatible ABI version: " + toString(file)); + return ver; + } + + return 0; +} + +template <typename ELFT> void elf::writeEhdr(uint8_t *buf, Partition &part) { + // For executable segments, the trap instructions are written before writing + // the header. Setting Elf header bytes to zero ensures that any unused bytes + // in header are zero-cleared, instead of having trap instructions. + memset(buf, 0, sizeof(typename ELFT::Ehdr)); + memcpy(buf, "\177ELF", 4); + + auto *eHdr = reinterpret_cast<typename ELFT::Ehdr *>(buf); + eHdr->e_ident[EI_CLASS] = config->is64 ? ELFCLASS64 : ELFCLASS32; + eHdr->e_ident[EI_DATA] = config->isLE ? ELFDATA2LSB : ELFDATA2MSB; + eHdr->e_ident[EI_VERSION] = EV_CURRENT; + eHdr->e_ident[EI_OSABI] = config->osabi; + eHdr->e_ident[EI_ABIVERSION] = getAbiVersion(); + eHdr->e_machine = config->emachine; + eHdr->e_version = EV_CURRENT; + eHdr->e_flags = config->eflags; + eHdr->e_ehsize = sizeof(typename ELFT::Ehdr); + eHdr->e_phnum = part.phdrs.size(); + eHdr->e_shentsize = sizeof(typename ELFT::Shdr); + + if (!config->relocatable) { + eHdr->e_phoff = sizeof(typename ELFT::Ehdr); + eHdr->e_phentsize = sizeof(typename ELFT::Phdr); + } +} + +template <typename ELFT> void elf::writePhdrs(uint8_t *buf, Partition &part) { + // Write the program header table. + auto *hBuf = reinterpret_cast<typename ELFT::Phdr *>(buf); + for (PhdrEntry *p : part.phdrs) { + hBuf->p_type = p->p_type; + hBuf->p_flags = p->p_flags; + hBuf->p_offset = p->p_offset; + hBuf->p_vaddr = p->p_vaddr; + hBuf->p_paddr = p->p_paddr; + hBuf->p_filesz = p->p_filesz; + hBuf->p_memsz = p->p_memsz; + hBuf->p_align = p->p_align; + ++hBuf; + } +} + +template <typename ELFT> +PartitionElfHeaderSection<ELFT>::PartitionElfHeaderSection() + : SyntheticSection(SHF_ALLOC, SHT_LLVM_PART_EHDR, 1, "") {} + +template <typename ELFT> +size_t PartitionElfHeaderSection<ELFT>::getSize() const { + return sizeof(typename ELFT::Ehdr); +} + +template <typename ELFT> +void PartitionElfHeaderSection<ELFT>::writeTo(uint8_t *buf) { + writeEhdr<ELFT>(buf, getPartition()); + + // Loadable partitions are always ET_DYN. + auto *eHdr = reinterpret_cast<typename ELFT::Ehdr *>(buf); + eHdr->e_type = ET_DYN; +} + +template <typename ELFT> +PartitionProgramHeadersSection<ELFT>::PartitionProgramHeadersSection() + : SyntheticSection(SHF_ALLOC, SHT_LLVM_PART_PHDR, 1, ".phdrs") {} + +template <typename ELFT> +size_t PartitionProgramHeadersSection<ELFT>::getSize() const { + return sizeof(typename ELFT::Phdr) * getPartition().phdrs.size(); +} + +template <typename ELFT> +void PartitionProgramHeadersSection<ELFT>::writeTo(uint8_t *buf) { + writePhdrs<ELFT>(buf, getPartition()); +} + +PartitionIndexSection::PartitionIndexSection() + : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".rodata") {} + +size_t PartitionIndexSection::getSize() const { + return 12 * (partitions.size() - 1); +} + +void PartitionIndexSection::finalizeContents() { + for (size_t i = 1; i != partitions.size(); ++i) + partitions[i].nameStrTab = mainPart->dynStrTab->addString(partitions[i].name); +} + +void PartitionIndexSection::writeTo(uint8_t *buf) { + uint64_t va = getVA(); + for (size_t i = 1; i != partitions.size(); ++i) { + write32(buf, mainPart->dynStrTab->getVA() + partitions[i].nameStrTab - va); + write32(buf + 4, partitions[i].elfHeader->getVA() - (va + 4)); + + SyntheticSection *next = + i == partitions.size() - 1 ? in.partEnd : partitions[i + 1].elfHeader; + write32(buf + 8, next->getVA() - partitions[i].elfHeader->getVA()); + + va += 12; + buf += 12; + } +} + +InStruct elf::in; + +std::vector<Partition> elf::partitions; +Partition *elf::mainPart; template GdbIndexSection *GdbIndexSection::create<ELF32LE>(); template GdbIndexSection *GdbIndexSection::create<ELF32BE>(); @@ -3168,11 +3552,6 @@ template void PltSection::addEntry<ELF32BE>(Symbol &Sym); template void PltSection::addEntry<ELF64LE>(Symbol &Sym); template void PltSection::addEntry<ELF64BE>(Symbol &Sym); -template void MipsGotSection::build<ELF32LE>(); -template void MipsGotSection::build<ELF32BE>(); -template void MipsGotSection::build<ELF64LE>(); -template void MipsGotSection::build<ELF64BE>(); - template class elf::MipsAbiFlagsSection<ELF32LE>; template class elf::MipsAbiFlagsSection<ELF32BE>; template class elf::MipsAbiFlagsSection<ELF64LE>; @@ -3213,12 +3592,27 @@ template class elf::SymbolTableSection<ELF32BE>; template class elf::SymbolTableSection<ELF64LE>; template class elf::SymbolTableSection<ELF64BE>; -template class elf::VersionTableSection<ELF32LE>; -template class elf::VersionTableSection<ELF32BE>; -template class elf::VersionTableSection<ELF64LE>; -template class elf::VersionTableSection<ELF64BE>; - template class elf::VersionNeedSection<ELF32LE>; template class elf::VersionNeedSection<ELF32BE>; template class elf::VersionNeedSection<ELF64LE>; template class elf::VersionNeedSection<ELF64BE>; + +template void elf::writeEhdr<ELF32LE>(uint8_t *Buf, Partition &Part); +template void elf::writeEhdr<ELF32BE>(uint8_t *Buf, Partition &Part); +template void elf::writeEhdr<ELF64LE>(uint8_t *Buf, Partition &Part); +template void elf::writeEhdr<ELF64BE>(uint8_t *Buf, Partition &Part); + +template void elf::writePhdrs<ELF32LE>(uint8_t *Buf, Partition &Part); +template void elf::writePhdrs<ELF32BE>(uint8_t *Buf, Partition &Part); +template void elf::writePhdrs<ELF64LE>(uint8_t *Buf, Partition &Part); +template void elf::writePhdrs<ELF64BE>(uint8_t *Buf, Partition &Part); + +template class elf::PartitionElfHeaderSection<ELF32LE>; +template class elf::PartitionElfHeaderSection<ELF32BE>; +template class elf::PartitionElfHeaderSection<ELF64LE>; +template class elf::PartitionElfHeaderSection<ELF64BE>; + +template class elf::PartitionProgramHeadersSection<ELF32LE>; +template class elf::PartitionProgramHeadersSection<ELF32BE>; +template class elf::PartitionProgramHeadersSection<ELF64LE>; +template class elf::PartitionProgramHeadersSection<ELF64BE>; |