forked from OSchip/llvm-project
ELF: Create .gnu.version and .gnu.version_r sections when linking against versioned DSOs.
Differential Revision: http://reviews.llvm.org/D19464 llvm-svn: 267775
This commit is contained in:
parent
a541320908
commit
21a12fc69a
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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});
|
||||
|
@ -1513,6 +1519,102 @@ SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
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),
|
||||
|
@ -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>;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
Binary file not shown.
Binary file not shown.
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue