[ELF] - Implemented version script hierarchies.

Patch implements hierarchies for version scripts. 
This allows to handle script files with dependencies, like next one has:

LIBSAMPLE_1.0{
  global:
  a;
};

LIBSAMPLE_2.0
{
  global:
  b;
}LIBSAMPLE_1.0;

Differential revision: http://reviews.llvm.org/D21556

llvm-svn: 273423
This commit is contained in:
George Rimar 2016-06-22 14:40:45 +00:00
parent dce8e4173b
commit 0ab48b7334
4 changed files with 84 additions and 4 deletions

View File

@ -37,6 +37,7 @@ enum class BuildIdKind { None, Fnv1, Md5, Sha1, Hexstring };
struct Version {
Version(llvm::StringRef Name) : Name(Name) {}
llvm::StringRef Name;
llvm::StringRef Parent;
std::vector<llvm::StringRef> Globals;
size_t NameOff; // Offset in string table.
};

View File

@ -1462,6 +1462,10 @@ template <class ELFT> void VersionDefinitionSection<ELFT>::finalize() {
this->Header.sh_size =
(sizeof(Elf_Verdef) + sizeof(Elf_Verdaux)) * getVerDefNum();
for (Version &V : Config->SymbolVersions)
if (!V.Parent.empty())
this->Header.sh_size += sizeof(Elf_Verdaux);
this->Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex;
this->Header.sh_addralign = sizeof(uint32_t);
@ -1471,12 +1475,22 @@ template <class ELFT> void VersionDefinitionSection<ELFT>::finalize() {
this->Header.sh_info = getVerDefNum();
}
static size_t getVersionNameStrTabOffset(StringRef Name) {
for (Version &V : Config->SymbolVersions)
if (V.Name == Name)
return V.NameOff;
error("unknown version name " + Name + " used as a dependency");
return 0;
}
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) {
size_t StrTabOffset, StringRef ParentName) {
bool HasParent = !ParentName.empty();
Verdef->vd_version = 1;
Verdef->vd_cnt = 1;
Verdef->vd_cnt = HasParent ? 2 : 1;
Verdef->vd_aux =
reinterpret_cast<char *>(Verdaux) - reinterpret_cast<char *>(Verdef);
Verdef->vd_next = sizeof(Elf_Verdef);
@ -1487,6 +1501,12 @@ static void writeDefinition(Elf_Verdef *&Verdef, Elf_Verdaux *&Verdaux,
++Verdef;
Verdaux->vda_name = StrTabOffset;
if (HasParent) {
Verdaux->vda_next = sizeof(Elf_Verdaux);
++Verdaux;
Verdaux->vda_name = getVersionNameStrTabOffset(ParentName);
}
Verdaux->vda_next = 0;
++Verdaux;
}
@ -1498,11 +1518,12 @@ void VersionDefinitionSection<ELFT>::writeTo(uint8_t *Buf) {
reinterpret_cast<Elf_Verdaux *>(Verdef + getVerDefNum());
writeDefinition(Verdef, Verdaux, VER_FLG_BASE, 1, getFileDefName(),
FileDefNameOff);
FileDefNameOff, "" /* Parent */);
uint32_t I = 2;
for (Version &V : Config->SymbolVersions)
writeDefinition(Verdef, Verdaux, 0 /* Flags */, I++, V.Name, V.NameOff);
writeDefinition(Verdef, Verdaux, 0 /* Flags */, I++, V.Name, V.NameOff,
V.Parent);
Verdef[-1].vd_next = 0;
}

View File

@ -94,6 +94,8 @@ void VersionScriptParser::parseVersion(StringRef Version) {
parseVersionSymbols(Version);
expect("}");
if (!Version.empty() && peek() != ";")
Config->SymbolVersions.back().Parent = next();
expect(";");
}

View File

@ -0,0 +1,56 @@
# 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: *; }LIBSAMPLE_1.0; \
# RUN: LIBSAMPLE_3.0{ \
# RUN: global: c; \
# RUN: local: *; }LIBSAMPLE_2.0;" > %t.script
# RUN: ld.lld --version-script %t.script -shared -soname shared %t.o -o %t.so
# RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s
# DSO: SHT_GNU_verdef {
# DSO-NEXT: Definition {
# DSO-NEXT: Version: 1
# DSO-NEXT: Flags: Base
# DSO-NEXT: Index: 1
# DSO-NEXT: Hash: 127830196
# DSO-NEXT: Name: shared
# DSO-NEXT: }
# DSO-NEXT: Definition {
# DSO-NEXT: Version: 1
# DSO-NEXT: Flags: 0x0
# DSO-NEXT: Index: 2
# DSO-NEXT: Hash: 98457184
# DSO-NEXT: Name: LIBSAMPLE_1.0
# DSO-NEXT: }
# DSO-NEXT: Definition {
# DSO-NEXT: Version: 1
# DSO-NEXT: Flags: 0x0
# DSO-NEXT: Index: 3
# DSO-NEXT: Hash: 98456416
# DSO-NEXT: Name: LIBSAMPLE_2.0
# DSO-NEXT: Predecessor: LIBSAMPLE_1.0
# DSO-NEXT: }
# DSO-NEXT: Definition {
# DSO-NEXT: Version: 1
# DSO-NEXT: Flags: 0x0
# DSO-NEXT: Index: 4
# DSO-NEXT: Hash: 98456672
# DSO-NEXT: Name: LIBSAMPLE_3.0
# DSO-NEXT: Predecessor: LIBSAMPLE_2.0
# DSO-NEXT: }
# DSO-NEXT: }
# RUN: echo "LIBSAMPLE_1.0{ \
# RUN: global: a; \
# RUN: local: *; }; \
# RUN: LIBSAMPLE_2.0{ \
# RUN: global: b; \
# RUN: local: *; }LIBSAMPLE_X.X; " > %t.script
# RUN: not ld.lld --version-script %t.script -shared %t.o -o %t.so 2>&1 \
# RUN: | FileCheck -check-prefix=ERR %s
# ERR: unknown version name LIBSAMPLE_X.X used as a dependency