diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -98,6 +98,8 @@ Tar = nullptr; memset(&In, 0, sizeof(In)); + Partitions = {Partition()}; + SharedFile::VernauxNum = 0; Config->ProgName = Args[0]; @@ -1344,7 +1346,7 @@ auto *Bss = make("COMMON", S->Size, S->Alignment); Bss->File = S->File; - Bss->Live = !Config->GcSections; + Bss->markDead(); InputSections.push_back(Bss); S->replace(Defined{S->File, S->getName(), S->Binding, S->StOther, S->Type, /*Value=*/0, S->Size, Bss}); @@ -1431,6 +1433,55 @@ } } +// This function reads a symbol partition specification section. These sections +// are used to control which partition a symbol is allocated to. See +// https://lld.llvm.org/Partitions.html for more details on partitions. +template +static void readSymbolPartitionSection(InputSectionBase *S) { + // Read the relocation that refers to the partition's entry point symbol. + Symbol *Sym; + if (S->AreRelocsRela) + Sym = &S->getFile()->getRelocTargetSym(S->template relas()[0]); + else + Sym = &S->getFile()->getRelocTargetSym(S->template rels()[0]); + if (!isa(Sym) || !Sym->includeInDynsym()) + return; + + StringRef PartName = reinterpret_cast(S->data().data()); + for (Partition &Part : Partitions) { + if (Part.Name != PartName) + continue; + Sym->Partition = Part.getNumber(); + return; + } + + // Forbid partitions from being used on incompatible targets, and forbid them + // from being used together with various linker features that assume a single + // set of output sections. + if (Script->HasSectionsCommand) + error(toString(S->File) + + ": partitions cannot be used with the SECTIONS command"); + if (Script->hasPhdrsCommands()) + error(toString(S->File) + + ": partitions cannot be used with the PHDRS command"); + if (!Config->SectionStartMap.empty()) + error(toString(S->File) + ": partitions cannot be used with " + "--section-start, -Ttext, -Tdata or -Tbss"); + if (Config->EMachine == EM_MIPS) + error(toString(S->File) + ": partitions cannot be used on this target"); + + // Impose a limit of no more than 254 partitions. This limit comes from the + // sizes of the Partition fields in InputSectionBase and Symbol, as well as + // the amount of space devoted to the partition number in RankFlags. + if (Partitions.size() == 254) + fatal("may not have more than 254 partitions"); + + Partitions.emplace_back(); + Partition &NewPart = Partitions.back(); + NewPart.Name = PartName; + Sym->Partition = NewPart.getNumber(); +} + template static Symbol *addUndefined(StringRef Name) { return Symtab->addSymbol( Undefined{nullptr, Name, STB_GLOBAL, STV_DEFAULT, 0}); @@ -1676,13 +1727,22 @@ for (InputSectionBase *S : F->getSections()) InputSections.push_back(cast(S)); - // We do not want to emit debug sections if --strip-all - // or -strip-debug are given. - if (Config->Strip != StripPolicy::None) { - llvm::erase_if(InputSections, [](InputSectionBase *S) { - return S->Name.startswith(".debug") || S->Name.startswith(".zdebug"); - }); - } + llvm::erase_if(InputSections, [](InputSectionBase *S) { + if (S->Type == SHT_LLVM_SYMPART) { + readSymbolPartitionSection(S); + return true; + } + + // We do not want to emit debug sections if --strip-all + // or -strip-debug are given. + return Config->Strip != StripPolicy::None && + (S->Name.startswith(".debug") || S->Name.startswith(".zdebug")); + }); + + // 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. + Target = getTarget(); Config->EFlags = Target->calcEFlags(); // MaxPageSize (sometimes called abi page size) is the maximum page size that diff --git a/lld/ELF/ICF.cpp b/lld/ELF/ICF.cpp --- a/lld/ELF/ICF.cpp +++ b/lld/ELF/ICF.cpp @@ -157,7 +157,7 @@ // Returns true if section S is subject of ICF. static bool isEligible(InputSection *S) { - if (!S->Live || S->KeepUnique || !(S->Flags & SHF_ALLOC)) + if (!S->isLive() || S->KeepUnique || !(S->Flags & SHF_ALLOC)) return false; // Don't merge writable sections. .data.rel.ro sections are marked as writable @@ -496,7 +496,7 @@ // we want to remove duplicate implicit dependencies such as link order // and relocation sections. for (InputSection *IS : Sections[I]->DependentSections) - IS->Live = false; + IS->markDead(); } }); } diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -54,10 +54,6 @@ // The next three bit fields are only used by InputSectionBase, but we // put them here so the struct packs better. - // The garbage collector sets sections' Live bits. - // If GC is disabled, all sections are considered live by default. - unsigned Live : 1; - // True if this section has already been placed to a linker script // output section. This is needed because, in a linker script, you // can refer to the same section more than once. For example, in @@ -76,6 +72,14 @@ // Set for sections that should not be folded by ICF. unsigned KeepUnique : 1; + // Pad the next field to a byte boundary. + unsigned : 2; + + // The 1-indexed partition that this section is assigned to by the garbage + // 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; + // These corresponds to the fields in Elf_Shdr. uint32_t Alignment; uint64_t Flags; @@ -95,12 +99,16 @@ uint64_t getVA(uint64_t Offset = 0) const; + bool isLive() const { return Partition != 0; } + void markLive() { Partition = 1; } + void markDead() { Partition = 0; } + protected: SectionBase(Kind SectionKind, StringRef Name, uint64_t Flags, uint64_t Entsize, uint64_t Alignment, uint32_t Type, uint32_t Info, uint32_t Link) - : Name(Name), Repl(this), SectionKind(SectionKind), Live(false), - Assigned(false), Bss(false), KeepUnique(false), Alignment(Alignment), + : Name(Name), Repl(this), SectionKind(SectionKind), Assigned(false), + Bss(false), KeepUnique(false), Partition(0), Alignment(Alignment), Flags(Flags), Entsize(Entsize), Type(Type), Link(Link), Info(Info) {} }; diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -442,7 +442,7 @@ continue; } SectionBase *Section = D->Section->Repl; - if (!Section->Live) { + if (!Section->isLive()) { P->setSymbolAndType(0, 0, false); continue; } @@ -1092,8 +1092,19 @@ void InputSection::replace(InputSection *Other) { Alignment = std::max(Alignment, Other->Alignment); + + // When a section is replaced with another section that was allocated to + // another partition, the replacement section (and its associated sections) + // need to be placed in the main partition so that both partitions will be + // able to access it. + if (Partition != Other->Partition) { + Partition = 1; + for (InputSection *IS : DependentSections) + IS->Partition = 1; + } + Other->Repl = Repl; - Other->Live = false; + Other->markDead(); } template diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -380,7 +380,7 @@ size_t SizeBefore = Ret.size(); for (InputSectionBase *Sec : InputSections) { - if (!Sec->Live || Sec->Assigned) + if (!Sec->isLive() || Sec->Assigned) continue; // For -emit-relocs we have to ignore entries like @@ -425,7 +425,7 @@ In.HashTab = nullptr; S->Assigned = false; - S->Live = false; + S->markDead(); discard(S->DependentSections); } } @@ -544,8 +544,9 @@ return Sec; } -static OutputSection *addInputSec(StringMap &Map, - InputSectionBase *IS, StringRef OutsecName) { +static OutputSection * +addInputSec(StringMap> &Map, + InputSectionBase *IS, StringRef OutsecName) { // Sections with SHT_GROUP or SHF_GROUP attributes reach here only when the -r // option is given. A section with SHT_GROUP defines a "section group", and // its members have SHF_GROUP attribute. Usually these flags have already been @@ -624,23 +625,26 @@ // // Given the above issues, we instead merge sections by name and error on // incompatible types and flags. - OutputSection *&Sec = Map[OutsecName]; - if (Sec) { + TinyPtrVector &V = Map[OutsecName]; + for (OutputSection *Sec : V) { + if (Sec->Partition != IS->Partition) + continue; Sec->addSection(cast(IS)); return nullptr; } - Sec = createSection(IS, OutsecName); + OutputSection *Sec = createSection(IS, OutsecName); + V.push_back(Sec); return Sec; } // Add sections that didn't match any sections command. void LinkerScript::addOrphanSections() { - StringMap Map; + StringMap> Map; std::vector V; auto Add = [&](InputSectionBase *S) { - if (!S->Live || S->Parent) + if (!S->isLive() || S->Parent) return; StringRef Name = getOutputSectionName(S); @@ -886,7 +890,7 @@ // A live output section means that some input section was added to it. It // might have been removed (if it was empty synthetic section), but we at // least know the flags. - if (Sec->Live) + if (Sec->isLive()) Flags = Sec->Flags; // We do not want to keep any special flags for output section @@ -897,7 +901,7 @@ SHF_WRITE | SHF_EXECINSTR); if (IsEmpty && isDiscardable(*Sec)) { - Sec->Live = false; + Sec->markDead(); Cmd = nullptr; } } diff --git a/lld/ELF/MapFile.cpp b/lld/ELF/MapFile.cpp --- a/lld/ELF/MapFile.cpp +++ b/lld/ELF/MapFile.cpp @@ -57,7 +57,7 @@ for (InputFile *File : ObjectFiles) for (Symbol *B : File->getSymbols()) if (auto *DR = dyn_cast(B)) - if (!DR->isSection() && DR->Section && DR->Section->Live && + if (!DR->isSection() && DR->Section && DR->Section->isLive() && (DR->File == File || DR->NeedsPltAddr || DR->Section->Bss)) V.push_back(DR); return V; @@ -238,7 +238,7 @@ if (isa(Sym)) Map[Sym].insert(File); if (auto *D = dyn_cast(Sym)) - if (!D->isLocal() && (!D->Section || D->Section->Live)) + if (!D->isLocal() && (!D->Section || D->Section->isLive())) Map[D].insert(File); } } diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp --- a/lld/ELF/MarkLive.cpp +++ b/lld/ELF/MarkLive.cpp @@ -25,6 +25,7 @@ #include "OutputSections.h" #include "SymbolTable.h" #include "Symbols.h" +#include "SyntheticSections.h" #include "Target.h" #include "lld/Common/Memory.h" #include "lld/Common/Strings.h" @@ -44,11 +45,15 @@ namespace { template class MarkLive { public: + MarkLive(unsigned Partition) : Partition(Partition) {} + void run(); + void moveToMain(); private: void enqueue(InputSectionBase *Sec, uint64_t Offset); void markSymbol(Symbol *Sym); + void mark(); template void resolveReloc(InputSectionBase &Sec, RelTy &Rel, bool IsLSDA); @@ -56,6 +61,9 @@ template void scanEhFrameSection(EhInputSection &EH, ArrayRef Rels); + // The index of the partition that we are currently processing. + unsigned Partition; + // A list of sections to visit. SmallVector Queue; @@ -183,9 +191,12 @@ if (auto *MS = dyn_cast(Sec)) MS->getSectionPiece(Offset)->Live = true; - if (Sec->Live) + // Set Sec->Partition to the meet (i.e. the "minimum") of Partition and + // Sec->Partition in the following lattice: 1 < other < 0. If Sec->Partition + // doesn't change, we don't need to do anything. + if (Sec->Partition == 1 || Sec->Partition == Partition) return; - Sec->Live = true; + Sec->Partition = Sec->Partition ? 1 : Partition; // Add input section to the queue. if (InputSection *S = dyn_cast(Sec)) @@ -203,6 +214,19 @@ // sections to set their "Live" bits. template void MarkLive::run() { // Add GC root symbols. + + // Preserve externally-visible symbols if the symbols defined by this + // file can interrupt other ELF file's symbols at runtime. + for (Symbol *S : Symtab->getSymbols()) + if (S->includeInDynsym() && S->Partition == Partition) + markSymbol(S); + + // If this isn't the main partition, that's all that we need to preserve. + if (Partition != 1) { + mark(); + return; + } + markSymbol(Symtab->find(Config->Entry)); markSymbol(Symtab->find(Config->Init)); markSymbol(Symtab->find(Config->Fini)); @@ -211,12 +235,6 @@ for (StringRef S : Script->ReferencedSymbols) markSymbol(Symtab->find(S)); - // Preserve externally-visible symbols if the symbols defined by this - // file can interrupt other ELF file's symbols at runtime. - for (Symbol *S : Symtab->getSymbols()) - if (S->includeInDynsym()) - markSymbol(S); - // Preserve special sections and those which are specified in linker // script KEEP command. for (InputSectionBase *Sec : InputSections) { @@ -225,7 +243,7 @@ // all of them. We also want to preserve personality routines and LSDA // referenced by .eh_frame sections, so we scan them for that here. if (auto *EH = dyn_cast(Sec)) { - EH->Live = true; + EH->markLive(); if (!EH->NumRelocations) continue; @@ -246,6 +264,10 @@ } } + mark(); +} + +template void MarkLive::mark() { // Mark all reachable sections. while (!Queue.empty()) { InputSectionBase &Sec = *Queue.pop_back_val(); @@ -263,6 +285,22 @@ } } +// Move the sections for some symbols to the main partition, specifically ifuncs +// (because they can result in an IRELATIVE being added to the main partition's +// GOT, which means that the ifunc must be available when the main partition is +// loaded) and TLS symbols (because we only know how to correctly process TLS +// relocations for the main partition). +template void MarkLive::moveToMain() { + for (InputFile *File : ObjectFiles) + for (Symbol *S : File->getSymbols()) + if (auto *D = dyn_cast(S)) + if ((D->Type == STT_GNU_IFUNC || D->Type == STT_TLS) && D->Section && + D->Section->isLive()) + markSymbol(S); + + mark(); +} + // Before calling this function, Live bits are off for all // input sections. This function make some or all of them on // so that they are emitted to the output file. @@ -270,7 +308,7 @@ // If -gc-sections is not given, no sections are removed. if (!Config->GcSections) { for (InputSectionBase *Sec : InputSections) - Sec->Live = true; + Sec->markLive(); // If a DSO defines a symbol referenced in a regular object, it is needed. for (Symbol *Sym : Symtab->getSymbols()) @@ -307,16 +345,23 @@ bool IsRel = (Sec->Type == SHT_REL || Sec->Type == SHT_RELA); if (!IsAlloc && !IsLinkOrder && !IsRel) - Sec->Live = true; + Sec->markLive(); } // Follow the graph to mark all live sections. - MarkLive().run(); + for (unsigned CurPart = 1; CurPart <= Partitions.size(); ++CurPart) + MarkLive(CurPart).run(); + + // If we have multiple partitions, some sections need to live in the main + // partition even if they were allocated to a loadable partition. Move them + // there now. + if (Partitions.size() != 1) + MarkLive(1).moveToMain(); // Report garbage-collected sections. if (Config->PrintGcSections) for (InputSectionBase *Sec : InputSections) - if (!Sec->Live) + if (!Sec->isLive()) message("removing unused section " + toString(Sec)); } diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -84,10 +84,10 @@ } void OutputSection::addSection(InputSection *IS) { - if (!Live) { + if (!isLive()) { // If IS is the first section to be added to this section, - // initialize Type, Entsize and flags from IS. - Live = true; + // initialize Partition, Type, Entsize and flags from IS. + Partition = IS->Partition; Type = IS->Type; Entsize = IS->Entsize; Flags = IS->Flags; @@ -158,7 +158,7 @@ } void OutputSection::sort(llvm::function_ref Order) { - assert(Live); + assert(isLive()); for (BaseCommand *B : SectionCommands) if (auto *ISD = dyn_cast(B)) sortByOrder(ISD->Sections, Order); diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -123,6 +123,7 @@ Sym->CanInline = true; Sym->Traced = Traced; Sym->ScriptDefined = false; + Sym->Partition = 1; return Sym; } diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -220,6 +220,9 @@ // True if this symbol is defined by a linker script. unsigned ScriptDefined : 1; + // The partition whose dynamic symbol table contains this symbol's definition. + uint8_t Partition = 1; + bool isSection() const { return Type == llvm::ELF::STT_SECTION; } bool isTls() const { return Type == llvm::ELF::STT_TLS; } bool isFunc() const { return Type == llvm::ELF::STT_FUNC; } @@ -485,6 +488,7 @@ Traced = Old.Traced; IsPreemptible = Old.IsPreemptible; ScriptDefined = Old.ScriptDefined; + Partition = Old.Partition; // Symbol length is computed lazily. If we already know a symbol length, // propagate it. diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -327,7 +327,7 @@ Warn(": unable to order absolute symbol: "); else if (D && isa(D->Section)) Warn(": unable to order synthetic symbol: "); - else if (D && !D->Section->Repl->Live) + else if (D && !D->Section->Repl->isLive()) Warn(": unable to order discarded symbol: "); } diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -31,6 +31,7 @@ namespace lld { namespace elf { class Defined; +struct Partition; class SyntheticSection : public InputSection { public: @@ -38,7 +39,7 @@ StringRef Name) : InputSection(nullptr, Flags, Type, Alignment, {}, Name, InputSectionBase::Synthetic) { - this->Live = true; + this->markLive(); } virtual ~SyntheticSection() = default; @@ -1058,6 +1059,14 @@ 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; } +}; + // Linker generated sections which can be used as inputs. struct InStruct { InputSection *ARMAttributes; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -107,7 +107,7 @@ for (InputSectionBase *Sec : InputSections) { if (Sec->Type != SHT_MIPS_ABIFLAGS) continue; - Sec->Live = false; + Sec->markDead(); Create = true; std::string Filename = toString(Sec->File); @@ -180,7 +180,7 @@ Elf_Mips_RegInfo Reginfo = {}; for (InputSectionBase *Sec : Sections) { - Sec->Live = false; + Sec->markDead(); std::string Filename = toString(Sec->File); ArrayRef D = Sec->data(); @@ -237,7 +237,7 @@ Elf_Mips_RegInfo Reginfo = {}; for (InputSectionBase *Sec : Sections) { - Sec->Live = false; + Sec->markDead(); if (Sec->data().size() != sizeof(Elf_Mips_RegInfo)) { error(toString(Sec->File) + ": invalid size of .reginfo section"); @@ -259,7 +259,7 @@ auto *Sec = make(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, Contents, ".interp"); - Sec->Live = true; + Sec->markLive(); return Sec; } @@ -358,7 +358,7 @@ // FDEs for garbage-collected or merged-by-ICF sections are dead. if (auto *D = dyn_cast(&B)) if (SectionBase *Sec = D->Section) - return Sec->Live; + return Sec->isLive(); return false; } @@ -1290,7 +1290,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()->Live) { + if (In.RelaPlt->getParent()->isLive()) { addInSec(DT_JMPREL, In.RelaPlt); Entries.push_back({DT_PLTRELSZ, addPltRelSz}); switch (Config->EMachine) { @@ -2370,7 +2370,7 @@ if (R.SectionIndex == -1ULL) continue; InputSectionBase *S = Sections[R.SectionIndex]; - if (!S || S == &InputSection::Discarded || !S->Live) + if (!S || S == &InputSection::Discarded || !S->isLive()) continue; // Range list with zero size has no effect. if (R.LowPC == R.HighPC) @@ -2503,7 +2503,7 @@ // a .gdb_index. So we can remove them from the output. for (InputSectionBase *S : InputSections) if (S->Name == ".debug_gnu_pubnames" || S->Name == ".debug_gnu_pubtypes") - S->Live = false; + S->markDead(); std::vector Chunks(Sections.size()); std::vector> NameAttrs(Sections.size()); @@ -2945,7 +2945,7 @@ // We do not want to handle sections that are not alive, so just remove // them instead of trying to merge. - if (!MS->Live) { + if (!MS->isLive()) { S = nullptr; continue; } @@ -3257,6 +3257,8 @@ InStruct elf::In; +std::vector elf::Partitions; + template GdbIndexSection *GdbIndexSection::create(); template GdbIndexSection *GdbIndexSection::create(); template GdbIndexSection *GdbIndexSection::create(); diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -157,7 +157,7 @@ template static void combineEhSections() { for (InputSectionBase *&S : InputSections) { - if (!S->Live) + if (!S->isLive()) continue; if (auto *ES = dyn_cast(S)) { @@ -608,7 +608,7 @@ Sec = Sec->Repl; // Exclude symbols pointing to garbage-collected sections. - if (isa(Sec) && !Sec->Live) + if (isa(Sec) && !Sec->isLive()) return false; if (auto *S = dyn_cast(Sec)) @@ -762,8 +762,9 @@ // * 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 << 17, - RF_NOT_ALLOC = 1 << 16, + RF_NOT_ADDR_SET = 1 << 25, + RF_NOT_ALLOC = 1 << 24, + RF_PARTITION = 1 << 16, // Partition number (8 bits) RF_NOT_INTERP = 1 << 15, RF_NOT_NOTE = 1 << 14, RF_WRITE = 1 << 13, @@ -783,7 +784,7 @@ }; static unsigned getSectionRank(const OutputSection *Sec) { - unsigned Rank = 0; + unsigned Rank = Sec->Partition * RF_PARTITION; // We want to put section specified by -T option first, so we // can start assigning VA starting from them later. @@ -954,11 +955,11 @@ // Note that relocations for non-alloc sections are directly // processed by InputSection::relocateNonAlloc. for (InputSectionBase *IS : InputSections) - if (IS->Live && isa(IS) && (IS->Flags & SHF_ALLOC)) + if (IS->isLive() && isa(IS) && (IS->Flags & SHF_ALLOC)) Fn(*IS); for (EhInputSection *ES : In.EhFrame->Sections) Fn(*ES); - if (In.ARMExidx && In.ARMExidx->Live) + if (In.ARMExidx && In.ARMExidx->isLive()) for (InputSection *Ex : In.ARMExidx->ExidxSections) Fn(*Ex); } @@ -1055,7 +1056,7 @@ static int getRankProximity(OutputSection *A, BaseCommand *B) { auto *Sec = dyn_cast(B); - return (Sec && Sec->Live) ? getRankProximityAux(A, Sec) : -1; + return (Sec && Sec->isLive()) ? getRankProximityAux(A, Sec) : -1; } // When placing orphan sections, we want to place them after symbol assignments @@ -1097,7 +1098,7 @@ int Proximity = getRankProximity(Sec, *I); for (; I != E; ++I) { auto *CurSec = dyn_cast(*I); - if (!CurSec || !CurSec->Live) + if (!CurSec || !CurSec->isLive()) continue; if (getRankProximity(Sec, CurSec) != Proximity || Sec->SortRank < CurSec->SortRank) @@ -1106,7 +1107,7 @@ auto IsLiveOutputSec = [](BaseCommand *Cmd) { auto *OS = dyn_cast(Cmd); - return OS && OS->Live; + return OS && OS->isLive(); }; auto J = std::find_if(llvm::make_reverse_iterator(I), llvm::make_reverse_iterator(B), IsLiveOutputSec); diff --git a/lld/test/ELF/partition-errors.s b/lld/test/ELF/partition-errors.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/partition-errors.s @@ -0,0 +1,23 @@ +// REQUIRES: x86, mips +// RUN: llvm-mc -triple=x86_64-unknown-linux -filetype=obj -o %t.o %s +// RUN: echo "SECTIONS {}" > %t.script +// RUN: not ld.lld --export-dynamic %t.o %t.script 2>&1 | FileCheck %s +// RUN: echo "PHDRS { text PT_LOAD; }" > %t2.script +// RUN: not ld.lld --export-dynamic %t.o %t2.script 2>&1 | FileCheck %s +// RUN: not ld.lld --export-dynamic %t.o --section-start .text=0 2>&1 | FileCheck %s +// RUN: not ld.lld --export-dynamic %t.o -Ttext=0 2>&1 | FileCheck %s +// RUN: not ld.lld --export-dynamic %t.o -Tdata=0 2>&1 | FileCheck %s +// RUN: not ld.lld --export-dynamic %t.o -Tbss=0 2>&1 | FileCheck %s + +// RUN: llvm-mc -triple=mipsel-unknown-linux -filetype=obj -o %t2.o %s +// RUN: not ld.lld --export-dynamic %t2.o 2>&1 | FileCheck %s + +// CHECK: error: {{.*}}.o: partitions cannot be used + +.section .llvm_sympart.f1,"",@llvm_sympart +.asciz "part1" +.quad f1 + +.text +.globl f1 +f1: diff --git a/lld/test/ELF/partition-icf.s b/lld/test/ELF/partition-icf.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/partition-icf.s @@ -0,0 +1,49 @@ +// REQUIRES: x86 +// RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux +// RUN: ld.lld %t.o -o %t --export-dynamic --gc-sections --icf=all +// RUN: llvm-readelf -S -s %t | FileCheck %s + +// CHECK: [ [[MAIN:[0-9]+]]] .text +// CHECK: [ [[P1:[0-9]+]]] .text +// CHECK: [ [[P2:[0-9]+]]] .text + +// CHECK: [[P1]] f1 +// CHECK: [[P2]] f2 +// CHECK: [[MAIN]] g1 +// CHECK: [[MAIN]] g2 + +.section .llvm_sympart.f1,"",@llvm_sympart +.asciz "part1" +.quad f1 + +.section .llvm_sympart.f2,"",@llvm_sympart +.asciz "part2" +.quad f2 + +.section .llvm_sympart.g1,"",@llvm_sympart +.asciz "part1" +.quad g1 + +.section .llvm_sympart.g2,"",@llvm_sympart +.asciz "part2" +.quad g2 + +.section .text.f1,"ax",@progbits +.globl f1 +f1: +.byte 1 + +.section .text.f2,"ax",@progbits +.globl f2 +f2: +.byte 2 + +.section .text.g1,"ax",@progbits +.globl g1 +g1: +.byte 3 + +.section .text.g2,"ax",@progbits +.globl g2 +g2: +.byte 3 diff --git a/lld/test/ELF/partition-move-to-main.s b/lld/test/ELF/partition-move-to-main.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/partition-move-to-main.s @@ -0,0 +1,44 @@ +// REQUIRES: x86 +// RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux +// RUN: ld.lld %t.o -o %t --export-dynamic --gc-sections +// RUN: llvm-readelf -S -s %t | FileCheck %s + +// Ordinarily, the TLS and IFUNC sections would be split into partitions. +// Make sure that that didn't happen by checking that there is only one +// of each section. + +// CHECK: .ifunc +// CHECK: .tdata + +// CHECK-NOT: .ifunc +// CHECK-NOT: .tdata + +.section .llvm_sympart.f1,"",@llvm_sympart +.asciz "part1" +.quad f1 + +.section .text._start,"ax",@progbits +.globl _start +_start: +call tls1 +call ifunc1 + +.section .text.f1,"ax",@progbits +.globl f1 +f1: +call tls2 +call ifunc2 + +.section .ifunc,"ax",@progbits,unique,1 +.type ifunc1 STT_GNU_IFUNC +ifunc1: + +.section .ifunc,"ax",@progbits,unique,2 +.type ifunc2 STT_GNU_IFUNC +ifunc2: + +.section .tdata,"awT",@progbits,unique,1 +tls1: + +.section .tdata,"awT",@progbits,unique,2 +tls2: diff --git a/lld/test/ELF/partitions.s b/lld/test/ELF/partitions.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/partitions.s @@ -0,0 +1,62 @@ +// REQUIRES: x86 +// RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux +// RUN: ld.lld %t.o -o %t --export-dynamic --gc-sections +// RUN: llvm-readelf -S -s %t | FileCheck %s + +// This is basically lld/docs/partitions.dot in object file form. +// Test that the sections are correctly allocated to partitions. + +// CHECK: [ [[MAIN:[0-9]+]]] .text +// CHECK: [ [[P1:[0-9]+]]] .text +// CHECK: [ [[P2:[0-9]+]]] .text + +// CHECK: [[MAIN]] _start +// CHECK: [[P1]] f1 +// CHECK: [[P2]] f2 +// CHECK: [[MAIN]] f3 +// CHECK: [[P1]] f4 +// CHECK: [[MAIN]] f5 +// CHECK: [[P2]] f6 + +.section .llvm_sympart.f1,"",@llvm_sympart +.asciz "part1" +.quad f1 + +.section .llvm_sympart.f2,"",@llvm_sympart +.asciz "part2" +.quad f2 + +.section .text._start,"ax",@progbits +.globl _start +_start: +call f3 + +.section .text.f1,"ax",@progbits +.globl f1 +f1: +call f3 +call f4 +call f5 + +.section .text.f2,"ax",@progbits +.globl f2 +f2: +call f3 +call f5 +call f6 + +.section .text.f3,"ax",@progbits +f3: +ret + +.section .text.f4,"ax",@progbits +f4: +ret + +.section .text.f5,"ax",@progbits +f5: +ret + +.section .text.f6,"ax",@progbits +f6: +ret