Index: lld/trunk/ELF/Config.h =================================================================== --- lld/trunk/ELF/Config.h +++ lld/trunk/ELF/Config.h @@ -37,6 +37,7 @@ struct Version { Version(llvm::StringRef Name) : Name(Name) {} llvm::StringRef Name; + llvm::StringRef Parent; std::vector Globals; size_t NameOff; // Offset in string table. }; Index: lld/trunk/ELF/OutputSections.cpp =================================================================== --- lld/trunk/ELF/OutputSections.cpp +++ lld/trunk/ELF/OutputSections.cpp @@ -1462,6 +1462,10 @@ this->Header.sh_size = (sizeof(Elf_Verdef) + sizeof(Elf_Verdaux)) * getVerDefNum(); + for (Version &V : Config->SymbolVersions) + if (!V.Parent.empty()) + this->Header.sh_size += sizeof(Elf_Verdaux); + this->Header.sh_link = Out::DynStrTab->SectionIndex; this->Header.sh_addralign = sizeof(uint32_t); @@ -1471,12 +1475,22 @@ this->Header.sh_info = getVerDefNum(); } +static size_t getVersionNameStrTabOffset(StringRef Name) { + for (Version &V : Config->SymbolVersions) + if (V.Name == Name) + return V.NameOff; + error("unknown version name " + Name + " used as a dependency"); + return 0; +} + template static void writeDefinition(Elf_Verdef *&Verdef, Elf_Verdaux *&Verdaux, uint32_t Flags, uint32_t Index, StringRef Name, - size_t StrTabOffset) { + size_t StrTabOffset, StringRef ParentName) { + bool HasParent = !ParentName.empty(); + Verdef->vd_version = 1; - Verdef->vd_cnt = 1; + Verdef->vd_cnt = HasParent ? 2 : 1; Verdef->vd_aux = reinterpret_cast(Verdaux) - reinterpret_cast(Verdef); Verdef->vd_next = sizeof(Elf_Verdef); @@ -1487,6 +1501,12 @@ ++Verdef; Verdaux->vda_name = StrTabOffset; + if (HasParent) { + Verdaux->vda_next = sizeof(Elf_Verdaux); + ++Verdaux; + Verdaux->vda_name = getVersionNameStrTabOffset(ParentName); + } + Verdaux->vda_next = 0; ++Verdaux; } @@ -1498,11 +1518,12 @@ reinterpret_cast(Verdef + getVerDefNum()); writeDefinition(Verdef, Verdaux, VER_FLG_BASE, 1, getFileDefName(), - FileDefNameOff); + FileDefNameOff, "" /* Parent */); uint32_t I = 2; for (Version &V : Config->SymbolVersions) - writeDefinition(Verdef, Verdaux, 0 /* Flags */, I++, V.Name, V.NameOff); + writeDefinition(Verdef, Verdaux, 0 /* Flags */, I++, V.Name, V.NameOff, + V.Parent); Verdef[-1].vd_next = 0; } Index: lld/trunk/ELF/SymbolListFile.cpp =================================================================== --- lld/trunk/ELF/SymbolListFile.cpp +++ lld/trunk/ELF/SymbolListFile.cpp @@ -94,6 +94,8 @@ parseVersionSymbols(Version); expect("}"); + if (!Version.empty() && peek() != ";") + Config->SymbolVersions.back().Parent = next(); expect(";"); } Index: lld/trunk/test/ELF/verdef-dependency.s =================================================================== --- lld/trunk/test/ELF/verdef-dependency.s +++ lld/trunk/test/ELF/verdef-dependency.s @@ -0,0 +1,56 @@ +# 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: *; }LIBSAMPLE_1.0; \ +# RUN: LIBSAMPLE_3.0{ \ +# RUN: global: c; \ +# RUN: local: *; }LIBSAMPLE_2.0;" > %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: SHT_GNU_verdef { +# DSO-NEXT: Definition { +# DSO-NEXT: Version: 1 +# DSO-NEXT: Flags: Base +# DSO-NEXT: Index: 1 +# DSO-NEXT: Hash: 127830196 +# DSO-NEXT: Name: shared +# DSO-NEXT: } +# DSO-NEXT: Definition { +# DSO-NEXT: Version: 1 +# DSO-NEXT: Flags: 0x0 +# DSO-NEXT: Index: 2 +# DSO-NEXT: Hash: 98457184 +# DSO-NEXT: Name: LIBSAMPLE_1.0 +# DSO-NEXT: } +# DSO-NEXT: Definition { +# DSO-NEXT: Version: 1 +# DSO-NEXT: Flags: 0x0 +# DSO-NEXT: Index: 3 +# DSO-NEXT: Hash: 98456416 +# DSO-NEXT: Name: LIBSAMPLE_2.0 +# DSO-NEXT: Predecessor: LIBSAMPLE_1.0 +# DSO-NEXT: } +# DSO-NEXT: Definition { +# DSO-NEXT: Version: 1 +# DSO-NEXT: Flags: 0x0 +# DSO-NEXT: Index: 4 +# DSO-NEXT: Hash: 98456672 +# DSO-NEXT: Name: LIBSAMPLE_3.0 +# DSO-NEXT: Predecessor: LIBSAMPLE_2.0 +# DSO-NEXT: } +# DSO-NEXT: } + +# RUN: echo "LIBSAMPLE_1.0{ \ +# RUN: global: a; \ +# RUN: local: *; }; \ +# RUN: LIBSAMPLE_2.0{ \ +# RUN: global: b; \ +# RUN: local: *; }LIBSAMPLE_X.X; " > %t.script +# RUN: not ld.lld --version-script %t.script -shared %t.o -o %t.so 2>&1 \ +# RUN: | FileCheck -check-prefix=ERR %s +# ERR: unknown version name LIBSAMPLE_X.X used as a dependency