Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -1005,6 +1005,13 @@ if (Args.hasArg(OPT_exclude_libs)) excludeLibs(Args, Files); + // Some symbols (such as __ehdr_start) are defined lazily only when there + // are undefined symbols for them, so we add these to trigger that logic. + // We also want to assign versions to symbols assigned by linkerscript, + // so have to create them early. + for (StringRef Sym : Script->Opt.ReferencedSymbols) + Symtab->addUndefined(Sym); + // Apply version scripts. Symtab->scanVersionScript(); @@ -1020,11 +1027,6 @@ if (ErrorCount) return; - // Some symbols (such as __ehdr_start) are defined lazily only when there - // are undefined symbols for them, so we add these to trigger that logic. - for (StringRef Sym : Script->Opt.ReferencedSymbols) - Symtab->addUndefined(Sym); - // Apply symbol renames for -wrap and -defsym Symtab->applySymbolRenames(); Index: ELF/ScriptParser.cpp =================================================================== --- ELF/ScriptParser.cpp +++ ELF/ScriptParser.cpp @@ -86,7 +86,7 @@ unsigned readPhdrType(); SortSectionPolicy readSortKind(); SymbolAssignment *readProvideHidden(bool Provide, bool Hidden); - SymbolAssignment *readProvideOrAssignment(StringRef Tok); + SymbolAssignment *readProvideOrAssignment(StringRef Tok, bool InSec); void readSort(); AssertCommand *readAssert(); Expr readAssertExpr(); @@ -242,7 +242,7 @@ readSections(); } else if (Tok == "VERSION") { readVersion(); - } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) { + } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok, false)) { Script->Opt.Commands.push_back(Cmd); } else { setError("unknown directive: " + Tok); @@ -405,7 +405,7 @@ expect("{"); while (!ErrorCount && !consume("}")) { StringRef Tok = next(); - BaseCommand *Cmd = readProvideOrAssignment(Tok); + BaseCommand *Cmd = readProvideOrAssignment(Tok, false); if (!Cmd) { if (Tok == "ASSERT") Cmd = readAssert(); @@ -629,7 +629,7 @@ StringRef Tok = next(); if (Tok == ";") { // Empty commands are allowed. Do nothing here. - } else if (SymbolAssignment *Assign = readProvideOrAssignment(Tok)) { + } else if (SymbolAssignment *Assign = readProvideOrAssignment(Tok, true)) { Cmd->Commands.push_back(Assign); } else if (BytesDataCommand *Data = readBytesDataCommand(Tok)) { Cmd->Commands.push_back(Data); @@ -696,9 +696,12 @@ return Cmd; } -SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) { +SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok, + bool InSec) { SymbolAssignment *Cmd = nullptr; if (peek() == "=" || peek() == "+=") { + if (!InSec && Tok != ".") + Script->Opt.ReferencedSymbols.push_back(Tok); Cmd = readAssignment(Tok); expect(";"); } else if (Tok == "PROVIDE") { Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -648,9 +648,17 @@ std::vector SymbolTable::findByVersion(SymbolVersion Ver) { if (Ver.IsExternCpp) return getDemangledSyms().lookup(Ver.Name); - if (SymbolBody *B = find(Ver.Name)) + if (SymbolBody *B = find(Ver.Name)) { if (!B->isUndefined()) return {B}; + // Is symbol is undefined it can be possible it was created for + // handling linkerscript assign command. Such symbol will be processed + // later, but we still want to assign version for them here. + auto It = llvm::find(Script->Opt.ReferencedSymbols, Ver.Name); + if (It != Script->Opt.ReferencedSymbols.end()) + return {B}; + return {}; + } return {}; } Index: test/ELF/linkerscript/align.s =================================================================== --- test/ELF/linkerscript/align.s +++ test/ELF/linkerscript/align.s @@ -61,8 +61,8 @@ # SYMBOLS-LABEL: SYMBOL TABLE: # SYMBOLS-NEXT: 0000000000000000 *UND* 00000000 # SYMBOLS-NEXT: 0000000000014008 .text 00000000 _start -# SYMBOLS-NEXT: 0000000000010000 *ABS* 00000000 __code_base__ # SYMBOLS-NEXT: 0000000000001000 *ABS* 00000000 VAR +# SYMBOLS-NEXT: 0000000000010000 *ABS* 00000000 __code_base__ # SYMBOLS-NEXT: 0000000000011000 .bbb 00000000 __start_bbb # SYMBOLS-NEXT: 0000000000012000 .bbb 00000000 __end_bbb 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,37 @@ +# 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: Symbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 0 +# CHECK-NEXT: Name: @ +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 2 +# CHECK-NEXT: Name: foo@@V +# 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: 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: