Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -42,14 +42,18 @@ }; // This enum represents what we can observe in SECTIONS tag of script: -// Expr is a location counter change, like ". = . + 0x1000" -// Section is a description of output section, like ".data :..." -enum class Command { Expr, Section }; +// * Expr is a location counter change, like ". = . + 0x1000" +// * Section is a description of output section, like ".data :..." +// * Content is a content of output section, it helps to distinguish PROVIDE +// command before and after section content, first one should have address +// equal to address of output section, second points to location after that. +// * Provide is PROVIDE command. +enum class Command { Expr, Section, Content, Provide }; struct LocationNode { Command Type; std::vector Expr; - StringRef SectionName; + StringRef Name; }; // This is a runner of the linker script. @@ -68,6 +72,7 @@ template void assignAddresses(std::vector *> &S); int compareSections(StringRef A, StringRef B); + std::vector getProvides(); bool DoLayout = false; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -103,8 +103,10 @@ for (OutputSectionBase *Sec : S) { StringRef Name = Sec->getName(); auto I = std::find(SectionOrder.begin(), SectionOrder.end(), Name); - if (I == SectionOrder.end()) + if (I == SectionOrder.end()) { Locations.push_back({Command::Section, {}, {Name}}); + Locations.push_back({Command::Content, {}, {Name}}); + } } } @@ -123,10 +125,18 @@ VA = evaluate(Node.Expr, VA); continue; } + if (Node.Type == Command::Provide) { + auto I = ElfSym::Provide.find(Node.Name); + if (I != ElfSym::Provide.end()) + I->second->Value = evaluate(Node.Expr, VA); + continue; + } + if (Node.Type != Command::Content) + continue; auto I = std::find_if(S.begin(), S.end(), [&](OutputSectionBase *Sec) { - return Sec->getName() == Node.SectionName; + return Sec->getName() == Node.Name; }); if (I == S.end()) continue; @@ -157,6 +167,14 @@ return I->second; } +std::vector LinkerScript::getProvides() { + std::vector Provides; + for (LocationNode &Node : Locations) + if (Node.Type == Command::Provide) + Provides.push_back(Node.Name); + return Provides; +} + // A compartor to sort output sections. Returns -1 or 1 if both // A and B are mentioned in linker scripts. Otherwise, returns 0 // to use the default rule which is implemented in Writer.cpp. @@ -222,6 +240,7 @@ void readSections(); void readLocationCounterValue(); + void readProvide(); void readOutputSectionDescription(); void readSectionPatterns(StringRef OutSec, bool Keep); @@ -386,6 +405,12 @@ expect("{"); while (!Error && !skip("}")) { StringRef Tok = peek(); + if (Tok == "PROVIDE") { + next(); + readProvide(); + continue; + } + if (Tok == ".") readLocationCounterValue(); else @@ -395,6 +420,7 @@ void ScriptParser::readSectionPatterns(StringRef OutSec, bool Keep) { expect("("); + Script->Locations.push_back({Command::Content, {}, {OutSec}}); while (!Error && !skip(")")) Script->Sections.emplace_back(OutSec, next(), Keep); } @@ -414,6 +440,22 @@ error("error in location counter expression"); } +void ScriptParser::readProvide() { + expect("("); + Script->Locations.push_back({Command::Provide, {}, {}}); + LocationNode &Node = Script->Locations.back(); + Node.Name = next(); + + expect("="); + while (!Error) { + StringRef Tok = next(); + if (Tok == ")") + break; + Node.Expr.push_back(Tok); + } + expect(";"); +} + void ScriptParser::readOutputSectionDescription() { StringRef OutSec = next(); Script->SectionOrder.push_back(OutSec); @@ -422,7 +464,9 @@ expect("{"); while (!Error && !skip("}")) { StringRef Tok = next(); - if (Tok == "*") { + if (Tok == "PROVIDE") { + readProvide(); + } else if (Tok == "*") { readSectionPatterns(OutSec, false); } else if (Tok == "KEEP") { expect("("); Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -411,6 +411,9 @@ // where R_[*]_IRELATIVE relocations do live. static SymbolBody *RelaIpltStart; static SymbolBody *RelaIpltEnd; + + // Used to implement linkescript PROVIDE command. + static llvm::StringMap *> Provide; }; template typename ElfSym::SymPair ElfSym::Etext; @@ -422,6 +425,8 @@ template SymbolBody *ElfSym::MipsGpDisp; template SymbolBody *ElfSym::RelaIpltStart; template SymbolBody *ElfSym::RelaIpltEnd; +template +llvm::StringMap *> ElfSym::Provide; } // namespace elf } // namespace lld Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1119,6 +1119,12 @@ Define("_end", ElfSym::End); Define("_etext", ElfSym::Etext); Define("_edata", ElfSym::Edata); + + std::vector Provides = Script->getProvides(); + for (StringRef S : Provides) + if (SymbolBody *B = Symtab.find(S)) + if (B->isUndefined()) + ElfSym::Provide[S] = Symtab.addAbsolute(S, STV_DEFAULT); } // Sort input sections by section name suffixes for Index: test/ELF/linkerscript-provide.s =================================================================== --- test/ELF/linkerscript-provide.s +++ test/ELF/linkerscript-provide.s @@ -0,0 +1,69 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "SECTIONS \ +# RUN: { \ +# RUN: PROVIDE (beginText = .); \ +# RUN: .text : \ +# RUN: { \ +# RUN: *(.text) \ +# RUN: } \ +# RUN: PROVIDE (unused = .); \ +# RUN: PROVIDE (endText = . + 0x50000); \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t2 --script %t.script %t +# RUN: llvm-readobj -sections -symbols %t2 | FileCheck %s + +# CHECK: Sections [ +# CHECK: Section { +# CHECK: Name: .text +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_EXECINSTR +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x[[ADDR:.*]] +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 10 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 4 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK: Symbols [ +# CHECK: Symbol { +# CHECK: Name: beginText +# CHECK-NEXT: Value: 0x[[ADDR]] +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Absolute +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: endText +# CHECK-NEXT: Value: 0x5012A +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Absolute +# CHECK-NEXT: } +# CHECK-NEXT: ] + +## Check case with PROVIDE inside section description. +# RUN: echo "SECTIONS \ +# RUN: { \ +# RUN: .text : \ +# RUN: { \ +# RUN: PROVIDE (beginText = .); \ +# RUN: *(.text) \ +# RUN: PROVIDE (endText = . + 0x50000); \ +# RUN: } \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t2 --script %t.script %t +# RUN: llvm-readobj -sections -symbols %t2 | FileCheck %s + +.globl _start +_start: + call beginText + call endText