diff options
author | Peter Collingbourne <peter@pcc.me.uk> | 2016-04-27 20:22:31 +0000 |
---|---|---|
committer | Peter Collingbourne <peter@pcc.me.uk> | 2016-04-27 20:22:31 +0000 |
commit | 21a12fc69ac28a41efe417ad45ef6aebbb062195 (patch) | |
tree | a31779ec424e285a57b04b0d5db49976cdad14a5 | |
parent | a54132090831711da0b2c96869b48539de2e09a1 (diff) | |
download | bcm5719-llvm-21a12fc69ac28a41efe417ad45ef6aebbb062195.tar.gz bcm5719-llvm-21a12fc69ac28a41efe417ad45ef6aebbb062195.zip |
ELF: Create .gnu.version and .gnu.version_r sections when linking against versioned DSOs.
Differential Revision: http://reviews.llvm.org/D19464
llvm-svn: 267775
-rw-r--r-- | lld/ELF/InputFiles.cpp | 61 | ||||
-rw-r--r-- | lld/ELF/InputFiles.h | 19 | ||||
-rw-r--r-- | lld/ELF/OutputSections.cpp | 112 | ||||
-rw-r--r-- | lld/ELF/OutputSections.h | 49 | ||||
-rw-r--r-- | lld/ELF/Symbols.h | 14 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 13 | ||||
-rwxr-xr-x | lld/test/ELF/Inputs/verneed.so.sh | 58 | ||||
-rwxr-xr-x | lld/test/ELF/Inputs/verneed1.so | bin | 0 -> 2632 bytes | |||
-rwxr-xr-x | lld/test/ELF/Inputs/verneed2.so | bin | 0 -> 2200 bytes | |||
-rw-r--r-- | lld/test/ELF/verneed-local.s | 8 | ||||
-rw-r--r-- | lld/test/ELF/verneed.s | 104 |
11 files changed, 434 insertions, 4 deletions
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 86084707238..aa39bb67502 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -407,6 +407,12 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() { case SHT_SYMTAB_SHNDX: this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec)); break; + case SHT_GNU_versym: + this->VersymSec = &Sec; + break; + case SHT_GNU_verdef: + this->VerdefSec = &Sec; + break; } } @@ -430,17 +436,70 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() { } } +// Parse the version definitions in the object file if present. Returns a vector +// whose nth element contains a pointer to the Elf_Verdef for version identifier +// n. Version identifiers that are not definitions map to nullptr. The array +// always has at least length 1. +template <class ELFT> +std::vector<const typename ELFT::Verdef *> +SharedFile<ELFT>::parseVerdefs(const Elf_Versym *&Versym) { + std::vector<const Elf_Verdef *> Verdefs(1); + // We only need to process symbol versions for this DSO if it has both a + // versym and a verdef section, which indicates that the DSO contains symbol + // version definitions. + if (!VersymSec || !VerdefSec) + return Verdefs; + + // The location of the first global versym entry. + Versym = reinterpret_cast<const Elf_Versym *>(this->ELFObj.base() + + VersymSec->sh_offset) + + this->Symtab->sh_info; + + // We cannot determine the largest verdef identifier without inspecting + // every Elf_Verdef, but both bfd and gold assign verdef identifiers + // sequentially starting from 1, so we predict that the largest identifier + // will be VerdefCount. + unsigned VerdefCount = VerdefSec->sh_info; + Verdefs.resize(VerdefCount + 1); + + // Build the Verdefs array by following the chain of Elf_Verdef objects + // from the start of the .gnu.version_d section. + const uint8_t *Verdef = this->ELFObj.base() + VerdefSec->sh_offset; + for (unsigned I = 0; I != VerdefCount; ++I) { + auto *CurVerdef = reinterpret_cast<const Elf_Verdef *>(Verdef); + Verdef += CurVerdef->vd_next; + unsigned VerdefIndex = CurVerdef->vd_ndx; + if (Verdefs.size() <= VerdefIndex) + Verdefs.resize(VerdefIndex + 1); + Verdefs[VerdefIndex] = CurVerdef; + } + + return Verdefs; +} + // Fully parse the shared object file. This must be called after parseSoName(). template <class ELFT> void SharedFile<ELFT>::parseRest() { + // Create mapping from version identifiers to Elf_Verdef entries. + const Elf_Versym *Versym = nullptr; + std::vector<const Elf_Verdef *> Verdefs = parseVerdefs(Versym); + Elf_Sym_Range Syms = this->getElfSymbols(true); uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end()); SymbolBodies.reserve(NumSymbols); for (const Elf_Sym &Sym : Syms) { + unsigned VersymIndex = 0; + if (Versym) { + VersymIndex = Versym->vs_index; + ++Versym; + // Ignore local symbols and non-default versions. + if (VersymIndex == 0 || (VersymIndex & VERSYM_HIDDEN)) + continue; + } StringRef Name = check(Sym.getName(this->StringTable)); if (Sym.isUndefined()) Undefs.push_back(Name); else - SymbolBodies.emplace_back(this, Name, Sym); + SymbolBodies.emplace_back(this, Name, Sym, Verdefs[VersymIndex]); } } diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h index ca6eeb37675..0c9a2220e1d 100644 --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -24,6 +24,8 @@ #include "llvm/Object/IRObjectFile.h" #include "llvm/Support/StringSaver.h" +#include <map> + namespace lld { namespace elf { @@ -245,10 +247,14 @@ template <class ELFT> class SharedFile : public ELFFileBase<ELFT> { typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::Word Elf_Word; typedef typename ELFT::SymRange Elf_Sym_Range; + typedef typename ELFT::Versym Elf_Versym; + typedef typename ELFT::Verdef Elf_Verdef; std::vector<SharedSymbol<ELFT>> SymbolBodies; std::vector<StringRef> Undefs; StringRef SoName; + const Elf_Shdr *VersymSec = nullptr; + const Elf_Shdr *VerdefSec = nullptr; public: StringRef getSoName() const { return SoName; } @@ -266,6 +272,19 @@ public: void parseSoName(); void parseRest(); + std::vector<const Elf_Verdef *> parseVerdefs(const Elf_Versym *&Versym); + + struct NeededVer { + // The string table offset of the version name in the output file. + size_t StrTab; + + // The version identifier for this version name. + uint16_t Index; + }; + + // Mapping from Elf_Verdef data structures to information about Elf_Vernaux + // data structures in the output file. + std::map<const Elf_Verdef *, NeededVer> VerdefMap; // Used for --as-needed bool AsNeeded = false; diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 15ddd9da318..00882741e06 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -654,6 +654,12 @@ 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()) { + Add({DT_VERSYM, Out<ELFT>::VerSym}); + Add({DT_VERNEED, Out<ELFT>::VerNeed}); + Add({DT_VERNEEDNUM, NeedNum}); + } + if (Config->EMachine == EM_MIPS) { Add({DT_MIPS_RLD_VERSION, 1}); Add({DT_MIPS_FLAGS, RHF_NOTPOT}); @@ -1514,6 +1520,102 @@ SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) { } template <class ELFT> +VersionTableSection<ELFT>::VersionTableSection() + : OutputSectionBase<ELFT>(".gnu.version", SHT_GNU_versym, SHF_ALLOC) {} + +template <class ELFT> void VersionTableSection<ELFT>::finalize() { + this->Header.sh_size = + sizeof(Elf_Versym) * (Out<ELFT>::DynSymTab->getSymbols().size() + 1); + this->Header.sh_entsize = sizeof(Elf_Versym); +} + +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 + // The reserved identifier for a non-versioned global symbol. + OutVersym->vs_index = 1; + ++OutVersym; + } +} + +template <class ELFT> +VersionNeedSection<ELFT>::VersionNeedSection() + : OutputSectionBase<ELFT>(".gnu.version_r", SHT_GNU_verneed, SHF_ALLOC) {} + +template <class ELFT> +void VersionNeedSection<ELFT>::addSymbol(SharedSymbol<ELFT> *SS) { + if (!SS->Verdef) { + // The reserved identifier for a non-versioned global symbol. + SS->VersionId = 1; + return; + } + SharedFile<ELFT> *F = SS->File; + // If we don't already know that we need an Elf_Verneed for this DSO, prepare + // to create one by adding it to our needed list and creating a dynstr entry + // for the soname. + if (F->VerdefMap.empty()) + Needed.push_back({F, Out<ELFT>::DynStrTab->addString(F->getSoName())}); + typename SharedFile<ELFT>::NeededVer &NV = F->VerdefMap[SS->Verdef]; + // If we don't already know that we need an Elf_Vernaux for this Elf_Verdef, + // prepare to create one by allocating a version identifier and creating a + // dynstr entry for the version name. + if (NV.Index == 0) { + NV.StrTab = Out<ELFT>::DynStrTab->addString( + SS->File->getStringTable().data() + SS->Verdef->getAux()->vda_name); + NV.Index = NextIndex++; + } + SS->VersionId = NV.Index; +} + +template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) { + // The Elf_Verneeds need to appear first, followed by the Elf_Vernauxs. + auto *Verneed = reinterpret_cast<Elf_Verneed *>(Buf); + auto *Vernaux = reinterpret_cast<Elf_Vernaux *>(Verneed + Needed.size()); + + for (std::pair<SharedFile<ELFT> *, size_t> &P : Needed) { + // Create an Elf_Verneed for this DSO. + Verneed->vn_version = 1; + Verneed->vn_cnt = P.first->VerdefMap.size(); + Verneed->vn_file = P.second; + Verneed->vn_aux = + reinterpret_cast<char *>(Vernaux) - reinterpret_cast<char *>(Verneed); + Verneed->vn_next = sizeof(Elf_Verneed); + ++Verneed; + + // Create the Elf_Vernauxs for this Elf_Verneed. The loop iterates over + // VerdefMap, which will only contain references to needed version + // definitions. Each Elf_Vernaux is based on the information contained in + // the Elf_Verdef in the source DSO. This loop iterates over a std::map of + // pointers, but is deterministic because the pointers refer to Elf_Verdef + // data structures within a single input file. + for (auto &NV : P.first->VerdefMap) { + Vernaux->vna_hash = NV.first->vd_hash; + Vernaux->vna_flags = 0; + Vernaux->vna_other = NV.second.Index; + Vernaux->vna_name = NV.second.StrTab; + Vernaux->vna_next = sizeof(Elf_Vernaux); + ++Vernaux; + } + + Vernaux[-1].vna_next = 0; + } + Verneed[-1].vn_next = 0; +} + +template <class ELFT> void VersionNeedSection<ELFT>::finalize() { + this->Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex; + this->Header.sh_info = Needed.size(); + unsigned Size = Needed.size() * sizeof(Elf_Verneed); + for (std::pair<SharedFile<ELFT> *, size_t> &P : Needed) + Size += P.first->VerdefMap.size() * sizeof(Elf_Vernaux); + this->Header.sh_size = Size; +} + +template <class ELFT> BuildIdSection<ELFT>::BuildIdSection(size_t HashSize) : OutputSectionBase<ELFT>(".note.gnu.build-id", SHT_NOTE, SHF_ALLOC), HashSize(HashSize) { @@ -1666,6 +1768,16 @@ template class SymbolTableSection<ELF32BE>; template class SymbolTableSection<ELF64LE>; template class SymbolTableSection<ELF64BE>; +template class VersionTableSection<ELF32LE>; +template class VersionTableSection<ELF32BE>; +template class VersionTableSection<ELF64LE>; +template class VersionTableSection<ELF64BE>; + +template class VersionNeedSection<ELF32LE>; +template class VersionNeedSection<ELF32BE>; +template class VersionNeedSection<ELF64LE>; +template class VersionNeedSection<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 19ea8ddaa84..f9c4b6eccbc 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -33,6 +33,8 @@ template <class ELFT> class MergeInputSection; template <class ELFT> class MipsReginfoInputSection; template <class ELFT> class OutputSection; template <class ELFT> class ObjectFile; +template <class ELFT> class SharedFile; +template <class ELFT> class SharedSymbol; template <class ELFT> class DefinedRegular; template <class ELFT> @@ -222,6 +224,49 @@ private: std::vector<std::pair<SymbolBody *, size_t>> Symbols; }; +// For more information about .gnu.version and .gnu.version_r see: +// https://www.akkadia.org/drepper/symbol-versioning + +// 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. +template <class ELFT> +class VersionTableSection final : public OutputSectionBase<ELFT> { + typedef typename ELFT::Versym Elf_Versym; + +public: + VersionTableSection(); + void finalize() override; + void writeTo(uint8_t *Buf) override; +}; + +// The .gnu.version_r section defines the version identifiers used by +// .gnu.version. It contains a linked list of Elf_Verneed data structures. Each +// Elf_Verneed specifies the version requirements for a single DSO, and contains +// a reference to a linked list of Elf_Vernaux data structures which define the +// mapping from version identifiers to version names. +template <class ELFT> +class VersionNeedSection final : public OutputSectionBase<ELFT> { + typedef typename ELFT::Verneed Elf_Verneed; + typedef typename ELFT::Vernaux Elf_Vernaux; + + // A vector of shared files that need Elf_Verneed data structures and the + // 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; + +public: + VersionNeedSection(); + void addSymbol(SharedSymbol<ELFT> *SS); + void finalize() override; + void writeTo(uint8_t *Buf) override; + size_t getNeedNum() const { return Needed.size(); } +}; + template <class ELFT> class RelocationSection final : public OutputSectionBase<ELFT> { typedef typename ELFT::Rel Elf_Rel; @@ -562,6 +607,8 @@ template <class ELFT> struct Out { static StringTableSection<ELFT> *StrTab; static SymbolTableSection<ELFT> *DynSymTab; static SymbolTableSection<ELFT> *SymTab; + static VersionTableSection<ELFT> *VerSym; + static VersionNeedSection<ELFT> *VerNeed; static Elf_Phdr *TlsPhdr; static OutputSectionBase<ELFT> *ElfHeader; static OutputSectionBase<ELFT> *ProgramHeaders; @@ -587,6 +634,8 @@ 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> VersionTableSection<ELFT> *Out<ELFT>::VerSym; +template <class ELFT> VersionNeedSection<ELFT> *Out<ELFT>::VerNeed; template <class ELFT> typename ELFT::Phdr *Out<ELFT>::TlsPhdr; template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::ElfHeader; template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::ProgramHeaders; diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 48f704329e0..dd06565a373 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -324,6 +324,7 @@ public: template <class ELFT> class SharedSymbol : public Defined { typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::Verdef Elf_Verdef; typedef typename ELFT::uint uintX_t; public: @@ -331,10 +332,11 @@ public: return S->kind() == SymbolBody::SharedKind; } - SharedSymbol(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym) + SharedSymbol(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym, + const Elf_Verdef *Verdef) : Defined(SymbolBody::SharedKind, Name, Sym.getBinding(), Sym.st_other, Sym.getType()), - File(F), Sym(Sym) { + File(F), Sym(Sym), Verdef(Verdef) { // IFuncs defined in DSOs are treated as functions by the static linker. if (isGnuIFunc()) Type = llvm::ELF::STT_FUNC; @@ -343,6 +345,14 @@ 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; + }; + // OffsetInBss is significant only when needsCopy() is true. uintX_t OffsetInBss = 0; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 5caa95a86c1..7799a7030b9 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -132,6 +132,8 @@ template <class ELFT> void elf::writeResult(SymbolTable<ELFT> *Symtab) { StringTableSection<ELFT> DynStrTab(".dynstr", true); StringTableSection<ELFT> ShStrTab(".shstrtab", false); SymbolTableSection<ELFT> DynSymTab(*Symtab, DynStrTab); + VersionTableSection<ELFT> VerSym; + VersionNeedSection<ELFT> VerNeed; OutputSectionBase<ELFT> ElfHeader("", 0, SHF_ALLOC); ElfHeader.setSize(sizeof(Elf_Ehdr)); @@ -195,6 +197,8 @@ 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>::VerSym = &VerSym; + Out<ELFT>::VerNeed = &VerNeed; Out<ELFT>::Bss = nullptr; Out<ELFT>::MipsRldMap = MipsRldMap.get(); Out<ELFT>::Opd = nullptr; @@ -1367,8 +1371,11 @@ template <class ELFT> void Writer<ELFT>::createSections() { if (Out<ELFT>::SymTab) Out<ELFT>::SymTab->addSymbol(Body); - if (isOutputDynamic() && S->includeInDynsym()) + if (isOutputDynamic() && S->includeInDynsym()) { Out<ELFT>::DynSymTab->addSymbol(Body); + if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(Body)) + Out<ELFT>::VerNeed->addSymbol(SS); + } } // Do not proceed if there was an undefined symbol. @@ -1436,6 +1443,10 @@ template <class ELFT> void Writer<ELFT>::addPredefinedSections() { Add(Out<ELFT>::StrTab); if (isOutputDynamic()) { Add(Out<ELFT>::DynSymTab); + if (Out<ELFT>::VerNeed->getNeedNum() != 0) { + Add(Out<ELFT>::VerSym); + Add(Out<ELFT>::VerNeed); + } Add(Out<ELFT>::GnuHashTab); Add(Out<ELFT>::HashTab); Add(Out<ELFT>::Dynamic); diff --git a/lld/test/ELF/Inputs/verneed.so.sh b/lld/test/ELF/Inputs/verneed.so.sh new file mode 100755 index 00000000000..3423f678e47 --- /dev/null +++ b/lld/test/ELF/Inputs/verneed.so.sh @@ -0,0 +1,58 @@ +#!/bin/sh -eu + +# This script was used to produce the verneed{1,2}.so files. + +tmp=$(mktemp -d) + +echo "v1 {}; v2 {}; v3 {}; { local: *; };" > $tmp/verneed.script + +cat > $tmp/verneed1.s <<eof +.globl f1_v1 +f1_v1: +ret + +.globl f1_v2 +f1_v2: +ret + +.globl f1_v3 +f1_v3: +ret + +.symver f1_v1, f1@v1 +.symver f1_v2, f1@v2 +.symver f1_v3, f1@@v3 + +.globl f2_v1 +f2_v1: +ret + +.globl f2_v2 +f2_v2: +ret + +.symver f2_v1, f2@v1 +.symver f2_v2, f2@@v2 + +.globl f3_v1 +f3_v1: +ret + +.symver f3_v1, f3@v1 +eof + +as -o $tmp/verneed1.o $tmp/verneed1.s +ld.gold -shared -o verneed1.so $tmp/verneed1.o --version-script $tmp/verneed.script -soname verneed1.so.0 + +cat > $tmp/verneed2.s <<eof +.globl g1_v1 +g1_v1: +ret + +.symver g1_v1, g1@@v1 +eof + +as -o $tmp/verneed2.o $tmp/verneed2.s +ld.gold -shared -o verneed2.so $tmp/verneed2.o --version-script $tmp/verneed.script -soname verneed2.so.0 + +rm -rf $tmp diff --git a/lld/test/ELF/Inputs/verneed1.so b/lld/test/ELF/Inputs/verneed1.so Binary files differnew file mode 100755 index 00000000000..744852b9660 --- /dev/null +++ b/lld/test/ELF/Inputs/verneed1.so diff --git a/lld/test/ELF/Inputs/verneed2.so b/lld/test/ELF/Inputs/verneed2.so Binary files differnew file mode 100755 index 00000000000..ba6c05ee6b1 --- /dev/null +++ b/lld/test/ELF/Inputs/verneed2.so diff --git a/lld/test/ELF/verneed-local.s b/lld/test/ELF/verneed-local.s new file mode 100644 index 00000000000..a50f670ed7b --- /dev/null +++ b/lld/test/ELF/verneed-local.s @@ -0,0 +1,8 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: not ld.lld %t.o %S/Inputs/verneed1.so -o %t 2>&1 | FileCheck %s + +# CHECK: undefined symbol: f3 in +.globl _start +_start: +call f3 diff --git a/lld/test/ELF/verneed.s b/lld/test/ELF/verneed.s new file mode 100644 index 00000000000..2f384537abd --- /dev/null +++ b/lld/test/ELF/verneed.s @@ -0,0 +1,104 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld %t.o %S/Inputs/verneed1.so %S/Inputs/verneed2.so -o %t +# RUN: llvm-readobj -sections -dyn-symbols -dynamic-table %t | FileCheck %s +# RUN: llvm-objdump -s %t | FileCheck --check-prefix=CONTENTS %s + +# CHECK: Index: 2 +# CHECK-NEXT: Name: .gnu.version (9) +# CHECK-NEXT: Type: SHT_GNU_versym (0x6FFFFFFF) +# CHECK-NEXT: Flags [ (0x2) +# CHECK-NEXT: SHF_ALLOC (0x2) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x10228 +# CHECK-NEXT: Offset: 0x228 +# CHECK-NEXT: Size: 8 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 0 +# CHECK-NEXT: EntrySize: 2 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Name: .gnu.version_r (22) +# CHECK-NEXT: Type: SHT_GNU_verneed (0x6FFFFFFE) +# CHECK-NEXT: Flags [ (0x2) +# CHECK-NEXT: SHF_ALLOC (0x2) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x10230 +# CHECK-NEXT: Offset: 0x230 +# CHECK-NEXT: Size: 80 +# CHECK-NEXT: Link: 5 +# CHECK-NEXT: Info: 2 +# CHECK-NEXT: AddressAlignment: 0 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } + +# CHECK: DynamicSymbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: @ (0) +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local (0x0) +# CHECK-NEXT: Type: None (0x0) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined (0x0) +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: f1@v3 (1) +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global (0x1) +# CHECK-NEXT: Type: None (0x0) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined (0x0) +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: f2@v2 (21) +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global (0x1) +# CHECK-NEXT: Type: None (0x0) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined (0x0) +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: g1@v1 (27) +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global (0x1) +# CHECK-NEXT: Type: None (0x0) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined (0x0) +# CHECK-NEXT: } +# CHECK-NEXT: ] + +# CHECK: 0x000000006FFFFFF0 VERSYM 0x10228 +# CHECK-NEXT: 0x000000006FFFFFFE VERNEED 0x10230 +# CHECK-NEXT: 0x000000006FFFFFFF VERNEEDNUM 2 + +# CONTENTS: Contents of section .gnu.version: +# CONTENTS-NEXT: 10228 00000200 03000400 +# CONTENTS-NEXT: Contents of section .gnu.version_r: +# vn_version +# vn_cnt +# vn_file vn_aux vn_next +# CONTENTS-NEXT: 10230 01000200 04000000 20000000 10000000 ........ ....... +# CONTENTS-NEXT: 10240 01000100 1e000000 30000000 00000000 ........0....... +# vna_hash vna_flags +# vna_other +# vna_name +# vna_next +# CONTENTS-NEXT: 10250 92070000 00000300 18000000 10000000 ................ +# CONTENTS-NEXT: 10260 93070000 00000200 12000000 00000000 ................ +# CONTENTS-NEXT: 10270 91070000 00000400 2c000000 00000000 ........,....... +# CONTENTS: Contents of section .dynstr: +# CONTENTS-NEXT: 102a8 00663100 7665726e 65656431 2e736f2e .f1.verneed1.so. +# CONTENTS-NEXT: 102b8 30007633 00663200 76320067 31007665 0.v3.f2.v2.g1.ve +# CONTENTS-NEXT: 102c8 726e6565 64322e73 6f2e3000 763100 rneed2.so.0.v1. + +.globl _start +_start: +call f1 +call f2 +call g1 |