Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -26,6 +26,7 @@ class ScriptParser; template class InputSectionBase; template class OutputSectionBase; +template class SymbolTable; // This class represents each rule in SECTIONS command. class SectionRule { @@ -46,14 +47,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; }; // ScriptConfiguration holds linker script parse results. @@ -83,6 +88,8 @@ bool shouldKeep(InputSectionBase *S); void assignAddresses(ArrayRef *> S); int compareSections(StringRef A, StringRef B); + void createSymbols(SymbolTable &Symtab, + ArrayRef *> Sections); private: uint32_t getSectionOrder(StringRef Name); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -204,8 +204,10 @@ // https://sourceware.org/binutils/docs/ld/Orphan-Sections.html#Orphan-Sections. for (OutputSectionBase *Sec : Sections) { StringRef Name = Sec->getName(); - if (getSectionOrder(Name) == (uint32_t)-1) + if (getSectionOrder(Name) == (uint32_t)-1) { Opt.Commands.push_back({SectionKind, {}, Name}); + Opt.Commands.push_back({ContentKind, {}, Name}); + } } // Assign addresses as instructed by linker script SECTIONS sub-commands. @@ -218,8 +220,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; @@ -249,11 +253,45 @@ } template +void LinkerScript::createSymbols( + SymbolTable &Symtab, ArrayRef *> Sections) { + typedef typename ELFT::uint uintX_t; + if (!Opt.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 : Opt.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); + } +} + +template uint32_t LinkerScript::getSectionOrder(StringRef Name) { auto Begin = Opt.Commands.begin(); auto End = Opt.Commands.end(); auto I = std::find_if(Begin, End, [&](SectionsCommand &N) { - return N.Kind == SectionKind && N.SectionName == Name; + return N.Kind == SectionKind && N.Name == Name; }); return I == End ? (uint32_t)-1 : (I - Begin); } @@ -321,6 +359,7 @@ void readSections(); void readLocationCounterValue(); + void readProvide(); void readOutputSectionDescription(); void readSectionPatterns(StringRef OutSec, bool Keep); @@ -486,6 +525,9 @@ expect("{"); while (!Error && !skip("}")) { StringRef Tok = peek(); + if (Tok == "PROVIDE") + setError("PROVIDE outside section declaration not allowed"); + if (Tok == ".") readLocationCounterValue(); else @@ -495,6 +537,7 @@ void ScriptParser::readSectionPatterns(StringRef OutSec, bool Keep) { expect("("); + Opt.Commands.push_back({ContentKind, {}, OutSec}); while (!Error && !skip(")")) Opt.Sections.emplace_back(OutSec, next(), Keep); } @@ -514,6 +557,27 @@ error("error in location counter expression"); } +void ScriptParser::readProvide() { + expect("("); + Opt.Commands.push_back({ProvideKind, {}, ""}); + SectionsCommand &Cmd = Opt.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(); Opt.Commands.push_back({SectionKind, {}, OutSec}); @@ -521,7 +585,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/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1239,6 +1239,8 @@ // Define __rel[a]_iplt_{start,end} symbols if needed. addRelIpltSymbols(); + Script::X->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