Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -1029,6 +1029,9 @@ for (StringRef Sym : Script->ReferencedSymbols) Symtab->addUndefined(Sym); + // We want to define linker script's symbols early, so that can version them. + Script->defineSymbols(); + // Handle the `--undefined ` options. for (StringRef S : Config->Undefined) Symtab->fetchIfLazy(S); Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -84,7 +84,7 @@ int Kind; }; -// This represents ". = " or " = ". +// This represents ". = " or " = " or -defsym=. struct SymbolAssignment : BaseCommand { SymbolAssignment(StringRef Name, Expr E, std::string Loc) : BaseCommand(AssignmentKind), Name(Name), Expression(E), Location(Loc) {} @@ -104,6 +104,9 @@ bool Provide = false; bool Hidden = false; + // Flag shows if this command is -defsym assignment. + bool IsDefsym = false; + // Holds file name and line number for error reporting. std::string Location; }; @@ -207,6 +210,7 @@ llvm::DenseMap NameToOutputSection; void addSymbol(SymbolAssignment *Cmd); + void doAssignment(SymbolAssignment *Cmd); void assignSymbol(SymbolAssignment *Cmd, bool InSec); void setDot(Expr E, const Twine &Loc, bool InSec); @@ -263,6 +267,8 @@ void allocateHeaders(std::vector &Phdrs); void processSectionCommands(); + void defineSymbols(); + // SECTIONS command list. std::vector SectionCommands; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -117,15 +117,6 @@ // 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; @@ -153,6 +144,49 @@ Cmd->Sym = cast(Sym); } +// Used for handling linker symbol assignments, for both finalizing +// their values and doing early definitions. +void LinkerScript::doAssignment(SymbolAssignment *Cmd) { + if (Cmd->Name == ".") + return; + + if (!Cmd->Provide) { + addSymbol(Cmd); + 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 (!B || B->isDefined()) + return; + Cmd->Provide = false; + addSymbol(Cmd); +} + +// Symbols defined in script should not be inlined by LTO. At the same time +// we don't know their final values until late stages of link. Here we scan +// over symbol assignment commands, create dummy symbols if needed and and set +// appropriate flag. +void LinkerScript::defineSymbols() { + assert(!Ctx); + for (BaseCommand *Base : SectionCommands) { + if (auto *Cmd = dyn_cast(Base)) { + if (Cmd->IsDefsym) + continue; + + // We can't calculate final value right now, so do not want to use + // underlying expression and temporarily swap it with dummy one. + Expr Prev = Cmd->Expression; + Cmd->Expression = [] { return ExprValue(0); }; + doAssignment(Cmd); + if (Cmd->Sym) + Cmd->Sym->CanInline = false; + Cmd->Expression = Prev; + } + } +} + // 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. @@ -364,7 +398,7 @@ for (BaseCommand *Base : SectionCommands) { // Handle symbol assignments outside of any output section. if (auto *Cmd = dyn_cast(Base)) { - addSymbol(Cmd); + doAssignment(Cmd); continue; } @@ -396,7 +430,7 @@ // ".foo : { ...; bar = .; }". Handle them. for (BaseCommand *Base : Sec->SectionCommands) if (auto *OutCmd = dyn_cast(Base)) - addSymbol(OutCmd); + doAssignment(OutCmd); // Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign // is given, input sections are aligned to that value, whether the Index: ELF/ScriptParser.cpp =================================================================== --- ELF/ScriptParser.cpp +++ ELF/ScriptParser.cpp @@ -275,6 +275,7 @@ if (!atEOF()) setError("EOF expected, but got " + next()); SymbolAssignment *Cmd = make(Name, E, getCurrentLocation()); + Cmd->IsDefsym = true; Script->SectionCommands.push_back(Cmd); } Index: test/ELF/linkerscript/symbols-synthetic.s =================================================================== --- test/ELF/linkerscript/symbols-synthetic.s +++ test/ELF/linkerscript/symbols-synthetic.s @@ -61,6 +61,7 @@ # SIMPLE-NEXT: 0000000000000120 .foo 00000000 _begin_sec # SIMPLE-NEXT: 0000000000000128 *ABS* 00000000 _end_sec_abs # SIMPLE-NEXT: 0000000000001048 .text 00000000 _start +# SIMPLE-NEXT: 0000000000000ee4 *ABS* 00000000 size_foo_3 # SIMPLE-NEXT: 0000000000000120 .foo 00000000 begin_foo # SIMPLE-NEXT: 0000000000000128 .foo 00000000 end_foo # SIMPLE-NEXT: 0000000000000008 *ABS* 00000000 size_foo_1 @@ -68,7 +69,6 @@ # SIMPLE-NEXT: 0000000000001000 .foo 00000000 begin_bar # SIMPLE-NEXT: 0000000000001004 .foo 00000000 end_bar # SIMPLE-NEXT: 0000000000000ee4 *ABS* 00000000 size_foo_2 -# SIMPLE-NEXT: 0000000000000ee4 *ABS* 00000000 size_foo_3 # SIMPLE-NEXT: 0000000000001004 .eh_frame_hdr 00000000 __eh_frame_hdr_start # SIMPLE-NEXT: 0000000000001010 *ABS* 00000000 __eh_frame_hdr_start2 # SIMPLE-NEXT: 0000000000001018 .eh_frame_hdr 00000000 __eh_frame_hdr_end Index: test/ELF/linkerscript/version-script.s =================================================================== --- test/ELF/linkerscript/version-script.s +++ test/ELF/linkerscript/version-script.s @@ -0,0 +1,38 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o + +# RUN: echo "bar = foo; VERSION { V { global: foo; bar; local: *; }; }" > %t.script +# RUN: ld.lld -T %t.script -shared --no-undefined-version %t.o -o %t.so +# RUN: llvm-readobj -V %t.so | FileCheck %s + +## Check that we are able to version symbols defined in script. +# CHECK: Symbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 0 +# CHECK-NEXT: Name: @ +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 0 +# CHECK-NEXT: Name: und@ +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 2 +# CHECK-NEXT: Name: foo@@V +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 2 +# CHECK-NEXT: Name: bar@@V +# CHECK-NEXT: } +# CHECK-NEXT: ] + +# RUN: echo "bar = und; VERSION { V { global: foo; bar; local: *; }; }" > %t.script +# RUN: not ld.lld -T %t.script -shared --no-undefined-version %t.o -o %t.so \ +# RUN: 2>&1 | FileCheck --check-prefix=ERR %s +# ERR: symbol not found: und + +.global und + +.text +.globl foo +.type foo,@function +foo: Index: test/ELF/lto/linker-script-symbols-assign.ll =================================================================== --- test/ELF/lto/linker-script-symbols-assign.ll +++ test/ELF/lto/linker-script-symbols-assign.ll @@ -6,16 +6,7 @@ ; RUN: llvm-readobj -symbols %t2.lto.o | FileCheck %s ; CHECK-NOT: bar -; CHECK: Symbol { -; CHECK: Name: foo -; CHECK-NEXT: Value: 0x0 -; CHECK-NEXT: Size: 4 -; CHECK-NEXT: Binding: Weak -; CHECK-NEXT: Type: Object -; CHECK-NEXT: Other: 0 -; CHECK-NEXT: Section: .bss.foo -; CHECK-NEXT: } -; CHECK-NEXT:] +; CHECK-NOT: foo ; RUN: llvm-readobj -symbols %t2 | FileCheck %s --check-prefix=VAL ; VAL: Symbol { Index: test/ELF/lto/linker-script-symbols-ipo.ll =================================================================== --- test/ELF/lto/linker-script-symbols-ipo.ll +++ test/ELF/lto/linker-script-symbols-ipo.ll @@ -16,9 +16,9 @@ ; RUN: llvm-objdump -d %t4 | FileCheck %s --check-prefix=NOIPO ; NOIPO: Disassembly of section .text: ; NOIPO: foo: -; NOIPO-NEXT: 201010: {{.*}} movl $2, %eax +; NOIPO-NEXT: 201000: {{.*}} movl $2, %eax ; NOIPO: _start: -; NOIPO-NEXT: 201020: {{.*}} jmp -21 +; NOIPO-NEXT: 201010: {{.*}} jmp -21 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu"