forked from OSchip/llvm-project
[ELF] - Basic versioned symbols support implemented.
Patch implements basic support of versioned symbols. There is no wildcards patterns matching except local: *; There is no support for hierarchies. There is no support for symbols overrides (@ vs @@ not handled). This patch allows programs that using simple scripts to link and run. Differential revision: http://reviews.llvm.org/D21018 llvm-svn: 273143
This commit is contained in:
parent
06e930d37a
commit
c31fee2212
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
@ -1432,6 +1443,68 @@ SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -1451,10 +1524,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;
|
||||
}
|
||||
}
|
||||
|
@ -1463,12 +1533,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;
|
||||
|
@ -1486,7 +1561,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) {
|
||||
|
@ -1742,6 +1817,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>;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
.text
|
||||
.globl _start
|
||||
_start:
|
||||
callq a
|
||||
callq b
|
||||
callq c
|
|
@ -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: ]
|
|
@ -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 %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: 146942095
|
||||
# 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
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue