If --dynamic-list is given, only those symbols are preemptible

Patch by Rafael Espíndola.

This is PR34053.

The implementation is a bit of a hack, given the precise location where
IsPreemtible is set, it cannot be used from
SymbolTable::handleAnonymousVersion.

I could add another method to SymbolTable if you think that would be
better.

Differential Revision: https://reviews.llvm.org/D36499

llvm-svn: 311468
This commit is contained in:
Rui Ueyama 2017-08-22 16:31:47 +00:00
parent 2724d45325
commit 9cbbacb910
6 changed files with 105 additions and 4 deletions

View File

@ -104,6 +104,7 @@ struct Configuration {
std::vector<llvm::StringRef> SearchPaths;
std::vector<llvm::StringRef> SymbolOrderingFile;
std::vector<llvm::StringRef> Undefined;
std::vector<SymbolVersion> DynamicList;
std::vector<SymbolVersion> VersionScriptGlobals;
std::vector<SymbolVersion> VersionScriptLocals;
std::vector<uint8_t> BuildIdVector;

View File

@ -175,9 +175,22 @@ static ExprValue bitOr(ExprValue A, ExprValue B) {
void ScriptParser::readDynamicList() {
expect("{");
readAnonymousDeclaration();
if (!atEOF())
std::vector<SymbolVersion> Locals;
std::vector<SymbolVersion> Globals;
std::tie(Locals, Globals) = readSymbols();
expect(";");
if (!atEOF()) {
setError("EOF expected, but got " + next());
return;
}
if (!Locals.empty()) {
setError("\"local:\" scope not supported in --dynamic-list");
return;
}
for (SymbolVersion V : Globals)
Config->DynamicList.push_back(V);
}
void ScriptParser::readVersionScript() {

View File

@ -680,6 +680,24 @@ void SymbolTable::handleAnonymousVersion() {
assignWildcardVersion(Ver, VER_NDX_LOCAL);
}
// Handles -dynamic-list.
void SymbolTable::handleDynamicList() {
for (SymbolVersion &Ver : Config->DynamicList) {
std::vector<SymbolBody *> Syms;
if (Ver.HasWildcard)
Syms = findByVersion(Ver);
else
Syms = findAllByVersion(Ver);
for (SymbolBody *B : Syms) {
if (!Config->Shared)
B->symbol()->VersionId = VER_NDX_GLOBAL;
else if (B->symbol()->includeInDynsym())
B->IsPreemptible = true;
}
}
}
// Set symbol versions to symbols. This function handles patterns
// containing no wildcard characters.
void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId,
@ -729,6 +747,7 @@ void SymbolTable::assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId) {
void SymbolTable::scanVersionScript() {
// Handle edge cases first.
handleAnonymousVersion();
handleDynamicList();
// Now we have version definitions, so we need to set version ids to symbols.
// Each version definition has a glob pattern, and all symbols that match

View File

@ -90,6 +90,8 @@ public:
void trace(StringRef Name);
void handleDynamicList();
private:
std::vector<SymbolBody *> findByVersion(SymbolVersion Ver);
std::vector<SymbolBody *> findAllByVersion(SymbolVersion Ver);

View File

@ -1219,8 +1219,9 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
applySynthetic({In<ELFT>::EhFrame},
[](SyntheticSection *SS) { SS->finalizeContents(); });
for (Symbol *S : Symtab->getSymbols())
S->body()->IsPreemptible = computeIsPreemptible(*S->body());
if (Config->DynamicList.empty())
for (Symbol *S : Symtab->getSymbols())
S->body()->IsPreemptible = computeIsPreemptible(*S->body());
// Scan relocations. This must be done after every symbol is declared so that
// we can correctly decide if a dynamic relocation is needed.

View File

@ -0,0 +1,65 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
# RUN: echo "{ foo; zed; };" > %t.list
# RUN: echo "{ global: foo; bar; local: *; };" > %t.vers
# RUN: ld.lld -fatal-warnings -dynamic-list %t.list -version-script %t.vers -shared %t.o -o %t.so
# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=RELOCS %s
# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=DYNSYMS %s
# RELOCS: Relocations [
# RELOCS-NEXT: Section ({{.*}}) .rela.plt {
# RELOCS-NEXT: R_X86_64_JUMP_SLOT foo 0x0
# RELOCS-NEXT: }
# RELOCS-NEXT: ]
# DYNSYMS: DynamicSymbols [
# DYNSYMS-NEXT: Symbol {
# DYNSYMS-NEXT: Name: @ (0)
# DYNSYMS-NEXT: Value: 0x0
# DYNSYMS-NEXT: Size: 0
# DYNSYMS-NEXT: Binding: Local
# DYNSYMS-NEXT: Type: None
# DYNSYMS-NEXT: Other: 0
# DYNSYMS-NEXT: Section: Undefined
# DYNSYMS-NEXT: }
# DYNSYMS-NEXT: Symbol {
# DYNSYMS-NEXT: Name: bar@
# DYNSYMS-NEXT: Value:
# DYNSYMS-NEXT: Size:
# DYNSYMS-NEXT: Binding: Global
# DYNSYMS-NEXT: Type:
# DYNSYMS-NEXT: Other:
# DYNSYMS-NEXT: Section:
# DYNSYMS-NEXT: }
# DYNSYMS-NEXT: Symbol {
# DYNSYMS-NEXT: Name: foo@
# DYNSYMS-NEXT: Value:
# DYNSYMS-NEXT: Size:
# DYNSYMS-NEXT: Binding: Global
# DYNSYMS-NEXT: Type:
# DYNSYMS-NEXT: Other:
# DYNSYMS-NEXT: Section:
# DYNSYMS-NEXT: }
# DYNSYMS-NEXT: ]
.globl foo
foo:
ret
.globl bar
bar:
ret
.globl baz
baz:
ret
.globl zed
zed:
ret
call foo@PLT
call bar@PLT
call baz@PLT
call zed@PLT