[ELF] - Recommit r273143("[ELF] - Basic versioned symbols support implemented.")
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
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index 4b71874..2f0bd9e 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -591,6 +591,11 @@
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 @@
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) {
@@ -1435,6 +1446,68 @@
}
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) {
this->Header.sh_addralign = sizeof(uint16_t);
@@ -1453,10 +1526,7 @@
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;
}
}
@@ -1465,12 +1535,17 @@
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;
@@ -1488,7 +1563,7 @@
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) {
@@ -1744,6 +1819,11 @@
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>;