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,9 @@ template void assignAddresses(std::vector *> &S); int compareSections(StringRef A, StringRef B); + template + void createSymbols(SymbolTable &Symtab, + ArrayRef *> Sections); bool DoLayout = false; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -172,7 +172,7 @@ template static OutputSectionBase * -findSection(std::vector *> &V, StringRef Name) { +findSection(ArrayRef *> V, StringRef Name) { for (OutputSectionBase *Sec : V) if (Sec->getName() == Name) return Sec; @@ -192,8 +192,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. @@ -206,8 +208,10 @@ VA = 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; @@ -235,6 +239,40 @@ return I->second; } +template +void LinkerScript::createSymbols(SymbolTable &Symtab, + ArrayRef *> Sections) { + typedef typename ELFT::uint uintX_t; + if (!Script->DoLayout) + return; + + // Currently we support only PROVIDE keywords inside + // output sections descriptions that are used to mark + // begin and end of the section. + StringRef SecName; + uintX_t Val; + for (SectionsCommand &Cmd : Commands) { + if (Cmd.Kind == SectionKind) { + SecName = Cmd.Name; + Val = 0; + } else if (Cmd.Kind == ContentKind) { + Val = DefinedSynthetic::SectionEnd; + } + + if (Cmd.Kind != ProvideKind) + continue; + + OutputSectionBase *Sec = findSection(Sections, SecName); + if (!Sec) + continue; + + StringRef SymName = Cmd.Name; + if (SymbolBody *S = Symtab.find(SymName)) + if (S->isUndefined()) + Symtab.addSynthetic(SymName, *Sec, Val); + } +} + // 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. @@ -300,6 +338,7 @@ void readSections(); void readLocationCounterValue(); + void readProvide(); void readOutputSectionDescription(); void readSectionPatterns(StringRef OutSec, bool Keep); @@ -464,6 +503,9 @@ expect("{"); while (!Error && !skip("}")) { StringRef Tok = peek(); + if (Tok == "PROVIDE") + setError("PROVIDE outside section declaration not allowed"); + if (Tok == ".") readLocationCounterValue(); else @@ -473,6 +515,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); } @@ -492,6 +535,27 @@ 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(";"); + + if (Cmd.Expr.empty()) + error("empty provide expression"); + else if (Cmd.Expr[0] != "." || Cmd.Expr.size() > 1) + error("PROVIDE does not support expressions"); +} + void ScriptParser::readOutputSectionDescription() { StringRef OutSec = next(); Script->SectionOrder.push_back(OutSec); @@ -500,7 +564,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("("); @@ -561,3 +627,16 @@ LinkerScript::assignAddresses(std::vector *> &); template void LinkerScript::assignAddresses(std::vector *> &); + +template void +LinkerScript::createSymbols(SymbolTable &, + ArrayRef *> Sections); +template void +LinkerScript::createSymbols(SymbolTable &, + ArrayRef *> Sections); +template void +LinkerScript::createSymbols(SymbolTable &, + ArrayRef *> Sections); +template void +LinkerScript::createSymbols(SymbolTable &, + ArrayRef *> Sections); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1215,6 +1215,8 @@ // Define __rel[a]_iplt_{start,end} symbols if needed. addRelIpltSymbols(); + Script->createSymbols(Symtab, OutputSections); + if (Out::EhFrameHdr->Sec) Out::EhFrameHdr->Sec->finalize(); Index: test/ELF/linkerscript-provide.s =================================================================== --- test/ELF/linkerscript-provide.s +++ test/ELF/linkerscript-provide.s @@ -0,0 +1,96 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +## We do not support PROVIDE keyword outside +## of output section declarations. +# RUN: echo "SECTIONS \ +# RUN: { \ +# RUN: PROVIDE (beginText = .); \ +# RUN: .text : \ +# RUN: { \ +# RUN: *(.text) \ +# RUN: } \ +# RUN: }" > %t.script +# RUN: not ld.lld -o %t2 --script %t.script %t 2>&1 | FileCheck -check-prefix=ERR1 %s +# ERR1: PROVIDE outside section declaration not allowed + +## We do not support PROVIDE keyword that +## contains anything except assign of location counter. +# RUN: echo "SECTIONS \ +# RUN: { \ +# RUN: .text : \ +# RUN: { \ +# RUN: PROVIDE (beginText = . + 0x0); \ +# RUN: *(.text) \ +# RUN: } \ +# RUN: }" > %t.script +# RUN: not ld.lld -o %t2 --script %t.script %t 2>&1 | FileCheck -check-prefix=ERR2 %s +# ERR2: PROVIDE does not support expressions + +## Empty expression is a error. +# RUN: echo "SECTIONS \ +# RUN: { \ +# RUN: .text : \ +# RUN: { \ +# RUN: PROVIDE (beginText = ); \ +# RUN: *(.text) \ +# RUN: } \ +# RUN: }" > %t.script +# RUN: not ld.lld -o %t2 --script %t.script %t 2>&1 | FileCheck -check-prefix=ERR3 %s +# ERR3: empty provide expression + +## Check case with PROVIDE inside section description. +# RUN: echo "SECTIONS \ +# RUN: { \ +# RUN: .text : \ +# RUN: { \ +# RUN: PROVIDE (beginText = .); \ +# RUN: *(.text) \ +# RUN: PROVIDE (endText = .); \ +# RUN: } \ +# 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: Symbol { +# CHECK: Name: beginText +# CHECK-NEXT: Value: 0x[[ADDR]] +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other [ +# CHECK-NEXT: STV_HIDDEN +# CHECK-NEXT: ] +# CHECK-NEXT: Section: .text +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: endText +# CHECK-NEXT: Value: 0x12A +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other [ +# CHECK-NEXT: STV_HIDDEN +# CHECK-NEXT: ] +# CHECK-NEXT: Section: .text +# CHECK-NEXT: } + +.globl _start +_start: + call beginText + call endText