Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -1068,6 +1068,11 @@ for (StringRef Sym : Script->ReferencedSymbols) Symtab->addUndefined(Sym); + // We want to define symbols assigned by linker script early, + // so we can version them and change attributes before normal + // script commands processing where their values are finalized. + Script->defineSymbols(); + // Handle the `--undefined ` options. for (StringRef S : Config->Undefined) Symtab->fetchIfLazy(S); Index: ELF/LTO.cpp =================================================================== --- ELF/LTO.cpp +++ ELF/LTO.cpp @@ -129,11 +129,6 @@ std::vector Syms = F.getSymbols(); std::vector Resols(Syms.size()); - DenseSet ScriptSymbols; - for (BaseCommand *Base : Script->SectionCommands) - if (auto *Cmd = dyn_cast(Base)) - ScriptSymbols.insert(Cmd->Name); - // Provide a resolution to the LTO API for each symbol. for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) { SymbolBody *Sym = Syms[SymNum]; @@ -164,7 +159,7 @@ // still not final: // 1) Aliased (with --defsym) or wrapped (with --wrap) symbols. // 2) Symbols redefined in linker script. - R.LinkerRedefined = !Sym->CanInline || ScriptSymbols.count(Sym->getName()); + R.LinkerRedefined = !Sym->CanInline; } checkError(LTOObj->add(std::move(F.Obj), Resols)); } Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -208,6 +208,8 @@ llvm::DenseMap NameToOutputSection; void addSymbol(SymbolAssignment *Cmd); + void handleAssignment(SymbolAssignment *Cmd); + void assignSymbol(SymbolAssignment *Cmd, bool InSec); void setDot(Expr E, const Twine &Loc, bool InSec); @@ -264,6 +266,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 @@ -31,6 +31,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/SaveAndRestore.h" #include #include #include @@ -117,15 +118,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. - SymbolBody *B = Symtab->find(Cmd->Name); - if (Cmd->Provide && (!B || B->isDefined())) - return; - // Define a symbol. SymbolBody *Sym; uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; @@ -154,6 +146,43 @@ Cmd->Sym = cast(Sym); } +void LinkerScript::handleAssignment(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. + SymbolBody *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)) { + // We can't calculate final value right now, so do not want to use + // underlying expression and temporarily swap it with dummy one. + SaveAndRestore R(Cmd->Expression, [] { return ExprValue(0); }); + handleAssignment(Cmd); + if (Cmd->Sym) + Cmd->Sym->CanInline = false; + } + } +} + // 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. @@ -363,7 +392,7 @@ for (BaseCommand *Base : SectionCommands) { // Handle symbol assignments outside of any output section. if (auto *Cmd = dyn_cast(Base)) { - addSymbol(Cmd); + handleAssignment(Cmd); continue; } @@ -395,7 +424,7 @@ // ".foo : { ...; bar = .; }". Handle them. for (BaseCommand *Base : Sec->SectionCommands) if (auto *OutCmd = dyn_cast(Base)) - addSymbol(OutCmd); + handleAssignment(OutCmd); // Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign // is given, input sections are aligned to that value, whether the Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -774,7 +774,11 @@ // to GOT. Default offset is 0x7ff0. // See "Global Data Symbols" in Chapter 6 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - ElfSym::MipsGp = Symtab->addAbsolute("_gp", STV_HIDDEN, STB_LOCAL); + SymbolBody *Gp = Symtab->find("_gp"); + if (!Gp || !isa(Gp)) + ElfSym::MipsGp = Symtab->addAbsolute("_gp", STV_HIDDEN, STB_LOCAL); + else + ElfSym::MipsGp = dyn_cast(Gp); // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between // start of function and 'gp' pointer into GOT. 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" Index: test/ELF/mips-gp-ext.s =================================================================== --- test/ELF/mips-gp-ext.s +++ test/ELF/mips-gp-ext.s @@ -27,10 +27,10 @@ # REQUIRES: mips # REL: Contents of section .text: -# REL-NEXT: 0000 3c080000 2108010c 8f82fffc +# REL-NEXT: 0000 3c080000 2108010c 8f82001c # ^-- %hi(_gp_disp) # ^-- %lo(_gp_disp) -# ^-- 8 - (0x10c - 0x100) +# ^-- 8 - (0x10c - 0x120) # G - (GP - .got) # REL: Contents of section .reginfo: @@ -39,18 +39,18 @@ # ^-- _gp # REL: Contents of section .data: -# REL-NEXT: 00f0 fffffef4 +# REL-NEXT: 0110 fffffef4 # ^-- 0-0x10c # REL: 00000000 .text 00000000 foo # REL: 00000000 *ABS* 00000000 .hidden _gp_disp -# REL: 0000010c *ABS* 00000000 .hidden _gp +# REL: 0000010c *ABS* 00000000 _gp # ABS: Contents of section .text: -# ABS-NEXT: 0000 3c080000 21080200 8f82ff08 +# ABS-NEXT: 0000 3c080000 21080200 8f82ff28 # ^-- %hi(_gp_disp) # ^-- %lo(_gp_disp) -# ^-- 8 - (0x200 - 0x100) +# ^-- 8 - (0x200 - 0x120) # G - (GP - .got) # ABS: Contents of section .reginfo: @@ -59,12 +59,12 @@ # ^-- _gp # ABS: Contents of section .data: -# ABS-NEXT: 00f0 fffffe00 +# ABS-NEXT: 0110 fffffe00 # ^-- 0-0x200 # ABS: 00000000 .text 00000000 foo # ABS: 00000000 *ABS* 00000000 .hidden _gp_disp -# ABS: 00000200 *ABS* 00000000 .hidden _gp +# ABS: 00000200 *ABS* 00000000 _gp .text foo: