diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -103,6 +103,13 @@ return sym; } +// A version script/dynamic list is only meaningful for a Defined symbol. +// A CommonSymbol will be converted to a Defined in replaceCommonSymbols(). +// A lazy symbol may be made Defined if an LTO libcall fetches it. +static bool canBeVersioned(const Symbol &sym) { + return sym.isDefined() || sym.isCommon() || sym.isLazy(); +} + // Initialize demangledSyms with a map from demangled symbols to symbol // objects. Used to handle "extern C++" directive in version scripts. // @@ -119,11 +126,9 @@ StringMap> &SymbolTable::getDemangledSyms() { if (!demangledSyms) { demangledSyms.emplace(); - for (Symbol *sym : symVector) { - if (!sym->isDefined() && !sym->isCommon()) - continue; - (*demangledSyms)[demangleItanium(sym->getName())].push_back(sym); - } + for (Symbol *sym : symVector) + if (canBeVersioned(*sym)) + (*demangledSyms)[demangleItanium(sym->getName())].push_back(sym); } return *demangledSyms; } @@ -131,9 +136,9 @@ std::vector SymbolTable::findByVersion(SymbolVersion ver) { if (ver.isExternCpp) return getDemangledSyms().lookup(ver.name); - if (Symbol *b = find(ver.name)) - if (b->isDefined() || b->isCommon()) - return {b}; + if (Symbol *sym = find(ver.name)) + if (canBeVersioned(*sym)) + return {sym}; return {}; } @@ -149,7 +154,7 @@ } for (Symbol *sym : symVector) - if ((sym->isDefined() || sym->isCommon()) && m.match(sym->getName())) + if (canBeVersioned(*sym) && m.match(sym->getName())) res.push_back(sym); return res; } diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -276,7 +276,7 @@ if (config->relocatable) return binding; if ((visibility != STV_DEFAULT && visibility != STV_PROTECTED) || - versionId == VER_NDX_LOCAL) + (versionId == VER_NDX_LOCAL && isDefined())) return STB_LOCAL; if (!config->gnuUnique && binding == STB_GNU_UNIQUE) return STB_GLOBAL; diff --git a/lld/test/ELF/lto/version-libcall.ll b/lld/test/ELF/lto/version-libcall.ll new file mode 100644 --- /dev/null +++ b/lld/test/ELF/lto/version-libcall.ll @@ -0,0 +1,44 @@ +; REQUIRES: x86 +;; The LTO code generator may create references which will fetch lazy symbols. +;; Test that version script local: directives can change the binding of such +;; symbols to STB_LOCAL. This is a bit complex because the LTO code generator +;; happens after version script scanning and can change symbols from Lazy to Defined. + +; RUN: llvm-as %s -o %t.bc +; RUN: echo '.globl __udivti3; __udivti3:' | llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o + +;; An exact pattern can localize a libcall. +; RUN: echo '{ global: foo; local: __udivti3; };' > %t.exact.ver +; RUN: ld.lld -shared --version-script %t.exact.ver %t.bc --start-lib %t1.o --end-lib -o %t.exact.so +; RUN: llvm-nm %t.exact.so | FileCheck %s + +;; A wildcard pattern can localize a libcall. +; RUN: echo '{ global: foo; local: *; };' > %t.wild.ver +; RUN: ld.lld -shared --version-script %t.wild.ver %t.bc --start-lib %t1.o --end-lib -o %t.wild.so +; RUN: llvm-nm %t.wild.so | FileCheck %s + +; CHECK: t __udivti3 +; CHECK: T foo + +;; Test that --dynamic-list works on such libcall fetched symbols. +; RUN: echo '{ foo; __udivti3; };' > %t.exact.list +; RUN: ld.lld -pie --dynamic-list %t.exact.list %t.bc --start-lib %t1.o --end-lib -o %t.exact +; RUN: llvm-nm %t.exact | FileCheck --check-prefix=LIST %s +; RUN: echo '{ foo; __udiv*; };' > %t.wild.list +; RUN: ld.lld -pie --dynamic-list %t.wild.list %t.bc --start-lib %t1.o --end-lib -o %t.wild +; RUN: llvm-nm %t.wild | FileCheck --check-prefix=LIST %s + +; LIST: T __udivti3 +; LIST: T foo + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare i64 @llvm.udiv.fix.i64(i64, i64, i32) + +;; The symbol table does not record __udivti3, but the reference will be created +;; on the fly. +define i64 @foo(i64 %x, i64 %y) { + %ret = call i64 @llvm.udiv.fix.i64(i64 %x, i64 %y, i32 31) + ret i64 %ret +}