From 4aed7ea6f89a091aede10ccf0fb45b3ce12c710d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 17 Jan 2018 17:29:21 -0500 Subject: update embedded LLD to 6.0.0rc1 --- deps/lld/ELF/LinkerScript.cpp | 1384 +++++++++++++++++------------------------ 1 file changed, 573 insertions(+), 811 deletions(-) (limited to 'deps/lld/ELF/LinkerScript.cpp') diff --git a/deps/lld/ELF/LinkerScript.cpp b/deps/lld/ELF/LinkerScript.cpp index 614f5e2c8b..16b306da46 100644 --- a/deps/lld/ELF/LinkerScript.cpp +++ b/deps/lld/ELF/LinkerScript.cpp @@ -14,20 +14,19 @@ #include "LinkerScript.h" #include "Config.h" #include "InputSection.h" -#include "Memory.h" #include "OutputSections.h" #include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" -#include "Threads.h" #include "Writer.h" +#include "lld/Common/Memory.h" +#include "lld/Common/Threads.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" @@ -50,62 +49,56 @@ using namespace lld::elf; LinkerScript *elf::Script; +static uint64_t getOutputSectionVA(SectionBase *InputSec, StringRef Loc) { + if (OutputSection *OS = InputSec->getOutputSection()) + return OS->Addr; + error(Loc + ": unable to evaluate expression: input section " + + InputSec->Name + " has no output section assigned"); + return 0; +} + uint64_t ExprValue::getValue() const { - if (Sec) { - if (OutputSection *OS = Sec->getOutputSection()) - return alignTo(Sec->getOffset(Val) + OS->Addr, Alignment); - error(Loc + ": unable to evaluate expression: input section " + Sec->Name + - " has no output section assigned"); - } + if (Sec) + return alignTo(Sec->getOffset(Val) + getOutputSectionVA(Sec, Loc), + Alignment); return alignTo(Val, Alignment); } uint64_t ExprValue::getSecAddr() const { if (Sec) - return Sec->getOffset(0) + Sec->getOutputSection()->Addr; + return Sec->getOffset(0) + getOutputSectionVA(Sec, Loc); return 0; } -template static SymbolBody *addRegular(SymbolAssignment *Cmd) { - Symbol *Sym; - uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; - std::tie(Sym, std::ignore) = Symtab::X->insert( - Cmd->Name, /*Type*/ 0, Visibility, /*CanOmitFromDynSym*/ false, - /*File*/ nullptr); - Sym->Binding = STB_GLOBAL; - ExprValue Value = Cmd->Expression(); - SectionBase *Sec = Value.isAbsolute() ? nullptr : Value.Sec; - - // We want to set symbol values early if we can. This allows us to use symbols - // as variables in linker scripts. Doing so allows us to write expressions - // like this: `alignment = 16; . = ALIGN(., alignment)` - uint64_t SymValue = Value.isAbsolute() ? Value.getValue() : 0; - replaceBody(Sym, Cmd->Name, /*IsLocal=*/false, Visibility, - STT_NOTYPE, SymValue, 0, Sec, nullptr); - return Sym->body(); +uint64_t ExprValue::getSectionOffset() const { + // If the alignment is trivial, we don't have to compute the full + // value to know the offset. This allows this function to succeed in + // cases where the output section is not yet known. + if (Alignment == 1) + return Val; + return getValue() - getSecAddr(); } -OutputSectionCommand * -LinkerScript::createOutputSectionCommand(StringRef Name, StringRef Location) { - OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name]; - OutputSectionCommand *Cmd; - if (CmdRef && CmdRef->Location.empty()) { +OutputSection *LinkerScript::createOutputSection(StringRef Name, + StringRef Location) { + OutputSection *&SecRef = NameToOutputSection[Name]; + OutputSection *Sec; + if (SecRef && SecRef->Location.empty()) { // There was a forward reference. - Cmd = CmdRef; + Sec = SecRef; } else { - Cmd = make(Name); - if (!CmdRef) - CmdRef = Cmd; + Sec = make(Name, SHT_NOBITS, 0); + if (!SecRef) + SecRef = Sec; } - Cmd->Location = Location; - return Cmd; + Sec->Location = Location; + return Sec; } -OutputSectionCommand * -LinkerScript::getOrCreateOutputSectionCommand(StringRef Name) { - OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name]; +OutputSection *LinkerScript::getOrCreateOutputSection(StringRef Name) { + OutputSection *&CmdRef = NameToOutputSection[Name]; if (!CmdRef) - CmdRef = make(Name); + CmdRef = make(Name, SHT_PROGBITS, 0); return CmdRef; } @@ -113,16 +106,56 @@ void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) { uint64_t Val = E().getValue(); if (Val < Dot && InSec) error(Loc + ": unable to move location counter backward for: " + - CurAddressState->OutSec->Name); + Ctx->OutSec->Name); Dot = Val; + // Update to location counter means update to section size. if (InSec) - CurAddressState->OutSec->Size = Dot - CurAddressState->OutSec->Addr; + Ctx->OutSec->Size = Dot - Ctx->OutSec->Addr; } -// Sets value of a symbol. Two kinds of symbols are processed: synthetic -// symbols, whose value is an offset from beginning of section and regular -// symbols whose value is absolute. +// This function is called from processSectionCommands, +// while we are fixing the output section layout. +void LinkerScript::addSymbol(SymbolAssignment *Cmd) { + if (Cmd->Name == ".") + return; + + // If a symbol was in PROVIDE(), we need to define it only when + // it is a referenced undefined symbol. + Symbol *B = Symtab->find(Cmd->Name); + if (Cmd->Provide && (!B || B->isDefined())) + return; + + // Define a symbol. + Symbol *Sym; + uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; + std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, /*Type*/ 0, Visibility, + /*CanOmitFromDynSym*/ false, + /*File*/ nullptr); + ExprValue Value = Cmd->Expression(); + SectionBase *Sec = Value.isAbsolute() ? nullptr : Value.Sec; + + // When this function is called, section addresses have not been + // fixed yet. So, we may or may not know the value of the RHS + // expression. + // + // For example, if an expression is `x = 42`, we know x is always 42. + // However, if an expression is `x = .`, there's no way to know its + // value at the moment. + // + // We want to set symbol values early if we can. This allows us to + // use symbols as variables in linker scripts. Doing so allows us to + // write expressions like this: `alignment = 16; . = ALIGN(., alignment)`. + uint64_t SymValue = Value.Sec ? 0 : Value.getValue(); + + replaceSymbol(Sym, nullptr, Cmd->Name, STB_GLOBAL, Visibility, + STT_NOTYPE, SymValue, 0, Sec); + Cmd->Sym = cast(Sym); +} + +// This function is called from assignAddresses, while we are +// fixing the output section addresses. This function is supposed +// to set the final value for a given symbol assignment. void LinkerScript::assignSymbol(SymbolAssignment *Cmd, bool InSec) { if (Cmd->Name == ".") { setDot(Cmd->Expression, Cmd->Location, InSec); @@ -132,116 +165,36 @@ void LinkerScript::assignSymbol(SymbolAssignment *Cmd, bool InSec) { if (!Cmd->Sym) return; - auto *Sym = cast(Cmd->Sym); ExprValue V = Cmd->Expression(); if (V.isAbsolute()) { - Sym->Value = V.getValue(); + Cmd->Sym->Section = nullptr; + Cmd->Sym->Value = V.getValue(); } else { - Sym->Section = V.Sec; - Sym->Value = alignTo(V.Val, V.Alignment); - } -} - -static SymbolBody *findSymbol(StringRef S) { - switch (Config->EKind) { - case ELF32LEKind: - return Symtab::X->find(S); - case ELF32BEKind: - return Symtab::X->find(S); - case ELF64LEKind: - return Symtab::X->find(S); - case ELF64BEKind: - return Symtab::X->find(S); - default: - llvm_unreachable("unknown Config->EKind"); + Cmd->Sym->Section = V.Sec; + Cmd->Sym->Value = V.getSectionOffset(); } } -static SymbolBody *addRegularSymbol(SymbolAssignment *Cmd) { - switch (Config->EKind) { - case ELF32LEKind: - return addRegular(Cmd); - case ELF32BEKind: - return addRegular(Cmd); - case ELF64LEKind: - return addRegular(Cmd); - case ELF64BEKind: - return addRegular(Cmd); - default: - llvm_unreachable("unknown Config->EKind"); - } -} - -void LinkerScript::addSymbol(SymbolAssignment *Cmd) { - if (Cmd->Name == ".") - return; - - // If a symbol was in PROVIDE(), we need to define it only when - // it is a referenced undefined symbol. - SymbolBody *B = findSymbol(Cmd->Name); - if (Cmd->Provide && (!B || B->isDefined())) - return; - - Cmd->Sym = addRegularSymbol(Cmd); -} - -bool SymbolAssignment::classof(const BaseCommand *C) { - return C->Kind == AssignmentKind; -} - -bool OutputSectionCommand::classof(const BaseCommand *C) { - return C->Kind == OutputSectionKind; -} - -// Fill [Buf, Buf + Size) with Filler. -// This is used for linker script "=fillexp" command. -static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) { - size_t I = 0; - for (; I + 4 < Size; I += 4) - memcpy(Buf + I, &Filler, 4); - memcpy(Buf + I, &Filler, Size - I); -} - -bool InputSectionDescription::classof(const BaseCommand *C) { - return C->Kind == InputSectionKind; -} - -bool AssertCommand::classof(const BaseCommand *C) { - return C->Kind == AssertKind; -} - -bool BytesDataCommand::classof(const BaseCommand *C) { - return C->Kind == BytesDataKind; -} - -static StringRef basename(InputSectionBase *S) { - if (S->File) - return sys::path::filename(S->File->getName()); - return ""; +static std::string getFilename(InputFile *File) { + if (!File) + return ""; + if (File->ArchiveName.empty()) + return File->getName(); + return (File->ArchiveName + "(" + File->getName() + ")").str(); } bool LinkerScript::shouldKeep(InputSectionBase *S) { - for (InputSectionDescription *ID : Opt.KeptSections) - if (ID->FilePat.match(basename(S))) + if (KeptSections.empty()) + return false; + std::string Filename = getFilename(S->File); + for (InputSectionDescription *ID : KeptSections) + if (ID->FilePat.match(Filename)) for (SectionPattern &P : ID->SectionPatterns) if (P.SectionPat.match(S->Name)) return true; return false; } -// If an input string is in the form of "foo.N" where N is a number, -// return N. Otherwise, returns 65536, which is one greater than the -// lowest priority. -static int getPriority(StringRef S) { - size_t Pos = S.rfind('.'); - if (Pos == StringRef::npos) - return 65536; - int V; - if (!to_integer(S.substr(Pos + 1), V, 10)) - return 65536; - return V; -} - // A helper function for the SORT() command. static std::function getComparator(SortSectionPolicy K) { @@ -267,28 +220,63 @@ getComparator(SortSectionPolicy K) { } // A helper function for the SORT() command. -static bool matchConstraints(ArrayRef Sections, +static bool matchConstraints(ArrayRef Sections, ConstraintKind Kind) { if (Kind == ConstraintKind::NoConstraint) return true; - bool IsRW = llvm::any_of(Sections, [](InputSectionBase *Sec) { - return static_cast(Sec)->Flags & SHF_WRITE; - }); + bool IsRW = llvm::any_of( + Sections, [](InputSection *Sec) { return Sec->Flags & SHF_WRITE; }); return (IsRW && Kind == ConstraintKind::ReadWrite) || (!IsRW && Kind == ConstraintKind::ReadOnly); } -static void sortSections(InputSection **Begin, InputSection **End, +static void sortSections(MutableArrayRef Vec, SortSectionPolicy K) { if (K != SortSectionPolicy::Default && K != SortSectionPolicy::None) - std::stable_sort(Begin, End, getComparator(K)); + std::stable_sort(Vec.begin(), Vec.end(), getComparator(K)); +} + +// Sort sections as instructed by SORT-family commands and --sort-section +// option. Because SORT-family commands can be nested at most two depth +// (e.g. SORT_BY_NAME(SORT_BY_ALIGNMENT(.text.*))) and because the command +// line option is respected even if a SORT command is given, the exact +// behavior we have here is a bit complicated. Here are the rules. +// +// 1. If two SORT commands are given, --sort-section is ignored. +// 2. If one SORT command is given, and if it is not SORT_NONE, +// --sort-section is handled as an inner SORT command. +// 3. If one SORT command is given, and if it is SORT_NONE, don't sort. +// 4. If no SORT command is given, sort according to --sort-section. +// 5. If no SORT commands are given and --sort-section is not specified, +// apply sorting provided by --symbol-ordering-file if any exist. +static void sortInputSections( + MutableArrayRef Vec, const SectionPattern &Pat, + const DenseMap &Order) { + if (Pat.SortOuter == SortSectionPolicy::None) + return; + + if (Pat.SortOuter == SortSectionPolicy::Default && + Config->SortSection == SortSectionPolicy::Default) { + // If -symbol-ordering-file was given, sort accordingly. + // Usually, Order is empty. + if (!Order.empty()) + sortByOrder(Vec, [&](InputSectionBase *S) { return Order.lookup(S); }); + return; + } + + if (Pat.SortInner == SortSectionPolicy::Default) + sortSections(Vec, Config->SortSection); + else + sortSections(Vec, Pat.SortInner); + sortSections(Vec, Pat.SortOuter); } // Compute and remember which sections the InputSectionDescription matches. std::vector -LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { +LinkerScript::computeInputSections(const InputSectionDescription *Cmd, + const DenseMap &Order) { std::vector Ret; // Collects all sections that satisfy constraints of Cmd. @@ -296,13 +284,8 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { size_t SizeBefore = Ret.size(); for (InputSectionBase *Sec : InputSections) { - if (Sec->Assigned) - continue; - - if (!Sec->Live) { - reportDiscarded(Sec); + if (!Sec->Live || Sec->Assigned) continue; - } // For -emit-relocs we have to ignore entries like // .rela.dyn : { *(.rela.data) } @@ -310,67 +293,51 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) continue; - StringRef Filename = basename(Sec); + std::string Filename = getFilename(Sec->File); if (!Cmd->FilePat.match(Filename) || Pat.ExcludedFilePat.match(Filename) || !Pat.SectionPat.match(Sec->Name)) continue; + // It is safe to assume that Sec is an InputSection + // because mergeable or EH input sections have already been + // handled and eliminated. Ret.push_back(cast(Sec)); Sec->Assigned = true; } - // Sort sections as instructed by SORT-family commands and --sort-section - // option. Because SORT-family commands can be nested at most two depth - // (e.g. SORT_BY_NAME(SORT_BY_ALIGNMENT(.text.*))) and because the command - // line option is respected even if a SORT command is given, the exact - // behavior we have here is a bit complicated. Here are the rules. - // - // 1. If two SORT commands are given, --sort-section is ignored. - // 2. If one SORT command is given, and if it is not SORT_NONE, - // --sort-section is handled as an inner SORT command. - // 3. If one SORT command is given, and if it is SORT_NONE, don't sort. - // 4. If no SORT command is given, sort according to --sort-section. - InputSection **Begin = Ret.data() + SizeBefore; - InputSection **End = Ret.data() + Ret.size(); - if (Pat.SortOuter != SortSectionPolicy::None) { - if (Pat.SortInner == SortSectionPolicy::Default) - sortSections(Begin, End, Config->SortSection); - else - sortSections(Begin, End, Pat.SortInner); - sortSections(Begin, End, Pat.SortOuter); - } + sortInputSections(MutableArrayRef(Ret).slice(SizeBefore), + Pat, Order); } return Ret; } -void LinkerScript::discard(ArrayRef V) { - for (InputSectionBase *S : V) { - S->Live = false; +void LinkerScript::discard(ArrayRef V) { + for (InputSection *S : V) { if (S == InX::ShStrTab || S == InX::Dynamic || S == InX::DynSymTab || S == InX::DynStrTab) error("discarding " + S->Name + " section is not allowed"); + + S->Assigned = false; + S->Live = false; discard(S->DependentSections); } } -std::vector -LinkerScript::createInputSectionList(OutputSectionCommand &OutCmd) { - std::vector Ret; - - for (BaseCommand *Base : OutCmd.Commands) { - auto *Cmd = dyn_cast(Base); - if (!Cmd) - continue; +std::vector LinkerScript::createInputSectionList( + OutputSection &OutCmd, const DenseMap &Order) { + std::vector Ret; - Cmd->Sections = computeInputSections(Cmd); - Ret.insert(Ret.end(), Cmd->Sections.begin(), Cmd->Sections.end()); + for (BaseCommand *Base : OutCmd.SectionCommands) { + if (auto *Cmd = dyn_cast(Base)) { + Cmd->Sections = computeInputSections(Cmd, Order); + Ret.insert(Ret.end(), Cmd->Sections.begin(), Cmd->Sections.end()); + } } - return Ret; } -void LinkerScript::processCommands(OutputSectionFactory &Factory) { +void LinkerScript::processSectionCommands() { // A symbol can be assigned before any section is mentioned in the linker // script. In an DSO, the symbol values are addresses, so the only important // section values are: @@ -382,28 +349,31 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { // which will map to whatever the first actual section is. Aether = make("", 0, SHF_ALLOC); Aether->SectionIndex = 1; - auto State = make_unique(Opt); - // CurAddressState captures the local AddressState and makes it accessible - // deliberately. This is needed as there are some cases where we cannot just + + // Ctx 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; + auto Deleter = make_unique(); + Ctx = Deleter.get(); + Ctx->OutSec = Aether; - for (size_t I = 0; I < Opt.Commands.size(); ++I) { + size_t I = 0; + DenseMap Order = buildSectionOrder(); + // Add input sections to output sections. + for (BaseCommand *Base : SectionCommands) { // Handle symbol assignments outside of any output section. - if (auto *Cmd = dyn_cast(Opt.Commands[I])) { + if (auto *Cmd = dyn_cast(Base)) { addSymbol(Cmd); continue; } - if (auto *Cmd = dyn_cast(Opt.Commands[I])) { - std::vector V = createInputSectionList(*Cmd); + if (auto *Sec = dyn_cast(Base)) { + std::vector V = createInputSectionList(*Sec, Order); // The output section name `/DISCARD/' is special. // Any input section assigned to it is discarded. - if (Cmd->Name == "/DISCARD/") { + if (Sec->Name == "/DISCARD/") { discard(V); continue; } @@ -413,250 +383,265 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { // sections satisfy a given constraint. If not, a directive is handled // as if it wasn't present from the beginning. // - // Because we'll iterate over Commands many more times, the easiest - // way to "make it as if it wasn't present" is to just remove it. - if (!matchConstraints(V, Cmd->Constraint)) { + // Because we'll iterate over SectionCommands many more times, the easy + // way to "make it as if it wasn't present" is to make it empty. + if (!matchConstraints(V, Sec->Constraint)) { for (InputSectionBase *S : V) S->Assigned = false; - Opt.Commands.erase(Opt.Commands.begin() + I); - --I; + Sec->SectionCommands.clear(); continue; } // A directive may contain symbol definitions like this: // ".foo : { ...; bar = .; }". Handle them. - for (BaseCommand *Base : Cmd->Commands) + for (BaseCommand *Base : Sec->SectionCommands) if (auto *OutCmd = dyn_cast(Base)) addSymbol(OutCmd); // Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign // is given, input sections are aligned to that value, whether the // given value is larger or smaller than the original section alignment. - if (Cmd->SubalignExpr) { - uint32_t Subalign = Cmd->SubalignExpr().getValue(); + if (Sec->SubalignExpr) { + uint32_t Subalign = Sec->SubalignExpr().getValue(); for (InputSectionBase *S : V) S->Alignment = Subalign; } // Add input sections to an output section. - for (InputSectionBase *S : V) - Factory.addInputSec(S, Cmd->Name, Cmd->Sec); - if (OutputSection *Sec = Cmd->Sec) { - assert(Sec->SectionIndex == INT_MAX); - Sec->SectionIndex = I; - if (Cmd->Noload) - Sec->Type = SHT_NOBITS; - SecToCommand[Sec] = Cmd; - } + for (InputSection *S : V) + Sec->addSection(S); + + Sec->SectionIndex = I++; + if (Sec->Noload) + Sec->Type = SHT_NOBITS; } } - CurAddressState = nullptr; + Ctx = nullptr; } -void LinkerScript::fabricateDefaultCommands() { - std::vector Commands; - - // Define start address - uint64_t StartAddr = -1; - - // The Sections with -T
have been sorted in order of ascending - // address. We must lower StartAddr if the lowest -T
as - // calls to setDot() must be monotonically increasing. - for (auto &KV : Config->SectionStartMap) - StartAddr = std::min(StartAddr, KV.second); - - Commands.push_back(make( - ".", - [=] { - return std::min(StartAddr, Config->ImageBase + elf::getHeaderSize()); - }, - "")); +static OutputSection *findByName(ArrayRef Vec, + StringRef Name) { + for (BaseCommand *Base : Vec) + if (auto *Sec = dyn_cast(Base)) + if (Sec->Name == Name) + return Sec; + return nullptr; +} - // For each OutputSection that needs a VA fabricate an OutputSectionCommand - // with an InputSectionDescription describing the InputSections - for (OutputSection *Sec : OutputSections) { - auto *OSCmd = createOutputSectionCommand(Sec->Name, ""); - OSCmd->Sec = Sec; - SecToCommand[Sec] = OSCmd; - - Commands.push_back(OSCmd); - if (Sec->Sections.size()) { - auto *ISD = make(""); - OSCmd->Commands.push_back(ISD); - for (InputSection *ISec : Sec->Sections) { - ISD->Sections.push_back(ISec); - ISec->Assigned = true; - } +static OutputSection *createSection(InputSectionBase *IS, + StringRef OutsecName) { + OutputSection *Sec = Script->createOutputSection(OutsecName, ""); + Sec->addSection(cast(IS)); + return Sec; +} + +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 + // stripped by InputFiles.cpp as section groups are processed and uniquified. + // However, for the -r option, we want to pass through all section groups + // as-is because adding/removing members or merging them with other groups + // change their semantics. + if (IS->Type == SHT_GROUP || (IS->Flags & SHF_GROUP)) + return createSection(IS, OutsecName); + + // Imagine .zed : { *(.foo) *(.bar) } script. Both foo and bar may have + // relocation sections .rela.foo and .rela.bar for example. Most tools do + // not allow multiple REL[A] sections for output section. Hence we + // should combine these relocation sections into single output. + // We skip synthetic sections because it can be .rela.dyn/.rela.plt or any + // other REL[A] sections created by linker itself. + if (!isa(IS) && + (IS->Type == SHT_REL || IS->Type == SHT_RELA)) { + auto *Sec = cast(IS); + OutputSection *Out = Sec->getRelocatedSection()->getOutputSection(); + + if (Out->RelocationSection) { + Out->RelocationSection->addSection(Sec); + return nullptr; } + + Out->RelocationSection = createSection(IS, OutsecName); + return Out->RelocationSection; + } + + // When control reaches here, mergeable sections have already been merged into + // synthetic sections. For relocatable case we want to create one output + // section per syntetic section so that they have a valid sh_entsize. + if (Config->Relocatable && (IS->Flags & SHF_MERGE)) + return createSection(IS, OutsecName); + + // The ELF spec just says + // ---------------------------------------------------------------- + // In the first phase, input sections that match in name, type and + // attribute flags should be concatenated into single sections. + // ---------------------------------------------------------------- + // + // However, it is clear that at least some flags have to be ignored for + // section merging. At the very least SHF_GROUP and SHF_COMPRESSED have to be + // ignored. We should not have two output .text sections just because one was + // in a group and another was not for example. + // + // It also seems that that wording was a late addition and didn't get the + // necessary scrutiny. + // + // Merging sections with different flags is expected by some users. One + // reason is that if one file has + // + // int *const bar __attribute__((section(".foo"))) = (int *)0; + // + // gcc with -fPIC will produce a read only .foo section. But if another + // file has + // + // int zed; + // int *const bar __attribute__((section(".foo"))) = (int *)&zed; + // + // gcc with -fPIC will produce a read write section. + // + // Last but not least, when using linker script the merge rules are forced by + // the script. Unfortunately, linker scripts are name based. This means that + // expressions like *(.foo*) can refer to multiple input sections with + // different flags. We cannot put them in different output sections or we + // would produce wrong results for + // + // start = .; *(.foo.*) end = .; *(.bar) + // + // and a mapping of .foo1 and .bar1 to one section and .foo2 and .bar2 to + // another. The problem is that there is no way to layout those output + // sections such that the .foo sections are the only thing between the start + // and end symbols. + // + // Given the above issues, we instead merge sections by name and error on + // incompatible types and flags. + OutputSection *&Sec = Map[OutsecName]; + if (Sec) { + Sec->addSection(cast(IS)); + return nullptr; } - // SECTIONS commands run before other non SECTIONS commands - Commands.insert(Commands.end(), Opt.Commands.begin(), Opt.Commands.end()); - Opt.Commands = std::move(Commands); + + Sec = createSection(IS, OutsecName); + return Sec; } // Add sections that didn't match any sections command. -void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { - unsigned NumCommands = Opt.Commands.size(); +void LinkerScript::addOrphanSections() { + unsigned End = SectionCommands.size(); + StringMap Map; + + std::vector V; for (InputSectionBase *S : InputSections) { if (!S->Live || S->Parent) continue; - StringRef Name = getOutputSectionName(S->Name); - auto End = Opt.Commands.begin() + NumCommands; - auto I = std::find_if(Opt.Commands.begin(), End, [&](BaseCommand *Base) { - if (auto *Cmd = dyn_cast(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, ""); - CmdRef->Sec = Sec; - Opt.Commands.push_back(CmdRef); - } - Cmd = CmdRef; - } else { - Cmd = cast(*I); - Factory.addInputSec(S, Name, Cmd->Sec); - if (OutputSection *Sec = Cmd->Sec) { - SecToCommand[Sec] = Cmd; - unsigned Index = std::distance(Opt.Commands.begin(), I); - assert(Sec->SectionIndex == INT_MAX || Sec->SectionIndex == Index); - Sec->SectionIndex = Index; - } + + StringRef Name = getOutputSectionName(S); + + if (Config->OrphanHandling == OrphanHandlingPolicy::Error) + error(toString(S) + " is being placed in '" + Name + "'"); + else if (Config->OrphanHandling == OrphanHandlingPolicy::Warn) + warn(toString(S) + " is being placed in '" + Name + "'"); + + if (OutputSection *Sec = + findByName(makeArrayRef(SectionCommands).slice(0, End), Name)) { + Sec->addSection(cast(S)); + continue; } - auto *ISD = make(""); - ISD->Sections.push_back(cast(S)); - Cmd->Commands.push_back(ISD); + + if (OutputSection *OS = addInputSec(Map, S, Name)) + V.push_back(OS); + assert(S->getOutputSection()->SectionIndex == INT_MAX); } + + // If no SECTIONS command was given, we should insert sections commands + // before others, so that we can handle scripts which refers them, + // for example: "foo = ABSOLUTE(ADDR(.text)));". + // When SECTIONS command is present we just add all orphans to the end. + if (HasSectionsCommand) + SectionCommands.insert(SectionCommands.end(), V.begin(), V.end()); + else + SectionCommands.insert(SectionCommands.begin(), V.begin(), V.end()); } -uint64_t LinkerScript::advance(uint64_t Size, unsigned Align) { - 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 LinkerScript::advance(uint64_t Size, unsigned Alignment) { + bool IsTbss = + (Ctx->OutSec->Flags & SHF_TLS) && Ctx->OutSec->Type == SHT_NOBITS; + uint64_t Start = IsTbss ? Dot + Ctx->ThreadBssOffset : Dot; + Start = alignTo(Start, Alignment); uint64_t End = Start + Size; if (IsTbss) - CurAddressState->ThreadBssOffset = End - Dot; + Ctx->ThreadBssOffset = End - Dot; else Dot = End; return End; } void LinkerScript::output(InputSection *S) { + uint64_t Before = advance(0, 1); uint64_t Pos = advance(S->getSize(), S->Alignment); - S->OutSecOff = Pos - S->getSize() - CurAddressState->OutSec->Addr; + S->OutSecOff = Pos - S->getSize() - Ctx->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) } - CurAddressState->OutSec->Size = Pos - CurAddressState->OutSec->Addr; + Ctx->OutSec->Size = Pos - Ctx->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 (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"); + if (Ctx->MemRegion) { + uint64_t &CurOffset = Ctx->MemRegionOffset[Ctx->MemRegion]; + CurOffset += Pos - Before; + uint64_t CurSize = CurOffset - Ctx->MemRegion->Origin; + if (CurSize > Ctx->MemRegion->Length) { + uint64_t OverflowAmt = CurSize - Ctx->MemRegion->Length; + error("section '" + Ctx->OutSec->Name + "' will not fit in region '" + + Ctx->MemRegion->Name + "': overflowed by " + Twine(OverflowAmt) + + " bytes"); } } } void LinkerScript::switchTo(OutputSection *Sec) { - if (CurAddressState->OutSec == Sec) + if (Ctx->OutSec == Sec) return; - CurAddressState->OutSec = Sec; - CurAddressState->OutSec->Addr = - advance(0, CurAddressState->OutSec->Alignment); + Ctx->OutSec = Sec; + Ctx->OutSec->Addr = advance(0, Ctx->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 (CurAddressState->LMAOffset) - CurAddressState->OutSec->LMAOffset = CurAddressState->LMAOffset(); -} - -void LinkerScript::process(BaseCommand &Base) { - // This handles the assignments to symbol or to the dot. - if (auto *Cmd = dyn_cast(&Base)) { - assignSymbol(Cmd, true); - return; - } - - // Handle BYTE(), SHORT(), LONG(), or QUAD(). - if (auto *Cmd = dyn_cast(&Base)) { - Cmd->Offset = Dot - CurAddressState->OutSec->Addr; - Dot += Cmd->Size; - CurAddressState->OutSec->Size = Dot - CurAddressState->OutSec->Addr; - return; - } - - // Handle ASSERT(). - if (auto *Cmd = dyn_cast(&Base)) { - Cmd->Expression(); - return; - } - - // Handle a single input section description command. - // It calculates and assigns the offsets for each section and also - // updates the output section size. - auto &Cmd = cast(Base); - for (InputSection *Sec : Cmd.Sections) { - // We tentatively added all synthetic sections at the beginning and removed - // empty ones afterwards (because there is no way to know whether they were - // going be empty or not other than actually running linker scripts.) - // We need to ignore remains of empty sections. - if (auto *S = dyn_cast(Sec)) - if (S->empty()) - continue; - - if (!Sec->Live) - continue; - assert(CurAddressState->OutSec == Sec->getParent()); - output(Sec); - } + if (Ctx->LMAOffset) + Ctx->OutSec->LMAOffset = Ctx->LMAOffset(); } // This function searches for a memory region to place the given output // section in. If found, a pointer to the appropriate memory region is // returned. Otherwise, a nullptr is returned. -MemoryRegion *LinkerScript::findMemoryRegion(OutputSectionCommand *Cmd) { +MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *Sec) { // If a memory region name was specified in the output section command, // then try to find that region first. - if (!Cmd->MemoryRegionName.empty()) { - auto It = Opt.MemoryRegions.find(Cmd->MemoryRegionName); - if (It != Opt.MemoryRegions.end()) - return &It->second; - error("memory region '" + Cmd->MemoryRegionName + "' not declared"); + if (!Sec->MemoryRegionName.empty()) { + auto It = MemoryRegions.find(Sec->MemoryRegionName); + if (It != MemoryRegions.end()) + return It->second; + error("memory region '" + Sec->MemoryRegionName + "' not declared"); return nullptr; } // If at least one memory region is defined, all sections must // belong to some memory region. Otherwise, we don't need to do // anything for memory regions. - if (Opt.MemoryRegions.empty()) + if (MemoryRegions.empty()) return nullptr; - OutputSection *Sec = Cmd->Sec; // See if a region can be found by matching section flags. - for (auto &Pair : Opt.MemoryRegions) { - MemoryRegion &M = Pair.second; - if ((M.Flags & Sec->Flags) && (M.NegFlags & Sec->Flags) == 0) - return &M; + for (auto &Pair : MemoryRegions) { + MemoryRegion *M = Pair.second; + if ((M->Flags & Sec->Flags) && (M->NegFlags & Sec->Flags) == 0) + return M; } // Otherwise, no suitable region was found. @@ -667,33 +652,73 @@ MemoryRegion *LinkerScript::findMemoryRegion(OutputSectionCommand *Cmd) { // This function assigns offsets to input sections and an output section // for a single sections command (e.g. ".text { *(.text); }"). -void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) { - OutputSection *Sec = Cmd->Sec; - if (!Sec) - return; - +void LinkerScript::assignOffsets(OutputSection *Sec) { if (!(Sec->Flags & SHF_ALLOC)) Dot = 0; - else if (Cmd->AddrExpr) - setDot(Cmd->AddrExpr, Cmd->Location, false); + else if (Sec->AddrExpr) + setDot(Sec->AddrExpr, Sec->Location, false); - if (Cmd->LMAExpr) { + Ctx->MemRegion = Sec->MemRegion; + if (Ctx->MemRegion) + Dot = Ctx->MemRegionOffset[Ctx->MemRegion]; + + if (Sec->LMAExpr) { uint64_t D = Dot; - CurAddressState->LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; }; + Ctx->LMAOffset = [=] { return Sec->LMAExpr().getValue() - D; }; } - 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 (CurAddressState->OutSec->Flags & SHF_COMPRESSED) - return; + // The Size previously denoted how many InputSections had been added to this + // section, and was used for sorting SHF_LINK_ORDER sections. Reset it to + // compute the actual size value. + Sec->Size = 0; + + // We visited SectionsCommands from processSectionCommands to + // layout sections. Now, we visit SectionsCommands again to fix + // section offsets. + for (BaseCommand *Base : Sec->SectionCommands) { + // This handles the assignments to symbol or to the dot. + if (auto *Cmd = dyn_cast(Base)) { + assignSymbol(Cmd, true); + continue; + } + + // Handle BYTE(), SHORT(), LONG(), or QUAD(). + if (auto *Cmd = dyn_cast(Base)) { + Cmd->Offset = Dot - Ctx->OutSec->Addr; + Dot += Cmd->Size; + if (Ctx->MemRegion) + Ctx->MemRegionOffset[Ctx->MemRegion] += Cmd->Size; + Ctx->OutSec->Size = Dot - Ctx->OutSec->Addr; + continue; + } + + // Handle ASSERT(). + if (auto *Cmd = dyn_cast(Base)) { + Cmd->Expression(); + continue; + } - for (BaseCommand *C : Cmd->Commands) - process(*C); + // Handle a single input section description command. + // It calculates and assigns the offsets for each section and also + // updates the output section size. + auto *Cmd = cast(Base); + for (InputSection *Sec : Cmd->Sections) { + // We tentatively added all synthetic sections at the beginning and + // removed empty ones afterwards (because there is no way to know + // whether they were going be empty or not other than actually running + // linker scripts.) We need to ignore remains of empty sections. + if (auto *S = dyn_cast(Sec)) + if (S->empty()) + continue; + + if (!Sec->Live) + continue; + assert(Ctx->OutSec == Sec->getParent()); + output(Sec); + } + } } void LinkerScript::removeEmptyCommands() { @@ -703,17 +728,15 @@ void LinkerScript::removeEmptyCommands() { // clutter the output. // We instead remove trivially empty sections. The bfd linker seems even // more aggressive at removing them. - auto Pos = std::remove_if( - Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) { - if (auto *Cmd = dyn_cast(Base)) - return Cmd->Sec == nullptr; - return false; - }); - Opt.Commands.erase(Pos, Opt.Commands.end()); + llvm::erase_if(SectionCommands, [&](BaseCommand *Base) { + if (auto *Sec = dyn_cast(Base)) + return !Sec->Live; + return false; + }); } -static bool isAllSectionDescription(const OutputSectionCommand &Cmd) { - for (BaseCommand *Base : Cmd.Commands) +static bool isAllSectionDescription(const OutputSection &Cmd) { + for (BaseCommand *Base : Cmd.SectionCommands) if (!isa(*Base)) return false; return true; @@ -721,38 +744,55 @@ static bool isAllSectionDescription(const OutputSectionCommand &Cmd) { void LinkerScript::adjustSectionsBeforeSorting() { // If the output section contains only symbol assignments, create a - // corresponding output section. The bfd linker seems to only create them if - // '.' is assigned to, but creating these section should not have any bad - // consequeces and gives us a section to put the symbol in. + // corresponding output section. The issue is what to do with linker script + // like ".foo : { symbol = 42; }". One option would be to convert it to + // "symbol = 42;". That is, move the symbol out of the empty section + // description. That seems to be what bfd does for this simple case. The + // problem is that this is not completely general. bfd will give up and + // create a dummy section too if there is a ". = . + 1" inside the section + // for example. + // Given that we want to create the section, we have to worry what impact + // it will have on the link. For example, if we just create a section with + // 0 for flags, it would change which PT_LOADs are created. + // We could remember that that particular section is dummy and ignore it in + // other parts of the linker, but unfortunately there are quite a few places + // that would need to change: + // * The program header creation. + // * The orphan section placement. + // * The address assignment. + // The other option is to pick flags that minimize the impact the section + // will have on the rest of the linker. That is why we copy the flags from + // the previous sections. Only a few flags are needed to keep the impact low. uint64_t Flags = SHF_ALLOC; - for (int I = 0, E = Opt.Commands.size(); I != E; ++I) { - auto *Cmd = dyn_cast(Opt.Commands[I]); - if (!Cmd) + for (BaseCommand *Cmd : SectionCommands) { + auto *Sec = dyn_cast(Cmd); + if (!Sec) continue; - if (OutputSection *Sec = Cmd->Sec) { - Flags = Sec->Flags; + if (Sec->Live) { + Flags = Sec->Flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR); continue; } - if (isAllSectionDescription(*Cmd)) + if (isAllSectionDescription(*Sec)) continue; - auto *OutSec = make(Cmd->Name, SHT_PROGBITS, Flags); - OutSec->SectionIndex = I; - Cmd->Sec = OutSec; - SecToCommand[OutSec] = Cmd; + Sec->Live = true; + Sec->Flags = Flags; } } void LinkerScript::adjustSectionsAfterSorting() { // Try and find an appropriate memory region to assign offsets in. - for (BaseCommand *Base : Opt.Commands) { - if (auto *Cmd = dyn_cast(Base)) { - Cmd->MemRegion = findMemoryRegion(Cmd); + for (BaseCommand *Base : SectionCommands) { + if (auto *Sec = dyn_cast(Base)) { + if (!Sec->Live) + continue; + Sec->MemRegion = findMemoryRegion(Sec); // Handle align (e.g. ".foo : ALIGN(16) { ... }"). - if (Cmd->AlignExpr && Cmd->Sec) - Cmd->Sec->updateAlignment(Cmd->AlignExpr().getValue()); + if (Sec->AlignExpr) + Sec->Alignment = + std::max(Sec->Alignment, Sec->AlignExpr().getValue()); } } @@ -764,108 +804,112 @@ void LinkerScript::adjustSectionsAfterSorting() { // SECTIONS { .aaa : { *(.aaa) } } std::vector DefPhdrs; auto FirstPtLoad = - std::find_if(Opt.PhdrsCommands.begin(), Opt.PhdrsCommands.end(), + std::find_if(PhdrsCommands.begin(), PhdrsCommands.end(), [](const PhdrsCommand &Cmd) { return Cmd.Type == PT_LOAD; }); - if (FirstPtLoad != Opt.PhdrsCommands.end()) + if (FirstPtLoad != PhdrsCommands.end()) DefPhdrs.push_back(FirstPtLoad->Name); // Walk the commands and propagate the program headers to commands that don't // explicitly specify them. - for (BaseCommand *Base : Opt.Commands) { - auto *Cmd = dyn_cast(Base); - if (!Cmd) + for (BaseCommand *Base : SectionCommands) { + auto *Sec = dyn_cast(Base); + if (!Sec) continue; - if (Cmd->Phdrs.empty()) { - OutputSection *Sec = Cmd->Sec; + if (Sec->Phdrs.empty()) { // 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; + if (Sec->Flags & SHF_ALLOC) + Sec->Phdrs = DefPhdrs; } else { - DefPhdrs = Cmd->Phdrs; + DefPhdrs = Sec->Phdrs; } } - - removeEmptyCommands(); } -void LinkerScript::processNonSectionCommands() { - for (BaseCommand *Base : Opt.Commands) { - if (auto *Cmd = dyn_cast(Base)) - assignSymbol(Cmd, false); - else if (auto *Cmd = dyn_cast(Base)) - Cmd->Expression(); - } +static OutputSection *findFirstSection(PhdrEntry *Load) { + for (OutputSection *Sec : OutputSections) + if (Sec->PtLoad == Load) + return Sec; + return nullptr; } -void LinkerScript::allocateHeaders(std::vector &Phdrs) { +// Try to find an address for the file and program headers output sections, +// which were unconditionally added to the first PT_LOAD segment earlier. +// +// When using the default layout, we check if the headers fit below the first +// allocated section. When using a linker script, we also check if the headers +// are covered by the output section. This allows omitting the headers by not +// leaving enough space for them in the linker script; this pattern is common +// in embedded systems. +// +// If there isn't enough space for these sections, we'll remove them from the +// PT_LOAD segment, and we'll also remove the PT_PHDR segment. +void LinkerScript::allocateHeaders(std::vector &Phdrs) { uint64_t Min = std::numeric_limits::max(); - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; + for (OutputSection *Sec : OutputSections) if (Sec->Flags & SHF_ALLOC) Min = std::min(Min, Sec->Addr); - } - auto FirstPTLoad = llvm::find_if( - Phdrs, [](const PhdrEntry &E) { return E.p_type == PT_LOAD; }); - if (FirstPTLoad == Phdrs.end()) + auto It = llvm::find_if( + Phdrs, [](const PhdrEntry *E) { return E->p_type == PT_LOAD; }); + if (It == Phdrs.end()) return; + PhdrEntry *FirstPTLoad = *It; uint64_t HeaderSize = getHeaderSize(); - if (HeaderSize <= Min || Script->hasPhdrsCommands()) { + // When linker script with SECTIONS is being used, don't output headers + // unless there's a space for them. + uint64_t Base = HasSectionsCommand ? alignDown(Min, Config->MaxPageSize) : 0; + if (HeaderSize <= Min - Base || Script->hasPhdrsCommands()) { Min = alignDown(Min - HeaderSize, Config->MaxPageSize); Out::ElfHeader->Addr = Min; Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size; return; } - assert(FirstPTLoad->First == Out::ElfHeader); - OutputSection *ActualFirst = nullptr; - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; - if (Sec->FirstInPtLoad == Out::ElfHeader) { - ActualFirst = Sec; - break; - } - } - if (ActualFirst) { - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; - if (Sec->FirstInPtLoad == Out::ElfHeader) - Sec->FirstInPtLoad = ActualFirst; - } - FirstPTLoad->First = ActualFirst; - } else { - Phdrs.erase(FirstPTLoad); - } + Out::ElfHeader->PtLoad = nullptr; + Out::ProgramHeaders->PtLoad = nullptr; + FirstPTLoad->FirstSec = findFirstSection(FirstPTLoad); - auto PhdrI = llvm::find_if( - Phdrs, [](const PhdrEntry &E) { return E.p_type == PT_PHDR; }); - if (PhdrI != Phdrs.end()) - Phdrs.erase(PhdrI); + llvm::erase_if(Phdrs, + [](const PhdrEntry *E) { return E->p_type == PT_PHDR; }); } -LinkerScript::AddressState::AddressState(const ScriptConfiguration &Opt) { - for (auto &MRI : Opt.MemoryRegions) { - const MemoryRegion *MR = &MRI.second; +LinkerScript::AddressState::AddressState() { + for (auto &MRI : Script->MemoryRegions) { + const MemoryRegion *MR = MRI.second; MemRegionOffset[MR] = MR->Origin; } } +static uint64_t getInitialDot() { + // By default linker scripts use an initial value of 0 for '.', + // but prefer -image-base if set. + if (Script->HasSectionsCommand) + return Config->ImageBase ? *Config->ImageBase : 0; + + uint64_t StartAddr = UINT64_MAX; + // The Sections with -T
have been sorted in order of ascending + // address. We must lower StartAddr if the lowest -T
as + // calls to setDot() must be monotonically increasing. + for (auto &KV : Config->SectionStartMap) + StartAddr = std::min(StartAddr, KV.second); + return std::min(StartAddr, Target->getImageBase() + elf::getHeaderSize()); +} + +// Here we assign addresses as instructed by linker script SECTIONS +// sub-commands. Doing that allows us to use final VA values, so here +// we also handle rest commands like symbol assignments and ASSERTs. void LinkerScript::assignAddresses() { - // Assign addresses as instructed by linker script SECTIONS sub-commands. - Dot = 0; - auto State = make_unique(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(); + Dot = getInitialDot(); + + auto Deleter = make_unique(); + Ctx = Deleter.get(); ErrorOnMissingSection = true; switchTo(Aether); - for (BaseCommand *Base : Opt.Commands) { + for (BaseCommand *Base : SectionCommands) { if (auto *Cmd = dyn_cast(Base)) { assignSymbol(Cmd, false); continue; @@ -876,380 +920,98 @@ void LinkerScript::assignAddresses() { continue; } - auto *Cmd = cast(Base); - assignOffsets(Cmd); + assignOffsets(cast(Base)); } - CurAddressState = nullptr; + Ctx = nullptr; } // Creates program headers as instructed by PHDRS linker script command. -std::vector LinkerScript::createPhdrs() { - std::vector Ret; +std::vector LinkerScript::createPhdrs() { + std::vector Ret; // Process PHDRS and FILEHDR keywords because they are not // real output sections and cannot be added in the following loop. - for (const PhdrsCommand &Cmd : Opt.PhdrsCommands) { - Ret.emplace_back(Cmd.Type, Cmd.Flags == UINT_MAX ? PF_R : Cmd.Flags); - PhdrEntry &Phdr = Ret.back(); + for (const PhdrsCommand &Cmd : PhdrsCommands) { + PhdrEntry *Phdr = make(Cmd.Type, Cmd.Flags ? *Cmd.Flags : PF_R); if (Cmd.HasFilehdr) - Phdr.add(Out::ElfHeader); + Phdr->add(Out::ElfHeader); if (Cmd.HasPhdrs) - Phdr.add(Out::ProgramHeaders); + Phdr->add(Out::ProgramHeaders); if (Cmd.LMAExpr) { - Phdr.p_paddr = Cmd.LMAExpr().getValue(); - Phdr.HasLMA = true; + Phdr->p_paddr = Cmd.LMAExpr().getValue(); + Phdr->HasLMA = true; } + Ret.push_back(Phdr); } // Add output sections to program headers. - for (OutputSectionCommand *Cmd : OutputSectionCommands) { + for (OutputSection *Sec : OutputSections) { // Assign headers specified by linker script - 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(); + for (size_t Id : getPhdrIndices(Sec)) { + Ret[Id]->add(Sec); + if (!PhdrsCommands[Id].Flags.hasValue()) + Ret[Id]->p_flags |= Sec->getPhdrFlags(); } } return Ret; } -bool LinkerScript::ignoreInterpSection() { - // Ignore .interp section in case we have PHDRS specification - // and PT_INTERP isn't listed. - if (Opt.PhdrsCommands.empty()) - return false; - for (PhdrsCommand &Cmd : Opt.PhdrsCommands) - if (Cmd.Type == PT_INTERP) - return false; - return true; -} - -OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const { - auto I = SecToCommand.find(Sec); - if (I == SecToCommand.end()) - return nullptr; - return I->second; -} - -void OutputSectionCommand::sort(std::function Order) { - typedef std::pair Pair; - auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; - - std::vector V; - assert(Commands.size() == 1); - auto *ISD = cast(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". +// Returns true if we should emit an .interp section. // -// 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(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; - if (Sec->Flags & SHF_EXECINSTR) - return Target->TrapInstr; - return 0; -} - -static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { - if (Size == 1) - *Buf = Data; - else if (Size == 2) - write16(Buf, Data, Config->Endianness); - else if (Size == 4) - write32(Buf, Data, Config->Endianness); - else if (Size == 8) - write64(Buf, Data, Config->Endianness); - else - llvm_unreachable("unsupported Size argument"); -} - -static bool compareByFilePosition(InputSection *A, InputSection *B) { - // Synthetic doesn't have link order dependecy, stable_sort will keep it last - if (A->kind() == InputSectionBase::Synthetic || - B->kind() == InputSectionBase::Synthetic) - return false; - InputSection *LA = A->getLinkOrderDep(); - InputSection *LB = B->getLinkOrderDep(); - OutputSection *AOut = LA->getParent(); - OutputSection *BOut = LB->getParent(); - if (AOut != BOut) - return AOut->SectionIndex < BOut->SectionIndex; - return LA->OutSecOff < LB->OutSecOff; -} - -template -static void finalizeShtGroup(OutputSection *OS, - ArrayRef Sections) { - assert(Config->Relocatable && Sections.size() == 1); - - // sh_link field for SHT_GROUP sections should contain the section index of - // the symbol table. - OS->Link = InX::SymTab->getParent()->SectionIndex; - - // sh_info then contain index of an entry in symbol table section which - // provides signature of the section group. - elf::ObjectFile *Obj = Sections[0]->getFile(); - ArrayRef Symbols = Obj->getSymbols(); - OS->Info = InX::SymTab->getSymbolIndex(Symbols[Sections[0]->Info - 1]); +// We usually do. But if PHDRS commands are given, and +// no PT_INTERP is there, there's no place to emit an +// .interp, so we don't do that in that case. +bool LinkerScript::needsInterpSection() { + if (PhdrsCommands.empty()) + return true; + for (PhdrsCommand &Cmd : PhdrsCommands) + if (Cmd.Type == PT_INTERP) + return true; + return false; } -template void OutputSectionCommand::finalize() { - // Link order may be distributed across several InputSectionDescriptions - // but sort must consider them all at once. - std::vector ScriptSections; - std::vector Sections; - for (BaseCommand *Base : Commands) - if (auto *ISD = dyn_cast(Base)) - for (InputSection *&IS : ISD->Sections) { - ScriptSections.push_back(&IS); - Sections.push_back(IS); - } - - if ((Sec->Flags & SHF_LINK_ORDER)) { - std::stable_sort(Sections.begin(), Sections.end(), compareByFilePosition); - for (int I = 0, N = Sections.size(); I < N; ++I) - *ScriptSections[I] = Sections[I]; - - // We must preserve the link order dependency of sections with the - // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We - // need to translate the InputSection sh_link to the OutputSection sh_link, - // all InputSections in the OutputSection have the same dependency. - if (auto *D = Sections.front()->getLinkOrderDep()) - Sec->Link = D->getParent()->SectionIndex; +ExprValue LinkerScript::getSymbolValue(StringRef Name, const Twine &Loc) { + if (Name == ".") { + if (Ctx) + return {Ctx->OutSec, false, Dot - Ctx->OutSec->Addr, Loc}; + error(Loc + ": unable to get location counter value"); + return 0; } - uint32_t Type = Sec->Type; - if (Type == SHT_GROUP) { - finalizeShtGroup(Sec, Sections); - return; - } - - if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL)) - return; - - InputSection *First = Sections[0]; - if (isa(First)) - return; - - Sec->Link = InX::SymTab->getParent()->SectionIndex; - // sh_info for SHT_REL[A] sections should contain the section header index of - // the section to which the relocation applies. - InputSectionBase *S = First->getRelocatedSection(); - Sec->Info = S->getOutputSection()->SectionIndex; - Sec->Flags |= SHF_INFO_LINK; -} - -// Compress section contents if this section contains debug info. -template void OutputSectionCommand::maybeCompress() { - typedef typename ELFT::Chdr Elf_Chdr; - - // Compress only DWARF debug sections. - if (!Config->CompressDebugSections || (Sec->Flags & SHF_ALLOC) || - !Name.startswith(".debug_")) - return; - - // Create a section header. - Sec->ZDebugHeader.resize(sizeof(Elf_Chdr)); - auto *Hdr = reinterpret_cast(Sec->ZDebugHeader.data()); - Hdr->ch_type = ELFCOMPRESS_ZLIB; - Hdr->ch_size = Sec->Size; - Hdr->ch_addralign = Sec->Alignment; - - // Write section contents to a temporary buffer and compress it. - std::vector Buf(Sec->Size); - writeTo(Buf.data()); - if (Error E = zlib::compress(toStringRef(Buf), Sec->CompressedData)) - fatal("compress failed: " + llvm::toString(std::move(E))); - - // Update section headers. - Sec->Size = sizeof(Elf_Chdr) + Sec->CompressedData.size(); - Sec->Flags |= SHF_COMPRESSED; -} - -template void OutputSectionCommand::writeTo(uint8_t *Buf) { - if (Sec->Type == SHT_NOBITS) - return; - - Sec->Loc = Buf; - - // If -compress-debug-section is specified and if this is a debug seciton, - // we've already compressed section contents. If that's the case, - // just write it down. - if (!Sec->CompressedData.empty()) { - memcpy(Buf, Sec->ZDebugHeader.data(), Sec->ZDebugHeader.size()); - memcpy(Buf + Sec->ZDebugHeader.size(), Sec->CompressedData.data(), - Sec->CompressedData.size()); - return; + if (Symbol *Sym = Symtab->find(Name)) { + if (auto *DS = dyn_cast(Sym)) + return {DS->Section, false, DS->Value, Loc}; + if (auto *SS = dyn_cast(Sym)) + if (!ErrorOnMissingSection || SS->CopyRelSec) + return {SS->CopyRelSec, false, 0, Loc}; } - // Write leading padding. - std::vector Sections; - for (BaseCommand *Cmd : Commands) - if (auto *ISD = dyn_cast(Cmd)) - for (InputSection *IS : ISD->Sections) - if (IS->Live) - Sections.push_back(IS); - uint32_t Filler = getFiller(); - if (Filler) - fill(Buf, Sections.empty() ? Sec->Size : Sections[0]->OutSecOff, Filler); - - parallelForEachN(0, Sections.size(), [=](size_t I) { - InputSection *IS = Sections[I]; - IS->writeTo(Buf); - - // Fill gaps between sections. - if (Filler) { - uint8_t *Start = Buf + IS->OutSecOff + IS->getSize(); - uint8_t *End; - if (I + 1 == Sections.size()) - End = Buf + Sec->Size; - else - End = Buf + Sections[I + 1]->OutSecOff; - fill(Start, End - Start, Filler); - } - }); - - // Linker scripts may have BYTE()-family commands with which you - // can write arbitrary bytes to the output. Process them if any. - for (BaseCommand *Base : Commands) - if (auto *Data = dyn_cast(Base)) - writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size); -} - -ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) { - if (S == ".") - return {CurAddressState->OutSec, Dot - CurAddressState->OutSec->Addr, Loc}; - if (SymbolBody *B = findSymbol(S)) { - if (auto *D = dyn_cast(B)) - return {D->Section, D->Value, Loc}; - if (auto *C = dyn_cast(B)) - return {InX::Common, C->Offset, Loc}; - } - error(Loc + ": symbol not found: " + S); + error(Loc + ": symbol not found: " + Name); return 0; } -bool LinkerScript::isDefined(StringRef S) { return findSymbol(S) != nullptr; } - -static const size_t NoPhdr = -1; +// Returns the index of the segment named Name. +static Optional getPhdrIndex(ArrayRef Vec, + StringRef Name) { + for (size_t I = 0; I < Vec.size(); ++I) + if (Vec[I].Name == Name) + return I; + return None; +} // 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 LinkerScript::getPhdrIndices(OutputSectionCommand *Cmd) { +std::vector LinkerScript::getPhdrIndices(OutputSection *Cmd) { std::vector Ret; - for (StringRef PhdrName : Cmd->Phdrs) { - size_t Index = getPhdrIndex(Cmd->Location, PhdrName); - if (Index != NoPhdr) - Ret.push_back(Index); - } - return Ret; -} -// Returns the index of the segment named PhdrName if found otherwise -// NoPhdr. When not found, if PhdrName is not the special case value 'NONE' -// (which can be used to explicitly specify that a section isn't assigned to a -// segment) then error. -size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) { - size_t I = 0; - for (PhdrsCommand &Cmd : Opt.PhdrsCommands) { - if (Cmd.Name == PhdrName) - return I; - ++I; + for (StringRef S : Cmd->Phdrs) { + if (Optional Idx = getPhdrIndex(PhdrsCommands, S)) + Ret.push_back(*Idx); + else if (S != "NONE") + error(Cmd->Location + ": section header '" + S + + "' is not listed in PHDRS"); } - if (PhdrName != "NONE") - error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS"); - return NoPhdr; + return Ret; } - -template void OutputSectionCommand::writeTo(uint8_t *Buf); -template void OutputSectionCommand::writeTo(uint8_t *Buf); -template void OutputSectionCommand::writeTo(uint8_t *Buf); -template void OutputSectionCommand::writeTo(uint8_t *Buf); - -template void OutputSectionCommand::maybeCompress(); -template void OutputSectionCommand::maybeCompress(); -template void OutputSectionCommand::maybeCompress(); -template void OutputSectionCommand::maybeCompress(); - -template void OutputSectionCommand::finalize(); -template void OutputSectionCommand::finalize(); -template void OutputSectionCommand::finalize(); -template void OutputSectionCommand::finalize(); -- cgit v1.2.3 From 38aed5af8bdefd13a355fc0728c6ad57e5efa3ff Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 7 Feb 2018 17:38:02 -0500 Subject: update embedded LLD to 6.0.0rc2 --- deps/lld-prebuilt/ELF/Options.inc | 4 +- deps/lld/ELF/AArch64ErrataFix.cpp | 3 +- deps/lld/ELF/Arch/X86.cpp | 144 ++++++++++++++++++++- deps/lld/ELF/Arch/X86_64.cpp | 127 +++++++++++++++++- deps/lld/ELF/Config.h | 1 + deps/lld/ELF/Driver.cpp | 3 +- deps/lld/ELF/InputFiles.cpp | 8 ++ deps/lld/ELF/LinkerScript.cpp | 53 +++++--- deps/lld/ELF/LinkerScript.h | 10 +- deps/lld/ELF/Options.td | 4 +- deps/lld/ELF/OutputSections.h | 5 +- deps/lld/ELF/ScriptParser.cpp | 15 ++- deps/lld/ELF/SymbolTable.cpp | 3 +- deps/lld/ELF/Writer.cpp | 6 +- deps/lld/ELF/Writer.h | 7 + .../lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp | 1 + deps/lld/test/ELF/Inputs/as-needed-lazy.s | 3 + .../lld/test/ELF/Inputs/mips-gp-dips-corrupt-ver.s | 14 ++ .../test/ELF/Inputs/mips-gp-dips-corrupt-ver.so | Bin 0 -> 2160 bytes deps/lld/test/ELF/as-needed-lazy.s | 14 ++ deps/lld/test/ELF/i386-retpoline-nopic.s | 65 ++++++++++ deps/lld/test/ELF/i386-retpoline-pic.s | 62 +++++++++ deps/lld/test/ELF/linkerscript/at-self-reference.s | 63 +++++++++ deps/lld/test/ELF/linkerscript/at2.s | 81 ++++++++++++ deps/lld/test/ELF/linkerscript/at3.s | 38 ++++++ deps/lld/test/ELF/linkerscript/merge-header-load.s | 21 +++ .../test/ELF/linkerscript/parse-section-in-addr.s | 10 ++ deps/lld/test/ELF/mips-gp-disp-ver.s | 15 +++ deps/lld/test/ELF/pie.s | 2 +- deps/lld/test/ELF/x86-64-retpoline-znow.s | 53 ++++++++ deps/lld/test/ELF/x86-64-retpoline.s | 66 ++++++++++ 31 files changed, 856 insertions(+), 45 deletions(-) create mode 100644 deps/lld/test/ELF/Inputs/as-needed-lazy.s create mode 100644 deps/lld/test/ELF/Inputs/mips-gp-dips-corrupt-ver.s create mode 100755 deps/lld/test/ELF/Inputs/mips-gp-dips-corrupt-ver.so create mode 100644 deps/lld/test/ELF/as-needed-lazy.s create mode 100644 deps/lld/test/ELF/i386-retpoline-nopic.s create mode 100644 deps/lld/test/ELF/i386-retpoline-pic.s create mode 100644 deps/lld/test/ELF/linkerscript/at-self-reference.s create mode 100644 deps/lld/test/ELF/linkerscript/at2.s create mode 100644 deps/lld/test/ELF/linkerscript/at3.s create mode 100644 deps/lld/test/ELF/linkerscript/merge-header-load.s create mode 100644 deps/lld/test/ELF/linkerscript/parse-section-in-addr.s create mode 100644 deps/lld/test/ELF/mips-gp-disp-ver.s create mode 100644 deps/lld/test/ELF/x86-64-retpoline-znow.s create mode 100644 deps/lld/test/ELF/x86-64-retpoline.s (limited to 'deps/lld/ELF/LinkerScript.cpp') diff --git a/deps/lld-prebuilt/ELF/Options.inc b/deps/lld-prebuilt/ELF/Options.inc index 640f1bdcc6..17659f0290 100644 --- a/deps/lld-prebuilt/ELF/Options.inc +++ b/deps/lld-prebuilt/ELF/Options.inc @@ -230,6 +230,8 @@ OPTION(prefix_2, "no-merge-exidx-entries", no_merge_exidx_entries, Flag, INVALID OPTION(prefix_2, "no-mmap-output-file", no_mmap_output_file, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) OPTION(prefix_3, "no-omagic", no_omagic, Flag, INVALID, INVALID, nullptr, 0, 0, "Do not set the text data sections to be writable", "", nullptr) +OPTION(prefix_2, "no-pie", no_pie, Flag, INVALID, INVALID, nullptr, 0, 0, + "Do not create a position independent executable", nullptr, nullptr) OPTION(prefix_2, "no-print-gc-sections", no_print_gc_sections, Flag, INVALID, INVALID, nullptr, 0, 0, "Do not list removed unused sections", nullptr, nullptr) OPTION(prefix_2, "no-rosegment", no_rosegment, Flag, INVALID, INVALID, nullptr, 0, 0, @@ -247,8 +249,6 @@ OPTION(prefix_2, "no-whole-archive", no_whole_archive, Flag, INVALID, INVALID, n OPTION(prefix_2, "noinhibit-exec", noinhibit_exec, Flag, INVALID, INVALID, nullptr, 0, 0, "Retain the executable output file whenever it is still usable", nullptr, nullptr) OPTION(prefix_2, "non_shared", alias_Bstatic_non_shared, Flag, INVALID, Bstatic, nullptr, 0, 0, nullptr, nullptr, nullptr) -OPTION(prefix_2, "nopie", nopie, Flag, INVALID, INVALID, nullptr, 0, 0, - "Do not create a position independent executable", nullptr, nullptr) OPTION(prefix_2, "nostdlib", nostdlib, Flag, INVALID, INVALID, nullptr, 0, 0, "Only search directories specified on the command line", nullptr, nullptr) OPTION(prefix_1, "N", alias_omagic, Flag, INVALID, omagic, nullptr, 0, 0, nullptr, nullptr, nullptr) diff --git a/deps/lld/ELF/AArch64ErrataFix.cpp b/deps/lld/ELF/AArch64ErrataFix.cpp index 9c0d536dea..48273d0eb3 100644 --- a/deps/lld/ELF/AArch64ErrataFix.cpp +++ b/deps/lld/ELF/AArch64ErrataFix.cpp @@ -47,6 +47,7 @@ using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; +using namespace llvm::support; using namespace llvm::support::endian; using namespace lld; @@ -357,7 +358,7 @@ static uint64_t scanCortexA53Errata843419(InputSection *IS, uint64_t &Off, uint64_t PatchOff = 0; const uint8_t *Buf = IS->Data.begin(); - const uint32_t *InstBuf = reinterpret_cast(Buf + Off); + const ulittle32_t *InstBuf = reinterpret_cast(Buf + Off); uint32_t Instr1 = *InstBuf++; uint32_t Instr2 = *InstBuf++; uint32_t Instr3 = *InstBuf++; diff --git a/deps/lld/ELF/Arch/X86.cpp b/deps/lld/ELF/Arch/X86.cpp index 10517bef14..09c16db53e 100644 --- a/deps/lld/ELF/Arch/X86.cpp +++ b/deps/lld/ELF/Arch/X86.cpp @@ -21,7 +21,7 @@ using namespace lld; using namespace lld::elf; namespace { -class X86 final : public TargetInfo { +class X86 : public TargetInfo { public: X86(); RelExpr getRelExpr(RelType Type, const Symbol &S, @@ -399,7 +399,145 @@ void X86::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { memcpy(Loc - 2, Inst, sizeof(Inst)); } +namespace { +class RetpolinePic : public X86 { +public: + RetpolinePic(); + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; +}; + +class RetpolineNoPic : public X86 { +public: + RetpolineNoPic(); + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; +}; +} // namespace + +RetpolinePic::RetpolinePic() { + PltHeaderSize = 48; + PltEntrySize = 32; +} + +void RetpolinePic::writeGotPlt(uint8_t *Buf, const Symbol &S) const { + write32le(Buf, S.getPltVA() + 17); +} + +void RetpolinePic::writePltHeader(uint8_t *Buf) const { + const uint8_t Insn[] = { + 0xff, 0xb3, 0, 0, 0, 0, // 0: pushl GOTPLT+4(%ebx) + 0x50, // 6: pushl %eax + 0x8b, 0x83, 0, 0, 0, 0, // 7: mov GOTPLT+8(%ebx), %eax + 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: call next + 0xf3, 0x90, // 12: loop: pause + 0x0f, 0xae, 0xe8, // 14: lfence + 0xeb, 0xf9, // 17: jmp loop + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16 + 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp) + 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx + 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp) + 0x89, 0xc8, // 2b: mov %ecx, %eax + 0x59, // 2d: pop %ecx + 0xc3, // 2e: ret + }; + memcpy(Buf, Insn, sizeof(Insn)); + + uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); + uint32_t GotPlt = InX::GotPlt->getVA() - Ebx; + write32le(Buf + 2, GotPlt + 4); + write32le(Buf + 9, GotPlt + 8); +} + +void RetpolinePic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Insn[] = { + 0x50, // pushl %eax + 0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax + 0xe8, 0, 0, 0, 0, // call plt+0x20 + 0xe9, 0, 0, 0, 0, // jmp plt+0x12 + 0x68, 0, 0, 0, 0, // pushl $reloc_offset + 0xe9, 0, 0, 0, 0, // jmp plt+0 + }; + memcpy(Buf, Insn, sizeof(Insn)); + + uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); + write32le(Buf + 3, GotPltEntryAddr - Ebx); + write32le(Buf + 8, -Index * PltEntrySize - PltHeaderSize - 12 + 32); + write32le(Buf + 13, -Index * PltEntrySize - PltHeaderSize - 17 + 18); + write32le(Buf + 18, RelOff); + write32le(Buf + 23, -Index * PltEntrySize - PltHeaderSize - 27); +} + +RetpolineNoPic::RetpolineNoPic() { + PltHeaderSize = 48; + PltEntrySize = 32; +} + +void RetpolineNoPic::writeGotPlt(uint8_t *Buf, const Symbol &S) const { + write32le(Buf, S.getPltVA() + 16); +} + +void RetpolineNoPic::writePltHeader(uint8_t *Buf) const { + const uint8_t PltData[] = { + 0xff, 0x35, 0, 0, 0, 0, // 0: pushl GOTPLT+4 + 0x50, // 6: pushl %eax + 0xa1, 0, 0, 0, 0, // 7: mov GOTPLT+8, %eax + 0xe8, 0x0f, 0x00, 0x00, 0x00, // c: call next + 0xf3, 0x90, // 11: loop: pause + 0x0f, 0xae, 0xe8, // 13: lfence + 0xeb, 0xf9, // 16: jmp loop + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 18: int3 + 0xcc, 0xcc, 0xcc, // 1f: int3; .align 16 + 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp) + 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx + 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp) + 0x89, 0xc8, // 2b: mov %ecx, %eax + 0x59, // 2d: pop %ecx + 0xc3, // 2e: ret + }; + memcpy(Buf, PltData, sizeof(PltData)); + + uint32_t GotPlt = InX::GotPlt->getVA(); + write32le(Buf + 2, GotPlt + 4); + write32le(Buf + 8, GotPlt + 8); +} + +void RetpolineNoPic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Insn[] = { + 0x50, // 0: pushl %eax + 0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax + 0xe8, 0, 0, 0, 0, // 6: call plt+0x20 + 0xe9, 0, 0, 0, 0, // b: jmp plt+0x11 + 0x68, 0, 0, 0, 0, // 10: pushl $reloc_offset + 0xe9, 0, 0, 0, 0, // 15: jmp plt+0 + }; + memcpy(Buf, Insn, sizeof(Insn)); + + write32le(Buf + 2, GotPltEntryAddr); + write32le(Buf + 7, -Index * PltEntrySize - PltHeaderSize - 11 + 32); + write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16 + 17); + write32le(Buf + 17, RelOff); + write32le(Buf + 22, -Index * PltEntrySize - PltHeaderSize - 26); +} + TargetInfo *elf::getX86TargetInfo() { - static X86 Target; - return &Target; + if (Config->ZRetpolineplt) { + if (Config->Pic) { + static RetpolinePic T; + return &T; + } + static RetpolineNoPic T; + return &T; + } + + static X86 T; + return &T; } diff --git a/deps/lld/ELF/Arch/X86_64.cpp b/deps/lld/ELF/Arch/X86_64.cpp index c977d9247d..3db391e9f0 100644 --- a/deps/lld/ELF/Arch/X86_64.cpp +++ b/deps/lld/ELF/Arch/X86_64.cpp @@ -23,7 +23,7 @@ using namespace lld; using namespace lld::elf; namespace { -template class X86_64 final : public TargetInfo { +template class X86_64 : public TargetInfo { public: X86_64(); RelExpr getRelExpr(RelType Type, const Symbol &S, @@ -460,12 +460,125 @@ void X86_64::relaxGot(uint8_t *Loc, uint64_t Val) const { write32le(Loc - 1, Val + 1); } -TargetInfo *elf::getX32TargetInfo() { - static X86_64 Target; - return &Target; +namespace { +template class Retpoline : public X86_64 { +public: + Retpoline(); + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; +}; + +template class RetpolineZNow : public X86_64 { +public: + RetpolineZNow(); + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override {} + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; +}; +} // namespace + +template Retpoline::Retpoline() { + TargetInfo::PltHeaderSize = 48; + TargetInfo::PltEntrySize = 32; +} + +template +void Retpoline::writeGotPlt(uint8_t *Buf, const Symbol &S) const { + write32le(Buf, S.getPltVA() + 17); +} + +template void Retpoline::writePltHeader(uint8_t *Buf) const { + const uint8_t Insn[] = { + 0xff, 0x35, 0, 0, 0, 0, // 0: pushq GOTPLT+8(%rip) + 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 6: mov GOTPLT+16(%rip), %r11 + 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: callq next + 0xf3, 0x90, // 12: loop: pause + 0x0f, 0xae, 0xe8, // 14: lfence + 0xeb, 0xf9, // 17: jmp loop + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16 + 0x4c, 0x89, 0x1c, 0x24, // 20: next: mov %r11, (%rsp) + 0xc3, // 24: ret + }; + memcpy(Buf, Insn, sizeof(Insn)); + + uint64_t GotPlt = InX::GotPlt->getVA(); + uint64_t Plt = InX::Plt->getVA(); + write32le(Buf + 2, GotPlt - Plt - 6 + 8); + write32le(Buf + 9, GotPlt - Plt - 13 + 16); +} + +template +void Retpoline::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Insn[] = { + 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 0: mov foo@GOTPLT(%rip), %r11 + 0xe8, 0, 0, 0, 0, // 7: callq plt+0x20 + 0xe9, 0, 0, 0, 0, // c: jmp plt+0x12 + 0x68, 0, 0, 0, 0, // 11: pushq + 0xe9, 0, 0, 0, 0, // 16: jmp plt+0 + }; + memcpy(Buf, Insn, sizeof(Insn)); + + uint64_t Off = TargetInfo::PltHeaderSize + TargetInfo::PltEntrySize * Index; + + write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7); + write32le(Buf + 8, -Off - 12 + 32); + write32le(Buf + 13, -Off - 17 + 18); + write32le(Buf + 18, Index); + write32le(Buf + 23, -Off - 27); +} + +template RetpolineZNow::RetpolineZNow() { + TargetInfo::PltHeaderSize = 32; + TargetInfo::PltEntrySize = 16; +} + +template +void RetpolineZNow::writePltHeader(uint8_t *Buf) const { + const uint8_t Insn[] = { + 0xe8, 0x0b, 0x00, 0x00, 0x00, // 0: call next + 0xf3, 0x90, // 5: loop: pause + 0x0f, 0xae, 0xe8, // 7: lfence + 0xeb, 0xf9, // a: jmp loop + 0xcc, 0xcc, 0xcc, 0xcc, // c: int3; .align 16 + 0x4c, 0x89, 0x1c, 0x24, // 10: next: mov %r11, (%rsp) + 0xc3, // 14: ret + }; + memcpy(Buf, Insn, sizeof(Insn)); } -TargetInfo *elf::getX86_64TargetInfo() { - static X86_64 Target; - return &Target; +template +void RetpolineZNow::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Insn[] = { + 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // mov foo@GOTPLT(%rip), %r11 + 0xe9, 0, 0, 0, 0, // jmp plt+0 + }; + memcpy(Buf, Insn, sizeof(Insn)); + + write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7); + write32le(Buf + 8, + -Index * TargetInfo::PltEntrySize - TargetInfo::PltHeaderSize - 12); } + +template TargetInfo *getTargetInfo() { + if (Config->ZRetpolineplt) { + if (Config->ZNow) { + static RetpolineZNow T; + return &T; + } + static Retpoline T; + return &T; + } + + static X86_64 T; + return &T; +} + +TargetInfo *elf::getX32TargetInfo() { return getTargetInfo(); } +TargetInfo *elf::getX86_64TargetInfo() { return getTargetInfo(); } diff --git a/deps/lld/ELF/Config.h b/deps/lld/ELF/Config.h index 74c325cb7c..ed42572096 100644 --- a/deps/lld/ELF/Config.h +++ b/deps/lld/ELF/Config.h @@ -159,6 +159,7 @@ struct Configuration { bool ZRelro; bool ZRodynamic; bool ZText; + bool ZRetpolineplt; bool ExitEarly; bool ZWxneeded; DiscardPolicy Discard; diff --git a/deps/lld/ELF/Driver.cpp b/deps/lld/ELF/Driver.cpp index b159fe63eb..6de8ed59e5 100644 --- a/deps/lld/ELF/Driver.cpp +++ b/deps/lld/ELF/Driver.cpp @@ -638,7 +638,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->Optimize = args::getInteger(Args, OPT_O, 1); Config->OrphanHandling = getOrphanHandling(Args); Config->OutputFile = Args.getLastArgValue(OPT_o); - Config->Pie = Args.hasFlag(OPT_pie, OPT_nopie, false); + Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie, false); Config->PrintGcSections = Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false); Config->Rpath = getRpath(Args); @@ -674,6 +674,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->ZNow = hasZOption(Args, "now"); Config->ZOrigin = hasZOption(Args, "origin"); Config->ZRelro = !hasZOption(Args, "norelro"); + Config->ZRetpolineplt = hasZOption(Args, "retpolineplt"); Config->ZRodynamic = hasZOption(Args, "rodynamic"); Config->ZStackSize = args::getZOptionValue(Args, OPT_z, "stack-size", 0); Config->ZText = !hasZOption(Args, "notext"); diff --git a/deps/lld/ELF/InputFiles.cpp b/deps/lld/ELF/InputFiles.cpp index f514870ca8..ccf4b3d767 100644 --- a/deps/lld/ELF/InputFiles.cpp +++ b/deps/lld/ELF/InputFiles.cpp @@ -856,6 +856,14 @@ template void SharedFile::parseRest() { continue; } + if (Config->EMachine == EM_MIPS) { + // FIXME: MIPS BFD linker puts _gp_disp symbol into DSO files + // and incorrectly assigns VER_NDX_LOCAL to this section global + // symbol. Here is a workaround for this bug. + if (Versym && VersymIndex == VER_NDX_LOCAL && Name == "_gp_disp") + continue; + } + const Elf_Verdef *Ver = nullptr; if (VersymIndex != VER_NDX_GLOBAL) { if (VersymIndex >= Verdefs.size() || VersymIndex == VER_NDX_LOCAL) { diff --git a/deps/lld/ELF/LinkerScript.cpp b/deps/lld/ELF/LinkerScript.cpp index 16b306da46..23c3a11a9d 100644 --- a/deps/lld/ELF/LinkerScript.cpp +++ b/deps/lld/ELF/LinkerScript.cpp @@ -589,8 +589,12 @@ void LinkerScript::output(InputSection *S) { // If there is a memory region associated with this input section, then // place the section in that region and update the region index. + if (Ctx->LMARegion) + Ctx->LMARegion->CurPos += Pos - Before; + // FIXME: should we also produce overflow errors for LMARegion? + if (Ctx->MemRegion) { - uint64_t &CurOffset = Ctx->MemRegionOffset[Ctx->MemRegion]; + uint64_t &CurOffset = Ctx->MemRegion->CurPos; CurOffset += Pos - Before; uint64_t CurSize = CurOffset - Ctx->MemRegion->Origin; if (CurSize > Ctx->MemRegion->Length) { @@ -608,13 +612,6 @@ void LinkerScript::switchTo(OutputSection *Sec) { Ctx->OutSec = Sec; Ctx->OutSec->Addr = advance(0, Ctx->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 (Ctx->LMAOffset) - Ctx->OutSec->LMAOffset = Ctx->LMAOffset(); } // This function searches for a memory region to place the given output @@ -624,9 +621,8 @@ MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *Sec) { // If a memory region name was specified in the output section command, // then try to find that region first. if (!Sec->MemoryRegionName.empty()) { - auto It = MemoryRegions.find(Sec->MemoryRegionName); - if (It != MemoryRegions.end()) - return It->second; + if (MemoryRegion *M = MemoryRegions.lookup(Sec->MemoryRegionName)) + return M; error("memory region '" + Sec->MemoryRegionName + "' not declared"); return nullptr; } @@ -659,16 +655,25 @@ void LinkerScript::assignOffsets(OutputSection *Sec) { setDot(Sec->AddrExpr, Sec->Location, false); Ctx->MemRegion = Sec->MemRegion; + Ctx->LMARegion = Sec->LMARegion; if (Ctx->MemRegion) - Dot = Ctx->MemRegionOffset[Ctx->MemRegion]; - - if (Sec->LMAExpr) { - uint64_t D = Dot; - Ctx->LMAOffset = [=] { return Sec->LMAExpr().getValue() - D; }; - } + Dot = Ctx->MemRegion->CurPos; switchTo(Sec); + if (Sec->LMAExpr) + Ctx->LMAOffset = Sec->LMAExpr().getValue() - Dot; + + if (MemoryRegion *MR = Sec->LMARegion) + Ctx->LMAOffset = MR->CurPos - Dot; + + // 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 (PhdrEntry *L = Ctx->OutSec->PtLoad) + L->LMAOffset = Ctx->LMAOffset; + // The Size previously denoted how many InputSections had been added to this // section, and was used for sorting SHF_LINK_ORDER sections. Reset it to // compute the actual size value. @@ -689,7 +694,9 @@ void LinkerScript::assignOffsets(OutputSection *Sec) { Cmd->Offset = Dot - Ctx->OutSec->Addr; Dot += Cmd->Size; if (Ctx->MemRegion) - Ctx->MemRegionOffset[Ctx->MemRegion] += Cmd->Size; + Ctx->MemRegion->CurPos += Cmd->Size; + if (Ctx->LMARegion) + Ctx->LMARegion->CurPos += Cmd->Size; Ctx->OutSec->Size = Dot - Ctx->OutSec->Addr; continue; } @@ -788,6 +795,12 @@ void LinkerScript::adjustSectionsAfterSorting() { if (auto *Sec = dyn_cast(Base)) { if (!Sec->Live) continue; + if (!Sec->LMARegionName.empty()) { + if (MemoryRegion *M = MemoryRegions.lookup(Sec->LMARegionName)) + Sec->LMARegion = M; + else + error("memory region '" + Sec->LMARegionName + "' not declared"); + } Sec->MemRegion = findMemoryRegion(Sec); // Handle align (e.g. ".foo : ALIGN(16) { ... }"). if (Sec->AlignExpr) @@ -878,8 +891,8 @@ void LinkerScript::allocateHeaders(std::vector &Phdrs) { LinkerScript::AddressState::AddressState() { for (auto &MRI : Script->MemoryRegions) { - const MemoryRegion *MR = MRI.second; - MemRegionOffset[MR] = MR->Origin; + MemoryRegion *MR = MRI.second; + MR->CurPos = MR->Origin; } } diff --git a/deps/lld/ELF/LinkerScript.h b/deps/lld/ELF/LinkerScript.h index 11131dda8e..0d7578cd2f 100644 --- a/deps/lld/ELF/LinkerScript.h +++ b/deps/lld/ELF/LinkerScript.h @@ -118,11 +118,17 @@ enum class ConstraintKind { NoConstraint, ReadOnly, ReadWrite }; // target memory. Instances of the struct are created by parsing the // MEMORY command. struct MemoryRegion { + MemoryRegion(StringRef Name, uint64_t Origin, uint64_t Length, uint32_t Flags, + uint32_t NegFlags) + : Name(Name), Origin(Origin), Length(Length), Flags(Flags), + NegFlags(NegFlags) {} + std::string Name; uint64_t Origin; uint64_t Length; uint32_t Flags; uint32_t NegFlags; + uint64_t CurPos = 0; }; // This struct represents one section match pattern in SECTIONS() command. @@ -200,8 +206,8 @@ class LinkerScript final { uint64_t ThreadBssOffset = 0; OutputSection *OutSec = nullptr; MemoryRegion *MemRegion = nullptr; - llvm::DenseMap MemRegionOffset; - std::function LMAOffset; + MemoryRegion *LMARegion = nullptr; + uint64_t LMAOffset = 0; }; llvm::DenseMap NameToOutputSection; diff --git a/deps/lld/ELF/Options.td b/deps/lld/ELF/Options.td index 20027e90ae..7350467281 100644 --- a/deps/lld/ELF/Options.td +++ b/deps/lld/ELF/Options.td @@ -202,6 +202,8 @@ def no_gnu_unique: F<"no-gnu-unique">, def no_merge_exidx_entries: F<"no-merge-exidx-entries">, HelpText<"Disable merging .ARM.exidx entries">; +def no_pie: F<"no-pie">, HelpText<"Do not create a position independent executable">; + def no_threads: F<"no-threads">, HelpText<"Do not run the linker multi-threaded">; @@ -211,8 +213,6 @@ def no_whole_archive: F<"no-whole-archive">, def noinhibit_exec: F<"noinhibit-exec">, HelpText<"Retain the executable output file whenever it is still usable">; -def nopie: F<"nopie">, HelpText<"Do not create a position independent executable">; - def no_omagic: Flag<["--"], "no-omagic">, MetaVarName<"">, HelpText<"Do not set the text data sections to be writable">; diff --git a/deps/lld/ELF/OutputSections.h b/deps/lld/ELF/OutputSections.h index b2845773e9..c006eae0c0 100644 --- a/deps/lld/ELF/OutputSections.h +++ b/deps/lld/ELF/OutputSections.h @@ -49,7 +49,7 @@ public: static bool classof(const BaseCommand *C); - uint64_t getLMA() const { return Addr + LMAOffset; } + uint64_t getLMA() const { return PtLoad ? Addr + PtLoad->LMAOffset : Addr; } template void writeHeaderTo(typename ELFT::Shdr *SHdr); unsigned SectionIndex; @@ -78,7 +78,6 @@ public: // The following fields correspond to Elf_Shdr members. uint64_t Offset = 0; - uint64_t LMAOffset = 0; uint64_t Addr = 0; uint32_t ShName = 0; @@ -89,6 +88,7 @@ public: // The following members are normally only used in linker scripts. MemoryRegion *MemRegion = nullptr; + MemoryRegion *LMARegion = nullptr; Expr AddrExpr; Expr AlignExpr; Expr LMAExpr; @@ -99,6 +99,7 @@ public: ConstraintKind Constraint = ConstraintKind::NoConstraint; std::string Location; std::string MemoryRegionName; + std::string LMARegionName; bool Noload = false; template void finalize(); diff --git a/deps/lld/ELF/ScriptParser.cpp b/deps/lld/ELF/ScriptParser.cpp index 4263944981..3d2606db8d 100644 --- a/deps/lld/ELF/ScriptParser.cpp +++ b/deps/lld/ELF/ScriptParser.cpp @@ -709,6 +709,14 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) { if (consume(">")) Cmd->MemoryRegionName = next(); + if (consume("AT")) { + expect(">"); + Cmd->LMARegionName = next(); + } + + if (Cmd->LMAExpr && !Cmd->LMARegionName.empty()) + error("section can't have both LMA and a load region"); + Cmd->Phdrs = readOutputSectionPhdrs(); if (consume("=")) @@ -922,7 +930,10 @@ ByteCommand *ScriptParser::readByteCommand(StringRef Tok) { StringRef ScriptParser::readParenLiteral() { expect("("); + bool Orig = InExpr; + InExpr = false; StringRef Tok = next(); + InExpr = Orig; expect(")"); return Tok; } @@ -1282,8 +1293,8 @@ void ScriptParser::readMemory() { // Add the memory region to the region map. if (Script->MemoryRegions.count(Name)) setError("region '" + Name + "' already defined"); - MemoryRegion *MR = make(); - *MR = {Name, Origin, Length, Flags, NegFlags}; + MemoryRegion *MR = + make(Name, Origin, Length, Flags, NegFlags); Script->MemoryRegions[Name] = MR; } } diff --git a/deps/lld/ELF/SymbolTable.cpp b/deps/lld/ELF/SymbolTable.cpp index b6bf219988..c3a00bea4a 100644 --- a/deps/lld/ELF/SymbolTable.cpp +++ b/deps/lld/ELF/SymbolTable.cpp @@ -491,12 +491,13 @@ void SymbolTable::addShared(StringRef Name, SharedFile &File, if (WasInserted || ((S->isUndefined() || S->isLazy()) && S->getVisibility() == STV_DEFAULT)) { uint8_t Binding = S->Binding; + bool WasUndefined = S->isUndefined(); replaceSymbol(S, File, Name, Sym.getBinding(), Sym.st_other, Sym.getType(), Sym.st_value, Sym.st_size, Alignment, VerdefIndex); if (!WasInserted) { S->Binding = Binding; - if (!S->isWeak() && !Config->GcSections) + if (!S->isWeak() && !Config->GcSections && WasUndefined) File.IsNeeded = true; } } diff --git a/deps/lld/ELF/Writer.cpp b/deps/lld/ELF/Writer.cpp index 5feff456ff..1c3b6495a0 100644 --- a/deps/lld/ELF/Writer.cpp +++ b/deps/lld/ELF/Writer.cpp @@ -822,6 +822,8 @@ void PhdrEntry::add(OutputSection *Sec) { p_align = std::max(p_align, Sec->Alignment); if (p_type == PT_LOAD) Sec->PtLoad = this; + if (Sec->LMAExpr) + ASectionHasLMA = true; } // The beginning and the ending of .rel[a].plt section are marked @@ -1626,7 +1628,9 @@ template std::vector Writer::createPhdrs() { // different flags or is loaded at a discontiguous address using AT linker // script command. uint64_t NewFlags = computeFlags(Sec->getPhdrFlags()); - if (Sec->LMAExpr || Flags != NewFlags) { + if ((Sec->LMAExpr && Load->ASectionHasLMA) || + Sec->MemRegion != Load->FirstSec->MemRegion || Flags != NewFlags) { + Load = AddHdr(PT_LOAD, NewFlags); Flags = NewFlags; } diff --git a/deps/lld/ELF/Writer.h b/deps/lld/ELF/Writer.h index d247068bab..f48f9d1e01 100644 --- a/deps/lld/ELF/Writer.h +++ b/deps/lld/ELF/Writer.h @@ -44,6 +44,13 @@ struct PhdrEntry { OutputSection *FirstSec = nullptr; OutputSection *LastSec = nullptr; bool HasLMA = false; + + // True if one of the sections in this program header has a LMA specified via + // linker script: AT(addr). We never allow 2 or more sections with LMA in the + // same program header. + bool ASectionHasLMA = false; + + uint64_t LMAOffset = 0; }; void addReservedSymbols(); diff --git a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp index b207c85523..aee9959ca6 100644 --- a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp +++ b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp @@ -621,6 +621,7 @@ void ArchHandler_x86_64::applyFixupFinal( // Fall into llvm_unreachable(). break; } + llvm_unreachable("invalid x86_64 Reference Kind"); } void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref, diff --git a/deps/lld/test/ELF/Inputs/as-needed-lazy.s b/deps/lld/test/ELF/Inputs/as-needed-lazy.s new file mode 100644 index 0000000000..7f9c360dda --- /dev/null +++ b/deps/lld/test/ELF/Inputs/as-needed-lazy.s @@ -0,0 +1,3 @@ +.global foo +foo: + nop diff --git a/deps/lld/test/ELF/Inputs/mips-gp-dips-corrupt-ver.s b/deps/lld/test/ELF/Inputs/mips-gp-dips-corrupt-ver.s new file mode 100644 index 0000000000..42bd32a1e7 --- /dev/null +++ b/deps/lld/test/ELF/Inputs/mips-gp-dips-corrupt-ver.s @@ -0,0 +1,14 @@ +# Source file for mips-gp-dips-corrupt-ver.so +# +# % cat gpdisp.ver +# LLD_1.0.0 { global: foo; }; +# +# % as mips-gp-dips-corrupt-ver.s -o mips-gp-dips-corrupt-ver.o +# % ld -shared -o mips-gp-dips-corrupt-ver.so \ +# --version-script gpdisp.ver mips-gp-dips-corrupt-ver.o + + .global foo + .text +foo: + lui $t0, %hi(_gp_disp) + addi $t0, $t0, %lo(_gp_disp) diff --git a/deps/lld/test/ELF/Inputs/mips-gp-dips-corrupt-ver.so b/deps/lld/test/ELF/Inputs/mips-gp-dips-corrupt-ver.so new file mode 100755 index 0000000000..289ffa538f Binary files /dev/null and b/deps/lld/test/ELF/Inputs/mips-gp-dips-corrupt-ver.so differ diff --git a/deps/lld/test/ELF/as-needed-lazy.s b/deps/lld/test/ELF/as-needed-lazy.s new file mode 100644 index 0000000000..e892b9980a --- /dev/null +++ b/deps/lld/test/ELF/as-needed-lazy.s @@ -0,0 +1,14 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/as-needed-lazy.s -o %t2.o +# RUN: ld.lld %t2.o -o %t2.so -shared +# RUN: rm -f %t2.a +# RUN: llvm-ar rc %t2.a %t2.o +# RUN: ld.lld %t1.o %t2.a --as-needed %t2.so -o %t +# RUN: llvm-readobj -d %t | FileCheck %s + +# CHECK-NOT: NEEDED + +.global _start +_start: + nop diff --git a/deps/lld/test/ELF/i386-retpoline-nopic.s b/deps/lld/test/ELF/i386-retpoline-nopic.s new file mode 100644 index 0000000000..79dd5a63cd --- /dev/null +++ b/deps/lld/test/ELF/i386-retpoline-nopic.s @@ -0,0 +1,65 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %p/Inputs/shared.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so + +// RUN: ld.lld %t1.o %t2.so -o %t.exe -z retpolineplt +// RUN: llvm-objdump -d -s %t.exe | FileCheck %s + +// CHECK: Disassembly of section .plt: +// CHECK-NEXT: .plt: +// CHECK-NEXT: 11010: ff 35 04 20 01 00 pushl 73732 +// CHECK-NEXT: 11016: 50 pushl %eax +// CHECK-NEXT: 11017: a1 08 20 01 00 movl 73736, %eax +// CHECK-NEXT: 1101c: e8 0f 00 00 00 calll 15 <.plt+0x20> +// CHECK-NEXT: 11021: f3 90 pause +// CHECK-NEXT: 11023: 0f ae e8 lfence +// CHECK-NEXT: 11026: eb f9 jmp -7 <.plt+0x11> +// CHECK-NEXT: 11028: cc int3 +// CHECK-NEXT: 11029: cc int3 +// CHECK-NEXT: 1102a: cc int3 +// CHECK-NEXT: 1102b: cc int3 +// CHECK-NEXT: 1102c: cc int3 +// CHECK-NEXT: 1102d: cc int3 +// CHECK-NEXT: 1102e: cc int3 +// CHECK-NEXT: 1102f: cc int3 +// CHECK-NEXT: 11030: 89 0c 24 movl %ecx, (%esp) +// CHECK-NEXT: 11033: 8b 4c 24 04 movl 4(%esp), %ecx +// CHECK-NEXT: 11037: 89 44 24 04 movl %eax, 4(%esp) +// CHECK-NEXT: 1103b: 89 c8 movl %ecx, %eax +// CHECK-NEXT: 1103d: 59 popl %ecx +// CHECK-NEXT: 1103e: c3 retl +// CHECK-NEXT: 1103f: cc int3 +// CHECK-NEXT: 11040: 50 pushl %eax +// CHECK-NEXT: 11041: a1 0c 20 01 00 movl 73740, %eax +// CHECK-NEXT: 11046: e8 e5 ff ff ff calll -27 <.plt+0x20> +// CHECK-NEXT: 1104b: e9 d1 ff ff ff jmp -47 <.plt+0x11> +// CHECK-NEXT: 11050: 68 00 00 00 00 pushl $0 +// CHECK-NEXT: 11055: e9 b6 ff ff ff jmp -74 <.plt> +// CHECK-NEXT: 1105a: cc int3 +// CHECK-NEXT: 1105b: cc int3 +// CHECK-NEXT: 1105c: cc int3 +// CHECK-NEXT: 1105d: cc int3 +// CHECK-NEXT: 1105e: cc int3 +// CHECK-NEXT: 1105f: cc int3 +// CHECK-NEXT: 11060: 50 pushl %eax +// CHECK-NEXT: 11061: a1 10 20 01 00 movl 73744, %eax +// CHECK-NEXT: 11066: e8 c5 ff ff ff calll -59 <.plt+0x20> +// CHECK-NEXT: 1106b: e9 b1 ff ff ff jmp -79 <.plt+0x11> +// CHECK-NEXT: 11070: 68 08 00 00 00 pushl $8 +// CHECK-NEXT: 11075: e9 96 ff ff ff jmp -106 <.plt> +// CHECK-NEXT: 1107a: cc int3 +// CHECK-NEXT: 1107b: cc int3 +// CHECK-NEXT: 1107c: cc int3 +// CHECK-NEXT: 1107d: cc int3 +// CHECK-NEXT: 1107e: cc int3 +// CHECK-NEXT: 1107f: cc int3 + +// CHECK: Contents of section .got.plt: +// CHECK-NEXT: 00300100 00000000 00000000 50100100 +// CHECK-NEXT: 70100100 + +.global _start +_start: + jmp bar@PLT + jmp zed@PLT diff --git a/deps/lld/test/ELF/i386-retpoline-pic.s b/deps/lld/test/ELF/i386-retpoline-pic.s new file mode 100644 index 0000000000..3555950b16 --- /dev/null +++ b/deps/lld/test/ELF/i386-retpoline-pic.s @@ -0,0 +1,62 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux -position-independent %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux -position-independent %p/Inputs/shared.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so + +// RUN: ld.lld %t1.o %t2.so -o %t.exe -z retpolineplt -pie +// RUN: llvm-objdump -d -s %t.exe | FileCheck %s + +// CHECK: Disassembly of section .plt: +// CHECK-NEXT: .plt: +// CHECK-NEXT: 1010: ff b3 04 20 00 00 pushl 8196(%ebx) +// CHECK-NEXT: 1016: 50 pushl %eax +// CHECK-NEXT: 1017: 8b 83 08 20 00 00 movl 8200(%ebx), %eax +// CHECK-NEXT: 101d: e8 0e 00 00 00 calll 14 <.plt+0x20> +// CHECK-NEXT: 1022: f3 90 pause +// CHECK-NEXT: 1024: 0f ae e8 lfence +// CHECK-NEXT: 1027: eb f9 jmp -7 <.plt+0x12> +// CHECK-NEXT: 1029: cc int3 +// CHECK-NEXT: 102a: cc int3 +// CHECK-NEXT: 102b: cc int3 +// CHECK-NEXT: 102c: cc int3 +// CHECK-NEXT: 102d: cc int3 +// CHECK-NEXT: 102e: cc int3 +// CHECK-NEXT: 102f: cc int3 +// CHECK-NEXT: 1030: 89 0c 24 movl %ecx, (%esp) +// CHECK-NEXT: 1033: 8b 4c 24 04 movl 4(%esp), %ecx +// CHECK-NEXT: 1037: 89 44 24 04 movl %eax, 4(%esp) +// CHECK-NEXT: 103b: 89 c8 movl %ecx, %eax +// CHECK-NEXT: 103d: 59 popl %ecx +// CHECK-NEXT: 103e: c3 retl +// CHECK-NEXT: 103f: cc int3 +// CHECK-NEXT: 1040: 50 pushl %eax +// CHECK-NEXT: 1041: 8b 83 0c 20 00 00 movl 8204(%ebx), %eax +// CHECK-NEXT: 1047: e8 e4 ff ff ff calll -28 <.plt+0x20> +// CHECK-NEXT: 104c: e9 d1 ff ff ff jmp -47 <.plt+0x12> +// CHECK-NEXT: 1051: 68 00 00 00 00 pushl $0 +// CHECK-NEXT: 1056: e9 b5 ff ff ff jmp -75 <.plt> +// CHECK-NEXT: 105b: cc int3 +// CHECK-NEXT: 105c: cc int3 +// CHECK-NEXT: 105d: cc int3 +// CHECK-NEXT: 105e: cc int3 +// CHECK-NEXT: 105f: cc int3 +// CHECK-NEXT: 1060: 50 pushl %eax +// CHECK-NEXT: 1061: 8b 83 10 20 00 00 movl 8208(%ebx), %eax +// CHECK-NEXT: 1067: e8 c4 ff ff ff calll -60 <.plt+0x20> +// CHECK-NEXT: 106c: e9 b1 ff ff ff jmp -79 <.plt+0x12> +// CHECK-NEXT: 1071: 68 08 00 00 00 pushl $8 +// CHECK-NEXT: 1076: e9 95 ff ff ff jmp -107 <.plt> +// CHECK-NEXT: 107b: cc int3 +// CHECK-NEXT: 107c: cc int3 +// CHECK-NEXT: 107d: cc int3 +// CHECK-NEXT: 107e: cc int3 +// CHECK-NEXT: 107f: cc int3 + +// CHECK: Contents of section .got.plt: +// CHECK-NEXT: 2000 00300000 00000000 00000000 51100000 +// CHECK-NEXT: 2010 71100000 + +.global _start +_start: + jmp bar@PLT + jmp zed@PLT diff --git a/deps/lld/test/ELF/linkerscript/at-self-reference.s b/deps/lld/test/ELF/linkerscript/at-self-reference.s new file mode 100644 index 0000000000..7208a4b9fc --- /dev/null +++ b/deps/lld/test/ELF/linkerscript/at-self-reference.s @@ -0,0 +1,63 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "SECTIONS { \ +# RUN: . = 0x1000; \ +# RUN: .aaa : AT(ADDR(.aaa)) { *(.aaa) } \ +# RUN: .bbb : AT(ADDR(.bbb)) { *(.bbb) } \ +# RUN: }" > %t.script +# RUN: ld.lld %t --script %t.script -o %t2 +# RUN: llvm-readobj -program-headers %t2 | FileCheck %s + +# CHECK: ProgramHeaders [ +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: VirtualAddress: 0x1000 +# CHECK-NEXT: PhysicalAddress: 0x1000 +# CHECK-NEXT: FileSize: 3 +# CHECK-NEXT: MemSize: 3 +# CHECK-NEXT: Flags [ (0x5) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_X (0x1) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x1008 +# CHECK-NEXT: VirtualAddress: 0x1008 +# CHECK-NEXT: PhysicalAddress: 0x1008 +# CHECK-NEXT: FileSize: 9 +# CHECK-NEXT: MemSize: 9 +# CHECK-NEXT: Flags [ (0x5) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_X (0x1) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_GNU_STACK (0x6474E551) +# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: VirtualAddress: 0x0 +# CHECK-NEXT: PhysicalAddress: 0x0 +# CHECK-NEXT: FileSize: 0 +# CHECK-NEXT: MemSize: 0 +# CHECK-NEXT: Flags [ (0x6) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_W (0x2) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 0 +# CHECK-NEXT: } +# CHECK-NEXT:] + +.global _start +_start: + nop + + +.section .aaa, "a" +.asciz "aa" + +.section .bbb, "a" +.align 8 +.quad 0 diff --git a/deps/lld/test/ELF/linkerscript/at2.s b/deps/lld/test/ELF/linkerscript/at2.s new file mode 100644 index 0000000000..1545b1d826 --- /dev/null +++ b/deps/lld/test/ELF/linkerscript/at2.s @@ -0,0 +1,81 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "MEMORY { \ +# RUN: AX (ax) : ORIGIN = 0x2000, LENGTH = 0x100 \ +# RUN: AW (aw) : ORIGIN = 0x3000, LENGTH = 0x100 \ +# RUN: FLASH (ax) : ORIGIN = 0x6000, LENGTH = 0x100 \ +# RUN: RAM (aw) : ORIGIN = 0x7000, LENGTH = 0x100 } \ +# RUN: SECTIONS { \ +# RUN: .foo1 : { *(.foo1) } > AX AT>FLASH \ +# RUN: .foo2 : { *(.foo2) } > AX \ +# RUN: .bar1 : { *(.bar1) } > AW AT> RAM \ +# RUN: .bar2 : { *(.bar2) } > AW AT > RAM \ +# RUN: .bar3 : { *(.bar3) } > AW AT >RAM \ +# RUN: }" > %t.script +# RUN: ld.lld %t --script %t.script -o %t2 +# RUN: llvm-readobj -program-headers %t2 | FileCheck %s +# RUN: llvm-objdump -section-headers %t2 | FileCheck %s --check-prefix=SECTIONS + +# CHECK: ProgramHeaders [ +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: VirtualAddress: 0x2000 +# CHECK-NEXT: PhysicalAddress: 0x6000 +# CHECK-NEXT: FileSize: 16 +# CHECK-NEXT: MemSize: 16 +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: PF_X +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x2000 +# CHECK-NEXT: VirtualAddress: 0x3000 +# CHECK-NEXT: PhysicalAddress: 0x7000 +# CHECK-NEXT: FileSize: 24 +# CHECK-NEXT: MemSize: 24 +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: PF_W +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } + +# SECTIONS: Sections: +# SECTIONS-NEXT: Idx Name Size Address +# SECTIONS-NEXT: 0 00000000 0000000000000000 +# SECTIONS-NEXT: 1 .foo1 00000008 0000000000002000 +# SECTIONS-NEXT: 2 .foo2 00000008 0000000000002008 +# SECTIONS-NEXT: 3 .text 00000000 0000000000002010 +# SECTIONS-NEXT: 4 .bar1 00000008 0000000000003000 +# SECTIONS-NEXT: 5 .bar2 00000008 0000000000003008 +# SECTIONS-NEXT: 6 .bar3 00000008 0000000000003010 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "MEMORY { \ +# RUN: FLASH (ax) : ORIGIN = 0x2000, LENGTH = 0x100 \ +# RUN: RAM (aw) : ORIGIN = 0x5000, LENGTH = 0x100 } \ +# RUN: SECTIONS { \ +# RUN: .foo1 : AT(0x500) { *(.foo1) } > FLASH AT>FLASH \ +# RUN: }" > %t2.script +# RUN: not ld.lld %t --script %t2.script -o %t2 2>&1 | \ +# RUN: FileCheck %s --check-prefix=ERR +# ERR: error: section can't have both LMA and a load region + +.section .foo1, "ax" +.quad 0 + +.section .foo2, "ax" +.quad 0 + +.section .bar1, "aw" +.quad 0 + +.section .bar2, "aw" +.quad 0 + +.section .bar3, "aw" +.quad 0 diff --git a/deps/lld/test/ELF/linkerscript/at3.s b/deps/lld/test/ELF/linkerscript/at3.s new file mode 100644 index 0000000000..10bbfc6e96 --- /dev/null +++ b/deps/lld/test/ELF/linkerscript/at3.s @@ -0,0 +1,38 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "MEMORY { \ +# RUN: FOO (ax) : ORIGIN = 0x1000, LENGTH = 0x100 \ +# RUN: BAR (ax) : ORIGIN = 0x2000, LENGTH = 0x100 \ +# RUN: ZED (ax) : ORIGIN = 0x3000, LENGTH = 0x100 \ +# RUN: FLASH (ax) : ORIGIN = 0x6000, LENGTH = 0x200 \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .foo1 : { *(.foo1) } > FOO AT>FLASH \ +# RUN: .foo2 : { *(.foo2) BYTE(0x42) } > BAR AT>FLASH \ +# RUN: .foo3 : { *(.foo3) } > ZED AT>FLASH \ +# RUN: }" > %t.script +# RUN: ld.lld %t.o --script %t.script -o %t +# RUN: llvm-readelf -sections -program-headers %t | FileCheck %s + +# CHECK: .foo1 PROGBITS 0000000000001000 001000 +# CHECK: .foo2 PROGBITS 0000000000002000 002000 +# CHECK: .foo3 PROGBITS 0000000000003000 003000 + +# CHECK: Program Headers: +# CHECK-NOT: LOAD + +# CHECK: Type Offset VirtAddr PhysAddr +# CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000006000 +# CHECK-NEXT: LOAD 0x002000 0x0000000000002000 0x0000000000006008 +# CHECK-NEXT: LOAD 0x003000 0x0000000000003000 0x0000000000006011 + +# CHECK-NOT: LOAD + +.section .foo1, "a" +.quad 0 + +.section .foo2, "ax" +.quad 0 + +.section .foo3, "ax" +.quad 0 diff --git a/deps/lld/test/ELF/linkerscript/merge-header-load.s b/deps/lld/test/ELF/linkerscript/merge-header-load.s new file mode 100644 index 0000000000..5fb866abef --- /dev/null +++ b/deps/lld/test/ELF/linkerscript/merge-header-load.s @@ -0,0 +1,21 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "SECTIONS { \ +# RUN: . = 0xffffffff80000200; \ +# RUN: .text : AT (0x4200) { *(.text) } \ +# RUN: }" > %t.script +# RUN: ld.lld %t.o --script %t.script -o %t +# RUN: llvm-readelf -program-headers %t | FileCheck %s + +# Test that we put the header in the first PT_LOAD. We used to create a PT_LOAD +# just for it and it would have a different virtual to physical address delta. + +# CHECK: Program Headers: +# CHECK: Type Offset VirtAddr PhysAddr +# CHECK-NEXT: PHDR 0x000040 0xffffffff80000040 0x0000000000004040 +# CHECK-NEXT: LOAD 0x000000 0xffffffff80000000 0x0000000000004000 +# CHECK-NOT: LOAD + +.global _start +_start: +nop diff --git a/deps/lld/test/ELF/linkerscript/parse-section-in-addr.s b/deps/lld/test/ELF/linkerscript/parse-section-in-addr.s new file mode 100644 index 0000000000..7a79f64631 --- /dev/null +++ b/deps/lld/test/ELF/linkerscript/parse-section-in-addr.s @@ -0,0 +1,10 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o + +# RUN: echo "SECTIONS { \ +# RUN: .foo-bar : AT(ADDR(.foo-bar)) { *(.text) } \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t.so --script %t.script %t.o -shared +# RUN: llvm-readelf -S %t.so | FileCheck %s + +# CHECK: .foo-bar diff --git a/deps/lld/test/ELF/mips-gp-disp-ver.s b/deps/lld/test/ELF/mips-gp-disp-ver.s new file mode 100644 index 0000000000..134a056a36 --- /dev/null +++ b/deps/lld/test/ELF/mips-gp-disp-ver.s @@ -0,0 +1,15 @@ +# MIPS BFD linker puts _gp_disp symbol into DSO files and assigns zero +# version definition index to it. This value means 'unversioned local symbol' +# while _gp_disp is a section global symbol. We have to handle this bug +# in the LLD because BFD linker is used for building MIPS toolchain +# libraries. This test checks such handling. + +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o %S/Inputs/mips-gp-dips-corrupt-ver.so + +# REQUIRES: mips + + .global __start + .text +__start: + lw $t0, %got(foo)($gp) diff --git a/deps/lld/test/ELF/pie.s b/deps/lld/test/ELF/pie.s index 5964db5c93..3efd6e337c 100644 --- a/deps/lld/test/ELF/pie.s +++ b/deps/lld/test/ELF/pie.s @@ -48,7 +48,7 @@ # CHECK: Type: PT_DYNAMIC ## Check -nopie -# RUN: ld.lld -nopie %t1.o -o %t2 +# RUN: ld.lld -no-pie %t1.o -o %t2 # RUN: llvm-readobj -file-headers -r %t2 | FileCheck %s --check-prefix=NOPIE # NOPIE-NOT: Type: SharedObject diff --git a/deps/lld/test/ELF/x86-64-retpoline-znow.s b/deps/lld/test/ELF/x86-64-retpoline-znow.s new file mode 100644 index 0000000000..6464e2c097 --- /dev/null +++ b/deps/lld/test/ELF/x86-64-retpoline-znow.s @@ -0,0 +1,53 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so + +// RUN: ld.lld -shared %t1.o %t2.so -o %t.exe -z retpolineplt -z now +// RUN: llvm-objdump -d -s %t.exe | FileCheck %s + +// CHECK: Disassembly of section .plt: +// CHECK-NEXT: .plt: +// CHECK-NEXT: 1010: e8 0b 00 00 00 callq 11 <.plt+0x10> +// CHECK-NEXT: 1015: f3 90 pause +// CHECK-NEXT: 1017: 0f ae e8 lfence +// CHECK-NEXT: 101a: eb f9 jmp -7 <.plt+0x5> +// CHECK-NEXT: 101c: cc int3 +// CHECK-NEXT: 101d: cc int3 +// CHECK-NEXT: 101e: cc int3 +// CHECK-NEXT: 101f: cc int3 +// CHECK-NEXT: 1020: 4c 89 1c 24 movq %r11, (%rsp) +// CHECK-NEXT: 1024: c3 retq +// CHECK-NEXT: 1025: cc int3 +// CHECK-NEXT: 1026: cc int3 +// CHECK-NEXT: 1027: cc int3 +// CHECK-NEXT: 1028: cc int3 +// CHECK-NEXT: 1029: cc int3 +// CHECK-NEXT: 102a: cc int3 +// CHECK-NEXT: 102b: cc int3 +// CHECK-NEXT: 102c: cc int3 +// CHECK-NEXT: 102d: cc int3 +// CHECK-NEXT: 102e: cc int3 +// CHECK-NEXT: 102f: cc int3 +// CHECK-NEXT: 1030: 4c 8b 1d c1 10 00 00 movq 4289(%rip), %r11 +// CHECK-NEXT: 1037: e9 d4 ff ff ff jmp -44 <.plt> +// CHECK-NEXT: 103c: cc int3 +// CHECK-NEXT: 103d: cc int3 +// CHECK-NEXT: 103e: cc int3 +// CHECK-NEXT: 103f: cc int3 +// CHECK-NEXT: 1040: 4c 8b 1d b9 10 00 00 movq 4281(%rip), %r11 +// CHECK-NEXT: 1047: e9 c4 ff ff ff jmp -60 <.plt> +// CHECK-NEXT: 104c: cc int3 +// CHECK-NEXT: 104d: cc int3 +// CHECK-NEXT: 104e: cc int3 +// CHECK-NEXT: 104f: cc int3 + +// CHECK: Contents of section .got.plt: +// CHECK-NEXT: 20e0 00200000 00000000 00000000 00000000 +// CHECK-NEXT: 20f0 00000000 00000000 00000000 00000000 +// CHECK-NEXT: 2100 00000000 00000000 + +.global _start +_start: + jmp bar@PLT + jmp zed@PLT diff --git a/deps/lld/test/ELF/x86-64-retpoline.s b/deps/lld/test/ELF/x86-64-retpoline.s new file mode 100644 index 0000000000..535f565331 --- /dev/null +++ b/deps/lld/test/ELF/x86-64-retpoline.s @@ -0,0 +1,66 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so + +// RUN: ld.lld -shared %t1.o %t2.so -o %t.exe -z retpolineplt +// RUN: llvm-objdump -d -s %t.exe | FileCheck %s + +// CHECK: Disassembly of section .plt: +// CHECK-NEXT: .plt: +// CHECK-NEXT: 1010: ff 35 f2 0f 00 00 pushq 4082(%rip) +// CHECK-NEXT: 1016: 4c 8b 1d f3 0f 00 00 movq 4083(%rip), %r11 +// CHECK-NEXT: 101d: e8 0e 00 00 00 callq 14 <.plt+0x20> +// CHECK-NEXT: 1022: f3 90 pause +// CHECK-NEXT: 1024: 0f ae e8 lfence +// CHECK-NEXT: 1027: eb f9 jmp -7 <.plt+0x12> +// CHECK-NEXT: 1029: cc int3 +// CHECK-NEXT: 102a: cc int3 +// CHECK-NEXT: 102b: cc int3 +// CHECK-NEXT: 102c: cc int3 +// CHECK-NEXT: 102d: cc int3 +// CHECK-NEXT: 102e: cc int3 +// CHECK-NEXT: 102f: cc int3 +// CHECK-NEXT: 1030: 4c 89 1c 24 movq %r11, (%rsp) +// CHECK-NEXT: 1034: c3 retq +// CHECK-NEXT: 1035: cc int3 +// CHECK-NEXT: 1036: cc int3 +// CHECK-NEXT: 1037: cc int3 +// CHECK-NEXT: 1038: cc int3 +// CHECK-NEXT: 1039: cc int3 +// CHECK-NEXT: 103a: cc int3 +// CHECK-NEXT: 103b: cc int3 +// CHECK-NEXT: 103c: cc int3 +// CHECK-NEXT: 103d: cc int3 +// CHECK-NEXT: 103e: cc int3 +// CHECK-NEXT: 103f: cc int3 +// CHECK-NEXT: 1040: 4c 8b 1d d1 0f 00 00 movq 4049(%rip), %r11 +// CHECK-NEXT: 1047: e8 e4 ff ff ff callq -28 <.plt+0x20> +// CHECK-NEXT: 104c: e9 d1 ff ff ff jmp -47 <.plt+0x12> +// CHECK-NEXT: 1051: 68 00 00 00 00 pushq $0 +// CHECK-NEXT: 1056: e9 b5 ff ff ff jmp -75 <.plt> +// CHECK-NEXT: 105b: cc int3 +// CHECK-NEXT: 105c: cc int3 +// CHECK-NEXT: 105d: cc int3 +// CHECK-NEXT: 105e: cc int3 +// CHECK-NEXT: 105f: cc int3 +// CHECK-NEXT: 1060: 4c 8b 1d b9 0f 00 00 movq 4025(%rip), %r11 +// CHECK-NEXT: 1067: e8 c4 ff ff ff callq -60 <.plt+0x20> +// CHECK-NEXT: 106c: e9 b1 ff ff ff jmp -79 <.plt+0x12> +// CHECK-NEXT: 1071: 68 01 00 00 00 pushq $1 +// CHECK-NEXT: 1076: e9 95 ff ff ff jmp -107 <.plt> +// CHECK-NEXT: 107b: cc int3 +// CHECK-NEXT: 107c: cc int3 +// CHECK-NEXT: 107d: cc int3 +// CHECK-NEXT: 107e: cc int3 +// CHECK-NEXT: 107f: cc int3 + +// CHECK: Contents of section .got.plt: +// CHECK-NEXT: 2000 00300000 00000000 00000000 00000000 +// CHECK-NEXT: 2010 00000000 00000000 51100000 00000000 +// CHECK-NEXT: 2020 71100000 00000000 + +.global _start +_start: + jmp bar@PLT + jmp zed@PLT -- cgit v1.2.3