diff options
-rw-r--r-- | lld/ELF/Config.h | 10 | ||||
-rw-r--r-- | lld/ELF/OutputSections.cpp | 96 | ||||
-rw-r--r-- | lld/ELF/OutputSections.h | 30 | ||||
-rw-r--r-- | lld/ELF/SymbolListFile.cpp | 28 | ||||
-rw-r--r-- | lld/ELF/SymbolListFile.h | 1 | ||||
-rw-r--r-- | lld/ELF/SymbolTable.cpp | 26 | ||||
-rw-r--r-- | lld/ELF/Symbols.cpp | 2 | ||||
-rw-r--r-- | lld/ELF/Symbols.h | 18 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 13 | ||||
-rw-r--r-- | lld/test/ELF/Inputs/verdef.s | 6 | ||||
-rw-r--r-- | lld/test/ELF/lto/version-script.ll | 50 | ||||
-rw-r--r-- | lld/test/ELF/verdef.s | 131 | ||||
-rw-r--r-- | lld/test/ELF/version-script.s | 40 |
13 files changed, 409 insertions, 42 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index be8059b46a9..d199db922cc 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -32,6 +32,15 @@ enum ELFKind { enum class BuildIdKind { None, Fnv1, Md5, Sha1, Hexstring }; +// This struct contains symbols version definition that +// can be found in version script if it is used for link. +struct Version { + Version(llvm::StringRef Name) : Name(Name) {} + llvm::StringRef Name; + std::vector<llvm::StringRef> Globals; + size_t NameOff; // Offset in string table. +}; + // This struct contains the global configuration for the linker. // Most fields are direct mapping from the command line options // and such fields have the same name as the corresponding options. @@ -50,6 +59,7 @@ struct Configuration { llvm::StringRef SoName; llvm::StringRef Sysroot; std::string RPath; + std::vector<Version> SymbolVersions; std::vector<llvm::StringRef> DynamicList; std::vector<llvm::StringRef> SearchPaths; std::vector<llvm::StringRef> Undefined; diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 4b71874511f..2f0bd9e7359 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -591,6 +591,11 @@ void GnuHashTableSection<ELFT>::addSymbols( V.push_back({Sym.Body, Sym.STName}); } +// Returns the number of version definition entries. Because the first entry +// is for the version definition itself, it is the number of versioned symbols +// plus one. Note that we don't support multiple versions yet. +static unsigned getVerDefNum() { return Config->SymbolVersions.size() + 1; } + template <class ELFT> DynamicSection<ELFT>::DynamicSection() : OutputSectionBase<ELFT>(".dynamic", SHT_DYNAMIC, SHF_ALLOC | SHF_WRITE) { @@ -693,10 +698,16 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() { if (!Config->Entry.empty()) Add({DT_DEBUG, (uint64_t)0}); - if (size_t NeedNum = Out<ELFT>::VerNeed->getNeedNum()) { + bool HasVerNeed = Out<ELFT>::VerNeed->getNeedNum() != 0; + if (HasVerNeed || Out<ELFT>::VerDef) Add({DT_VERSYM, Out<ELFT>::VerSym}); + if (Out<ELFT>::VerDef) { + Add({DT_VERDEF, Out<ELFT>::VerDef}); + Add({DT_VERDEFNUM, getVerDefNum()}); + } + if (HasVerNeed) { Add({DT_VERNEED, Out<ELFT>::VerNeed}); - Add({DT_VERNEEDNUM, NeedNum}); + Add({DT_VERNEEDNUM, Out<ELFT>::VerNeed->getNeedNum()}); } if (Config->EMachine == EM_MIPS) { @@ -1435,6 +1446,68 @@ SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) { } template <class ELFT> +VersionDefinitionSection<ELFT>::VersionDefinitionSection() + : OutputSectionBase<ELFT>(".gnu.version_d", SHT_GNU_verdef, SHF_ALLOC) {} + +static StringRef getFileDefName() { + if (!Config->SoName.empty()) + return Config->SoName; + return Config->OutputFile; +} + +template <class ELFT> void VersionDefinitionSection<ELFT>::finalize() { + FileDefNameOff = Out<ELFT>::DynStrTab->addString(getFileDefName()); + for (Version &V : Config->SymbolVersions) + V.NameOff = Out<ELFT>::DynStrTab->addString(V.Name); + + this->Header.sh_size = + (sizeof(Elf_Verdef) + sizeof(Elf_Verdaux)) * getVerDefNum(); + this->Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex; + this->Header.sh_addralign = sizeof(uint32_t); + + // sh_info should be set to the number of definitions. This fact is missed in + // documentation, but confirmed by binutils community: + // https://sourceware.org/ml/binutils/2014-11/msg00355.html + this->Header.sh_info = getVerDefNum(); +} + +template <class Elf_Verdef, class Elf_Verdaux> +static void writeDefinition(Elf_Verdef *&Verdef, Elf_Verdaux *&Verdaux, + uint32_t Flags, uint32_t Index, StringRef Name, + size_t StrTabOffset) { + Verdef->vd_version = 1; + Verdef->vd_cnt = 1; + Verdef->vd_aux = + reinterpret_cast<char *>(Verdaux) - reinterpret_cast<char *>(Verdef); + Verdef->vd_next = sizeof(Elf_Verdef); + + Verdef->vd_flags = Flags; + Verdef->vd_ndx = Index; + Verdef->vd_hash = hashSysv(Name); + ++Verdef; + + Verdaux->vda_name = StrTabOffset; + Verdaux->vda_next = 0; + ++Verdaux; +} + +template <class ELFT> +void VersionDefinitionSection<ELFT>::writeTo(uint8_t *Buf) { + Elf_Verdef *Verdef = reinterpret_cast<Elf_Verdef *>(Buf); + Elf_Verdaux *Verdaux = + reinterpret_cast<Elf_Verdaux *>(Verdef + getVerDefNum()); + + writeDefinition(Verdef, Verdaux, VER_FLG_BASE, 1, getFileDefName(), + FileDefNameOff); + + uint32_t I = 2; + for (Version &V : Config->SymbolVersions) + writeDefinition(Verdef, Verdaux, 0 /* Flags */, I++, V.Name, V.NameOff); + + Verdef[-1].vd_next = 0; +} + +template <class ELFT> VersionTableSection<ELFT>::VersionTableSection() : OutputSectionBase<ELFT>(".gnu.version", SHT_GNU_versym, SHF_ALLOC) { this->Header.sh_addralign = sizeof(uint16_t); @@ -1453,10 +1526,7 @@ template <class ELFT> void VersionTableSection<ELFT>::writeTo(uint8_t *Buf) { auto *OutVersym = reinterpret_cast<Elf_Versym *>(Buf) + 1; for (const std::pair<SymbolBody *, size_t> &P : Out<ELFT>::DynSymTab->getSymbols()) { - if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(P.first)) - OutVersym->vs_index = SS->VersionId; - else - OutVersym->vs_index = VER_NDX_GLOBAL; + OutVersym->vs_index = P.first->symbol()->VersionId; ++OutVersym; } } @@ -1465,12 +1535,17 @@ template <class ELFT> VersionNeedSection<ELFT>::VersionNeedSection() : OutputSectionBase<ELFT>(".gnu.version_r", SHT_GNU_verneed, SHF_ALLOC) { this->Header.sh_addralign = sizeof(uint32_t); + + // Identifiers in verneed section start at 2 because 0 and 1 are reserved + // for VER_NDX_LOCAL and VER_NDX_GLOBAL. + // First identifiers are reserved by verdef section if it exist. + NextIndex = getVerDefNum() + 1; } template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(SharedSymbol<ELFT> *SS) { if (!SS->Verdef) { - SS->VersionId = VER_NDX_GLOBAL; + SS->symbol()->VersionId = VER_NDX_GLOBAL; return; } SharedFile<ELFT> *F = SS->File; @@ -1488,7 +1563,7 @@ void VersionNeedSection<ELFT>::addSymbol(SharedSymbol<ELFT> *SS) { SS->File->getStringTable().data() + SS->Verdef->getAux()->vda_name); NV.Index = NextIndex++; } - SS->VersionId = NV.Index; + SS->symbol()->VersionId = NV.Index; } template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) { @@ -1744,6 +1819,11 @@ template class VersionNeedSection<ELF32BE>; template class VersionNeedSection<ELF64LE>; template class VersionNeedSection<ELF64BE>; +template class VersionDefinitionSection<ELF32LE>; +template class VersionDefinitionSection<ELF32BE>; +template class VersionDefinitionSection<ELF64LE>; +template class VersionDefinitionSection<ELF64BE>; + template class BuildIdSection<ELF32LE>; template class BuildIdSection<ELF32BE>; template class BuildIdSection<ELF64LE>; diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index 4b05e71dd4e..7fe0e9c02d7 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -25,6 +25,7 @@ namespace elf { class SymbolBody; struct SectionPiece; +struct Version; template <class ELFT> class SymbolTable; template <class ELFT> class SymbolTableSection; template <class ELFT> class StringTableSection; @@ -248,10 +249,30 @@ private: // For more information about .gnu.version and .gnu.version_r see: // https://www.akkadia.org/drepper/symbol-versioning +// The .gnu.version_d section which has a section type of SHT_GNU_verdef shall +// contain symbol version definitions. The number of entries in this section +// shall be contained in the DT_VERDEFNUM entry of the .dynamic section. +// The section shall contain an array of Elf_Verdef structures, optionally +// followed by an array of Elf_Verdaux structures. +template <class ELFT> +class VersionDefinitionSection final : public OutputSectionBase<ELFT> { + typedef typename ELFT::Verdef Elf_Verdef; + typedef typename ELFT::Verdaux Elf_Verdaux; + + unsigned FileDefNameOff; + +public: + VersionDefinitionSection(); + void finalize() override; + void writeTo(uint8_t *Buf) override; +}; + // The .gnu.version section specifies the required version of each symbol in the // dynamic symbol table. It contains one Elf_Versym for each dynamic symbol // table entry. An Elf_Versym is just a 16-bit integer that refers to a version -// identifier defined in the .gnu.version_r section. +// identifier defined in the either .gnu.version_r or .gnu.version_d section. +// The values 0 and 1 are reserved. All other values are used for versions in +// the own object or in any of the dependencies. template <class ELFT> class VersionTableSection final : public OutputSectionBase<ELFT> { typedef typename ELFT::Versym Elf_Versym; @@ -276,9 +297,8 @@ class VersionNeedSection final : public OutputSectionBase<ELFT> { // string table offsets of their sonames. std::vector<std::pair<SharedFile<ELFT> *, size_t>> Needed; - // The next available version identifier. Identifiers start at 2 because 0 and - // 1 are reserved. - unsigned NextIndex = 2; + // The next available version identifier. + unsigned NextIndex; public: VersionNeedSection(); @@ -630,6 +650,7 @@ template <class ELFT> struct Out { static StringTableSection<ELFT> *StrTab; static SymbolTableSection<ELFT> *DynSymTab; static SymbolTableSection<ELFT> *SymTab; + static VersionDefinitionSection<ELFT> *VerDef; static VersionTableSection<ELFT> *VerSym; static VersionNeedSection<ELFT> *VerNeed; static Elf_Phdr *TlsPhdr; @@ -658,6 +679,7 @@ template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::ShStrTab; template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::StrTab; template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::DynSymTab; template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::SymTab; +template <class ELFT> VersionDefinitionSection<ELFT> *Out<ELFT>::VerDef; template <class ELFT> VersionTableSection<ELFT> *Out<ELFT>::VerSym; template <class ELFT> VersionNeedSection<ELFT> *Out<ELFT>::VerNeed; template <class ELFT> typename ELFT::Phdr *Out<ELFT>::TlsPhdr; diff --git a/lld/ELF/SymbolListFile.cpp b/lld/ELF/SymbolListFile.cpp index 3d1377be438..2d5d1c52371 100644 --- a/lld/ELF/SymbolListFile.cpp +++ b/lld/ELF/SymbolListFile.cpp @@ -77,21 +77,21 @@ public: void run(); private: - void parseVersion(); + void parseVersion(StringRef Version); void parseLocal(); - void parseVersionSymbols(); + void parseVersionSymbols(StringRef Version); }; -void VersionScriptParser::parseVersion() { +void VersionScriptParser::parseVersion(StringRef Version) { expect("{"); if (peek() == "global:") { next(); - parseVersionSymbols(); + parseVersionSymbols(Version); } if (peek() == "local:") parseLocal(); else - parseVersionSymbols(); + parseVersionSymbols(Version); expect("}"); expect(";"); @@ -104,13 +104,21 @@ void VersionScriptParser::parseLocal() { Config->VersionScriptGlobalByDefault = false; } -void VersionScriptParser::parseVersionSymbols() { +void VersionScriptParser::parseVersionSymbols(StringRef Version) { + std::vector<StringRef> *Globals; + if (Version.empty()) { + Globals = &Config->VersionScriptGlobals; + } else { + Config->SymbolVersions.push_back(elf::Version(Version)); + Globals = &Config->SymbolVersions.back().Globals; + } + for (;;) { StringRef Cur = peek(); if (Cur == "}" || Cur == "local:") return; next(); - Config->VersionScriptGlobals.push_back(Cur); + Globals->push_back(Cur); expect(";"); } } @@ -119,18 +127,18 @@ void VersionScriptParser::run() { StringRef Msg = "anonymous version definition is used in " "combination with other version definitions"; if (peek() == "{") { - parseVersion(); + parseVersion(""); if (!atEOF()) setError(Msg); return; } while (!atEOF() && !Error) { - if (next() == "{") { + if (peek() == "{") { setError(Msg); return; } - parseVersion(); + parseVersion(next()); } } diff --git a/lld/ELF/SymbolListFile.h b/lld/ELF/SymbolListFile.h index 60362a805ff..8f826d2957e 100644 --- a/lld/ELF/SymbolListFile.h +++ b/lld/ELF/SymbolListFile.h @@ -11,6 +11,7 @@ #define LLD_ELF_SYMBOL_LIST_FILE_H #include "lld/Core/LLVM.h" +#include "llvm/ADT/MapVector.h" #include "llvm/Support/MemoryBuffer.h" namespace lld { diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index e9cee22c1bf..c5d92325451 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -175,7 +175,10 @@ std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) { Sym->Visibility = STV_DEFAULT; Sym->IsUsedInRegularObj = false; Sym->ExportDynamic = false; - Sym->VersionScriptGlobal = Config->VersionScriptGlobalByDefault; + if (Config->VersionScriptGlobalByDefault) + Sym->VersionId = VER_NDX_GLOBAL; + else + Sym->VersionId = VER_NDX_LOCAL; SymVector.push_back(Sym); } else { Sym = SymVector[P.first->second]; @@ -514,9 +517,24 @@ template <class ELFT> void SymbolTable<ELFT>::scanDynamicList() { // symbols with the VersionScriptGlobal flag, which acts as a filter on the // dynamic symbol table. template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() { - for (StringRef S : Config->VersionScriptGlobals) - if (SymbolBody *B = find(S)) - B->symbol()->VersionScriptGlobal = true; + // If version script does not contain versions declarations, + // we just should mark global symbols. + if (!Config->VersionScriptGlobals.empty()) { + for (StringRef S : Config->VersionScriptGlobals) + if (SymbolBody *B = find(S)) + B->symbol()->VersionId = VER_NDX_GLOBAL; + return; + } + + // If we have symbols version declarations, we should + // assign version references for each symbol. + size_t I = 2; + for (Version &V : Config->SymbolVersions) { + for (StringRef Name : V.Globals) + if (SymbolBody *B = find(Name)) + B->symbol()->VersionId = I; + ++I; + } } template class elf::SymbolTable<ELF32LE>; diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index 0ba571b7e9a..9fd5de2220e 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -267,7 +267,7 @@ std::string elf::demangle(StringRef Name) { bool Symbol::includeInDynsym() const { if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) return false; - return (ExportDynamic && VersionScriptGlobal) || body()->isShared() || + return (ExportDynamic && VersionId != VER_NDX_LOCAL) || body()->isShared() || (body()->isUndefined() && Config->Shared); } diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 8b103ae889a..62ef088784d 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -30,6 +30,7 @@ class BitcodeFile; class InputFile; class LazyObjectFile; class SymbolBody; +struct Version; template <class ELFT> class ObjectFile; template <class ELFT> class OutputSection; template <class ELFT> class OutputSectionBase; @@ -302,13 +303,8 @@ public: SharedFile<ELFT> *File; const Elf_Sym &Sym; - // This field is initially a pointer to the symbol's version definition. As - // symbols are added to the version table, this field is replaced with the - // version identifier to be stored in .gnu.version in the output file. - union { - const Elf_Verdef *Verdef; - uint16_t VersionId; - }; + // This field is a pointer to the symbol's version definition. + const Elf_Verdef *Verdef; // OffsetInBss is significant only when needsCopy() is true. uintX_t OffsetInBss = 0; @@ -407,6 +403,9 @@ struct Symbol { // it is weak. uint8_t Binding; + // Version definition index. + uint16_t VersionId; + // Symbol visibility. This is the computed minimum visibility of all // observed non-DSO symbols. unsigned Visibility : 2; @@ -423,11 +422,6 @@ struct Symbol { // --export-dynamic, and by dynamic lists. unsigned ExportDynamic : 1; - // This flag acts as an additional filter on the dynamic symbol list. It is - // set if there is no version script, or if the symbol appears in the global - // section of the version script. - unsigned VersionScriptGlobal : 1; - bool includeInDynsym() const; bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; } diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 65ddb2010db..d5761e79292 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -136,6 +136,7 @@ template <class ELFT> void elf::writeResult(SymbolTable<ELFT> *Symtab) { std::unique_ptr<StringTableSection<ELFT>> StrTab; std::unique_ptr<SymbolTableSection<ELFT>> SymTabSec; std::unique_ptr<OutputSection<ELFT>> MipsRldMap; + std::unique_ptr<VersionDefinitionSection<ELFT>> VerDef; if (Config->BuildId == BuildIdKind::Fnv1) BuildId.reset(new BuildIdFnv1<ELFT>); @@ -170,6 +171,8 @@ template <class ELFT> void elf::writeResult(SymbolTable<ELFT> *Symtab) { MipsRldMap->setSize(sizeof(uintX_t)); MipsRldMap->updateAlignment(sizeof(uintX_t)); } + if (!Config->SymbolVersions.empty()) + VerDef.reset(new VersionDefinitionSection<ELFT>()); Out<ELFT>::Bss = &Bss; Out<ELFT>::BuildId = BuildId.get(); @@ -189,6 +192,7 @@ template <class ELFT> void elf::writeResult(SymbolTable<ELFT> *Symtab) { Out<ELFT>::ShStrTab = &ShStrTab; Out<ELFT>::StrTab = StrTab.get(); Out<ELFT>::SymTab = SymTabSec.get(); + Out<ELFT>::VerDef = VerDef.get(); Out<ELFT>::VerSym = &VerSym; Out<ELFT>::VerNeed = &VerNeed; Out<ELFT>::MipsRldMap = MipsRldMap.get(); @@ -904,10 +908,15 @@ template <class ELFT> void Writer<ELFT>::addPredefinedSections() { Add(Out<ELFT>::StrTab); if (isOutputDynamic()) { Add(Out<ELFT>::DynSymTab); - if (Out<ELFT>::VerNeed->getNeedNum() != 0) { + + bool HasVerNeed = Out<ELFT>::VerNeed->getNeedNum() != 0; + if (Out<ELFT>::VerDef || HasVerNeed) Add(Out<ELFT>::VerSym); + if (Out<ELFT>::VerDef) + Add(Out<ELFT>::VerDef); + if (HasVerNeed) Add(Out<ELFT>::VerNeed); - } + Add(Out<ELFT>::GnuHashTab); Add(Out<ELFT>::HashTab); Add(Out<ELFT>::Dynamic); diff --git a/lld/test/ELF/Inputs/verdef.s b/lld/test/ELF/Inputs/verdef.s new file mode 100644 index 00000000000..349d5fd0c26 --- /dev/null +++ b/lld/test/ELF/Inputs/verdef.s @@ -0,0 +1,6 @@ +.text +.globl _start +_start: + callq a + callq b + callq c diff --git a/lld/test/ELF/lto/version-script.ll b/lld/test/ELF/lto/version-script.ll new file mode 100644 index 00000000000..11a7f073ab5 --- /dev/null +++ b/lld/test/ELF/lto/version-script.ll @@ -0,0 +1,50 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.o +; RUN: echo "VERSION_1.0{ global: foo; local: *; }; VERSION_2.0{ global: bar; local: *; };" > %t.script +; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -shared --version-script %t.script -save-temps +; RUN: llvm-dis < %t2.lto.bc | FileCheck %s +; RUN: llvm-readobj -V -dyn-symbols %t2 | FileCheck --check-prefix=DSO %s + +target triple = "x86_64-unknown-linux-gnu" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +define void @foo() { + ret void +} + +define void @bar() { + ret void +} + +; CHECK: define void @foo() +; CHECK: define void @bar() + +; DSO: DynamicSymbols [ +; DSO: Symbol { +; DSO: Name: @ (0) +; DSO: Value: 0x0 +; DSO: Size: 0 +; DSO: Binding: Local +; DSO: Type: None +; DSO: Other: 0 +; DSO: Section: Undefined +; DSO: } +; DSO: Symbol { +; DSO: Name: foo@@VERSION_1.0 +; DSO: Value: 0x1000 +; DSO: Size: 1 +; DSO: Binding: Global +; DSO: Type: Function +; DSO: Other: 0 +; DSO: Section: .text +; DSO: } +; DSO: Symbol { +; DSO: Name: bar@@VERSION_2.0 +; DSO: Value: 0x1010 +; DSO: Size: 1 +; DSO: Binding: Global +; DSO: Type: Function +; DSO: Other: 0 +; DSO: Section: .text +; DSO: } +; DSO: ] diff --git a/lld/test/ELF/verdef.s b/lld/test/ELF/verdef.s new file mode 100644 index 00000000000..41c1d160b60 --- /dev/null +++ b/lld/test/ELF/verdef.s @@ -0,0 +1,131 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "LIBSAMPLE_1.0{ \ +# RUN: global: a; \ +# RUN: local: *; }; \ +# RUN: LIBSAMPLE_2.0{ \ +# RUN: global: b; \ +# RUN: local: *; }; \ +# RUN: LIBSAMPLE_3.0{ \ +# RUN: global: c; \ +# RUN: local: *; };" > %t.script +# RUN: ld.lld --version-script %t.script -shared -soname shared %t.o -o %t.so +# RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s + +# DSO: Version symbols { +# DSO-NEXT: Section Name: .gnu.version +# DSO-NEXT: Address: 0x228 +# DSO-NEXT: Offset: 0x228 +# DSO-NEXT: Link: 1 +# DSO-NEXT: Symbols [ +# DSO-NEXT: Symbol { +# DSO-NEXT: Version: 0 +# DSO-NEXT: Name: @ +# DSO-NEXT: } +# DSO-NEXT: Symbol { +# DSO-NEXT: Version: 2 +# DSO-NEXT: Name: a@@LIBSAMPLE_1.0 +# DSO-NEXT: } +# DSO-NEXT: Symbol { +# DSO-NEXT: Version: 3 +# DSO-NEXT: Name: b@@LIBSAMPLE_2.0 +# DSO-NEXT: } +# DSO-NEXT: Symbol { +# DSO-NEXT: Version: 4 +# DSO-NEXT: Name: c@@LIBSAMPLE_3.0 +# DSO-NEXT: } +# DSO-NEXT: ] +# DSO-NEXT: } +# DSO-NEXT: Version definition { +# DSO-NEXT: Section Name: .gnu.version_d +# DSO-NEXT: Address: 0x230 +# DSO-NEXT: Offset: 0x230 +# DSO-NEXT: Link: 5 +# DSO-NEXT: Entries [ +# DSO-NEXT: Entry { +# DSO-NEXT: Offset: 0x0 +# DSO-NEXT: Rev: 1 +# DSO-NEXT: Flags: 1 +# DSO-NEXT: Index: 1 +# DSO-NEXT: Cnt: 1 +# DSO-NEXT: Hash: 127830196 +# DSO-NEXT: Name: +# DSO-NEXT: } +# DSO-NEXT: Entry { +# DSO-NEXT: Offset: 0x14 +# DSO-NEXT: Rev: 1 +# DSO-NEXT: Flags: 0 +# DSO-NEXT: Index: 2 +# DSO-NEXT: Cnt: 1 +# DSO-NEXT: Hash: 98457184 +# DSO-NEXT: Name: LIBSAMPLE_1.0 +# DSO-NEXT: } +# DSO-NEXT: Entry { +# DSO-NEXT: Offset: 0x28 +# DSO-NEXT: Rev: 1 +# DSO-NEXT: Flags: 0 +# DSO-NEXT: Index: 3 +# DSO-NEXT: Cnt: 1 +# DSO-NEXT: Hash: 98456416 +# DSO-NEXT: Name: LIBSAMPLE_2.0 +# DSO-NEXT: } +# DSO-NEXT: Entry { +# DSO-NEXT: Offset: 0x3C +# DSO-NEXT: Rev: 1 +# DSO-NEXT: Flags: 0 +# DSO-NEXT: Index: 4 +# DSO-NEXT: Cnt: 1 +# DSO-NEXT: Hash: 98456672 +# DSO-NEXT: Name: LIBSAMPLE_3.0 +# DSO-NEXT: } +# DSO-NEXT: ] +# DSO-NEXT: } +# DSO-NEXT: SHT_GNU_verneed { +# DSO-NEXT: } + +## Check that we can link agains DSO we produced. +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/verdef.s -o %tmain.o +# RUN: ld.lld %tmain.o %t.so -o %tout +# RUN: llvm-readobj -V %tout | FileCheck --check-prefix=MAIN %s + +# MAIN: Version symbols { +# MAIN-NEXT: Section Name: .gnu.version +# MAIN-NEXT: Address: 0x10228 +# MAIN-NEXT: Offset: 0x228 +# MAIN-NEXT: Link: 1 +# MAIN-NEXT: Symbols [ +# MAIN-NEXT: Symbol { +# MAIN-NEXT: Version: 0 +# MAIN-NEXT: Name: @ +# MAIN-NEXT: } +# MAIN-NEXT: Symbol { +# MAIN-NEXT: Version: 2 +# MAIN-NEXT: Name: a@LIBSAMPLE_1.0 +# MAIN-NEXT: } +# MAIN-NEXT: Symbol { +# MAIN-NEXT: Version: 3 +# MAIN-NEXT: Name: b@LIBSAMPLE_2.0 +# MAIN-NEXT: } +# MAIN-NEXT: Symbol { +# MAIN-NEXT: Version: 4 +# MAIN-NEXT: Name: c@LIBSAMPLE_3.0 +# MAIN-NEXT: } +# MAIN-NEXT: ] +# MAIN-NEXT: } +# MAIN-NEXT: Version definition { +# MAIN-NEXT: } + +.globl a +.type a,@function +a: +retq + +.globl b +.type b,@function +b: +retq + +.globl c +.type c,@function +c: +retq diff --git a/lld/test/ELF/version-script.s b/lld/test/ELF/version-script.s index 8310aedb290..b4b48f22eb2 100644 --- a/lld/test/ELF/version-script.s +++ b/lld/test/ELF/version-script.s @@ -26,7 +26,7 @@ # RUN: global: foo3; \ # RUN: local: *; }; " > %t4.script # RUN: ld.lld --version-script %t4.script -shared %t.o %t2.so -o %t4.so -# RUN: llvm-readobj -dyn-symbols %t4.so | FileCheck --check-prefix=DSO %s +# RUN: llvm-readobj -dyn-symbols %t4.so | FileCheck --check-prefix=VERDSO %s # RUN: echo "VERSION_1.0{ \ # RUN: global: foo1; \ @@ -140,6 +140,44 @@ # EXE-NEXT: } # EXE-NEXT: ] +# VERDSO: DynamicSymbols [ +# VERDSO-NEXT: Symbol { +# VERDSO-NEXT: Name: @ +# VERDSO-NEXT: Value: 0x0 +# VERDSO-NEXT: Size: 0 +# VERDSO-NEXT: Binding: Local +# VERDSO-NEXT: Type: None +# VERDSO-NEXT: Other: 0 +# VERDSO-NEXT: Section: Undefined +# VERDSO-NEXT: } +# VERDSO-NEXT: Symbol { +# VERDSO-NEXT: Name: bar@ +# VERDSO-NEXT: Value: 0x0 +# VERDSO-NEXT: Size: 0 +# VERDSO-NEXT: Binding: Global +# VERDSO-NEXT: Type: Function +# VERDSO-NEXT: Other: 0 +# VERDSO-NEXT: Section: Undefined +# VERDSO-NEXT: } +# VERDSO-NEXT: Symbol { +# VERDSO-NEXT: Name: foo1@@VERSION_1.0 +# VERDSO-NEXT: Value: 0x1000 +# VERDSO-NEXT: Size: 0 +# VERDSO-NEXT: Binding: Global +# VERDSO-NEXT: Type: None +# VERDSO-NEXT: Other: 0 +# VERDSO-NEXT: Section: .text +# VERDSO-NEXT: } +# VERDSO-NEXT: Symbol { +# VERDSO-NEXT: Name: foo3@@VERSION_2.0 +# VERDSO-NEXT: Value: 0x1007 +# VERDSO-NEXT: Size: 0 +# VERDSO-NEXT: Binding: Global +# VERDSO-NEXT: Type: None +# VERDSO-NEXT: Other: 0 +# VERDSO-NEXT: Section: .text +# VERDSO-NEXT: } +# VERDSO-NEXT: ] # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o # RUN: ld.lld -shared %t.o %t2.so -o %t.so |