Skip to content

Commit

Permalink
[ELF] - Recommit r273143("[ELF] - Basic versioned symbols support imp…
Browse files Browse the repository at this point in the history
…lemented.")

With fix:
-soname flag was not set in testcase. Hash calculated for base def was different on local
and bot machines because filename fos used for calculating.

Initial commit message:
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: 273152
  • Loading branch information
George Rimar committed Jun 20, 2016
1 parent 7b8481b commit d356630
Show file tree
Hide file tree
Showing 13 changed files with 409 additions and 42 deletions.
10 changes: 10 additions & 0 deletions lld/ELF/Config.h
Expand Up @@ -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.
Expand All @@ -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;
Expand Down
96 changes: 88 additions & 8 deletions lld/ELF/OutputSections.cpp
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -1434,6 +1445,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) {
Expand All @@ -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;
}
}
Expand All @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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>;
Expand Down
30 changes: 26 additions & 4 deletions lld/ELF/OutputSections.h
Expand Up @@ -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;
Expand Down Expand Up @@ -248,10 +249,30 @@ class SymbolTableSection final : public OutputSectionBase<ELFT> {
// 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;
Expand All @@ -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();
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
28 changes: 18 additions & 10 deletions lld/ELF/SymbolListFile.cpp
Expand Up @@ -77,21 +77,21 @@ class VersionScriptParser final : public ScriptParserBase {
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(";");
Expand All @@ -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(";");
}
}
Expand All @@ -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());
}
}

Expand Down
1 change: 1 addition & 0 deletions lld/ELF/SymbolListFile.h
Expand Up @@ -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 {
Expand Down
26 changes: 22 additions & 4 deletions lld/ELF/SymbolTable.cpp
Expand Up @@ -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];
Expand Down Expand Up @@ -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>;
Expand Down
2 changes: 1 addition & 1 deletion lld/ELF/Symbols.cpp
Expand Up @@ -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);
}

Expand Down

0 comments on commit d356630

Please sign in to comment.