Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -22,6 +22,7 @@ class ScriptParser; template class InputSectionBase; template class OutputSectionBase; +template class SymbolTable; // This class represents each rule in SECTIONS command. class SectionRule { @@ -42,14 +43,18 @@ }; // This enum represents what we can observe in SECTIONS tag of script: -// ExprKind is a location counter change, like ". = . + 0x1000" -// SectionKind is a description of output section, like ".data :..." -enum SectionsCommandKind { ExprKind, SectionKind }; +// * ExprKind is a location counter change, like ". = . + 0x1000" +// * SectionKind is a description of output section, like ".data :..." +// * ContentKind 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. +// * ProvideKind is PROVIDE command. +enum SectionsCommandKind { ExprKind, SectionKind, ContentKind, ProvideKind }; struct SectionsCommand { SectionsCommandKind Kind; std::vector Expr; - StringRef SectionName; + StringRef Name; }; // This is a runner of the linker script. @@ -68,6 +73,7 @@ template void assignAddresses(std::vector *> &S); int compareSections(StringRef A, StringRef B); + template void createSymbols(SymbolTable &Symtab); bool DoLayout = false; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -112,8 +112,10 @@ for (OutputSectionBase *Sec : Sections) { StringRef Name = Sec->getName(); auto I = std::find(SectionOrder.begin(), SectionOrder.end(), Name); - if (I == SectionOrder.end()) + if (I == SectionOrder.end()) { Commands.push_back({SectionKind, {}, Name}); + Commands.push_back({ContentKind, {}, Name}); + } } // Assign addresses as instructed by linker script SECTIONS sub-commands. @@ -126,8 +128,16 @@ VA = evaluate(Cmd.Expr, VA); continue; } + if (Cmd.Kind == ProvideKind) { + auto I = ElfSym::Provide.find(Cmd.Name); + if (I != ElfSym::Provide.end()) + I->second->Value = evaluate(Cmd.Expr, VA); + continue; + } + if (Cmd.Kind != ContentKind) + continue; - OutputSectionBase *Sec = findSection(Sections, Cmd.SectionName); + OutputSectionBase *Sec = findSection(Sections, Cmd.Name); if (!Sec) continue; @@ -155,6 +165,21 @@ return I->second; } +template +void LinkerScript::createSymbols(SymbolTable &Symtab) { + if (!Script->DoLayout) + return; + + for (SectionsCommand &Cmd : Commands) { + if (Cmd.Kind != ProvideKind) + continue; + StringRef Name = Cmd.Name; + if (SymbolBody *S = Symtab.find(Name)) + if (S->isUndefined()) + ElfSym::Provide[Name] = Symtab.addAbsolute(Name, STV_DEFAULT); + } +} + // 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. @@ -220,6 +245,7 @@ void readSections(); void readLocationCounterValue(); + void readProvide(); void readOutputSectionDescription(); void readSectionPatterns(StringRef OutSec, bool Keep); @@ -384,6 +410,12 @@ expect("{"); while (!Error && !skip("}")) { StringRef Tok = peek(); + if (Tok == "PROVIDE") { + next(); + readProvide(); + continue; + } + if (Tok == ".") readLocationCounterValue(); else @@ -393,6 +425,7 @@ void ScriptParser::readSectionPatterns(StringRef OutSec, bool Keep) { expect("("); + Script->Commands.push_back({ContentKind, {}, OutSec}); while (!Error && !skip(")")) Script->Sections.emplace_back(OutSec, next(), Keep); } @@ -412,6 +445,22 @@ error("error in location counter expression"); } +void ScriptParser::readProvide() { + expect("("); + Script->Commands.push_back({ProvideKind, {}, ""}); + SectionsCommand &Cmd = Script->Commands.back(); + Cmd.Name = next(); + + expect("="); + while (!Error) { + StringRef Tok = next(); + if (Tok == ")") + break; + Cmd.Expr.push_back(Tok); + } + expect(";"); +} + void ScriptParser::readOutputSectionDescription() { StringRef OutSec = next(); Script->SectionOrder.push_back(OutSec); @@ -420,7 +469,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("("); @@ -481,3 +532,8 @@ LinkerScript::assignAddresses(std::vector *> &); template void LinkerScript::assignAddresses(std::vector *> &); + +template void LinkerScript::createSymbols(SymbolTable &); +template void LinkerScript::createSymbols(SymbolTable &); +template void LinkerScript::createSymbols(SymbolTable &); +template void LinkerScript::createSymbols(SymbolTable &); 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 @@ -1122,6 +1122,8 @@ Define("_end", ElfSym::End); Define("_etext", ElfSym::Etext); Define("_edata", ElfSym::Edata); + + Script->createSymbols(Symtab); } // 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