diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-07-13 19:26:06 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-07-13 19:26:06 +0000 |
commit | 267829774358b5aebd3e726ae318813bd48129bb (patch) | |
tree | 5a8904da0d9716ea10b69258f5d50e0b1ee2ec2c /ELF | |
parent | 0317860f00ca8e821989c92c8a6cc461fd5f2009 (diff) | |
download | src-267829774358b5aebd3e726ae318813bd48129bb.tar.gz src-267829774358b5aebd3e726ae318813bd48129bb.zip |
Vendor import of lld trunk r307894:vendor/lld/lld-trunk-r307894
Notes
Notes:
svn path=/vendor/lld/dist/; revision=320965
svn path=/vendor/lld/lld-trunk-r307894/; revision=320966; tag=vendor/lld/lld-trunk-r307894
Diffstat (limited to 'ELF')
-rw-r--r-- | ELF/Config.h | 1 | ||||
-rw-r--r-- | ELF/Driver.cpp | 2 | ||||
-rw-r--r-- | ELF/Error.cpp | 5 | ||||
-rw-r--r-- | ELF/Error.h | 1 | ||||
-rw-r--r-- | ELF/Filesystem.cpp | 3 | ||||
-rw-r--r-- | ELF/GdbIndex.h | 1 | ||||
-rw-r--r-- | ELF/InputFiles.cpp | 5 | ||||
-rw-r--r-- | ELF/InputSection.cpp | 6 | ||||
-rw-r--r-- | ELF/LinkerScript.cpp | 308 | ||||
-rw-r--r-- | ELF/LinkerScript.h | 30 | ||||
-rw-r--r-- | ELF/OutputSections.cpp | 98 | ||||
-rw-r--r-- | ELF/OutputSections.h | 7 | ||||
-rw-r--r-- | ELF/Relocations.cpp | 32 | ||||
-rw-r--r-- | ELF/Relocations.h | 9 | ||||
-rw-r--r-- | ELF/ScriptParser.cpp | 3 | ||||
-rw-r--r-- | ELF/SymbolTable.cpp | 49 | ||||
-rw-r--r-- | ELF/Symbols.cpp | 20 | ||||
-rw-r--r-- | ELF/Symbols.h | 6 | ||||
-rw-r--r-- | ELF/SyntheticSections.cpp | 65 | ||||
-rw-r--r-- | ELF/SyntheticSections.h | 5 | ||||
-rw-r--r-- | ELF/Thunks.cpp | 32 | ||||
-rw-r--r-- | ELF/Thunks.h | 4 | ||||
-rw-r--r-- | ELF/Writer.cpp | 167 |
23 files changed, 453 insertions, 406 deletions
diff --git a/ELF/Config.h b/ELF/Config.h index 32e86b0ec7b6..5e3b77637316 100644 --- a/ELF/Config.h +++ b/ELF/Config.h @@ -97,6 +97,7 @@ struct Configuration { llvm::StringRef ThinLTOCacheDir; std::string Rpath; std::vector<VersionDefinition> VersionDefinitions; + std::vector<llvm::StringRef> Argv; std::vector<llvm::StringRef> AuxiliaryList; std::vector<llvm::StringRef> SearchPaths; std::vector<llvm::StringRef> SymbolOrderingFile; diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index 5fb33caea46f..10ad13f214d5 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -74,13 +74,13 @@ bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Error) { ErrorCount = 0; ErrorOS = &Error; - Argv0 = Args[0]; InputSections.clear(); Tar = nullptr; Config = make<Configuration>(); Driver = make<LinkerDriver>(); Script = make<LinkerScript>(); + Config->Argv = {Args.begin(), Args.end()}; Driver->main(Args, CanExitEarly); freeArena(); diff --git a/ELF/Error.cpp b/ELF/Error.cpp index 7a58668bdcc0..224570ea7424 100644 --- a/ELF/Error.cpp +++ b/ELF/Error.cpp @@ -27,7 +27,6 @@ using namespace lld::elf; uint64_t elf::ErrorCount; raw_ostream *elf::ErrorOS; -StringRef elf::Argv0; // The functions defined in this file can be called from multiple threads, // but outs() or errs() are not thread-safe. We protect them using a mutex. @@ -46,7 +45,7 @@ static void newline(const Twine &Msg) { } static void print(StringRef S, raw_ostream::Colors C) { - *ErrorOS << Argv0 + ": "; + *ErrorOS << Config->Argv[0] << ": "; if (Config->ColorDiagnostics) { ErrorOS->changeColor(C, true); *ErrorOS << S; @@ -59,7 +58,7 @@ static void print(StringRef S, raw_ostream::Colors C) { void elf::log(const Twine &Msg) { if (Config->Verbose) { std::lock_guard<std::mutex> Lock(Mu); - outs() << Argv0 << ": " << Msg << "\n"; + outs() << Config->Argv[0] << ": " << Msg << "\n"; outs().flush(); } } diff --git a/ELF/Error.h b/ELF/Error.h index dd6e37c99b15..89bc2111b44e 100644 --- a/ELF/Error.h +++ b/ELF/Error.h @@ -37,7 +37,6 @@ namespace elf { extern uint64_t ErrorCount; extern llvm::raw_ostream *ErrorOS; -extern llvm::StringRef Argv0; void log(const Twine &Msg); void message(const Twine &Msg); diff --git a/ELF/Filesystem.cpp b/ELF/Filesystem.cpp index b63d521a83b0..d468ae0c618a 100644 --- a/ELF/Filesystem.cpp +++ b/ELF/Filesystem.cpp @@ -38,7 +38,8 @@ using namespace lld::elf; // This function spawns a background thread to call unlink. // The calling thread returns almost immediately. void elf::unlinkAsync(StringRef Path) { - if (!Config->Threads || !sys::fs::exists(Config->OutputFile)) + if (!Config->Threads || !sys::fs::exists(Config->OutputFile) || + !sys::fs::is_regular_file(Config->OutputFile)) return; // First, rename Path to avoid race condition. We cannot remove diff --git a/ELF/GdbIndex.h b/ELF/GdbIndex.h index 527667f7280e..c49f8946e199 100644 --- a/ELF/GdbIndex.h +++ b/ELF/GdbIndex.h @@ -45,6 +45,7 @@ struct NameTypeEntry { // debug information performed. That information futher used // for filling gdb index section areas. struct GdbIndexChunk { + InputSection *DebugInfoSec; std::vector<AddressEntry> AddressArea; std::vector<CompilationUnitEntry> CompilationUnits; std::vector<NameTypeEntry> NamesAndTypes; diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index e07f24d665df..d3c307d5cb6b 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -45,14 +45,11 @@ namespace { // LLVM DWARF parser will not be able to parse .debug_line correctly, unless // we assign each section some unique address. This callback method assigns // each section an address equal to its offset in ELF object file. -class ObjectInfo : public LoadedObjectInfo { +class ObjectInfo : public LoadedObjectInfoHelper<ObjectInfo> { public: uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override { return static_cast<const ELFSectionRef &>(Sec).getOffset(); } - std::unique_ptr<LoadedObjectInfo> clone() const override { - return std::unique_ptr<LoadedObjectInfo>(); - } }; } diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index b1d5e1349460..c6a539b8dfa5 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -276,7 +276,9 @@ template <class ELFT> std::string InputSectionBase::getSrcMsg(uint64_t Offset) { template <class ELFT> std::string InputSectionBase::getObjMsg(uint64_t Off) { // Synthetic sections don't have input files. elf::ObjectFile<ELFT> *File = getFile<ELFT>(); - std::string Filename = File ? File->getName() : "(internal)"; + if (!File) + return ("(internal):(" + Name + "+0x" + utohexstr(Off) + ")").str(); + std::string Filename = File->getName(); std::string Archive; if (!File->ArchiveName.empty()) @@ -466,7 +468,7 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A, static uint64_t getARMStaticBase(const SymbolBody &Body) { OutputSection *OS = Body.getOutputSection(); if (!OS || !OS->FirstInPtLoad) - fatal("SBREL relocation to " + Body.getName() + " without static base\n"); + fatal("SBREL relocation to " + Body.getName() + " without static base"); return OS->FirstInPtLoad->Addr; } diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index d369a6f978a2..a182d5a3a096 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -111,17 +111,13 @@ LinkerScript::getOrCreateOutputSectionCommand(StringRef Name) { void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) { uint64_t Val = E().getValue(); - if (Val < Dot) { - if (InSec) - error(Loc + ": unable to move location counter backward for: " + - CurOutSec->Name); - else - error(Loc + ": unable to move location counter backward"); - } + if (Val < Dot && InSec) + error(Loc + ": unable to move location counter backward for: " + + CurAddressState->OutSec->Name); Dot = Val; // Update to location counter means update to section size. if (InSec) - CurOutSec->Size = Dot - CurOutSec->Addr; + CurAddressState->OutSec->Size = Dot - CurAddressState->OutSec->Addr; } // Sets value of a symbol. Two kinds of symbols are processed: synthetic @@ -373,7 +369,13 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { // which will map to whatever the first actual section is. Aether = make<OutputSection>("", 0, SHF_ALLOC); Aether->SectionIndex = 1; - CurOutSec = Aether; + auto State = make_unique<AddressState>(Opt); + // CurAddressState captures the local AddressState and makes it accessible + // deliberately. This is needed as there are some cases where we cannot just + // thread the current state through to a lambda function created by the + // script parser. + CurAddressState = State.get(); + CurAddressState->OutSec = Aether; Dot = 0; for (size_t I = 0; I < Opt.Commands.size(); ++I) { @@ -435,7 +437,7 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { } } } - CurOutSec = nullptr; + CurAddressState = nullptr; } void LinkerScript::fabricateDefaultCommands() { @@ -481,20 +483,31 @@ void LinkerScript::fabricateDefaultCommands() { // Add sections that didn't match any sections command. void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { + unsigned NumCommands = Opt.Commands.size(); for (InputSectionBase *S : InputSections) { if (!S->Live || S->Parent) continue; StringRef Name = getOutputSectionName(S->Name); - auto I = std::find_if( - Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) { - if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) - return Cmd->Name == Name; - return false; - }); - if (I == Opt.Commands.end()) { + auto End = Opt.Commands.begin() + NumCommands; + auto I = std::find_if(Opt.Commands.begin(), End, [&](BaseCommand *Base) { + if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) + return Cmd->Name == Name; + return false; + }); + OutputSectionCommand *Cmd; + if (I == End) { Factory.addInputSec(S, Name); + OutputSection *Sec = S->getOutputSection(); + assert(Sec->SectionIndex == INT_MAX); + OutputSectionCommand *&CmdRef = SecToCommand[Sec]; + if (!CmdRef) { + CmdRef = createOutputSectionCommand(Sec->Name, "<internal>"); + CmdRef->Sec = Sec; + Opt.Commands.push_back(CmdRef); + } + Cmd = CmdRef; } else { - auto *Cmd = cast<OutputSectionCommand>(*I); + Cmd = cast<OutputSectionCommand>(*I); Factory.addInputSec(S, Name, Cmd->Sec); if (OutputSection *Sec = Cmd->Sec) { SecToCommand[Sec] = Cmd; @@ -502,21 +515,22 @@ void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { assert(Sec->SectionIndex == INT_MAX || Sec->SectionIndex == Index); Sec->SectionIndex = Index; } - auto *ISD = make<InputSectionDescription>(""); - ISD->Sections.push_back(cast<InputSection>(S)); - Cmd->Commands.push_back(ISD); } + auto *ISD = make<InputSectionDescription>(""); + ISD->Sections.push_back(cast<InputSection>(S)); + Cmd->Commands.push_back(ISD); } } uint64_t LinkerScript::advance(uint64_t Size, unsigned Align) { - bool IsTbss = (CurOutSec->Flags & SHF_TLS) && CurOutSec->Type == SHT_NOBITS; - uint64_t Start = IsTbss ? Dot + ThreadBssOffset : Dot; + bool IsTbss = (CurAddressState->OutSec->Flags & SHF_TLS) && + CurAddressState->OutSec->Type == SHT_NOBITS; + uint64_t Start = IsTbss ? Dot + CurAddressState->ThreadBssOffset : Dot; Start = alignTo(Start, Align); uint64_t End = Start + Size; if (IsTbss) - ThreadBssOffset = End - Dot; + CurAddressState->ThreadBssOffset = End - Dot; else Dot = End; return End; @@ -524,40 +538,43 @@ uint64_t LinkerScript::advance(uint64_t Size, unsigned Align) { void LinkerScript::output(InputSection *S) { uint64_t Pos = advance(S->getSize(), S->Alignment); - S->OutSecOff = Pos - S->getSize() - CurOutSec->Addr; + S->OutSecOff = Pos - S->getSize() - CurAddressState->OutSec->Addr; // Update output section size after adding each section. This is so that // SIZEOF works correctly in the case below: // .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) } - CurOutSec->Size = Pos - CurOutSec->Addr; + CurAddressState->OutSec->Size = Pos - CurAddressState->OutSec->Addr; // If there is a memory region associated with this input section, then // place the section in that region and update the region index. - if (CurMemRegion) { - CurMemRegion->Offset += CurOutSec->Size; - uint64_t CurSize = CurMemRegion->Offset - CurMemRegion->Origin; - if (CurSize > CurMemRegion->Length) { - uint64_t OverflowAmt = CurSize - CurMemRegion->Length; - error("section '" + CurOutSec->Name + "' will not fit in region '" + - CurMemRegion->Name + "': overflowed by " + Twine(OverflowAmt) + - " bytes"); + if (CurAddressState->MemRegion) { + uint64_t &CurOffset = + CurAddressState->MemRegionOffset[CurAddressState->MemRegion]; + CurOffset += CurAddressState->OutSec->Size; + uint64_t CurSize = CurOffset - CurAddressState->MemRegion->Origin; + if (CurSize > CurAddressState->MemRegion->Length) { + uint64_t OverflowAmt = CurSize - CurAddressState->MemRegion->Length; + error("section '" + CurAddressState->OutSec->Name + + "' will not fit in region '" + CurAddressState->MemRegion->Name + + "': overflowed by " + Twine(OverflowAmt) + " bytes"); } } } void LinkerScript::switchTo(OutputSection *Sec) { - if (CurOutSec == Sec) + if (CurAddressState->OutSec == Sec) return; - CurOutSec = Sec; - CurOutSec->Addr = advance(0, CurOutSec->Alignment); + CurAddressState->OutSec = Sec; + CurAddressState->OutSec->Addr = + advance(0, CurAddressState->OutSec->Alignment); // If neither AT nor AT> is specified for an allocatable section, the linker // will set the LMA such that the difference between VMA and LMA for the // section is the same as the preceding output section in the same region // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html - if (LMAOffset) - CurOutSec->LMAOffset = LMAOffset(); + if (CurAddressState->LMAOffset) + CurAddressState->OutSec->LMAOffset = CurAddressState->LMAOffset(); } void LinkerScript::process(BaseCommand &Base) { @@ -569,9 +586,9 @@ void LinkerScript::process(BaseCommand &Base) { // Handle BYTE(), SHORT(), LONG(), or QUAD(). if (auto *Cmd = dyn_cast<BytesDataCommand>(&Base)) { - Cmd->Offset = Dot - CurOutSec->Addr; + Cmd->Offset = Dot - CurAddressState->OutSec->Addr; Dot += Cmd->Size; - CurOutSec->Size = Dot - CurOutSec->Addr; + CurAddressState->OutSec->Size = Dot - CurAddressState->OutSec->Addr; return; } @@ -596,7 +613,7 @@ void LinkerScript::process(BaseCommand &Base) { if (!Sec->Live) continue; - assert(CurOutSec == Sec->getParent()); + assert(CurAddressState->OutSec == Sec->getParent()); output(Sec); } } @@ -649,17 +666,17 @@ void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) { if (Cmd->LMAExpr) { uint64_t D = Dot; - LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; }; + CurAddressState->LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; }; } - CurMemRegion = Cmd->MemRegion; - if (CurMemRegion) - Dot = CurMemRegion->Offset; + CurAddressState->MemRegion = Cmd->MemRegion; + if (CurAddressState->MemRegion) + Dot = CurAddressState->MemRegionOffset[CurAddressState->MemRegion]; switchTo(Sec); // We do not support custom layout for compressed debug sectons. // At this point we already know their size and have compressed content. - if (CurOutSec->Flags & SHF_COMPRESSED) + if (CurAddressState->OutSec->Flags & SHF_COMPRESSED) return; for (BaseCommand *C : Cmd->Commands) @@ -746,30 +763,20 @@ void LinkerScript::adjustSectionsAfterSorting() { if (!Cmd) continue; - if (Cmd->Phdrs.empty()) - Cmd->Phdrs = DefPhdrs; - else + if (Cmd->Phdrs.empty()) { + OutputSection *Sec = Cmd->Sec; + // To match the bfd linker script behaviour, only propagate program + // headers to sections that are allocated. + if (Sec && (Sec->Flags & SHF_ALLOC)) + Cmd->Phdrs = DefPhdrs; + } else { DefPhdrs = Cmd->Phdrs; + } } removeEmptyCommands(); } -void LinkerScript::createOrphanCommands() { - for (OutputSection *Sec : OutputSections) { - if (Sec->SectionIndex != INT_MAX) - continue; - OutputSectionCommand *Cmd = - createOutputSectionCommand(Sec->Name, "<internal>"); - Cmd->Sec = Sec; - SecToCommand[Sec] = Cmd; - auto *ISD = make<InputSectionDescription>(""); - ISD->Sections = Sec->Sections; - Cmd->Commands.push_back(ISD); - Opt.Commands.push_back(Cmd); - } -} - void LinkerScript::processNonSectionCommands() { for (BaseCommand *Base : Opt.Commands) { if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) @@ -779,22 +786,25 @@ void LinkerScript::processNonSectionCommands() { } } -static bool -allocateHeaders(std::vector<PhdrEntry> &Phdrs, - ArrayRef<OutputSectionCommand *> OutputSectionCommands, - uint64_t Min) { - auto FirstPTLoad = - std::find_if(Phdrs.begin(), Phdrs.end(), - [](const PhdrEntry &E) { return E.p_type == PT_LOAD; }); +void LinkerScript::allocateHeaders(std::vector<PhdrEntry> &Phdrs) { + uint64_t Min = std::numeric_limits<uint64_t>::max(); + for (OutputSectionCommand *Cmd : OutputSectionCommands) { + OutputSection *Sec = Cmd->Sec; + if (Sec->Flags & SHF_ALLOC) + Min = std::min<uint64_t>(Min, Sec->Addr); + } + + auto FirstPTLoad = llvm::find_if( + Phdrs, [](const PhdrEntry &E) { return E.p_type == PT_LOAD; }); if (FirstPTLoad == Phdrs.end()) - return false; + return; uint64_t HeaderSize = getHeaderSize(); if (HeaderSize <= Min || Script->hasPhdrsCommands()) { Min = alignDown(Min - HeaderSize, Config->MaxPageSize); Out::ElfHeader->Addr = Min; Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size; - return true; + return; } assert(FirstPTLoad->First == Out::ElfHeader); @@ -817,17 +827,28 @@ allocateHeaders(std::vector<PhdrEntry> &Phdrs, Phdrs.erase(FirstPTLoad); } - auto PhdrI = std::find_if(Phdrs.begin(), Phdrs.end(), [](const PhdrEntry &E) { - return E.p_type == PT_PHDR; - }); + auto PhdrI = llvm::find_if( + Phdrs, [](const PhdrEntry &E) { return E.p_type == PT_PHDR; }); if (PhdrI != Phdrs.end()) Phdrs.erase(PhdrI); - return false; } -void LinkerScript::assignAddresses(std::vector<PhdrEntry> &Phdrs) { +LinkerScript::AddressState::AddressState(const ScriptConfiguration &Opt) { + for (auto &MRI : Opt.MemoryRegions) { + const MemoryRegion *MR = &MRI.second; + MemRegionOffset[MR] = MR->Origin; + } +} + +void LinkerScript::assignAddresses() { // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = 0; + auto State = make_unique<AddressState>(Opt); + // CurAddressState captures the local AddressState and makes it accessible + // deliberately. This is needed as there are some cases where we cannot just + // thread the current state through to a lambda function created by the + // script parser. + CurAddressState = State.get(); ErrorOnMissingSection = true; switchTo(Aether); @@ -845,15 +866,7 @@ void LinkerScript::assignAddresses(std::vector<PhdrEntry> &Phdrs) { auto *Cmd = cast<OutputSectionCommand>(Base); assignOffsets(Cmd); } - - uint64_t MinVA = std::numeric_limits<uint64_t>::max(); - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; - if (Sec->Flags & SHF_ALLOC) - MinVA = std::min<uint64_t>(MinVA, Sec->Addr); - } - - allocateHeaders(Phdrs, OutputSectionCommands, MinVA); + CurAddressState = nullptr; } // Creates program headers as instructed by PHDRS linker script command. @@ -879,12 +892,9 @@ std::vector<PhdrEntry> LinkerScript::createPhdrs() { // Add output sections to program headers. for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; - if (!(Sec->Flags & SHF_ALLOC)) - break; - // Assign headers specified by linker script - for (size_t Id : getPhdrIndices(Sec)) { + for (size_t Id : getPhdrIndices(Cmd)) { + OutputSection *Sec = Cmd->Sec; Ret[Id].add(Sec); if (Opt.PhdrsCommands[Id].Flags == UINT_MAX) Ret[Id].p_flags |= Sec->getPhdrFlags(); @@ -911,6 +921,92 @@ OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const { return I->second; } +void OutputSectionCommand::sort(std::function<int(InputSectionBase *S)> Order) { + typedef std::pair<unsigned, InputSection *> Pair; + auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; + + std::vector<Pair> V; + assert(Commands.size() == 1); + auto *ISD = cast<InputSectionDescription>(Commands[0]); + for (InputSection *S : ISD->Sections) + V.push_back({Order(S), S}); + std::stable_sort(V.begin(), V.end(), Comp); + ISD->Sections.clear(); + for (Pair &P : V) + ISD->Sections.push_back(P.second); +} + +// Returns true if S matches /Filename.?\.o$/. +static bool isCrtBeginEnd(StringRef S, StringRef Filename) { + if (!S.endswith(".o")) + return false; + S = S.drop_back(2); + if (S.endswith(Filename)) + return true; + return !S.empty() && S.drop_back().endswith(Filename); +} + +static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); } +static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); } + +// .ctors and .dtors are sorted by this priority from highest to lowest. +// +// 1. The section was contained in crtbegin (crtbegin contains +// some sentinel value in its .ctors and .dtors so that the runtime +// can find the beginning of the sections.) +// +// 2. The section has an optional priority value in the form of ".ctors.N" +// or ".dtors.N" where N is a number. Unlike .{init,fini}_array, +// they are compared as string rather than number. +// +// 3. The section is just ".ctors" or ".dtors". +// +// 4. The section was contained in crtend, which contains an end marker. +// +// In an ideal world, we don't need this function because .init_array and +// .ctors are duplicate features (and .init_array is newer.) However, there +// are too many real-world use cases of .ctors, so we had no choice to +// support that with this rather ad-hoc semantics. +static bool compCtors(const InputSection *A, const InputSection *B) { + bool BeginA = isCrtbegin(A->File->getName()); + bool BeginB = isCrtbegin(B->File->getName()); + if (BeginA != BeginB) + return BeginA; + bool EndA = isCrtend(A->File->getName()); + bool EndB = isCrtend(B->File->getName()); + if (EndA != EndB) + return EndB; + StringRef X = A->Name; + StringRef Y = B->Name; + assert(X.startswith(".ctors") || X.startswith(".dtors")); + assert(Y.startswith(".ctors") || Y.startswith(".dtors")); + X = X.substr(6); + Y = Y.substr(6); + if (X.empty() && Y.empty()) + return false; + return X < Y; +} + +// Sorts input sections by the special rules for .ctors and .dtors. +// Unfortunately, the rules are different from the one for .{init,fini}_array. +// Read the comment above. +void OutputSectionCommand::sortCtorsDtors() { + assert(Commands.size() == 1); + auto *ISD = cast<InputSectionDescription>(Commands[0]); + std::stable_sort(ISD->Sections.begin(), ISD->Sections.end(), compCtors); +} + +// Sorts input sections by section name suffixes, so that .foo.N comes +// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections. +// We want to keep the original order if the priorities are the same +// because the compiler keeps the original initialization order in a +// translation unit and we need to respect that. +// For more detail, read the section of the GCC's manual about init_priority. +void OutputSectionCommand::sortInitFini() { + // Sort sections by priority. + sort([](InputSectionBase *S) { return getPriority(S->Name); }); +} + uint32_t OutputSectionCommand::getFiller() { if (Filler) return *Filler; @@ -1085,16 +1181,9 @@ template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) { writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size); } -bool LinkerScript::hasLMA(OutputSection *Sec) { - if (OutputSectionCommand *Cmd = getCmd(Sec)) - if (Cmd->LMAExpr) - return true; - return false; -} - ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) { if (S == ".") - return {CurOutSec, Dot - CurOutSec->Addr, Loc}; + return {CurAddressState->OutSec, Dot - CurAddressState->OutSec->Addr, Loc}; if (SymbolBody *B = findSymbol(S)) { if (auto *D = dyn_cast<DefinedRegular>(B)) return {D->Section, D->Value, Loc}; @@ -1111,17 +1200,14 @@ static const size_t NoPhdr = -1; // Returns indices of ELF headers containing specific section. Each index is a // zero based number of ELF header listed within PHDRS {} script block. -std::vector<size_t> LinkerScript::getPhdrIndices(OutputSection *Sec) { - if (OutputSectionCommand *Cmd = getCmd(Sec)) { - std::vector<size_t> Ret; - for (StringRef PhdrName : Cmd->Phdrs) { - size_t Index = getPhdrIndex(Cmd->Location, PhdrName); - if (Index != NoPhdr) - Ret.push_back(Index); - } - return Ret; +std::vector<size_t> LinkerScript::getPhdrIndices(OutputSectionCommand *Cmd) { + std::vector<size_t> Ret; + for (StringRef PhdrName : Cmd->Phdrs) { + size_t Index = getPhdrIndex(Cmd->Location, PhdrName); + if (Index != NoPhdr) + Ret.push_back(Index); } - return {}; + return Ret; } // Returns the index of the segment named PhdrName if found otherwise diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h index f8a34a1e97dd..dd5a7d797f60 100644 --- a/ELF/LinkerScript.h +++ b/ELF/LinkerScript.h @@ -110,7 +110,6 @@ struct MemoryRegion { std::string Name; uint64_t Origin; uint64_t Length; - uint64_t Offset; uint32_t Flags; uint32_t NegFlags; }; @@ -140,6 +139,10 @@ struct OutputSectionCommand : BaseCommand { template <class ELFT> void writeTo(uint8_t *Buf); template <class ELFT> void maybeCompress(); uint32_t getFiller(); + + void sort(std::function<int(InputSectionBase *S)> Order); + void sortInitFini(); + void sortCtorsDtors(); }; // This struct represents one section match pattern in SECTIONS() command. @@ -222,6 +225,17 @@ struct ScriptConfiguration { }; class LinkerScript final { + // Temporary state used in processCommands() and assignAddresses() + // that must be reinitialized for each call to the above functions, and must + // not be used outside of the scope of a call to the above functions. + struct AddressState { + uint64_t ThreadBssOffset = 0; + OutputSection *OutSec = nullptr; + MemoryRegion *MemRegion = nullptr; + llvm::DenseMap<const MemoryRegion *, uint64_t> MemRegionOffset; + std::function<uint64_t()> LMAOffset; + AddressState(const ScriptConfiguration &Opt); + }; llvm::DenseMap<OutputSection *, OutputSectionCommand *> SecToCommand; llvm::DenseMap<StringRef, OutputSectionCommand *> NameToOutputSectionCommand; @@ -234,7 +248,7 @@ class LinkerScript final { std::vector<InputSectionBase *> createInputSectionList(OutputSectionCommand &Cmd); - std::vector<size_t> getPhdrIndices(OutputSection *Sec); + std::vector<size_t> getPhdrIndices(OutputSectionCommand *Cmd); size_t getPhdrIndex(const Twine &Loc, StringRef PhdrName); MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd); @@ -244,14 +258,10 @@ class LinkerScript final { void output(InputSection *Sec); void process(BaseCommand &Base); + AddressState *CurAddressState = nullptr; OutputSection *Aether; uint64_t Dot; - uint64_t ThreadBssOffset = 0; - - std::function<uint64_t()> LMAOffset; - OutputSection *CurOutSec = nullptr; - MemoryRegion *CurMemRegion = nullptr; public: bool ErrorOnMissingSection = false; @@ -276,13 +286,11 @@ public: std::vector<PhdrEntry> createPhdrs(); bool ignoreInterpSection(); - bool hasLMA(OutputSection *Sec); bool shouldKeep(InputSectionBase *S); void assignOffsets(OutputSectionCommand *Cmd); - void createOrphanCommands(); void processNonSectionCommands(); - void assignAddresses(std::vector<PhdrEntry> &Phdrs); - + void assignAddresses(); + void allocateHeaders(std::vector<PhdrEntry> &Phdrs); void addSymbol(SymbolAssignment *Cmd); void processCommands(OutputSectionFactory &Factory); diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index c0bf6b32e6e2..d6ae5dcae167 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -101,100 +101,6 @@ void OutputSection::addSection(InputSection *S) { this->Entsize = std::max(this->Entsize, S->Entsize); } -// This function is called after we sort input sections -// and scan relocations to setup sections' offsets. -void OutputSection::assignOffsets() { - OutputSectionCommand *Cmd = Script->getCmd(this); - uint64_t Off = 0; - for (BaseCommand *Base : Cmd->Commands) - if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) - for (InputSection *S : ISD->Sections) - Off = updateOffset(Off, S); - this->Size = Off; -} - -void OutputSection::sort(std::function<int(InputSectionBase *S)> Order) { - typedef std::pair<unsigned, InputSection *> Pair; - auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; - - std::vector<Pair> V; - for (InputSection *S : Sections) - V.push_back({Order(S), S}); - std::stable_sort(V.begin(), V.end(), Comp); - Sections.clear(); - for (Pair &P : V) - Sections.push_back(P.second); -} - -// Sorts input sections by section name suffixes, so that .foo.N comes -// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections. -// We want to keep the original order if the priorities are the same -// because the compiler keeps the original initialization order in a -// translation unit and we need to respect that. -// For more detail, read the section of the GCC's manual about init_priority. -void OutputSection::sortInitFini() { - // Sort sections by priority. - sort([](InputSectionBase *S) { return getPriority(S->Name); }); -} - -// Returns true if S matches /Filename.?\.o$/. -static bool isCrtBeginEnd(StringRef S, StringRef Filename) { - if (!S.endswith(".o")) - return false; - S = S.drop_back(2); - if (S.endswith(Filename)) - return true; - return !S.empty() && S.drop_back().endswith(Filename); -} - -static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); } -static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); } - -// .ctors and .dtors are sorted by this priority from highest to lowest. -// -// 1. The section was contained in crtbegin (crtbegin contains -// some sentinel value in its .ctors and .dtors so that the runtime -// can find the beginning of the sections.) -// -// 2. The section has an optional priority value in the form of ".ctors.N" -// or ".dtors.N" where N is a number. Unlike .{init,fini}_array, -// they are compared as string rather than number. -// -// 3. The section is just ".ctors" or ".dtors". -// -// 4. The section was contained in crtend, which contains an end marker. -// -// In an ideal world, we don't need this function because .init_array and -// .ctors are duplicate features (and .init_array is newer.) However, there -// are too many real-world use cases of .ctors, so we had no choice to -// support that with this rather ad-hoc semantics. -static bool compCtors(const InputSection *A, const InputSection *B) { - bool BeginA = isCrtbegin(A->File->getName()); - bool BeginB = isCrtbegin(B->File->getName()); - if (BeginA != BeginB) - return BeginA; - bool EndA = isCrtend(A->File->getName()); - bool EndB = isCrtend(B->File->getName()); - if (EndA != EndB) - return EndB; - StringRef X = A->Name; - StringRef Y = B->Name; - assert(X.startswith(".ctors") || X.startswith(".dtors")); - assert(Y.startswith(".ctors") || Y.startswith(".dtors")); - X = X.substr(6); - Y = Y.substr(6); - if (X.empty() && Y.empty()) - return false; - return X < Y; -} - -// Sorts input sections by the special rules for .ctors and .dtors. -// Unfortunately, the rules are different from the one for .{init,fini}_array. -// Read the comment above. -void OutputSection::sortCtorsDtors() { - std::stable_sort(Sections.begin(), Sections.end(), compCtors); -} - static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) { // The ELF spec just says // ---------------------------------------------------------------- @@ -249,9 +155,7 @@ static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) { return SectionKey{OutsecName, Flags, Alignment}; } -OutputSectionFactory::OutputSectionFactory( - std::vector<OutputSection *> &OutputSections) - : OutputSections(OutputSections) {} +OutputSectionFactory::OutputSectionFactory() {} static uint64_t getIncompatibleFlags(uint64_t Flags) { return Flags & (SHF_ALLOC | SHF_TLS); diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h index d5f77838d530..68ee066a13da 100644 --- a/ELF/OutputSections.h +++ b/ELF/OutputSections.h @@ -80,10 +80,6 @@ public: uint32_t ShName = 0; void addSection(InputSection *S); - void sort(std::function<int(InputSectionBase *S)> Order); - void sortInitFini(); - void sortCtorsDtors(); - void assignOffsets(); std::vector<InputSection *> Sections; // Used for implementation of --compress-debug-sections option. @@ -135,7 +131,7 @@ namespace elf { // linker scripts. class OutputSectionFactory { public: - OutputSectionFactory(std::vector<OutputSection *> &OutputSections); + OutputSectionFactory(); ~OutputSectionFactory(); void addInputSec(InputSectionBase *IS, StringRef OutsecName); @@ -144,7 +140,6 @@ public: private: llvm::SmallDenseMap<SectionKey, OutputSection *> Map; - std::vector<OutputSection *> &OutputSections; }; uint64_t getHeaderSize(); diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index fd823fe0ed42..52dbe4b583d0 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -557,9 +557,9 @@ static RelExpr adjustExpr(SymbolBody &Body, RelExpr Expr, uint32_t Type, // the refered symbol can be preemepted to refer to the executable. if (Config->Shared || (Config->Pic && !isRelExpr(Expr))) { error("can't create dynamic relocation " + toString(Type) + " against " + - (Body.getName().empty() ? "local symbol in readonly segment" + (Body.getName().empty() ? "local symbol" : "symbol: " + toString(Body)) + - getLocation<ELFT>(S, Body, RelOff)); + " in readonly segment" + getLocation<ELFT>(S, Body, RelOff)); return Expr; } @@ -1049,10 +1049,17 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS, std::pair<Thunk *, bool> ThunkCreator::getThunk(SymbolBody &Body, uint32_t Type) { - auto res = ThunkedSymbols.insert({&Body, nullptr}); - if (res.second) - res.first->second = addThunk(Type, Body); - return std::make_pair(res.first->second, res.second); + auto Res = ThunkedSymbols.insert({&Body, std::vector<Thunk *>()}); + if (!Res.second) { + // Check existing Thunks for Body to see if they can be reused + for (Thunk *ET : Res.first->second) + if (ET->isCompatibleWith(Type)) + return std::make_pair(ET, false); + } + // No existing compatible Thunk in range, create a new one + Thunk *T = addThunk(Type, Body); + Res.first->second.push_back(T); + return std::make_pair(T, true); } // Call Fn on every executable InputSection accessed via the linker script @@ -1066,13 +1073,12 @@ void ThunkCreator::forEachExecInputSection( OutputSection *OS = Cmd->Sec; if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR)) continue; - if (OutputSectionCommand *C = Script->getCmd(OS)) - for (BaseCommand *BC : C->Commands) - if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) { - CurTS = nullptr; - for (InputSection* IS : ISD->Sections) - Fn(OS, &ISD->Sections, IS); - } + for (BaseCommand *BC : Cmd->Commands) + if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) { + CurTS = nullptr; + for (InputSection *IS : ISD->Sections) + Fn(OS, &ISD->Sections, IS); + } } } diff --git a/ELF/Relocations.h b/ELF/Relocations.h index 445308b27cec..fc3e3444ac24 100644 --- a/ELF/Relocations.h +++ b/ELF/Relocations.h @@ -144,14 +144,17 @@ private: std::pair<Thunk *, bool> getThunk(SymbolBody &Body, uint32_t Type); ThunkSection *addThunkSection(OutputSection *OS, std::vector<InputSection *> *, uint64_t Off); - // Track Symbols that already have a Thunk - llvm::DenseMap<SymbolBody *, Thunk *> ThunkedSymbols; + // Record all the available Thunks for a Symbol + llvm::DenseMap<SymbolBody *, std::vector<Thunk *>> ThunkedSymbols; // Find a Thunk from the Thunks symbol definition, we can use this to find // the Thunk from a relocation to the Thunks symbol definition. llvm::DenseMap<SymbolBody *, Thunk *> Thunks; - // Track InputSections that have a ThunkSection placed in front + // Track InputSections that have an inline ThunkSection placed in front + // an inline ThunkSection may have control fall through to the section below + // so we need to make sure that there is only one of them. + // The Mips LA25 Thunk is an example of an inline ThunkSection. llvm::DenseMap<InputSection *, ThunkSection *> ThunkedSections; // All the ThunkSections that we have created, organised by OutputSection diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp index 4a44944fe7ed..72940ca0cfd4 100644 --- a/ELF/ScriptParser.cpp +++ b/ELF/ScriptParser.cpp @@ -1191,8 +1191,7 @@ void ScriptParser::readMemory() { if (It != Script->Opt.MemoryRegions.end()) setError("region '" + Name + "' already defined"); else - Script->Opt.MemoryRegions[Name] = {Name, Origin, Length, - Origin, Flags, NegFlags}; + Script->Opt.MemoryRegions[Name] = {Name, Origin, Length, Flags, NegFlags}; } } diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp index d75b89f17527..c802d74b8ff8 100644 --- a/ELF/SymbolTable.cpp +++ b/ELF/SymbolTable.cpp @@ -211,6 +211,13 @@ static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { // Find an existing symbol or create and insert a new one. template <class ELFT> std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) { + // <name>@@<version> means the symbol is the default version. In that + // case symbol <name> must exist and <name>@@<version> will be used to + // resolve references to <name>. + size_t Pos = Name.find("@@"); + if (Pos != StringRef::npos) + Name = Name.take_front(Pos); + auto P = Symtab.insert( {CachedHashStringRef(Name), SymIndex((int)SymVector.size(), false)}); SymIndex &V = P.first->second; @@ -319,7 +326,7 @@ static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) { if (WasInserted) return 1; SymbolBody *Body = S->body(); - if (Body->isLazy() || !Body->isInCurrentDSO()) + if (!Body->isInCurrentDSO()) return 1; if (Binding == STB_WEAK) return -1; @@ -689,6 +696,12 @@ void SymbolTable<ELFT>::assignExactVersion(SymbolVersion Ver, uint16_t VersionId // Assign the version. for (SymbolBody *B : Syms) { + // Skip symbols containing version info because symbol versions + // specified by symbol names take precedence over version scripts. + // See parseSymbolVersion(). + if (B->getName().find('@') != StringRef::npos) + continue; + Symbol *Sym = B->symbol(); if (Sym->InVersionScript) warn("duplicate symbol '" + Ver.Name + "' in version script"); @@ -702,47 +715,21 @@ void SymbolTable<ELFT>::assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId) { if (!Ver.HasWildcard) return; - std::vector<SymbolBody *> Syms = findAllByVersion(Ver); // Exact matching takes precendence over fuzzy matching, // so we set a version to a symbol only if no version has been assigned // to the symbol. This behavior is compatible with GNU. - for (SymbolBody *B : Syms) + for (SymbolBody *B : findAllByVersion(Ver)) if (B->symbol()->VersionId == Config->DefaultSymbolVersion) B->symbol()->VersionId = VersionId; } -static bool isDefaultVersion(SymbolBody *B) { - return B->isInCurrentDSO() && B->getName().find("@@") != StringRef::npos; -} - // This function processes version scripts by updating VersionId // member of symbols. template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() { - // Symbol themselves might know their versions because symbols - // can contain versions in the form of <name>@<version>. - // Let them parse and update their names to exclude version suffix. - for (Symbol *Sym : SymVector) { - SymbolBody *Body = Sym->body(); - bool IsDefault = isDefaultVersion(Body); - Body->parseSymbolVersion(); - - if (!IsDefault) - continue; - - // <name>@@<version> means the symbol is the default version. If that's the - // case, the symbol is not used only to resolve <name> of version <version> - // but also undefined unversioned symbols with name <name>. - SymbolBody *S = find(Body->getName()); - if (S && S->isUndefined()) - S->copy(Body); - } - // Handle edge cases first. handleAnonymousVersion(); - if (Config->VersionDefinitions.empty()) - return; // Now we have version definitions, so we need to set version ids to symbols. // Each version definition has a glob pattern, and all symbols that match @@ -761,6 +748,12 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() { for (VersionDefinition &V : llvm::reverse(Config->VersionDefinitions)) for (SymbolVersion &Ver : V.Globals) assignWildcardVersion(Ver, V.Id); + + // Symbol themselves might know their versions because symbols + // can contain versions in the form of <name>@<version>. + // Let them parse and update their names to exclude version suffix. + for (Symbol *Sym : SymVector) + Sym->body()->parseSymbolVersion(); } template class elf::SymbolTable<ELF32LE>; diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp index e8cd662c69ac..1d17f57f0c30 100644 --- a/ELF/Symbols.cpp +++ b/ELF/Symbols.cpp @@ -159,19 +159,12 @@ bool SymbolBody::isPreemptible() const { return true; } -// Overwrites all attributes except symbol name with Other's so that -// this symbol becomes an alias to Other. This is useful for handling -// some options such as --wrap. -// -// The reason why we want to keep the symbol name is because, if we -// copy symbol names, we'll end up having symbol tables in resulting -// executables or DSOs containing two or more identical symbols, which -// is just inconvenient. +// Overwrites all attributes with Other's so that this symbol becomes +// an alias to Other. This is useful for handling some options such as +// --wrap. void SymbolBody::copy(SymbolBody *Other) { - StringRef S = Name; memcpy(symbol()->Body.buffer, Other->symbol()->Body.buffer, sizeof(Symbol::Body)); - Name = S; } uint64_t SymbolBody::getVA(int64_t Addend) const { @@ -272,7 +265,12 @@ void SymbolBody::parseSymbolVersion() { } // It is an error if the specified version is not defined. - error(toString(File) + ": symbol " + S + " has undefined version " + Verstr); + // Usually version script is not provided when linking executable, + // but we may still want to override a versioned symbol from DSO, + // so we do not report error in this case. + if (Config->Shared) + error(toString(File) + ": symbol " + S + " has undefined version " + + Verstr); } Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, diff --git a/ELF/Symbols.h b/ELF/Symbols.h index 773e1ad9588a..a1b3a6fba911 100644 --- a/ELF/Symbols.h +++ b/ELF/Symbols.h @@ -65,7 +65,9 @@ public: return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind; } bool isShared() const { return SymbolKind == SharedKind; } - bool isInCurrentDSO() const { return !isUndefined() && !isShared(); } + bool isInCurrentDSO() const { + return !isUndefined() && !isShared() && !isLazy(); + } bool isLocal() const { return IsLocal; } bool isPreemptible() const; StringRef getName() const { return Name; } @@ -218,7 +220,7 @@ public: Verdef(Verdef), ElfSym(ElfSym) { // IFuncs defined in DSOs are treated as functions by the static linker. if (isGnuIFunc()) - Type = llvm::ELF::STT_FUNC; + this->Type = llvm::ELF::STT_FUNC; this->File = File; } diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index 995d05692ee2..fd724fac327c 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -1071,10 +1071,11 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { return; // Already finalized. this->Link = InX::DynStrTab->getParent()->SectionIndex; - if (In<ELFT>::RelaDyn->getParent()->Size > 0) { + if (In<ELFT>::RelaDyn->getParent() && !In<ELFT>::RelaDyn->empty()) { bool IsRela = Config->IsRela; add({IsRela ? DT_RELA : DT_REL, In<ELFT>::RelaDyn}); - add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->getParent()->Size}); + add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->getParent(), + Entry::SecSize}); add({IsRela ? DT_RELAENT : DT_RELENT, uint64_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))}); @@ -1087,9 +1088,9 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels}); } } - if (In<ELFT>::RelaPlt->getParent()->Size > 0) { + if (In<ELFT>::RelaPlt->getParent() && !In<ELFT>::RelaPlt->empty()) { add({DT_JMPREL, In<ELFT>::RelaPlt}); - add({DT_PLTRELSZ, In<ELFT>::RelaPlt->getParent()->Size}); + add({DT_PLTRELSZ, In<ELFT>::RelaPlt->getParent(), Entry::SecSize}); switch (Config->EMachine) { case EM_MIPS: add({DT_MIPS_PLTGOT, In<ELFT>::GotPlt}); @@ -1699,9 +1700,9 @@ unsigned PltSection::getPltRelocOff() const { return (HeaderSize == 0) ? InX::Plt->getSize() : 0; } -GdbIndexSection::GdbIndexSection() +GdbIndexSection::GdbIndexSection(std::vector<GdbIndexChunk> &&Chunks) : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"), - StringPool(llvm::StringTableBuilder::ELF) {} + StringPool(llvm::StringTableBuilder::ELF), Chunks(std::move(Chunks)) {} // Iterative hash function for symbol's name is described in .gdb_index format // specification. Note that we use one for version 5 to 7 here, it is different @@ -1713,11 +1714,10 @@ static uint32_t hash(StringRef Str) { return R; } -static std::vector<CompilationUnitEntry> readCuList(DWARFContext &Dwarf, - InputSection *Sec) { +static std::vector<CompilationUnitEntry> readCuList(DWARFContext &Dwarf) { std::vector<CompilationUnitEntry> Ret; for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units()) - Ret.push_back({Sec->OutSecOff + CU->getOffset(), CU->getLength() + 4}); + Ret.push_back({CU->getOffset(), CU->getLength() + 4}); return Ret; } @@ -1764,19 +1764,15 @@ static std::vector<InputSection *> getDebugInfoSections() { std::vector<InputSection *> Ret; for (InputSectionBase *S : InputSections) if (InputSection *IS = dyn_cast<InputSection>(S)) - if (IS->getParent() && IS->Name == ".debug_info") + if (IS->Name == ".debug_info") Ret.push_back(IS); return Ret; } void GdbIndexSection::buildIndex() { - std::vector<InputSection *> V = getDebugInfoSections(); - if (V.empty()) + if (Chunks.empty()) return; - for (InputSection *Sec : V) - Chunks.push_back(readDwarf(Sec)); - uint32_t CuId = 0; for (GdbIndexChunk &D : Chunks) { for (AddressEntry &E : D.AddressArea) @@ -1802,23 +1798,33 @@ void GdbIndexSection::buildIndex() { } } -GdbIndexChunk GdbIndexSection::readDwarf(InputSection *Sec) { - Expected<std::unique_ptr<object::ObjectFile>> Obj = - object::ObjectFile::createObjectFile(Sec->File->MB); - if (!Obj) { - error(toString(Sec->File) + ": error creating DWARF context"); - return {}; - } - - DWARFContextInMemory Dwarf(*Obj.get()); - +static GdbIndexChunk readDwarf(DWARFContextInMemory &Dwarf, InputSection *Sec) { GdbIndexChunk Ret; - Ret.CompilationUnits = readCuList(Dwarf, Sec); + Ret.DebugInfoSec = Sec; + Ret.CompilationUnits = readCuList(Dwarf); Ret.AddressArea = readAddressArea(Dwarf, Sec); Ret.NamesAndTypes = readPubNamesAndTypes(Dwarf, Config->IsLE); return Ret; } +template <class ELFT> GdbIndexSection *elf::createGdbIndex() { + std::vector<GdbIndexChunk> Chunks; + for (InputSection *Sec : getDebugInfoSections()) { + InputFile *F = Sec->File; + std::error_code EC; + ELFObjectFile<ELFT> Obj(F->MB, EC); + if (EC) + fatal(EC.message()); + DWARFContextInMemory Dwarf(Obj, nullptr, [&](Error E) { + error(toString(F) + ": error parsing DWARF data:\n>>> " + + toString(std::move(E))); + return ErrorPolicy::Continue; + }); + Chunks.push_back(readDwarf(Dwarf, Sec)); + } + return make<GdbIndexSection>(std::move(Chunks)); +} + static size_t getCuSize(std::vector<GdbIndexChunk> &C) { size_t Ret = 0; for (GdbIndexChunk &D : C) @@ -1876,7 +1882,7 @@ void GdbIndexSection::writeTo(uint8_t *Buf) { // Write the CU list. for (GdbIndexChunk &D : Chunks) { for (CompilationUnitEntry &Cu : D.CompilationUnits) { - write64le(Buf, Cu.CuOffset); + write64le(Buf, D.DebugInfoSec->OutSecOff + Cu.CuOffset); write64le(Buf + 8, Cu.CuLength); Buf += 16; } @@ -2345,6 +2351,11 @@ StringTableSection *InX::ShStrTab; StringTableSection *InX::StrTab; SymbolTableBaseSection *InX::SymTab; +template GdbIndexSection *elf::createGdbIndex<ELF32LE>(); +template GdbIndexSection *elf::createGdbIndex<ELF32BE>(); +template GdbIndexSection *elf::createGdbIndex<ELF64LE>(); +template GdbIndexSection *elf::createGdbIndex<ELF64BE>(); + template void PltSection::addEntry<ELF32LE>(SymbolBody &Sym); template void PltSection::addEntry<ELF32BE>(SymbolBody &Sym); template void PltSection::addEntry<ELF64LE>(SymbolBody &Sym); diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h index be9a43c8155b..ddd8ca99a61b 100644 --- a/ELF/SyntheticSections.h +++ b/ELF/SyntheticSections.h @@ -503,7 +503,7 @@ class GdbIndexSection final : public SyntheticSection { const unsigned SymTabEntrySize = 2 * OffsetTypeSize; public: - GdbIndexSection(); + GdbIndexSection(std::vector<GdbIndexChunk> &&Chunks); void finalizeContents() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override; @@ -524,7 +524,6 @@ public: std::vector<GdbIndexChunk> Chunks; private: - GdbIndexChunk readDwarf(InputSection *Sec); void buildIndex(); uint32_t CuTypesOffset; @@ -538,6 +537,8 @@ private: bool Finalized = false; }; +template <class ELFT> GdbIndexSection *createGdbIndex(); + // --eh-frame-hdr option tells linker to construct a header for all the // .eh_frame sections. This header is placed to a section named .eh_frame_hdr // and also to a PT_GNU_EH_FRAME segment. diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp index 752a881d7867..cae31027e557 100644 --- a/ELF/Thunks.cpp +++ b/ELF/Thunks.cpp @@ -57,6 +57,7 @@ public: uint32_t size() const override { return 12; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; + bool isCompatibleWith(uint32_t RelocType) const override; }; class ARMV7PILongThunk final : public Thunk { @@ -66,28 +67,31 @@ public: uint32_t size() const override { return 16; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; + bool isCompatibleWith(uint32_t RelocType) const override; }; class ThumbV7ABSLongThunk final : public Thunk { public: ThumbV7ABSLongThunk(const SymbolBody &Dest) : Thunk(Dest) { - this->alignment = 2; + alignment = 2; } uint32_t size() const override { return 10; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; + bool isCompatibleWith(uint32_t RelocType) const override; }; class ThumbV7PILongThunk final : public Thunk { public: ThumbV7PILongThunk(const SymbolBody &Dest) : Thunk(Dest) { - this->alignment = 2; + alignment = 2; } uint32_t size() const override { return 12; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; + bool isCompatibleWith(uint32_t RelocType) const override; }; // MIPS LA25 thunk @@ -128,6 +132,11 @@ void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) { addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS); } +bool ARMV7ABSLongThunk::isCompatibleWith(uint32_t RelocType) const { + // Thumb branch relocations can't use BLX + return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; +} + void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { const uint8_t Data[] = { 0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S @@ -147,6 +156,12 @@ void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) { addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS); } +bool ThumbV7ABSLongThunk::isCompatibleWith(uint32_t RelocType) const { + // ARM branch relocations can't use BLX + return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 && + RelocType != R_ARM_PLT32; +} + void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { const uint8_t Data[] = { 0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) +8) @@ -168,6 +183,11 @@ void ARMV7PILongThunk::addSymbols(ThunkSection &IS) { addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS); } +bool ARMV7PILongThunk::isCompatibleWith(uint32_t RelocType) const { + // Thumb branch relocations can't use BLX + return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; +} + void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { const uint8_t Data[] = { 0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4) @@ -189,9 +209,15 @@ void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) { addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS); } +bool ThumbV7PILongThunk::isCompatibleWith(uint32_t RelocType) const { + // ARM branch relocations can't use BLX + return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 && + RelocType != R_ARM_PLT32; +} + // Write MIPS LA25 thunk code to call PIC function from the non-PIC one. void MipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const { - uint64_t S = this->Destination.getVA(); + uint64_t S = Destination.getVA(); write32(Buf, 0x3c190000, Config->Endianness); // lui $25, %hi(func) write32(Buf + 4, 0x08000000 | (S >> 2), Config->Endianness); // j func write32(Buf + 8, 0x27390000, Config->Endianness); // addiu $25, $25, %lo(func) diff --git a/ELF/Thunks.h b/ELF/Thunks.h index 38ee090e75e1..00b6b2cf2994 100644 --- a/ELF/Thunks.h +++ b/ELF/Thunks.h @@ -41,6 +41,10 @@ public: // a branch and fall through to the first Symbol in the Target. virtual InputSection *getTargetInputSection() const { return nullptr; } + // To reuse a Thunk the caller as identified by the RelocType must be + // compatible with it. + virtual bool isCompatibleWith(uint32_t RelocType) const { return true; } + // The alignment requirement for this Thunk, defaults to the size of the // typical code section alignment. const SymbolBody &Destination; diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 080d8e787301..bf43ee5c5f91 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -73,13 +73,12 @@ private: std::unique_ptr<FileOutputBuffer> Buffer; - OutputSectionFactory Factory{OutputSections}; + OutputSectionFactory Factory; void addRelIpltSymbols(); void addStartEndSymbols(); void addStartStopSymbols(OutputSection *Sec); uint64_t getEntryAddr(); - OutputSection *findSection(StringRef Name); OutputSection *findSectionInScript(StringRef Name); OutputSectionCommand *findSectionCommand(StringRef Name); @@ -152,10 +151,6 @@ template <class ELFT> static void combineEhFrameSections() { } template <class ELFT> void Writer<ELFT>::clearOutputSections() { - if (Script->Opt.HasSections) - Script->createOrphanCommands(); - else - Script->fabricateDefaultCommands(); // Clear the OutputSections to make sure it is not used anymore. Any // code from this point on should be using the linker script // commands. @@ -190,9 +185,10 @@ template <class ELFT> void Writer<ELFT>::run() { // output sections by default rules. We still need to give the // linker script a chance to run, because it might contain // non-SECTIONS commands such as ASSERT. - createSections(); Script->processCommands(Factory); + createSections(); } + clearOutputSections(); if (Config->Discard != DiscardPolicy::All) copyLocalSymbols(); @@ -218,7 +214,8 @@ template <class ELFT> void Writer<ELFT>::run() { OutputSectionCommands.begin(), OutputSectionCommands.end(), [](OutputSectionCommand *Cmd) { Cmd->maybeCompress<ELFT>(); }); - Script->assignAddresses(Phdrs); + Script->assignAddresses(); + Script->allocateHeaders(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 @@ -383,7 +380,7 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() { Add(InX::IgotPlt); if (Config->GdbIndex) { - InX::GdbIndex = make<GdbIndexSection>(); + InX::GdbIndex = createGdbIndex<ELFT>(); Add(InX::GdbIndex); } @@ -499,11 +496,18 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() { template <class ELFT> void Writer<ELFT>::addSectionSymbols() { // Create one STT_SECTION symbol for each output section we might // have a relocation with. - for (OutputSection *Sec : OutputSections) { - if (Sec->Sections.empty()) + for (BaseCommand *Base : Script->Opt.Commands) { + auto *Cmd = dyn_cast<OutputSectionCommand>(Base); + if (!Cmd) continue; - - InputSection *IS = Sec->Sections[0]; + auto I = llvm::find_if(Cmd->Commands, [](BaseCommand *Base) { + if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) + return !ISD->Sections.empty(); + return false; + }); + if (I == Cmd->Commands.end()) + continue; + InputSection *IS = cast<InputSectionDescription>(*I)->Sections[0]; if (isa<SyntheticSection>(IS) || IS->Type == SHT_REL || IS->Type == SHT_RELA) continue; @@ -864,20 +868,19 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() { // Sort input sections by section name suffixes for // __attribute__((init_priority(N))). -static void sortInitFini(OutputSection *S) { - if (S) - reinterpret_cast<OutputSection *>(S)->sortInitFini(); +static void sortInitFini(OutputSectionCommand *Cmd) { + if (Cmd) + Cmd->sortInitFini(); } // Sort input sections by the special rule for .ctors and .dtors. -static void sortCtorsDtors(OutputSection *S) { - if (S) - reinterpret_cast<OutputSection *>(S)->sortCtorsDtors(); +static void sortCtorsDtors(OutputSectionCommand *Cmd) { + if (Cmd) + Cmd->sortCtorsDtors(); } // Sort input sections using the list provided by --symbol-ordering-file. -template <class ELFT> -static void sortBySymbolsOrder(ArrayRef<OutputSection *> OutputSections) { +template <class ELFT> static void sortBySymbolsOrder() { if (Config->SymbolOrderingFile.empty()) return; @@ -902,9 +905,9 @@ static void sortBySymbolsOrder(ArrayRef<OutputSection *> OutputSections) { } // Sort sections by priority. - for (OutputSection *Base : OutputSections) - if (auto *Sec = dyn_cast<OutputSection>(Base)) - Sec->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); }); + for (BaseCommand *Base : Script->Opt.Commands) + if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) + Cmd->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); }); } template <class ELFT> @@ -934,11 +937,12 @@ template <class ELFT> void Writer<ELFT>::createSections() { if (IS) Factory.addInputSec(IS, getOutputSectionName(IS->Name)); - sortBySymbolsOrder<ELFT>(OutputSections); - sortInitFini(findSection(".init_array")); - sortInitFini(findSection(".fini_array")); - sortCtorsDtors(findSection(".ctors")); - sortCtorsDtors(findSection(".dtors")); + Script->fabricateDefaultCommands(); + sortBySymbolsOrder<ELFT>(); + sortInitFini(findSectionCommand(".init_array")); + sortInitFini(findSectionCommand(".fini_array")); + sortCtorsDtors(findSectionCommand(".ctors")); + sortCtorsDtors(findSectionCommand(".dtors")); } // We want to find how similar two ranks are. @@ -1132,7 +1136,7 @@ static void applySynthetic(const std::vector<SyntheticSection *> &Sections, // to make them visible from linkescript side. But not all sections are always // required to be in output. For example we don't need dynamic section content // sometimes. This function filters out such unused sections from the output. -static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V) { +static void removeUnusedSyntheticSections() { // All input synthetic sections that can be empty are placed after // all regular ones. We iterate over them all and exit at first // non-synthetic. @@ -1145,29 +1149,53 @@ static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V) { continue; if ((SS == InX::Got || SS == InX::MipsGot) && ElfSym::GlobalOffsetTable) continue; - OS->Sections.erase(std::find(OS->Sections.begin(), OS->Sections.end(), SS)); - SS->Live = false; + + OutputSectionCommand *Cmd = Script->getCmd(OS); + std::vector<BaseCommand *>::iterator Empty = Cmd->Commands.end(); + for (auto I = Cmd->Commands.begin(), E = Cmd->Commands.end(); I != E; ++I) { + BaseCommand *B = *I; + if (auto *ISD = dyn_cast<InputSectionDescription>(B)) { + auto P = std::find(ISD->Sections.begin(), ISD->Sections.end(), SS); + if (P != ISD->Sections.end()) + ISD->Sections.erase(P); + if (ISD->Sections.empty()) + Empty = I; + } + } + if (Empty != Cmd->Commands.end()) + Cmd->Commands.erase(Empty); + // If there are no other sections in the output section, remove it from the // output. - if (OS->Sections.empty()) - V.erase(std::find(V.begin(), V.end(), OS)); + if (Cmd->Commands.empty()) { + // Also remove script commands matching the output section. + auto &Cmds = Script->Opt.Commands; + auto I = std::remove_if(Cmds.begin(), Cmds.end(), [&](BaseCommand *Cmd) { + if (auto *OSCmd = dyn_cast<OutputSectionCommand>(Cmd)) + return OSCmd->Sec == OS; + return false; + }); + Cmds.erase(I, Cmds.end()); + } } } // Create output section objects and add them to OutputSections. template <class ELFT> void Writer<ELFT>::finalizeSections() { - Out::DebugInfo = findSection(".debug_info"); - Out::PreinitArray = findSection(".preinit_array"); - Out::InitArray = findSection(".init_array"); - Out::FiniArray = findSection(".fini_array"); + Out::DebugInfo = findSectionInScript(".debug_info"); + Out::PreinitArray = findSectionInScript(".preinit_array"); + Out::InitArray = findSectionInScript(".init_array"); + Out::FiniArray = findSectionInScript(".fini_array"); // The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop // symbols for sections, so that the runtime can get the start and end // addresses of each section by section name. Add such symbols. if (!Config->Relocatable) { addStartEndSymbols(); - for (OutputSection *Sec : OutputSections) - addStartStopSymbols(Sec); + for (BaseCommand *Base : Script->Opt.Commands) + if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) + if (Cmd->Sec) + addStartStopSymbols(Cmd->Sec); } // Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type. @@ -1218,9 +1246,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { return; addPredefinedSections(); - removeUnusedSyntheticSections(OutputSections); + removeUnusedSyntheticSections(); - clearOutputSections(); sortSections(); // Now that we have the final list, create a list of all the @@ -1257,12 +1284,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size(); } - // Compute the size of .rela.dyn and .rela.plt early since we need - // them to populate .dynamic. - for (SyntheticSection *SS : {In<ELFT>::RelaDyn, In<ELFT>::RelaPlt}) - if (SS->getParent() && !SS->empty()) - SS->getParent()->assignOffsets(); - // Dynamic section must be the last one in this list and dynamic // symbol table section (DynSymTab) must be the first one. applySynthetic({InX::DynSymTab, InX::Bss, InX::BssRelRo, @@ -1286,6 +1307,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { // are out of range. This will need to turn into a loop that converges // when no more Thunks are added ThunkCreator TC; + Script->assignAddresses(); if (TC.createThunks(OutputSectionCommands)) { applySynthetic({InX::MipsGot}, [](SyntheticSection *SS) { SS->updateAllocSize(); }); @@ -1308,21 +1330,18 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { template <class ELFT> void Writer<ELFT>::addPredefinedSections() { // ARM ABI requires .ARM.exidx to be terminated by some piece of data. // We have the terminater synthetic section class. Add that at the end. - auto *OS = dyn_cast_or_null<OutputSection>(findSection(".ARM.exidx")); - if (!OS || OS->Sections.empty() || Config->Relocatable) + OutputSectionCommand *Cmd = findSectionCommand(".ARM.exidx"); + if (!Cmd || Cmd->Commands.empty() || Config->Relocatable) return; auto *Sentinel = make<ARMExidxSentinelSection>(); - OS->addSection(Sentinel); - // If there are linker script commands existing at this point then add the - // sentinel to the last of these too. - if (OutputSectionCommand *C = Script->getCmd(OS)) { - auto ISD = std::find_if(C->Commands.rbegin(), C->Commands.rend(), - [](const BaseCommand *Base) { - return isa<InputSectionDescription>(Base); - }); - cast<InputSectionDescription>(*ISD)->Sections.push_back(Sentinel); - } + Cmd->Sec->addSection(Sentinel); + // Add the sentinel to the last of these too. + auto ISD = std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(), + [](const BaseCommand *Base) { + return isa<InputSectionDescription>(Base); + }); + cast<InputSectionDescription>(*ISD)->Sections.push_back(Sentinel); } // The linker is expected to define SECNAME_start and SECNAME_end @@ -1346,7 +1365,7 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() { Define("__init_array_start", "__init_array_end", Out::InitArray); Define("__fini_array_start", "__fini_array_end", Out::FiniArray); - if (OutputSection *Sec = findSection(".ARM.exidx")) + if (OutputSection *Sec = findSectionInScript(".ARM.exidx")) Define("__exidx_start", "__exidx_end", Sec); } @@ -1366,9 +1385,10 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) { template <class ELFT> OutputSectionCommand *Writer<ELFT>::findSectionCommand(StringRef Name) { - for (OutputSectionCommand *Cmd : OutputSectionCommands) - if (Cmd->Name == Name) - return Cmd; + for (BaseCommand *Base : Script->Opt.Commands) + if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) + if (Cmd->Name == Name) + return Cmd; return nullptr; } @@ -1378,13 +1398,6 @@ template <class ELFT> OutputSection *Writer<ELFT>::findSectionInScript(StringRef return nullptr; } -template <class ELFT> OutputSection *Writer<ELFT>::findSection(StringRef Name) { - for (OutputSection *Sec : OutputSections) - if (Sec->Name == Name) - return Sec; - return nullptr; -} - static bool needsPtLoad(OutputSection *Sec) { if (!(Sec->Flags & SHF_ALLOC)) return false; @@ -1446,7 +1459,7 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() { // different flags or is loaded at a discontiguous address using AT linker // script command. uint64_t NewFlags = computeFlags(Sec->getPhdrFlags()); - if (Script->hasLMA(Sec) || Flags != NewFlags) { + if (Cmd->LMAExpr || Flags != NewFlags) { Load = AddHdr(PT_LOAD, NewFlags); Flags = NewFlags; } @@ -1514,7 +1527,7 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() { for (OutputSectionCommand *Cmd : OutputSectionCommands) { OutputSection *Sec = Cmd->Sec; if (Sec->Type == SHT_NOTE) { - if (!Note || Script->hasLMA(Sec)) + if (!Note || Cmd->LMAExpr) Note = AddHdr(PT_NOTE, PF_R); Note->add(Sec); } else { @@ -1528,11 +1541,9 @@ template <class ELFT> void Writer<ELFT>::addPtArmExid(std::vector<PhdrEntry> &Phdrs) { if (Config->EMachine != EM_ARM) return; - auto I = - std::find_if(OutputSectionCommands.begin(), OutputSectionCommands.end(), - [](OutputSectionCommand *Cmd) { - return Cmd->Sec->Type == SHT_ARM_EXIDX; - }); + auto I = llvm::find_if(OutputSectionCommands, [](OutputSectionCommand *Cmd) { + return Cmd->Sec->Type == SHT_ARM_EXIDX; + }); if (I == OutputSectionCommands.end()) return; |