diff --git a/lld/ELF/Arch/X86.cpp b/lld/ELF/Arch/X86.cpp --- a/lld/ELF/Arch/X86.cpp +++ b/lld/ELF/Arch/X86.cpp @@ -169,7 +169,7 @@ } void X86::writeGotPltHeader(uint8_t *Buf) const { - write32le(Buf, In.Dynamic->getVA()); + write32le(Buf, Main->Dynamic->getVA()); } void X86::writeGotPlt(uint8_t *Buf, const Symbol &S) const { diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp --- a/lld/ELF/Arch/X86_64.cpp +++ b/lld/ELF/Arch/X86_64.cpp @@ -129,7 +129,7 @@ // required, but it is documented in the psabi and the glibc dynamic linker // seems to use it (note that this is relevant for linking ld.so, not any // other program). - write64le(Buf, In.Dynamic->getVA()); + write64le(Buf, Main->Dynamic->getVA()); } void X86_64::writeGotPlt(uint8_t *Buf, const Symbol &S) const { diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1739,6 +1739,10 @@ (S->Name.startswith(".debug") || S->Name.startswith(".zdebug")); }); + // Now that the number of partitions is fixed, save a pointer to the main + // partition. + Main = &Partitions[0]; + // The Target instance handles target-specific stuff, such as applying // relocations or writing a PLT section. It also contains target-dependent // values such as a default image base address. diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -25,11 +25,14 @@ struct SectionPiece; class Defined; +struct Partition; class SyntheticSection; class MergeSyntheticSection; template class ObjFile; class OutputSection; +extern std::vector Partitions; + // This is the base class of all sections that lld handles. Some are sections in // input files, some are sections in the produced output file and some exist // just as a convenience for implementing special ways of combining some @@ -79,6 +82,7 @@ // collector, or 0 if this section is dead. Normally there is only one // partition, so this will either be 0 or 1. unsigned Partition : 8; + elf::Partition &getPartition() const; // These corresponds to the fields in Elf_Shdr. uint32_t Alignment; diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -413,16 +413,16 @@ void LinkerScript::discard(ArrayRef V) { for (InputSection *S : V) { - if (S == In.ShStrTab || S == In.RelaDyn || S == In.RelrDyn) + if (S == In.ShStrTab || S == Main->RelaDyn || S == Main->RelrDyn) error("discarding " + S->Name + " section is not allowed"); // You can discard .hash and .gnu.hash sections by linker scripts. Since // they are synthesized sections, we need to handle them differently than // other regular sections. - if (S == In.GnuHashTab) - In.GnuHashTab = nullptr; - if (S == In.HashTab) - In.HashTab = nullptr; + if (S == Main->GnuHashTab) + Main->GnuHashTab = nullptr; + if (S == Main->HashTab) + Main->HashTab = nullptr; S->Assigned = false; S->markDead(); @@ -902,6 +902,8 @@ if (IsEmpty && isDiscardable(*Sec)) { Sec->markDead(); Cmd = nullptr; + } else if (!Sec->isLive()) { + Sec->markLive(); } } diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -172,7 +172,7 @@ auto AddTlsReloc = [&](uint64_t Off, RelType Type, Symbol *Dest, bool Dyn) { if (Dyn) - In.RelaDyn->addReloc(Type, In.Got, Off, Dest); + Main->RelaDyn->addReloc(Type, In.Got, Off, Dest); else In.Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest}); }; @@ -221,7 +221,7 @@ Config->Shared) { if (In.Got->addDynTlsEntry(Sym)) { uint64_t Off = In.Got->getGlobalDynOffset(Sym); - In.RelaDyn->addReloc( + Main->RelaDyn->addReloc( {Target->TlsDescRel, In.Got, Off, !Sym.IsPreemptible, &Sym, 0}); } if (Expr != R_TLSDESC_CALL) @@ -241,8 +241,8 @@ if (Expr == R_TLSLD_HINT) return 1; if (In.Got->addTlsIndex()) - In.RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, - In.Got->getTlsIndexOff(), nullptr); + Main->RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, + In.Got->getTlsIndexOff(), nullptr); C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } @@ -278,13 +278,14 @@ if (Config->Shared) { if (In.Got->addDynTlsEntry(Sym)) { uint64_t Off = In.Got->getGlobalDynOffset(Sym); - In.RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, Off, &Sym); + Main->RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, Off, &Sym); // If the symbol is preemptible we need the dynamic linker to write // the offset too. uint64_t OffsetOff = Off + Config->Wordsize; if (Sym.IsPreemptible) - In.RelaDyn->addReloc(Target->TlsOffsetRel, In.Got, OffsetOff, &Sym); + Main->RelaDyn->addReloc(Target->TlsOffsetRel, In.Got, OffsetOff, + &Sym); else In.Got->Relocations.push_back( {R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Sym}); @@ -301,8 +302,8 @@ Offset, Addend, &Sym}); if (!Sym.isInGot()) { In.Got->addEntry(Sym); - In.RelaDyn->addReloc(Target->TlsGotRel, In.Got, Sym.getGotOffset(), - &Sym); + Main->RelaDyn->addReloc(Target->TlsGotRel, In.Got, Sym.getGotOffset(), + &Sym); } } else { C.Relocations.push_back( @@ -607,7 +608,7 @@ for (SharedSymbol *Sym : getSymbolsAt(SS)) replaceWithDefined(*Sym, Sec, 0, Sym->Size); - In.RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS); + Main->RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS); } // MIPS has an odd notion of "paired" relocations to calculate addends. @@ -813,19 +814,21 @@ static void addRelativeReloc(InputSectionBase *IS, uint64_t OffsetInSec, Symbol *Sym, int64_t Addend, RelExpr Expr, RelType Type) { + Partition &Part = IS->getPartition(); + // Add a relative relocation. If RelrDyn section is enabled, and the // relocation offset is guaranteed to be even, add the relocation to // the RelrDyn section, otherwise add it to the RelaDyn section. // RelrDyn sections don't support odd offsets. Also, RelrDyn sections // don't store the addend values, so we must write it to the relocated // address. - if (In.RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) { + if (Part.RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) { IS->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym}); - In.RelrDyn->Relocs.push_back({IS, OffsetInSec}); + Part.RelrDyn->Relocs.push_back({IS, OffsetInSec}); return; } - In.RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend, Expr, - Type); + Part.RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend, + Expr, Type); } template @@ -863,9 +866,9 @@ addRelativeReloc(In.Got, Off, &Sym, 0, R_ABS, Target->GotRel); return; } - In.RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel, In.Got, - Off, &Sym, 0, Sym.IsPreemptible ? R_ADDEND : R_ABS, - Target->GotRel); + Main->RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel, + In.Got, Off, &Sym, 0, + Sym.IsPreemptible ? R_ADDEND : R_ABS, Target->GotRel); } // Return true if we can define a symbol in the executable that @@ -918,7 +921,8 @@ addRelativeReloc(&Sec, Offset, &Sym, Addend, Expr, Type); return; } else if (RelType Rel = Target->getDynRel(Type)) { - In.RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, R_ADDEND, Type); + Sec.getPartition().RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, + R_ADDEND, Type); // MIPS ABI turns using of GOT and dynamic relocations inside out. // While regular ABI uses dynamic relocations to fill up GOT entries @@ -1140,7 +1144,7 @@ // direct relocation on through. if (Sym.isGnuIFunc() && Config->ZIfuncNoplt) { Sym.ExportDynamic = true; - In.RelaDyn->addReloc(Type, &Sec, Offset, &Sym, Addend, R_ADDEND, Type); + Main->RelaDyn->addReloc(Type, &Sec, Offset, &Sym, Addend, R_ADDEND, Type); return; } diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -31,7 +31,9 @@ namespace lld { namespace elf { class Defined; -struct Partition; +struct PhdrEntry; +class SymbolTableBaseSection; +class VersionNeedBaseSection; class SyntheticSection : public InputSection { public: @@ -422,7 +424,7 @@ UseSymVA(false), Addend(Addend), OutputSec(OutputSec) {} uint64_t getOffset() const; - uint32_t getSymIndex() const; + uint32_t getSymIndex(SymbolTableBaseSection *SymTab) const; // Computes the addend of the dynamic relocation. Note that this is not the // same as the Addend member variable as it also includes the symbol address @@ -431,7 +433,6 @@ RelType Type; -private: Symbol *Sym; const InputSectionBase *InputSec = nullptr; uint64_t OffsetInSec; @@ -490,9 +491,9 @@ size_t getRelativeRelocCount() const { return NumRelativeRelocs; } void finalizeContents() override; int32_t DynamicTag, SizeDynamicTag; + std::vector Relocs; protected: - std::vector Relocs; size_t NumRelativeRelocs = 0; }; @@ -769,6 +770,7 @@ private: enum { EntrySize = 28 }; void writeOne(uint8_t *Buf, uint32_t Index, StringRef Name, size_t NameOff); + StringRef getFileDefName(); unsigned FileDefNameOff; }; @@ -1053,57 +1055,99 @@ bool Finalized = false; }; +template +class PartitionElfHeaderSection : public SyntheticSection { +public: + PartitionElfHeaderSection(); + size_t getSize() const override; + void writeTo(uint8_t *Buf) override; +}; + +template +class PartitionProgramHeadersSection : public SyntheticSection { +public: + PartitionProgramHeadersSection(); + size_t getSize() const override; + void writeTo(uint8_t *Buf) override; +}; + +class PartitionIndexSection : public SyntheticSection { +public: + PartitionIndexSection(); + size_t getSize() const override; + void finalizeContents() override; + void writeTo(uint8_t *Buf) override; +}; + InputSection *createInterpSection(); MergeInputSection *createCommentSection(); template void splitSections(); void mergeSections(); +template void writeEhdr(uint8_t *Buf, Partition &Part); +template void writePhdrs(uint8_t *Buf, Partition &Part); + Defined *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, uint64_t Size, InputSectionBase &Section); void addVerneed(Symbol *SS); -extern std::vector Partitions; - // Linker generated per-partition sections. struct Partition { StringRef Name; - unsigned getNumber() const { return this - &Partitions[0] + 1; } -}; + uint64_t NameStrTab; + + SyntheticSection *ElfHeader; + SyntheticSection *ProgramHeaders; + std::vector Phdrs; -// Linker generated sections which can be used as inputs. -struct InStruct { - InputSection *ARMAttributes; ARMExidxSyntheticSection *ARMExidx; - BssSection *Bss; - BssSection *BssRelRo; BuildIdSection *BuildId; - EhFrameHeader *EhFrameHdr; - EhFrameSection *EhFrame; SyntheticSection *Dynamic; StringTableSection *DynStrTab; SymbolTableBaseSection *DynSymTab; + EhFrameHeader *EhFrameHdr; + EhFrameSection *EhFrame; GnuHashTableSection *GnuHashTab; HashTableSection *HashTab; + RelocationBaseSection *RelaDyn; + RelrBaseSection *RelrDyn; + VersionDefinitionSection *VerDef; + SyntheticSection *VerNeed; + VersionTableSection *VerSym; + + unsigned getNumber() const { return this - &Partitions[0] + 1; } +}; + +extern Partition *Main; + +inline Partition &SectionBase::getPartition() const { + assert(isLive()); + return Partitions[Partition - 1]; +} + +// Linker generated sections which can be used as inputs and are not specific to +// a partition. +struct InStruct { + InputSection *ARMAttributes; + BssSection *Bss; + BssSection *BssRelRo; GotSection *Got; GotPltSection *GotPlt; IgotPltSection *IgotPlt; PPC64LongBranchTargetSection *PPC64LongBranchTarget; MipsGotSection *MipsGot; MipsRldMapSection *MipsRldMap; + SyntheticSection *PartEnd; + SyntheticSection *PartIndex; PltSection *Plt; PltSection *Iplt; - RelocationBaseSection *RelaDyn; - RelrBaseSection *RelrDyn; RelocationBaseSection *RelaPlt; RelocationBaseSection *RelaIplt; StringTableSection *ShStrTab; StringTableSection *StrTab; SymbolTableBaseSection *SymTab; SymtabShndxSection *SymTabShndx; - VersionDefinitionSection *VerDef; - SyntheticSection *VerNeed; - VersionTableSection *VerSym; }; extern InStruct In; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -355,10 +355,11 @@ const RelTy &Rel = Rels[FirstRelI]; Symbol &B = Sec->template getFile()->getRelocTargetSym(Rel); - // FDEs for garbage-collected or merged-by-ICF sections are dead. + // FDEs for garbage-collected or merged-by-ICF sections, or sections in + // another partition, are dead. if (auto *D = dyn_cast(&B)) if (SectionBase *Sec = D->Section) - return Sec->isLive(); + return Sec->Partition == Partition; return false; } @@ -453,7 +454,7 @@ uint8_t *Buf = Out::BufferStart + getParent()->Offset + OutSecOff; std::vector Ret; - uint64_t VA = In.EhFrameHdr->getVA(); + uint64_t VA = getPartition().EhFrameHdr->getVA(); for (CieRecord *Rec : CieRecords) { uint8_t Enc = getFdeEncoding(Rec->Cie); for (EhSectionPiece *Fde : Rec->Fdes) { @@ -537,8 +538,8 @@ for (EhInputSection *S : Sections) S->relocateAlloc(Buf, nullptr); - if (In.EhFrameHdr && In.EhFrameHdr->getParent()) - In.EhFrameHdr->write(); + if (getPartition().EhFrameHdr && getPartition().EhFrameHdr->getParent()) + getPartition().EhFrameHdr->write(); } GotSection::GotSection() @@ -889,7 +890,7 @@ Symbol *S = P.first; uint64_t Offset = P.second * Config->Wordsize; if (S->IsPreemptible) - In.RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S); + Main->RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S); } for (std::pair &P : Got.DynTlsSymbols) { Symbol *S = P.first; @@ -897,7 +898,7 @@ if (S == nullptr) { if (!Config->Pic) continue; - In.RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S); + Main->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 @@ -905,13 +906,13 @@ // thread-locals that have been marked as local through a linker script) if (!S->IsPreemptible && !Config->Pic) continue; - In.RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S); + Main->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) continue; Offset += Config->Wordsize; - In.RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S); + Main->RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S); } } @@ -923,7 +924,7 @@ // Dynamic relocations for "global" entries. for (const std::pair &P : Got.Global) { uint64_t Offset = P.second * Config->Wordsize; - In.RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first); + Main->RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first); } if (!Config->Pic) continue; @@ -933,14 +934,14 @@ 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)}); + Main->RelaDyn->addReloc({Target->RelativeRel, this, Offset, L.first, + int64_t(PI * 0x10000)}); } } for (const std::pair &P : Got.Local16) { uint64_t Offset = P.second * Config->Wordsize; - In.RelaDyn->addReloc({Target->RelativeRel, this, Offset, true, - P.first.first, P.first.second}); + Main->RelaDyn->addReloc({Target->RelativeRel, this, Offset, true, + P.first.first, P.first.second}); } } } @@ -1195,20 +1196,30 @@ // Add remaining entries to complete .dynamic contents. template void DynamicSection::finalizeContents() { + elf::Partition &Part = getPartition(); + bool IsMain = Part.Name.empty(); + for (StringRef S : Config->FilterList) - addInt(DT_FILTER, In.DynStrTab->addString(S)); + addInt(DT_FILTER, Part.DynStrTab->addString(S)); for (StringRef S : Config->AuxiliaryList) - addInt(DT_AUXILIARY, In.DynStrTab->addString(S)); + addInt(DT_AUXILIARY, Part.DynStrTab->addString(S)); if (!Config->Rpath.empty()) addInt(Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH, - In.DynStrTab->addString(Config->Rpath)); + Part.DynStrTab->addString(Config->Rpath)); for (SharedFile *File : SharedFiles) if (File->IsNeeded) - addInt(DT_NEEDED, In.DynStrTab->addString(File->SoName)); - if (!Config->SoName.empty()) - addInt(DT_SONAME, In.DynStrTab->addString(Config->SoName)); + 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; @@ -1256,12 +1267,12 @@ if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic) addInt(DT_DEBUG, 0); - if (OutputSection *Sec = In.DynStrTab->getParent()) + if (OutputSection *Sec = Part.DynStrTab->getParent()) this->Link = Sec->SectionIndex; - if (In.RelaDyn->isNeeded()) { - 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, @@ -1271,16 +1282,16 @@ // 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(); + size_t NumRelativeRels = Part.RelaDyn->getRelativeRelocCount(); if (Config->ZCombreloc && NumRelativeRels) addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels); } } - if (In.RelrDyn && !In.RelrDyn->Relocs.empty()) { + if (Part.RelrDyn && !Part.RelrDyn->Relocs.empty()) { addInSec(Config->UseAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR, - In.RelrDyn); + Part.RelrDyn); addSize(Config->UseAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ, - In.RelrDyn->getParent()); + Part.RelrDyn->getParent()); addInt(Config->UseAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT, sizeof(Elf_Relr)); } @@ -1290,7 +1301,7 @@ // 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 // .rel[a].plt section. - if (In.RelaPlt->getParent()->isLive()) { + if (IsMain && In.RelaPlt->getParent()->isLive()) { addInSec(DT_JMPREL, In.RelaPlt); Entries.push_back({DT_PLTRELSZ, addPltRelSz}); switch (Config->EMachine) { @@ -1307,46 +1318,48 @@ addInt(DT_PLTREL, Config->IsRela ? DT_RELA : DT_REL); } - 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()); + 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 (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 (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); } - 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 || In.VerDef) - addInSec(DT_VERSYM, In.VerSym); - if (In.VerDef) { - addInSec(DT_VERDEF, In.VerDef); + 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, In.VerNeed); + addInSec(DT_VERNEED, Part.VerNeed); unsigned NeedNum = 0; for (SharedFile *F : SharedFiles) if (!F->Vernauxs.empty()) @@ -1358,14 +1371,14 @@ 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_SYMTABNO, Part.DynSymTab->getNumSymbols()); add(DT_MIPS_LOCAL_GOTNO, [] { return In.MipsGot->getLocalEntriesNum(); }); if (const Symbol *B = In.MipsGot->getFirstGlobalEntry()) addInt(DT_MIPS_GOTSYM, B->DynsymIndex); else - addInt(DT_MIPS_GOTSYM, In.DynSymTab->getNumSymbols()); + addInt(DT_MIPS_GOTSYM, Part.DynSymTab->getNumSymbols()); addInSec(DT_PLTGOT, In.MipsGot); if (In.MipsRldMap) { if (!Config->Pie) @@ -1415,9 +1428,9 @@ return getMipsPageAddr(OutputSec->Addr) + Addend; } -uint32_t DynamicReloc::getSymIndex() const { +uint32_t DynamicReloc::getSymIndex(SymbolTableBaseSection *SymTab) const { if (Sym && !UseSymVA) - return Sym->DynsymIndex; + return SymTab->getSymbolIndex(Sym); return 0; } @@ -1451,11 +1464,13 @@ } 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. - if (In.DynSymTab && In.DynSymTab->getParent()) - getParent()->Link = In.DynSymTab->getParent()->SectionIndex; + if (SymTab && SymTab->getParent()) + getParent()->Link = SymTab->getParent()->SectionIndex; else getParent()->Link = 0; @@ -1471,12 +1486,13 @@ Config->Wordsize, ".relr.dyn") {} template -static void encodeDynamicReloc(typename ELFT::Rela *P, +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(), Rel.Type, Config->IsMips64EL); + P->setSymbolAndType(Rel.getSymIndex(SymTab), Rel.Type, Config->IsMips64EL); } template @@ -1489,19 +1505,22 @@ } template void RelocationSection::writeTo(uint8_t *Buf) { + SymbolTableBaseSection *SymTab = getPartition().DynSymTab; + // 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(), - A.getOffset()) < - std::make_tuple(B.Type != Target->RelativeRel, B.getSymIndex(), - B.getOffset()); - }); + 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(reinterpret_cast(Buf), Rel); + encodeDynamicReloc(SymTab, reinterpret_cast(Buf), Rel); Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); } } @@ -1579,7 +1598,7 @@ for (const DynamicReloc &Rel : Relocs) { Elf_Rela R; - encodeDynamicReloc(&R, Rel); + encodeDynamicReloc(getPartition().DynSymTab, &R, Rel); if (R.getType(Config->IsMips64EL) == Target->RelativeRel) Relatives.push_back(R); @@ -1827,16 +1846,20 @@ // Because the first symbol entry is a null entry, 1 is the first. 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); + 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 == Main->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 @@ -1879,8 +1902,11 @@ } size_t SymbolTableBaseSection::getSymbolIndex(Symbol *Sym) { - // Initializes symbol lookup tables lazily. This is used only - // for -r or -emit-relocs. + if (this == Main->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; @@ -1933,6 +1959,7 @@ 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; @@ -1949,14 +1976,17 @@ ESym->st_other |= Sym->StOther & 0xe0; ESym->st_name = Ent.StrTabOffset; - ESym->st_shndx = getSymSectionIndex(Ent.Sym); + 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) + if (ESym->st_shndx == SHN_UNDEF || !IsDefinedHere) ESym->st_size = 0; else ESym->st_size = Sym->getSize(); @@ -2081,7 +2111,7 @@ } void GnuHashTableSection::finalizeContents() { - if (OutputSection *Sec = In.DynSymTab->getParent()) + if (OutputSection *Sec = getPartition().DynSymTab->getParent()) getParent()->Link = Sec->SectionIndex; // Computes bloom filter size in word size. We want to allocate 12 @@ -2107,7 +2137,7 @@ // Write a header. write32(Buf, NBuckets); - write32(Buf + 4, In.DynSymTab->getNumSymbols() - Symbols.size()); + write32(Buf + 4, getPartition().DynSymTab->getNumSymbols() - Symbols.size()); write32(Buf + 8, MaskWords); write32(Buf + 12, Shift2); Buf += 16; @@ -2155,7 +2185,8 @@ continue; // Write a hash bucket. Hash buckets contain indices in the following hash // value table. - write32(Buckets + I->BucketIdx, I->Sym->DynsymIndex); + write32(Buckets + I->BucketIdx, + getPartition().DynSymTab->getSymbolIndex(I->Sym)); OldBucket = I->BucketIdx; } } @@ -2174,8 +2205,8 @@ // We cannot use 'auto' for Mid because GCC 6.1 cannot deduce // its type correctly. std::vector::iterator Mid = - std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) { - return !S.Sym->isDefined(); + 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 @@ -2214,22 +2245,26 @@ } void HashTableSection::finalizeContents() { - if (OutputSection *Sec = In.DynSymTab->getParent()) + SymbolTableBaseSection *SymTab = getPartition().DynSymTab; + + if (OutputSection *Sec = SymTab->getParent()) getParent()->Link = Sec->SectionIndex; - unsigned NumEntries = 2; // nbucket and nchain. - NumEntries += In.DynSymTab->getNumSymbols(); // The chain entries. + unsigned NumEntries = 2; // nbucket and nchain. + NumEntries += SymTab->getNumSymbols(); // The chain entries. // Create as many buckets as there are symbols. - NumEntries += In.DynSymTab->getNumSymbols(); + NumEntries += SymTab->getNumSymbols(); this->Size = NumEntries * 4; } void HashTableSection::writeTo(uint8_t *Buf) { + SymbolTableBaseSection *SymTab = getPartition().DynSymTab; + // See comment in GnuHashTableSection::writeTo. memset(Buf, 0, Size); - unsigned NumSymbols = In.DynSymTab->getNumSymbols(); + unsigned NumSymbols = SymTab->getNumSymbols(); uint32_t *P = reinterpret_cast(Buf); write32(P++, NumSymbols); // nbucket @@ -2238,7 +2273,7 @@ uint32_t *Buckets = P; uint32_t *Chains = P + NumSymbols; - for (const SymbolTableEntry &S : In.DynSymTab->getSymbols()) { + for (const SymbolTableEntry &S : SymTab->getSymbols()) { Symbol *Sym = S.Sym; StringRef Name = Sym->getName(); unsigned I = Sym->DynsymIndex; @@ -2616,13 +2651,14 @@ uint8_t *Buf = Out::BufferStart + getParent()->Offset + OutSecOff; using FdeData = EhFrameSection::FdeData; - std::vector Fdes = In.EhFrame->getFdeData(); + std::vector 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 + 4, + getPartition().EhFrame->getParent()->Addr - this->getVA() - 4); write32(Buf + 8, Fdes.size()); Buf += 12; @@ -2635,27 +2671,31 @@ 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::isNeeded() const { return In.EhFrame->isNeeded(); } +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() { +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()); + FileDefNameOff = getPartition().DynStrTab->addString(getFileDefName()); for (VersionDefinition &V : Config->VersionDefinitions) - V.NameOff = In.DynStrTab->addString(V.Name); + V.NameOff = getPartition().DynStrTab->addString(V.Name); - if (OutputSection *Sec = In.DynStrTab->getParent()) + 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 @@ -2708,23 +2748,23 @@ 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; } size_t VersionTableSection::getSize() const { - return (In.DynSymTab->getSymbols().size() + 1) * 2; + return (getPartition().DynSymTab->getSymbols().size() + 1) * 2; } void VersionTableSection::writeTo(uint8_t *Buf) { Buf += 2; - for (const SymbolTableEntry &S : In.DynSymTab->getSymbols()) { + for (const SymbolTableEntry &S : getPartition().DynSymTab->getSymbols()) { write16(Buf, S.Sym->VersionId); Buf += 2; } } bool VersionTableSection::isNeeded() const { - return In.VerDef || In.VerNeed->isNeeded(); + return getPartition().VerDef || getPartition().VerNeed->isNeeded(); } void elf::addVerneed(Symbol *SS) { @@ -2758,7 +2798,7 @@ continue; Verneeds.emplace_back(); Verneed &VN = Verneeds.back(); - VN.NameStrTab = In.DynStrTab->addString(F->SoName); + VN.NameStrTab = getPartition().DynStrTab->addString(F->SoName); for (unsigned I = 0; I != F->Vernauxs.size(); ++I) { if (F->Vernauxs[I] == 0) continue; @@ -2766,12 +2806,12 @@ reinterpret_cast(F->Verdefs[I]); VN.Vernauxs.push_back( {Verdef->vd_hash, F->Vernauxs[I], - In.DynStrTab->addString(F->getStringTable().data() + - Verdef->getAux()->vda_name)}); + getPartition().DynStrTab->addString(F->getStringTable().data() + + Verdef->getAux()->vda_name)}); } } - if (OutputSection *Sec = In.DynStrTab->getParent()) + if (OutputSection *Sec = getPartition().DynStrTab->getParent()) getParent()->Link = Sec->SectionIndex; getParent()->Info = Verneeds.size(); } @@ -3255,9 +3295,131 @@ return !Finalized || !Entries.empty(); } +static uint8_t getAbiVersion() { + // MIPS non-PIC executable gets ABI version 1. + if (Config->EMachine == EM_MIPS) { + if (!Config->Pic && !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 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(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 void elf::writePhdrs(uint8_t *Buf, Partition &Part) { + // Write the program header table. + auto *HBuf = reinterpret_cast(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 +PartitionElfHeaderSection::PartitionElfHeaderSection() + : SyntheticSection(SHF_ALLOC, SHT_LLVM_PART_EHDR, 1, "") {} + +template +size_t PartitionElfHeaderSection::getSize() const { + return sizeof(typename ELFT::Ehdr); +} + +template +void PartitionElfHeaderSection::writeTo(uint8_t *Buf) { + writeEhdr(Buf, getPartition()); + + // Loadable partitions are always ET_DYN. + auto *EHdr = reinterpret_cast(Buf); + EHdr->e_type = ET_DYN; +} + +template +PartitionProgramHeadersSection::PartitionProgramHeadersSection() + : SyntheticSection(SHF_ALLOC, SHT_LLVM_PART_PHDR, 1, ".phdrs") {} + +template +size_t PartitionProgramHeadersSection::getSize() const { + return sizeof(typename ELFT::Phdr) * getPartition().Phdrs.size(); +} + +template +void PartitionProgramHeadersSection::writeTo(uint8_t *Buf) { + writePhdrs(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 = Main->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, Main->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 elf::Partitions; +Partition *elf::Main; template GdbIndexSection *GdbIndexSection::create(); template GdbIndexSection *GdbIndexSection::create(); @@ -3323,3 +3485,23 @@ template class elf::VersionNeedSection; template class elf::VersionNeedSection; template class elf::VersionNeedSection; + +template void elf::writeEhdr(uint8_t *Buf, Partition &Part); +template void elf::writeEhdr(uint8_t *Buf, Partition &Part); +template void elf::writeEhdr(uint8_t *Buf, Partition &Part); +template void elf::writeEhdr(uint8_t *Buf, Partition &Part); + +template void elf::writePhdrs(uint8_t *Buf, Partition &Part); +template void elf::writePhdrs(uint8_t *Buf, Partition &Part); +template void elf::writePhdrs(uint8_t *Buf, Partition &Part); +template void elf::writePhdrs(uint8_t *Buf, Partition &Part); + +template class elf::PartitionElfHeaderSection; +template class elf::PartitionElfHeaderSection; +template class elf::PartitionElfHeaderSection; +template class elf::PartitionElfHeaderSection; + +template class elf::PartitionProgramHeadersSection; +template class elf::PartitionProgramHeadersSection; +template class elf::PartitionProgramHeadersSection; +template class elf::PartitionProgramHeadersSection; diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -278,9 +278,10 @@ return; In.PPC64LongBranchTarget->addEntry(Dest); - In.RelaDyn->addReloc({Target->RelativeRel, In.PPC64LongBranchTarget, - Dest.getPPC64LongBranchOffset(), true, &Dest, - getPPC64GlobalEntryToLocalEntryOffset(Dest.StOther)}); + Main->RelaDyn->addReloc( + {Target->RelativeRel, In.PPC64LongBranchTarget, + Dest.getPPC64LongBranchOffset(), true, &Dest, + getPPC64GlobalEntryToLocalEntryOffset(Dest.StOther)}); } }; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -61,13 +61,13 @@ void checkExecuteOnly(); void setReservedSymbolSections(); - std::vector createPhdrs(); - void removeEmptyPTLoad(); - void addPhdrForSection(std::vector &Phdrs, unsigned ShType, - unsigned PType, unsigned PFlags); + std::vector createPhdrs(Partition &Part); + void removeEmptyPTLoad(std::vector &PhdrEntry); + void addPhdrForSection(Partition &Part, unsigned ShType, unsigned PType, + unsigned PFlags); void assignFileOffsets(); void assignFileOffsetsBinary(); - void setPhdrs(); + void setPhdrs(Partition &Part); void checkSections(); void fixSectionAlignments(); void openFile(); @@ -83,8 +83,6 @@ void addStartEndSymbols(); void addStartStopSymbols(OutputSection *Sec); - std::vector Phdrs; - uint64_t FileSize; uint64_t SectionHeaderOff; }; @@ -144,7 +142,8 @@ template void elf::writeResult() { Writer().run(); } -template void Writer::removeEmptyPTLoad() { +template +void Writer::removeEmptyPTLoad(std::vector &Phdrs) { llvm::erase_if(Phdrs, [&](const PhdrEntry *P) { if (P->p_type != PT_LOAD) return false; @@ -155,16 +154,39 @@ }); } +template static void copySectionsIntoPartitions() { + std::vector NewSections; + for (unsigned Part = 2; Part != Partitions.size() + 1; ++Part) { + for (InputSectionBase *S : InputSections) { + if (!(S->Flags & SHF_ALLOC) || !S->isLive()) + continue; + InputSectionBase *Copy; + if (S->Type == SHT_NOTE) + Copy = make(cast(*S)); + else if (auto *ES = dyn_cast(S)) + Copy = make(*ES); + else + continue; + Copy->Partition = Part; + NewSections.push_back(Copy); + } + } + + InputSections.insert(InputSections.end(), NewSections.begin(), + NewSections.end()); +} + template static void combineEhSections() { for (InputSectionBase *&S : InputSections) { if (!S->isLive()) continue; + Partition &Part = S->getPartition(); if (auto *ES = dyn_cast(S)) { - In.EhFrame->addSection(ES); + Part.EhFrame->addSection(ES); S = nullptr; - } else if (S->kind() == SectionBase::Regular && In.ARMExidx && - In.ARMExidx->addSection(cast(S))) { + } else if (S->kind() == SectionBase::Regular && Part.ARMExidx && + Part.ARMExidx->addSection(cast(S))) { S = nullptr; } } @@ -277,10 +299,10 @@ ElfSym::Edata2 = Add("_edata", -1); } -static OutputSection *findSection(StringRef Name) { +static OutputSection *findSection(StringRef Name, unsigned Partition = 1) { for (BaseCommand *Base : Script->SectionCommands) if (auto *Sec = dyn_cast(Base)) - if (Sec->Name == Name) + if (Sec->Name == Name && Sec->Partition == Partition) return Sec; return nullptr; } @@ -293,41 +315,25 @@ auto Add = [](InputSectionBase *Sec) { InputSections.push_back(Sec); }; - In.DynStrTab = make(".dynstr", true); - In.Dynamic = make>(); - if (Config->AndroidPackDynRelocs) { - In.RelaDyn = make>( - Config->IsRela ? ".rela.dyn" : ".rel.dyn"); - } else { - In.RelaDyn = make>( - Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc); - } In.ShStrTab = make(".shstrtab", false); Out::ProgramHeaders = make("", 0, SHF_ALLOC); Out::ProgramHeaders->Alignment = Config->Wordsize; - if (needsInterpSection()) - Add(createInterpSection()); - if (Config->Strip != StripPolicy::All) { In.StrTab = make(".strtab", false); In.SymTab = make>(*In.StrTab); In.SymTabShndx = make(); } - if (Config->BuildId != BuildIdKind::None) { - In.BuildId = make(); - Add(In.BuildId); - } - In.Bss = make(".bss", 0, 1); Add(In.Bss); // If there is a SECTIONS command and a .data.rel.ro section name use name // .data.rel.ro.bss so that we match in the .data.rel.ro output section. // This makes sure our relro is contiguous. - bool HasDataRelRo = Script->HasSectionsCommand && findSection(".data.rel.ro"); + bool HasDataRelRo = + Script->HasSectionsCommand && findSection(".data.rel.ro", 0); In.BssRelRo = make(HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1); Add(In.BssRelRo); @@ -346,39 +352,105 @@ Add(Sec); } - if (Config->HasDynSymTab) { - In.DynSymTab = make>(*In.DynStrTab); - Add(In.DynSymTab); + for (Partition &Part : Partitions) { + auto Add = [&](InputSectionBase *Sec) { + Sec->Partition = Part.getNumber(); + InputSections.push_back(Sec); + }; - In.VerSym = make(); - Add(In.VerSym); + if (!Part.Name.empty()) { + Part.ElfHeader = make>(); + Part.ElfHeader->Name = Part.Name; + Add(Part.ElfHeader); - if (!Config->VersionDefinitions.empty()) { - In.VerDef = make(); - Add(In.VerDef); + Part.ProgramHeaders = make>(); + Add(Part.ProgramHeaders); } - In.VerNeed = make>(); - Add(In.VerNeed); + if (Config->BuildId != BuildIdKind::None) { + Part.BuildId = make(); + Add(Part.BuildId); + } - if (Config->GnuHash) { - In.GnuHashTab = make(); - Add(In.GnuHashTab); + Part.DynStrTab = make(".dynstr", true); + Part.DynSymTab = make>(*Part.DynStrTab); + Part.Dynamic = make>(); + if (Config->AndroidPackDynRelocs) { + Part.RelaDyn = make>( + Config->IsRela ? ".rela.dyn" : ".rel.dyn"); + } else { + Part.RelaDyn = make>( + Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc); } - if (Config->SysvHash) { - In.HashTab = make(); - Add(In.HashTab); + if (needsInterpSection()) + Add(createInterpSection()); + + if (Config->HasDynSymTab) { + Part.DynSymTab = make>(*Part.DynStrTab); + Add(Part.DynSymTab); + + Part.VerSym = make(); + Add(Part.VerSym); + + if (!Config->VersionDefinitions.empty()) { + Part.VerDef = make(); + Add(Part.VerDef); + } + + Part.VerNeed = make>(); + Add(Part.VerNeed); + + if (Config->GnuHash) { + Part.GnuHashTab = make(); + Add(Part.GnuHashTab); + } + + if (Config->SysvHash) { + Part.HashTab = make(); + Add(Part.HashTab); + } + + Add(Part.Dynamic); + Add(Part.DynStrTab); + Add(Part.RelaDyn); + } + + if (Config->RelrPackDynRelocs) { + Part.RelrDyn = make>(); + Add(Part.RelrDyn); + } + + if (!Config->Relocatable) { + if (Config->EhFrameHdr) { + Part.EhFrameHdr = make(); + Add(Part.EhFrameHdr); + } + Part.EhFrame = make(); + Add(Part.EhFrame); } - Add(In.Dynamic); - Add(In.DynStrTab); - Add(In.RelaDyn); + if (Config->EMachine == EM_ARM && !Config->Relocatable) { + // The ARMExidxsyntheticsection replaces all the individual .ARM.exidx + // InputSections. + Part.ARMExidx = make(); + Add(Part.ARMExidx); + } } - if (Config->RelrPackDynRelocs) { - In.RelrDyn = make>(); - Add(In.RelrDyn); + if (Partitions.size() != 1) { + // Create the partition end marker. This needs to be in partition number 255 + // so that it is sorted after all other partitions. It also has other + // special handling (see createPhdrs()). + In.PartEnd = make(".part.end", Config->MaxPageSize, 1); + In.PartEnd->Partition = 255; + Add(In.PartEnd); + + In.PartIndex = make(); + addOptionalRegular("__part_index_begin", In.PartIndex, 0); + addOptionalRegular("__part_index_end", In.PartIndex, + In.PartIndex->getSize()); + Add(In.PartIndex); } // Add .got. MIPS' .got is so different from the other archs, @@ -445,15 +517,6 @@ if (Config->Relocatable) Add(make()); - if (!Config->Relocatable) { - if (Config->EhFrameHdr) { - In.EhFrameHdr = make(); - Add(In.EhFrameHdr); - } - In.EhFrame = make(); - Add(In.EhFrame); - } - if (In.SymTab) Add(In.SymTab); if (In.SymTabShndx) @@ -461,17 +524,14 @@ Add(In.ShStrTab); if (In.StrTab) Add(In.StrTab); - - if (Config->EMachine == EM_ARM && !Config->Relocatable) { - // The ARMExidxsyntheticsection replaces all the individual .ARM.exidx - // InputSections. - In.ARMExidx = make(); - Add(In.ARMExidx); - } } // The main function of the writer. template void Writer::run() { + // Make copies of any input sections that need to be copied into each + // partition. + copySectionsIntoPartitions(); + // Create linker-synthesized sections such as .got or .plt. // Such sections are of type input section. createSyntheticSections(); @@ -514,19 +574,21 @@ for (OutputSection *Sec : OutputSections) Sec->maybeCompress(); - Script->allocateHeaders(Phdrs); + Script->allocateHeaders(Main->Phdrs); // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a // 0 sized region. This has to be done late since only after assignAddresses // we know the size of the sections. - removeEmptyPTLoad(); + for (Partition &Part : Partitions) + removeEmptyPTLoad(Part.Phdrs); if (!Config->OFormatBinary) assignFileOffsets(); else assignFileOffsetsBinary(); - setPhdrs(); + for (Partition &Part : Partitions) + setPhdrs(Part); if (Config->Relocatable) for (OutputSection *Sec : OutputSections) @@ -741,7 +803,7 @@ // .dynamic section contains data for the dynamic linker, and // there's no need to write to it at runtime, so it's better to put // it into RELRO. - if (Sec == In.Dynamic->getParent()) + if (Sec->Name == ".dynamic") return true; // Sections with some special names are put into RELRO. This is a @@ -762,9 +824,11 @@ // * It is easy to check if a give branch was taken. // * It is easy two see how similar two ranks are (see getRankProximity). enum RankFlags { - RF_NOT_ADDR_SET = 1 << 25, - RF_NOT_ALLOC = 1 << 24, - RF_PARTITION = 1 << 16, // Partition number (8 bits) + RF_NOT_ADDR_SET = 1 << 27, + RF_NOT_ALLOC = 1 << 26, + RF_PARTITION = 1 << 18, // Partition number (8 bits) + RF_NOT_PART_EHDR = 1 << 17, + RF_NOT_PART_PHDR = 1 << 16, RF_NOT_INTERP = 1 << 15, RF_NOT_NOTE = 1 << 14, RF_WRITE = 1 << 13, @@ -797,6 +861,14 @@ if (!(Sec->Flags & SHF_ALLOC)) return Rank | RF_NOT_ALLOC; + if (Sec->Type == SHT_LLVM_PART_EHDR) + return Rank; + Rank |= RF_NOT_PART_EHDR; + + if (Sec->Type == SHT_LLVM_PART_PHDR) + return Rank; + Rank |= RF_NOT_PART_PHDR; + // Put .interp first because some loaders want to see that section // on the first page of the executable file when loaded into memory. if (Sec->Name == ".interp") @@ -957,11 +1029,13 @@ for (InputSectionBase *IS : InputSections) if (IS->isLive() && isa(IS) && (IS->Flags & SHF_ALLOC)) Fn(*IS); - for (EhInputSection *ES : In.EhFrame->Sections) - Fn(*ES); - if (In.ARMExidx && In.ARMExidx->isLive()) - for (InputSection *Ex : In.ARMExidx->ExidxSections) - Fn(*Ex); + for (Partition &Part : Partitions) { + for (EhInputSection *ES : Part.EhFrame->Sections) + Fn(*ES); + if (Part.ARMExidx && Part.ARMExidx->isLive()) + for (InputSection *Ex : Part.ARMExidx->ExidxSections) + Fn(*Ex); + } } // This function generates assignments for predefined symbols (e.g. _end or @@ -990,12 +1064,14 @@ PhdrEntry *Last = nullptr; PhdrEntry *LastRO = nullptr; - for (PhdrEntry *P : Phdrs) { - if (P->p_type != PT_LOAD) - continue; - Last = P; - if (!(P->p_flags & PF_W)) - LastRO = P; + for (Partition &Part : Partitions) { + for (PhdrEntry *P : Part.Phdrs) { + if (P->p_type != PT_LOAD) + continue; + Last = P; + if (!(P->p_flags & PF_W)) + LastRO = P; + } } if (LastRO) { @@ -1494,10 +1570,11 @@ if (In.MipsGot) In.MipsGot->updateAllocSize(); - Changed |= In.RelaDyn->updateAllocSize(); - - if (In.RelrDyn) - Changed |= In.RelrDyn->updateAllocSize(); + for (Partition &Part : Partitions) { + Changed |= Part.RelaDyn->updateAllocSize(); + if (Part.RelrDyn) + Changed |= Part.RelrDyn->updateAllocSize(); + } if (!Changed) return; @@ -1593,10 +1670,10 @@ // It should be okay as no one seems to care about the type. // Even the author of gold doesn't remember why gold behaves that way. // https://sourceware.org/ml/binutils/2002-03/msg00360.html - if (In.Dynamic->Parent) + if (Main->Dynamic->Parent) Symtab->addSymbol(Defined{/*File=*/nullptr, "_DYNAMIC", STB_WEAK, STV_HIDDEN, STT_NOTYPE, - /*Value=*/0, /*Size=*/0, In.Dynamic}); + /*Value=*/0, /*Size=*/0, Main->Dynamic}); // Define __rel[a]_iplt_{start,end} symbols if needed. addRelIpltSymbols(); @@ -1609,7 +1686,8 @@ // This responsible for splitting up .eh_frame section into // pieces. The relocation scan uses those pieces, so this has to be // earlier. - finalizeSynthetic(In.EhFrame); + for (Partition &Part : Partitions) + finalizeSynthetic(Part.EhFrame); for (Symbol *S : Symtab->getSymbols()) if (!S->IsPreemptible) @@ -1656,13 +1734,24 @@ In.SymTab->addSymbol(Sym); if (Sym->includeInDynsym()) { - In.DynSymTab->addSymbol(Sym); + Partitions[Sym->Partition - 1].DynSymTab->addSymbol(Sym); if (auto *File = dyn_cast_or_null(Sym->File)) if (File->IsNeeded && !Sym->isUndefined()) addVerneed(Sym); } } + // We also need to scan the dynamic relocation tables of the other partitions + // and add any referenced symbols to the partition's dynsym. + for (Partition &Part : MutableArrayRef(Partitions).slice(1)) { + DenseSet Syms; + for (const SymbolTableEntry &E : Part.DynSymTab->getSymbols()) + Syms.insert(E.Sym); + for (DynamicReloc &Reloc : Part.RelaDyn->Relocs) + if (Reloc.Sym && !Reloc.UseSymVA && Syms.insert(Reloc.Sym).second) + Part.DynSymTab->addSymbol(Reloc.Sym); + } + // Do not proceed if there was an undefined symbol. if (errorCount()) return; @@ -1702,22 +1791,27 @@ // The headers have to be created before finalize as that can influence the // image base and the dynamic section on mips includes the image base. if (!Config->Relocatable && !Config->OFormatBinary) { - Phdrs = Script->hasPhdrsCommands() ? Script->createPhdrs() : createPhdrs(); - if (Config->EMachine == EM_ARM) { - // PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME - addPhdrForSection(Phdrs, SHT_ARM_EXIDX, PT_ARM_EXIDX, PF_R); - } - if (Config->EMachine == EM_MIPS) { - // Add separate segments for MIPS-specific sections. - addPhdrForSection(Phdrs, SHT_MIPS_REGINFO, PT_MIPS_REGINFO, PF_R); - addPhdrForSection(Phdrs, SHT_MIPS_OPTIONS, PT_MIPS_OPTIONS, PF_R); - addPhdrForSection(Phdrs, SHT_MIPS_ABIFLAGS, PT_MIPS_ABIFLAGS, PF_R); + for (Partition &Part : Partitions) { + Part.Phdrs = Script->hasPhdrsCommands() ? Script->createPhdrs() + : createPhdrs(Part); + if (Config->EMachine == EM_ARM) { + // PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME + addPhdrForSection(Part, SHT_ARM_EXIDX, PT_ARM_EXIDX, PF_R); + } + if (Config->EMachine == EM_MIPS) { + // Add separate segments for MIPS-specific sections. + addPhdrForSection(Part, SHT_MIPS_REGINFO, PT_MIPS_REGINFO, PF_R); + addPhdrForSection(Part, SHT_MIPS_OPTIONS, PT_MIPS_OPTIONS, PF_R); + addPhdrForSection(Part, SHT_MIPS_ABIFLAGS, PT_MIPS_ABIFLAGS, PF_R); + } } - Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size(); + Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Main->Phdrs.size(); // Find the TLS segment. This happens before the section layout loop so that - // Android relocation packing can look up TLS symbol addresses. - for (PhdrEntry *P : Phdrs) + // Android relocation packing can look up TLS symbol addresses. We only need + // to care about the main partition here because all TLS symbols were moved + // to the main partition (see MarkLive.cpp). + for (PhdrEntry *P : Main->Phdrs) if (P->p_type == PT_TLS) Out::TlsPhdr = P; } @@ -1726,32 +1820,36 @@ // have the headers, we can find out which sections they point to. setReservedSymbolSections(); - // Dynamic section must be the last one in this list and dynamic - // symbol table section (DynSymTab) must be the first one. - finalizeSynthetic(In.DynSymTab); - finalizeSynthetic(In.ARMExidx); finalizeSynthetic(In.Bss); finalizeSynthetic(In.BssRelRo); - finalizeSynthetic(In.GnuHashTab); - finalizeSynthetic(In.HashTab); finalizeSynthetic(In.SymTabShndx); finalizeSynthetic(In.ShStrTab); finalizeSynthetic(In.StrTab); - finalizeSynthetic(In.VerDef); finalizeSynthetic(In.Got); finalizeSynthetic(In.MipsGot); finalizeSynthetic(In.IgotPlt); finalizeSynthetic(In.GotPlt); - finalizeSynthetic(In.RelaDyn); - finalizeSynthetic(In.RelrDyn); finalizeSynthetic(In.RelaIplt); finalizeSynthetic(In.RelaPlt); finalizeSynthetic(In.Plt); finalizeSynthetic(In.Iplt); - finalizeSynthetic(In.EhFrameHdr); - finalizeSynthetic(In.VerSym); - finalizeSynthetic(In.VerNeed); - finalizeSynthetic(In.Dynamic); + finalizeSynthetic(In.PartIndex); + + // Dynamic section must be the last one in this list and dynamic + // symbol table section (DynSymTab) must be the first one. + for (Partition &Part : Partitions) { + finalizeSynthetic(Part.ARMExidx); + finalizeSynthetic(Part.DynSymTab); + finalizeSynthetic(Part.GnuHashTab); + finalizeSynthetic(Part.HashTab); + finalizeSynthetic(Part.VerDef); + finalizeSynthetic(Part.RelaDyn); + finalizeSynthetic(Part.RelrDyn); + finalizeSynthetic(Part.EhFrameHdr); + finalizeSynthetic(Part.VerSym); + finalizeSynthetic(Part.VerNeed); + finalizeSynthetic(Part.Dynamic); + } if (!Script->HasSectionsCommand && !Config->Relocatable) fixSectionAlignments(); @@ -1892,27 +1990,39 @@ // Decide which program headers to create and which sections to include in each // one. -template std::vector Writer::createPhdrs() { +template +std::vector Writer::createPhdrs(Partition &Part) { std::vector Ret; auto AddHdr = [&](unsigned Type, unsigned Flags) -> PhdrEntry * { Ret.push_back(make(Type, Flags)); return Ret.back(); }; + unsigned PartNo = Part.getNumber(); + bool IsMain = PartNo == 1; + // The first phdr entry is PT_PHDR which describes the program header itself. - AddHdr(PT_PHDR, PF_R)->add(Out::ProgramHeaders); + if (IsMain) + AddHdr(PT_PHDR, PF_R)->add(Out::ProgramHeaders); + else + AddHdr(PT_PHDR, PF_R)->add(Part.ProgramHeaders->getParent()); // PT_INTERP must be the second entry if exists. - if (OutputSection *Cmd = findSection(".interp")) + if (OutputSection *Cmd = findSection(".interp", PartNo)) AddHdr(PT_INTERP, Cmd->getPhdrFlags())->add(Cmd); // Add the first PT_LOAD segment for regular output sections. uint64_t Flags = computeFlags(PF_R); - PhdrEntry *Load = AddHdr(PT_LOAD, Flags); + PhdrEntry *Load = nullptr; // Add the headers. We will remove them if they don't fit. - Load->add(Out::ElfHeader); - Load->add(Out::ProgramHeaders); + // In the other partitions the headers are ordinary sections, so they don't + // need to be added here. + if (IsMain) { + Load = AddHdr(PT_LOAD, Flags); + Load->add(Out::ElfHeader); + Load->add(Out::ProgramHeaders); + } // PT_GNU_RELRO includes all sections that should be marked as // read-only by dynamic linker after proccessing relocations. @@ -1922,7 +2032,7 @@ bool InRelroPhdr = false; OutputSection *RelroEnd = nullptr; for (OutputSection *Sec : OutputSections) { - if (!needsPtLoad(Sec)) + if (Sec->Partition != PartNo || !needsPtLoad(Sec)) continue; if (isRelroSection(Sec)) { InRelroPhdr = true; @@ -1943,6 +2053,18 @@ if (!needsPtLoad(Sec)) continue; + // Normally, sections in partitions other than the current partition are + // ignored. But partition number 255 is a special case: it contains the + // partition end marker (.part.end). It needs to be added to the main + // partition so that a segment is created for it in the main partition, + // which will cause the dynamic loader to reserve space for the other + // partitions. + if (Sec->Partition != PartNo) { + if (IsMain && Sec->Partition == 255) + AddHdr(PT_LOAD, computeFlags(Sec->getPhdrFlags()))->add(Sec); + continue; + } + // Segments are contiguous memory regions that has the same attributes // (e.g. executable or writable). There is one phdr for each segment. // Therefore, we need to create a new phdr when the next section has @@ -1951,7 +2073,8 @@ // time, we don't want to create a separate load segment for the headers, // even if the first output section has an AT or AT> attribute. uint64_t NewFlags = computeFlags(Sec->getPhdrFlags()); - if (((Sec->LMAExpr || + if (!Load || + ((Sec->LMAExpr || (Sec->LMARegion && (Sec->LMARegion != Load->FirstSec->LMARegion))) && Load->LastSec != Out::ProgramHeaders) || Sec->MemRegion != Load->FirstSec->MemRegion || Flags != NewFlags || @@ -1966,27 +2089,27 @@ // Add a TLS segment if any. PhdrEntry *TlsHdr = make(PT_TLS, PF_R); for (OutputSection *Sec : OutputSections) - if (Sec->Flags & SHF_TLS) + if (Sec->Partition == PartNo && Sec->Flags & SHF_TLS) TlsHdr->add(Sec); if (TlsHdr->FirstSec) Ret.push_back(TlsHdr); // Add an entry for .dynamic. - if (OutputSection *Sec = In.Dynamic->getParent()) + if (OutputSection *Sec = Part.Dynamic->getParent()) AddHdr(PT_DYNAMIC, Sec->getPhdrFlags())->add(Sec); if (RelRo->FirstSec) Ret.push_back(RelRo); // PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr. - if (In.EhFrame->isNeeded() && In.EhFrameHdr && In.EhFrame->getParent() && - In.EhFrameHdr->getParent()) - AddHdr(PT_GNU_EH_FRAME, In.EhFrameHdr->getParent()->getPhdrFlags()) - ->add(In.EhFrameHdr->getParent()); + if (Part.EhFrame->isNeeded() && Part.EhFrameHdr && + Part.EhFrame->getParent() && Part.EhFrameHdr->getParent()) + AddHdr(PT_GNU_EH_FRAME, Part.EhFrameHdr->getParent()->getPhdrFlags()) + ->add(Part.EhFrameHdr->getParent()); // PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes // the dynamic linker fill the segment with random data. - if (OutputSection *Cmd = findSection(".openbsd.randomdata")) + if (OutputSection *Cmd = findSection(".openbsd.randomdata", PartNo)) AddHdr(PT_OPENBSD_RANDOMIZE, Cmd->getPhdrFlags())->add(Cmd); // PT_GNU_STACK is a special section to tell the loader to make the @@ -2009,6 +2132,8 @@ // same alignment. PhdrEntry *Note = nullptr; for (OutputSection *Sec : OutputSections) { + if (Sec->Partition != PartNo) + continue; if (Sec->Type == SHT_NOTE && (Sec->Flags & SHF_ALLOC)) { if (!Note || Sec->LMAExpr || Note->LastSec->Alignment != Sec->Alignment) Note = AddHdr(PT_NOTE, PF_R); @@ -2021,17 +2146,18 @@ } template -void Writer::addPhdrForSection(std::vector &Phdrs, - unsigned ShType, unsigned PType, - unsigned PFlags) { - auto I = llvm::find_if( - OutputSections, [=](OutputSection *Cmd) { return Cmd->Type == ShType; }); +void Writer::addPhdrForSection(Partition &Part, unsigned ShType, + unsigned PType, unsigned PFlags) { + unsigned PartNo = Part.getNumber(); + auto I = llvm::find_if(OutputSections, [=](OutputSection *Cmd) { + return Cmd->Partition == PartNo && Cmd->Type == ShType; + }); if (I == OutputSections.end()) return; PhdrEntry *Entry = make(PType, PFlags); Entry->add(*I); - Phdrs.push_back(Entry); + Part.Phdrs.push_back(Entry); } // The first section of each PT_LOAD, the first section in PT_GNU_RELRO and the @@ -2045,27 +2171,29 @@ }; }; - for (const PhdrEntry *P : Phdrs) - if (P->p_type == PT_LOAD && P->FirstSec) - PageAlign(P->FirstSec); + for (Partition &Part : Partitions) { + for (const PhdrEntry *P : Part.Phdrs) + if (P->p_type == PT_LOAD && P->FirstSec) + PageAlign(P->FirstSec); - for (const PhdrEntry *P : Phdrs) { - if (P->p_type != PT_GNU_RELRO) - continue; + for (const PhdrEntry *P : Part.Phdrs) { + if (P->p_type != PT_GNU_RELRO) + continue; - if (P->FirstSec) - PageAlign(P->FirstSec); + if (P->FirstSec) + PageAlign(P->FirstSec); - // Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we - // have to align it to a page. - auto End = OutputSections.end(); - auto I = llvm::find(OutputSections, P->LastSec); - if (I == End || (I + 1) == End) - continue; + // Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we + // have to align it to a page. + auto End = OutputSections.end(); + auto I = llvm::find(OutputSections, P->LastSec); + if (I == End || (I + 1) == End) + continue; - OutputSection *Cmd = (*(I + 1)); - if (needsPtLoad(Cmd)) - PageAlign(Cmd); + OutputSection *Cmd = (*(I + 1)); + if (needsPtLoad(Cmd)) + PageAlign(Cmd); + } } } @@ -2125,9 +2253,10 @@ Off = setFileOffset(Out::ProgramHeaders, Off); PhdrEntry *LastRX = nullptr; - for (PhdrEntry *P : Phdrs) - if (P->p_type == PT_LOAD && (P->p_flags & PF_X)) - LastRX = P; + for (Partition &Part : Partitions) + for (PhdrEntry *P : Part.Phdrs) + if (P->p_type == PT_LOAD && (P->p_flags & PF_X)) + LastRX = P; for (OutputSection *Sec : OutputSections) { Off = setFileOffset(Sec, Off); @@ -2165,8 +2294,8 @@ // Finalize the program headers. We call this function after we assign // file offsets and VAs to all sections. -template void Writer::setPhdrs() { - for (PhdrEntry *P : Phdrs) { +template void Writer::setPhdrs(Partition &Part) { + for (PhdrEntry *P : Part.Phdrs) { OutputSection *First = P->FirstSec; OutputSection *Last = P->LastSec; @@ -2179,6 +2308,11 @@ P->p_offset = First->Offset; P->p_vaddr = First->Addr; + // File offsets in partitions other than the main partition are relative + // to the offset of the ELF headers. Perform that adjustment now. + if (Part.ElfHeader) + P->p_offset -= Part.ElfHeader->getParent()->Offset; + if (!P->HasLMA) P->p_paddr = First->getLMA(); } @@ -2326,68 +2460,14 @@ return ET_EXEC; } -static uint8_t getAbiVersion() { - // MIPS non-PIC executable gets ABI version 1. - if (Config->EMachine == EM_MIPS) { - if (getELFType() == ET_EXEC && - (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 void Writer::writeHeader() { - // 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(Out::BufferStart, 0, sizeof(Elf_Ehdr)); - memcpy(Out::BufferStart, "\177ELF", 4); + writeEhdr(Out::BufferStart, *Main); + writePhdrs(Out::BufferStart + sizeof(Elf_Ehdr), *Main); - // Write the ELF header. auto *EHdr = reinterpret_cast(Out::BufferStart); - 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_type = getELFType(); - EHdr->e_machine = Config->EMachine; - EHdr->e_version = EV_CURRENT; EHdr->e_entry = getEntryAddr(); EHdr->e_shoff = SectionHeaderOff; - EHdr->e_flags = Config->EFlags; - EHdr->e_ehsize = sizeof(Elf_Ehdr); - EHdr->e_phnum = Phdrs.size(); - EHdr->e_shentsize = sizeof(Elf_Shdr); - - if (!Config->Relocatable) { - EHdr->e_phoff = sizeof(Elf_Ehdr); - EHdr->e_phentsize = sizeof(Elf_Phdr); - } - - // Write the program header table. - auto *HBuf = reinterpret_cast(Out::BufferStart + EHdr->e_phoff); - for (PhdrEntry *P : 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; - } // Write the section header table. // @@ -2462,25 +2542,27 @@ if (Script->HasSectionsCommand) return; - // Fill the last page. - for (PhdrEntry *P : Phdrs) - if (P->p_type == PT_LOAD && (P->p_flags & PF_X)) - fillTrap(Out::BufferStart + alignDown(P->p_offset + P->p_filesz, - Config->CommonPageSize), - Out::BufferStart + - alignTo(P->p_offset + P->p_filesz, Config->CommonPageSize)); - - // Round up the file size of the last segment to the page boundary iff it is - // an executable segment to ensure that other tools don't accidentally - // trim the instruction padding (e.g. when stripping the file). - PhdrEntry *Last = nullptr; - for (PhdrEntry *P : Phdrs) - if (P->p_type == PT_LOAD) - Last = P; + for (Partition &Part : Partitions) { + // Fill the last page. + for (PhdrEntry *P : Part.Phdrs) + if (P->p_type == PT_LOAD && (P->p_flags & PF_X)) + fillTrap(Out::BufferStart + alignDown(P->p_offset + P->p_filesz, + Config->CommonPageSize), + Out::BufferStart + alignTo(P->p_offset + P->p_filesz, + Config->CommonPageSize)); + + // Round up the file size of the last segment to the page boundary iff it is + // an executable segment to ensure that other tools don't accidentally + // trim the instruction padding (e.g. when stripping the file). + PhdrEntry *Last = nullptr; + for (PhdrEntry *P : Part.Phdrs) + if (P->p_type == PT_LOAD) + Last = P; - if (Last && (Last->p_flags & PF_X)) - Last->p_memsz = Last->p_filesz = - alignTo(Last->p_filesz, Config->CommonPageSize); + if (Last && (Last->p_flags & PF_X)) + Last->p_memsz = Last->p_filesz = + alignTo(Last->p_filesz, Config->CommonPageSize); + } } // Write section contents to a mmap'ed file. @@ -2531,16 +2613,18 @@ } template void Writer::writeBuildId() { - if (!In.BuildId || !In.BuildId->getParent()) + if (!Main->BuildId || !Main->BuildId->getParent()) return; if (Config->BuildId == BuildIdKind::Hexstring) { - In.BuildId->writeBuildId(Config->BuildIdVector); + for (Partition &Part : Partitions) + Part.BuildId->writeBuildId(Config->BuildIdVector); return; } // Compute a hash of all sections of the output file. - std::vector BuildId(In.BuildId->HashSize); + size_t HashSize = Main->BuildId->HashSize; + std::vector BuildId(HashSize); llvm::ArrayRef Buf{Out::BufferStart, size_t(FileSize)}; switch (Config->BuildId) { @@ -2551,22 +2635,23 @@ break; case BuildIdKind::Md5: computeHash(BuildId, Buf, [&](uint8_t *Dest, ArrayRef Arr) { - memcpy(Dest, MD5::hash(Arr).data(), In.BuildId->HashSize); + memcpy(Dest, MD5::hash(Arr).data(), HashSize); }); break; case BuildIdKind::Sha1: computeHash(BuildId, Buf, [&](uint8_t *Dest, ArrayRef Arr) { - memcpy(Dest, SHA1::hash(Arr).data(), In.BuildId->HashSize); + memcpy(Dest, SHA1::hash(Arr).data(), HashSize); }); break; case BuildIdKind::Uuid: - if (auto EC = llvm::getRandomBytes(BuildId.data(), In.BuildId->HashSize)) + if (auto EC = llvm::getRandomBytes(BuildId.data(), HashSize)) error("entropy source failure: " + EC.message()); break; default: llvm_unreachable("unknown BuildIdKind"); } - In.BuildId->writeBuildId(BuildId); + for (Partition &Part : Partitions) + Part.BuildId->writeBuildId(BuildId); } template void elf::writeResult(); diff --git a/lld/test/ELF/linkerscript/orphan-report.s b/lld/test/ELF/linkerscript/orphan-report.s --- a/lld/test/ELF/linkerscript/orphan-report.s +++ b/lld/test/ELF/linkerscript/orphan-report.s @@ -27,6 +27,7 @@ # REPORT-NEXT: :(.dynamic) is being placed in '.dynamic' # REPORT-NEXT: :(.dynstr) is being placed in '.dynstr' # REPORT-NEXT: :(.rela.dyn) is being placed in '.rela.dyn' +# REPORT-NEXT: :(.eh_frame) is being placed in '.eh_frame' # REPORT-NEXT: :(.got) is being placed in '.got' # REPORT-NEXT: :(.got.plt) is being placed in '.got.plt' # REPORT-NEXT: :(.got.plt) is being placed in '.got.plt' @@ -34,7 +35,6 @@ # REPORT-NEXT: :(.rela.plt) is being placed in '.rela.plt' # REPORT-NEXT: :(.plt) is being placed in '.plt' # REPORT-NEXT: :(.plt) is being placed in '.plt' -# REPORT-NEXT: :(.eh_frame) is being placed in '.eh_frame' # REPORT-NEXT: :(.symtab) is being placed in '.symtab' # REPORT-NEXT: :(.symtab_shndx) is being placed in '.symtab_shndx' # REPORT-NEXT: :(.shstrtab) is being placed in '.shstrtab' diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -843,6 +843,8 @@ // for safe ICF. SHT_LLVM_DEPENDENT_LIBRARIES = 0x6fff4c04, // LLVM Dependent Library Specifiers. SHT_LLVM_SYMPART = 0x6fff4c05, // Symbol partition specification. + SHT_LLVM_PART_EHDR = 0x6fff4c05, // ELF header for loadable partition. + SHT_LLVM_PART_PHDR = 0x6fff4c06, // Phdrs for loadable partition. // Android's experimental support for SHT_RELR sections. // https://android.googlesource.com/platform/bionic/+/b7feec74547f84559a1467aca02708ff61346d2a/libc/include/elf.h#512 SHT_ANDROID_RELR = 0x6fffff00, // Relocation entries; only offsets.