Index: lld/trunk/ELF/Arch/PPC.cpp =================================================================== --- lld/trunk/ELF/Arch/PPC.cpp +++ lld/trunk/ELF/Arch/PPC.cpp @@ -157,7 +157,7 @@ // _GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC // glibc stores _dl_runtime_resolve in _GLOBAL_OFFSET_TABLE_[1], // link_map in _GLOBAL_OFFSET_TABLE_[2]. - write32(Buf, In.Dynamic->getVA()); + write32(Buf, Main->Dynamic->getVA()); } void PPC::writeGotPlt(uint8_t *Buf, const Symbol &S) const { Index: lld/trunk/ELF/Arch/X86.cpp =================================================================== --- lld/trunk/ELF/Arch/X86.cpp +++ lld/trunk/ELF/Arch/X86.cpp @@ -167,7 +167,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 { Index: lld/trunk/ELF/Arch/X86_64.cpp =================================================================== --- lld/trunk/ELF/Arch/X86_64.cpp +++ lld/trunk/ELF/Arch/X86_64.cpp @@ -132,7 +132,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 { Index: lld/trunk/ELF/Config.h =================================================================== --- lld/trunk/ELF/Config.h +++ lld/trunk/ELF/Config.h @@ -73,7 +73,6 @@ llvm::StringRef Name; uint16_t Id = 0; std::vector Globals; - size_t NameOff = 0; // Offset in the string table }; // This struct contains the global configuration for the linker. Index: lld/trunk/ELF/Driver.cpp =================================================================== --- lld/trunk/ELF/Driver.cpp +++ lld/trunk/ELF/Driver.cpp @@ -1810,6 +1810,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]; + // Read .note.gnu.property sections from input object files which // contain a hint to tweak linker's and loader's behaviors. Config->AndFeatures = getAndFeatures(); Index: lld/trunk/ELF/InputSection.h =================================================================== --- lld/trunk/ELF/InputSection.h +++ lld/trunk/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 @@ -76,6 +79,7 @@ // collector, or 0 if this section is dead. Normally there is only one // partition, so this will either be 0 or 1. uint8_t Partition; + elf::Partition &getPartition() const; // These corresponds to the fields in Elf_Shdr. uint32_t Alignment; Index: lld/trunk/ELF/LinkerScript.cpp =================================================================== --- lld/trunk/ELF/LinkerScript.cpp +++ lld/trunk/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(); @@ -904,6 +904,8 @@ if (IsEmpty && isDiscardable(*Sec)) { Sec->markDead(); Cmd = nullptr; + } else if (!Sec->isLive()) { + Sec->markLive(); } } Index: lld/trunk/ELF/Relocations.cpp =================================================================== --- lld/trunk/ELF/Relocations.cpp +++ lld/trunk/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}); }; @@ -222,7 +222,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) @@ -242,8 +242,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; } @@ -274,13 +274,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}); @@ -297,8 +298,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( @@ -604,7 +605,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. @@ -818,19 +819,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 @@ -868,9 +871,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 @@ -923,7 +926,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 @@ -1151,7 +1155,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; } Index: lld/trunk/ELF/SyntheticSections.h =================================================================== --- lld/trunk/ELF/SyntheticSections.h +++ lld/trunk/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: @@ -429,7 +431,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 @@ -438,7 +440,6 @@ RelType Type; -private: Symbol *Sym; const InputSectionBase *InputSec = nullptr; uint64_t OffsetInSec; @@ -497,9 +498,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; }; @@ -776,8 +777,10 @@ private: enum { EntrySize = 28 }; void writeOne(uint8_t *Buf, uint32_t Index, StringRef Name, size_t NameOff); + StringRef getFileDefName(); unsigned FileDefNameOff; + std::vector VerDefNameOffs; }; // The .gnu.version section specifies the required version of each symbol in the @@ -1071,58 +1074,100 @@ 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; PPC32Got2Section *PPC32Got2; - 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; Index: lld/trunk/ELF/SyntheticSections.cpp =================================================================== --- lld/trunk/ELF/SyntheticSections.cpp +++ lld/trunk/ELF/SyntheticSections.cpp @@ -389,10 +389,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; } @@ -487,7 +488,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) { @@ -571,8 +572,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() @@ -923,7 +924,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; @@ -931,7 +932,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 @@ -939,13 +940,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); } } @@ -957,7 +958,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; @@ -967,14 +968,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}); } } } @@ -1233,20 +1234,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; @@ -1294,12 +1305,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, @@ -1309,16 +1320,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)); } @@ -1328,7 +1339,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) { @@ -1352,46 +1363,48 @@ 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()); + 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); + 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 || 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()) @@ -1403,14 +1416,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) @@ -1465,9 +1478,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; } @@ -1501,11 +1514,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; @@ -1521,12 +1536,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 @@ -1539,19 +1555,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); } } @@ -1629,7 +1648,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); @@ -1877,16 +1896,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 @@ -1929,8 +1952,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; @@ -1983,6 +2009,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; @@ -1999,14 +2026,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(); @@ -2016,8 +2046,10 @@ // occur if -r is given). if (BssSection *CommonSec = getCommonSec(Ent.Sym)) ESym->st_value = CommonSec->Alignment; - else + else if (IsDefinedHere) ESym->st_value = Sym->getVA(); + else + ESym->st_value = 0; ++ESym; } @@ -2131,7 +2163,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 @@ -2157,7 +2189,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; @@ -2205,7 +2237,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; } } @@ -2224,8 +2257,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 @@ -2264,22 +2297,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 @@ -2288,7 +2325,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; @@ -2674,13 +2711,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; @@ -2693,27 +2731,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); + VerDefNameOffs.push_back(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 @@ -2743,9 +2785,10 @@ void VersionDefinitionSection::writeTo(uint8_t *Buf) { writeOne(Buf, 1, getFileDefName(), FileDefNameOff); + auto NameOffIt = VerDefNameOffs.begin(); for (VersionDefinition &V : Config->VersionDefinitions) { Buf += EntrySize; - writeOne(Buf, V.Id, V.Name, V.NameOff); + writeOne(Buf, V.Id, V.Name, *NameOffIt++); } // Need to terminate the last version definition. @@ -2766,23 +2809,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) { @@ -2816,7 +2859,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; @@ -2824,12 +2867,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(); } @@ -3343,9 +3386,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(); @@ -3411,3 +3576,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; Index: lld/trunk/ELF/Thunks.cpp =================================================================== --- lld/trunk/ELF/Thunks.cpp +++ lld/trunk/ELF/Thunks.cpp @@ -300,9 +300,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)}); } }; Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/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; } } @@ -278,10 +300,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; } @@ -294,41 +316,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); @@ -347,39 +353,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); + }; + + if (!Part.Name.empty()) { + Part.ElfHeader = make>(); + Part.ElfHeader->Name = Part.Name; + Add(Part.ElfHeader); + + Part.ProgramHeaders = make>(); + Add(Part.ProgramHeaders); + } + + if (Config->BuildId != BuildIdKind::None) { + Part.BuildId = make(); + Add(Part.BuildId); + } + + 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); + } - In.VerSym = make(); - Add(In.VerSym); + if (needsInterpSection()) + Add(createInterpSection()); - if (!Config->VersionDefinitions.empty()) { - In.VerDef = make(); - Add(In.VerDef); - } + 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); + } - In.VerNeed = make>(); - Add(In.VerNeed); + Add(Part.Dynamic); + Add(Part.DynStrTab); + Add(Part.RelaDyn); + } - if (Config->GnuHash) { - In.GnuHashTab = make(); - Add(In.GnuHashTab); + if (Config->RelrPackDynRelocs) { + Part.RelrDyn = make>(); + Add(Part.RelrDyn); } - if (Config->SysvHash) { - In.HashTab = make(); - Add(In.HashTab); + 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, @@ -454,15 +526,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) @@ -470,17 +533,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(); @@ -523,19 +583,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) @@ -750,7 +812,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 @@ -771,9 +833,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, @@ -806,6 +870,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") @@ -966,11 +1038,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 @@ -999,12 +1073,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) { @@ -1505,10 +1581,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; @@ -1604,10 +1681,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(); @@ -1641,7 +1718,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); Symtab->forEachSymbol([](Symbol *S) { if (!S->IsPreemptible) @@ -1691,13 +1769,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; @@ -1737,22 +1826,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; } @@ -1761,33 +1855,37 @@ // 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.PPC32Got2); - 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(); @@ -1928,27 +2026,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. @@ -1958,7 +2068,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; @@ -1979,6 +2089,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 @@ -1987,7 +2109,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 || @@ -2002,27 +2125,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 @@ -2045,6 +2168,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); @@ -2057,17 +2182,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 @@ -2081,27 +2207,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); + } } } @@ -2161,9 +2289,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); @@ -2201,8 +2330,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; @@ -2215,6 +2344,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(); } @@ -2362,68 +2496,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. // @@ -2498,25 +2578,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; - - if (Last && (Last->p_flags & PF_X)) - Last->p_memsz = Last->p_filesz = - alignTo(Last->p_filesz, Config->CommonPageSize); + 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->FirstSec->Offset + P->p_filesz, + Config->CommonPageSize), + Out::BufferStart + alignTo(P->FirstSec->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); + } } // Write section contents to a mmap'ed file. @@ -2567,16 +2649,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) { @@ -2587,22 +2671,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(); Index: lld/trunk/test/ELF/linkerscript/orphan-report.s =================================================================== --- lld/trunk/test/ELF/linkerscript/orphan-report.s +++ lld/trunk/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' Index: lld/trunk/test/ELF/partition-exidx.s =================================================================== --- lld/trunk/test/ELF/partition-exidx.s +++ lld/trunk/test/ELF/partition-exidx.s @@ -0,0 +1,49 @@ +// Test that exidx output sections are created correctly for each partition. + +// REQUIRES: arm +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o +// RUN: ld.lld %t.o -o %t -shared --gc-sections + +// RUN: llvm-objcopy --extract-main-partition %t %t0 +// RUN: llvm-objcopy --extract-partition=part1 %t %t1 + +// Change upper case to lower case so that we can match unwind info (which is dumped +// in upper case) against program headers (which are dumped in lower case). +// RUN: llvm-readelf -l --unwind %t0 | tr A-Z a-z | FileCheck %s +// RUN: llvm-readelf -l --unwind %t1 | tr A-Z a-z | FileCheck %s + +// Each file should have one exidx section for its text section and one sentinel. +// CHECK: sectionoffset: 0x[[EXIDX_OFFSET:.*]] +// CHECK-NEXT: entries [ +// CHECK-NEXT: entry { +// CHECK-NEXT: functionaddress: 0x[[TEXT_ADDR:.*]] +// CHECK-NEXT: model: cantunwind +// CHECK-NEXT: } +// CHECK-NEXT: entry { +// CHECK-NEXT: functionaddress: +// CHECK-NEXT: model: cantunwind +// CHECK-NEXT: } +// CHECK-NEXT: ] + +// CHECK: load {{[^ ]*}} 0x{{0*}}[[TEXT_ADDR]] {{.*}} r e +// CHECK: exidx 0x{{0*}}[[EXIDX_OFFSET]] {{.*}} 0x00010 0x00010 r + +.section .llvm_sympart,"",%llvm_sympart +.asciz "part1" +.4byte p1 + +.section .text.p0,"ax",%progbits +.globl p0 +p0: +.fnstart +bx lr +.cantunwind +.fnend + +.section .text.p1,"ax",%progbits +.globl p1 +p1: +.fnstart +bx lr +.cantunwind +.fnend Index: lld/trunk/test/ELF/partition-notes.s =================================================================== --- lld/trunk/test/ELF/partition-notes.s +++ lld/trunk/test/ELF/partition-notes.s @@ -0,0 +1,45 @@ +// Test that notes (both from object files and synthetic) are duplicated into +// each partition. + +// REQUIRES: x86 + +// RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux +// RUN: ld.lld %t.o -o %t --shared --gc-sections --build-id=sha1 + +// RUN: llvm-objcopy --extract-main-partition %t %t0 +// RUN: llvm-objcopy --extract-partition=part1 %t %t1 + +// RUN: llvm-readelf --all %t0 | FileCheck --check-prefixes=CHECK,PART0 %s +// RUN: llvm-readelf --all %t1 | FileCheck --check-prefixes=CHECK,PART1 %s + +// CHECK: Program Headers: +// CHECK: NOTE 0x{{0*}}[[NOTE_OFFSET:[^ ]*]] + +// CHECK: Displaying notes found at file offset 0x{{0*}}[[NOTE_OFFSET]] +// CHECK-NEXT: Owner +// CHECK-NEXT: foo 0x00000004 NT_VERSION (version) +// CHECK-NEXT: Displaying notes +// CHECK-NEXT: Owner +// CHECK-NEXT: GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring) +// CHECK-NEXT: Build ID: 0f4d5297cbbe52e4bea558eeb792944670de22e1 + +.section .llvm_sympart,"",@llvm_sympart +.asciz "part1" +.quad p1 + +.section .data.p0,"aw",@progbits +.globl p0 +p0: + +.section .data.p1,"aw",@progbits +.globl p1 +p1: + +.section .note.obj,"a",@note +.align 4 +.long 2f-1f +.long 3f-2f +.long 1 +1: .asciz "foo" +2: .asciz "bar" +3: Index: lld/trunk/test/ELF/partition-pack-dyn-relocs.s =================================================================== --- lld/trunk/test/ELF/partition-pack-dyn-relocs.s +++ lld/trunk/test/ELF/partition-pack-dyn-relocs.s @@ -0,0 +1,51 @@ +// Test that both Android and RELR packed relocation sections are created +// correctly for each partition. + +// REQUIRES: x86 + +// RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux +// RUN: ld.lld %t.o -o %t --shared --gc-sections --pack-dyn-relocs=android+relr + +// RUN: llvm-objcopy --extract-main-partition %t %t0 +// RUN: llvm-objcopy --extract-partition=part1 %t %t1 + +// RUN: llvm-readelf --all %t0 | FileCheck --check-prefixes=CHECK,PART0 %s +// RUN: llvm-readelf --all %t1 | FileCheck --check-prefixes=CHECK,PART1 %s + +// CHECK: Section Headers: +// CHECK: .rela.dyn ANDROID_RELA {{0*}}[[ANDROID_RELA_ADDR:[^ ]*]] +// CHECK: .relr.dyn RELR {{0*}}[[RELR_ADDR:[^ ]*]] +// CHECK: .data PROGBITS 000000000000[[DATA_SEGMENT:.]]000 + +// CHECK: Relocation section '.rela.dyn' +// CHECK-NEXT: Offset +// PART0-NEXT: 000000000000[[DATA_SEGMENT]]008 {{.*}} R_X86_64_64 000000000000[[DATA_SEGMENT]]000 p0 + 0 +// PART1-NEXT: 000000000000[[DATA_SEGMENT]]008 {{.*}} R_X86_64_64 000000000000[[DATA_SEGMENT]]000 p1 + 0 +// CHECK-EMPTY: + +// CHECK: Relocation section '.relr.dyn' +// CHECK-NEXT: Offset +// CHECK-NEXT: 000000000000[[DATA_SEGMENT]]000 {{.*}} R_X86_64_RELATIVE +// CHECK-EMPTY: + +// CHECK: Dynamic section +// CHECK: 0x0000000060000011 (ANDROID_RELA) 0x[[ANDROID_RELA_ADDR]] +// CHECK: 0x0000000000000024 (RELR) 0x[[RELR_ADDR]] + +.section .llvm_sympart,"",@llvm_sympart +.asciz "part1" +.quad p1 + +.section .data.p0,"aw",@progbits +.align 8 +.globl p0 +p0: +.quad __ehdr_start +.quad p0 + +.section .data.p1,"aw",@progbits +.align 8 +.globl p1 +p1: +.quad __ehdr_start +.quad p1 Index: lld/trunk/test/ELF/partition-synthetic-sections.s =================================================================== --- lld/trunk/test/ELF/partition-synthetic-sections.s +++ lld/trunk/test/ELF/partition-synthetic-sections.s @@ -0,0 +1,241 @@ +// Test that synthetic sections are created correctly for each partition. + +// REQUIRES: x86 + +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/verneed1.s -o %t1.o +// RUN: echo "v1 {}; v2 {}; v3 { local: *; };" > %t1.script +// RUN: ld.lld -shared %t1.o --version-script %t1.script -o %t1.so -soname verneed1.so.0 + +// RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux +// RUN: echo "x1 { global: p0; }; x2 { global: p1; p1alias; };" > %t.script +// RUN: ld.lld %t.o %t1.so --version-script %t.script -o %t --shared --gc-sections --eh-frame-hdr -soname main.so + +// RUN: llvm-objcopy --extract-main-partition %t %t0 +// RUN: llvm-objcopy --extract-partition=part1 %t %t1 + +// RUN: llvm-readelf --all --unwind %t0 | FileCheck --check-prefixes=CHECK,PART0 %s +// RUN: llvm-readelf --all --unwind %t1 | FileCheck --check-prefixes=CHECK,PART1 %s + +// FIXME: llvm-objcopy does not preserve padding (see pr42145) so for now we +// check the combined output file. +// RUN: od -Ax -x %t | FileCheck %s -check-prefix=FILL + +// RUN: llvm-objdump -s -j .rodata -j .dynstr %t0 | FileCheck --check-prefix=PART-INDEX %s + +// CHECK: Section Headers: +// CHECK-NEXT: Name +// CHECK-NEXT: NULL +// CHECK-NEXT: .dynsym DYNSYM {{0*}}[[DYNSYM_ADDR:[^ ]*]] +// CHECK-NEXT: .gnu.version VERSYM {{0*}}[[VERSYM_ADDR:[^ ]*]] +// CHECK-NEXT: .gnu.version_d VERDEF {{0*}}[[VERDEF_ADDR:[^ ]*]] +// CHECK-NEXT: .gnu.version_r VERNEED {{0*}}[[VERNEED_ADDR:[^ ]*]] +// CHECK-NEXT: .gnu.hash GNU_HASH {{0*}}[[GNU_HASH_ADDR:[^ ]*]] +// CHECK-NEXT: .hash HASH {{0*}}[[HASH_ADDR:[^ ]*]] +// CHECK-NEXT: .dynstr STRTAB {{0*}}[[DYNSTR_ADDR:[^ ]*]] +// CHECK-NEXT: .rela.dyn RELA {{0*}}[[RELA_DYN_ADDR:[^ ]*]] +// PART0-NEXT: .rela.plt RELA {{0*}}[[RELA_PLT_ADDR:[^ ]*]] +// CHECK-NEXT: .eh_frame_hdr PROGBITS {{0*}}[[EH_FRAME_HDR_ADDR:[^ ]*]] +// CHECK-NEXT: .eh_frame PROGBITS {{0*}}[[EH_FRAME_ADDR:[^ ]*]] +// PART0-NEXT: .rodata PROGBITS +// CHECK-NEXT: .text PROGBITS {{0*}}[[TEXT_ADDR:[^ ]*]] +// PART0-NEXT: .plt PROGBITS +// PART0-NEXT: .init_array INIT_ARRAY {{0*}}[[INIT_ARRAY_ADDR:[^ ]*]] +// CHECK-NEXT: .dynamic DYNAMIC {{0*}}[[DYNAMIC_ADDR:[^ ]*]] +// CHECK-NEXT: .data PROGBITS 000000000000[[DATA_SEGMENT:.]]000 +// PART0-NEXT: .got.plt PROGBITS {{0*}}[[GOT_PLT_ADDR:[^ ]*]] +// PART0-NEXT: .part.end NOBITS {{0*}}[[PART_END_ADDR:[^ ]*]] +// CHECK-NEXT: .comment PROGBITS +// CHECK-NEXT: .symtab SYMTAB +// CHECK-NEXT: .shstrtab STRTAB +// CHECK-NEXT: .strtab STRTAB +// CHECK-NEXT: Key to Flags + +// CHECK: Relocation section '.rela.dyn' +// CHECK-NEXT: Offset +// PART0-NEXT: 000000000000[[DATA_SEGMENT]]000 {{.*}} R_X86_64_64 {{.*}} f1@v3 + 0 +// PART0-NEXT: {{0*}}[[INIT_ARRAY_ADDR]] {{.*}} R_X86_64_64 {{.*}} p0@@x1 + 0 +// PART1-NEXT: 000000000000[[DATA_SEGMENT]]018 {{.*}} R_X86_64_RELATIVE 3000 +// PART1-NEXT: 000000000000[[DATA_SEGMENT]]000 {{.*}} R_X86_64_64 {{.*}} f2@v2 + 0 +// PART1-NEXT: 000000000000[[DATA_SEGMENT]]008 {{.*}} R_X86_64_64 {{.*}} p0@@x1 + 0 +// PART1-NEXT: 000000000000[[DATA_SEGMENT]]010 {{.*}} R_X86_64_64 {{.*}} p0@@x1 + 0 +// CHECK-EMPTY: + +// PART0: Relocation section '.rela.plt' +// PART0-NEXT: Offset +// PART0-NEXT: 000000000000[[DATA_SEGMENT]]020 {{.*}} R_X86_64_JUMP_SLOT {{.*}} f1@v3 + 0 +// PART0-NEXT: 000000000000[[DATA_SEGMENT]]028 {{.*}} R_X86_64_JUMP_SLOT {{.*}} f2@v2 + 0 +// PART0-EMPTY: + +// CHECK: Symbol table '.dynsym' +// PART0: 1: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND f1@v3 +// PART0: 2: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND f2@v2 +// PART0: 3: {{0*}}[[TEXT_ADDR]] 0 NOTYPE GLOBAL DEFAULT {{.*}} p0@@x1 +// PART1: 1: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND f2@v2 +// PART1: 2: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND p0@@x1 +// PART1: 3: {{0*}}[[TEXT_ADDR]] 0 NOTYPE GLOBAL DEFAULT {{.*}} p1@@x2 +// PART1: 4: {{0*}}[[TEXT_ADDR]] 0 NOTYPE GLOBAL DEFAULT {{.*}} p1alias@@x2 +// CHECK-EMPTY: + +// PART0: Symbol table '.symtab' +// PART0: 000000000000048c 0 NOTYPE LOCAL HIDDEN {{.*}} __part_index_begin +// PART0: 0000000000000498 0 NOTYPE LOCAL HIDDEN {{.*}} __part_index_end + +// PART-INDEX: Contents of section .dynstr: +// PART-INDEX-NEXT: 03a8 00663100 66320070 30007061 72743100 .f1.f2.p0.part1. +// PART-INDEX: Contents of section .rodata: +// 0x48c + 0xffffff26 = 0x3b2 +// 0x490 + 0x3b70 = 0x4000 +// PART-INDEX-NEXT: 048c 26ffffff 703b0000 00400000 + +// CHECK: {{.*}}EH_FRAME Header +// CHECK: Address: 0x[[EH_FRAME_HDR_ADDR]] +// CHECK: eh_frame_ptr: 0x[[EH_FRAME_ADDR]] +// CHECK: initial_location: 0x[[TEXT_ADDR]] +// CHECK: address: 0x[[FDE_ADDR:.*]] + +// CHECK: .eh_frame section +// CHECK: 0x[[EH_FRAME_ADDR]]] CIE length=20 +// CHECK-NOT: FDE +// CHECK: 0x[[FDE_ADDR]]] FDE length=20 cie={{.}}0x[[EH_FRAME_ADDR]] +// CHECK-NEXT: initial_location: 0x[[TEXT_ADDR]] +// CHECK-NOT: FDE +// CHECK: CIE length=0 + +// CHECK: Dynamic section +// CHECK-NEXT: Tag +// CHECK-NEXT: 0x0000000000000001 (NEEDED) Shared library: [verneed1.so.0] +// PART0-NEXT: 0x000000000000000e (SONAME) Library soname: [main.so] +// PART1-NEXT: 0x0000000000000001 (NEEDED) Shared library: [main.so] +// PART1-NEXT: 0x000000000000000e (SONAME) Library soname: [part1] +// CHECK-NEXT: 0x0000000000000007 (RELA) 0x[[RELA_DYN_ADDR]] +// CHECK-NEXT: 0x0000000000000008 (RELASZ) +// CHECK-NEXT: 0x0000000000000009 (RELAENT) 24 (bytes) +// PART1-NEXT: 0x000000006ffffff9 (RELACOUNT) 1 +// PART0-NEXT: 0x0000000000000017 (JMPREL) 0x[[RELA_PLT_ADDR]] +// PART0-NEXT: 0x0000000000000002 (PLTRELSZ) 48 (bytes) +// PART0-NEXT: 0x0000000000000003 (PLTGOT) 0x[[GOT_PLT_ADDR]] +// PART0-NEXT: 0x0000000000000014 (PLTREL) RELA +// CHECK-NEXT: 0x0000000000000006 (SYMTAB) 0x[[DYNSYM_ADDR]] +// CHECK-NEXT: 0x000000000000000b (SYMENT) 24 (bytes) +// CHECK-NEXT: 0x0000000000000005 (STRTAB) 0x[[DYNSTR_ADDR]] +// CHECK-NEXT: 0x000000000000000a (STRSZ) +// CHECK-NEXT: 0x000000006ffffef5 (GNU_HASH) 0x[[GNU_HASH_ADDR]] +// CHECK-NEXT: 0x0000000000000004 (HASH) 0x[[HASH_ADDR]] +// PART0-NEXT: 0x0000000000000019 (INIT_ARRAY) 0x[[INIT_ARRAY_ADDR]] +// PART0-NEXT: 0x000000000000001b (INIT_ARRAYSZ) 8 (bytes) +// CHECK-NEXT: 0x000000006ffffff0 (VERSYM) 0x[[VERSYM_ADDR]] +// CHECK-NEXT: 0x000000006ffffffc (VERDEF) 0x[[VERDEF_ADDR]] +// CHECK-NEXT: 0x000000006ffffffd (VERDEFNUM) 3 +// CHECK-NEXT: 0x000000006ffffffe (VERNEED) 0x[[VERNEED_ADDR]] +// CHECK-NEXT: 0x000000006fffffff (VERNEEDNUM) 1 +// PART0-NEXT: 0x0000000000000000 (NULL) 0x0 + +// CHECK: Program Headers: +// CHECK-NEXT: Type +// PART0-NEXT: PHDR {{.*}} 0x000230 0x000230 R +// PART1-NEXT: PHDR {{.*}} 0x0001f8 0x0001f8 R +// PART0-NEXT: LOAD 0x000000 0x0000000000000000 0x0000000000000000 {{.*}} R 0x1000 +// PART0-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 {{.*}} R E 0x1000 +// PART0-NEXT: LOAD 0x002000 0x0000000000002000 0x0000000000002000 {{.*}} RW 0x1000 +// PART0-NEXT: LOAD 0x003000 0x0000000000003000 0x0000000000003000 {{.*}} RW 0x1000 +// PART0-NEXT: LOAD 0x004000 0x0000000000008000 0x0000000000008000 0x000000 0x001000 RW 0x1000 +// PART1-NEXT: LOAD 0x000000 0x0000000000004000 0x0000000000004000 {{.*}} R 0x1000 +// PART1-NEXT: LOAD 0x001000 0x0000000000005000 0x0000000000005000 {{.*}} R E 0x1000 +// PART1-NEXT: LOAD 0x002000 0x0000000000006000 0x0000000000006000 {{.*}} RW 0x1000 +// PART1-NEXT: LOAD 0x003000 0x0000000000007000 0x0000000000007000 {{.*}} RW 0x1000 +// CHECK-NEXT: DYNAMIC {{.*}} 0x{{0*}}[[DYNAMIC_ADDR]] 0x{{0*}}[[DYNAMIC_ADDR]] {{.*}} RW 0x8 +// PART0-NEXT: GNU_RELRO 0x002000 0x0000000000002000 0x0000000000002000 {{.*}} R 0x1 +// PART1-NEXT: GNU_RELRO 0x002000 0x0000000000006000 0x0000000000006000 {{.*}} R 0x1 +// CHECK-NEXT: GNU_EH_FRAME {{.*}} 0x{{0*}}[[EH_FRAME_HDR_ADDR]] 0x{{0*}}[[EH_FRAME_HDR_ADDR]] {{.*}} R 0x4 +// CHECK-NEXT: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x0 +// CHECK-EMPTY: + +// CHECK: Version symbols section '.gnu.version' +// CHECK-NEXT: Addr: +// PART0-NEXT: 000: 0 (*local*) 4 (v3) 5 (v2) 2 (x1) +// PART1-NEXT: 000: 0 (*local*) 5 (v2) 2 (x1) 3 (x2) + +// CHECK: Version definition section '.gnu.version_d' +// CHECK-NEXT: Addr: +// PART0-NEXT: 0x0000: Rev: 1 Flags: BASE Index: 1 Cnt: 1 Name: main.so +// PART1-NEXT: 0x0000: Rev: 1 Flags: BASE Index: 1 Cnt: 1 Name: part1 +// CHECK-NEXT: 0x001c: Rev: 1 Flags: none Index: 2 Cnt: 1 Name: x1 +// CHECK-NEXT: 0x0038: Rev: 1 Flags: none Index: 3 Cnt: 1 Name: x2 + +// CHECK: Version needs section '.gnu.version_r' +// CHECK-NEXT: Addr: +// CHECK-NEXT: 0x0000: Version: 1 File: verneed1.so.0 Cnt: 2 +// CHECK-NEXT: 0x0010: Name: v2 Flags: none Version: 5 +// CHECK-NEXT: 0x0020: Name: v3 Flags: none Version: 4 + +// PART0: Histogram for bucket list length (total of 4 buckets) +// PART0-NEXT: Length Number % of total Coverage +// PART0-NEXT: 0 1 ( 25.0%) 0.0% +// PART0-NEXT: 1 3 ( 75.0%) 100.0% +// PART0-NEXT: Histogram for `.gnu.hash' bucket list length (total of 1 buckets) +// PART0-NEXT: Length Number % of total Coverage +// PART0-NEXT: 0 0 ( 0.0%) 0.0% +// PART0-NEXT: 1 1 (100.0%) 100.0% + +// PART1: Histogram for bucket list length (total of 5 buckets) +// PART1-NEXT: Length Number % of total Coverage +// PART1-NEXT: 0 3 ( 60.0%) 0.0% +// PART1-NEXT: 1 2 ( 40.0%) 100.0% +// PART1-NEXT: Histogram for `.gnu.hash' bucket list length (total of 1 buckets) +// PART1-NEXT: Length Number % of total Coverage +// PART1-NEXT: 0 0 ( 0.0%) 0.0% +// PART1-NEXT: 1 0 ( 0.0%) 0.0% +// PART1-NEXT: 2 1 (100.0%) 100.0% + +// FILL: 001040 cccc cccc cccc cccc cccc cccc cccc cccc +// FILL-NEXT: * +// FILL-NEXT: 002000 + +// FILL: 005010 cccc cccc cccc cccc cccc cccc cccc cccc +// FILL-NEXT: * +// FILL-NEXT: 006000 + +.section .llvm_sympart,"",@llvm_sympart +.asciz "part1" +.quad p1 + +.section .llvm_sympart2,"",@llvm_sympart +.asciz "part1" +.quad p1alias + +.section .text.p0,"ax",@progbits +.globl p0 +p0: +.cfi_startproc +lea d0(%rip), %rax +call f1 +ret +.cfi_endproc + +.section .data.d0,"aw",@progbits +d0: +.quad f1 + +.section .text.p1,"ax",@progbits +.globl p1 +p1: +.globl p1alias +p1alias: +.cfi_startproc +lea d1(%rip), %rax +call f2 +ret +.cfi_endproc + +.section .data.d1,"aw",@progbits +d1: +.quad f2 +.quad p0 +.quad p0 +.quad d0 + +.section .init_array,"aw",@init_array +.quad p0 + +.globl __part_index_begin +.globl __part_index_end