Skip to content

Commit

Permalink
[ELF] - Reorder local symbols.
Browse files Browse the repository at this point in the history
This fixes PR36716 (https://bugs.llvm.org/show_bug.cgi?id=36716),

Patch sorts local symbols to match the
following order: file1, local1, hidden1, file2, local2, hidden2 ...

Differential revision: https://reviews.llvm.org/D45325

llvm-svn: 329787
  • Loading branch information
George Rimar committed Apr 11, 2018
1 parent 27695da commit c552619
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 16 deletions.
25 changes: 22 additions & 3 deletions lld/ELF/SyntheticSections.cpp
Expand Up @@ -1545,16 +1545,35 @@ void SymbolTableBaseSection::finalizeContents() {
// The ELF spec requires that all local symbols precede global symbols, so we
// sort symbol entries in this function. (For .dynsym, we don't do that because
// symbols for dynamic linking are inherently all globals.)
//
// Aside from above, we put local symbols in groups starting with the STT_FILE
// symbol. That is convenient for purpose of identifying where are local symbols
// coming from.
void SymbolTableBaseSection::postThunkContents() {
if (this->Type == SHT_DYNSYM)
return;
// move all local symbols before global symbols.
auto It = std::stable_partition(

// Move all local symbols before global symbols.
auto E = std::stable_partition(
Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) {
return S.Sym->isLocal() || S.Sym->computeBinding() == STB_LOCAL;
});
size_t NumLocals = It - Symbols.begin();
size_t NumLocals = E - Symbols.begin();
getParent()->Info = NumLocals + 1;

// Assign the growing unique ID for each local symbol's file.
DenseMap<InputFile *, unsigned> FileIDs;
for (auto I = Symbols.begin(); I != E; ++I)
FileIDs.insert({I->Sym->File, FileIDs.size()});

// Sort the local symbols to group them by file. We do not need to care about
// the STT_FILE symbols, they are already naturally placed first in each group.
// That happens because STT_FILE is always the first symbol in the object and
// hence precede all other local symbols we add for a file.
std::stable_sort(Symbols.begin(), E,
[&](const SymbolTableEntry &L, const SymbolTableEntry &R) {
return FileIDs[L.Sym->File] < FileIDs[R.Sym->File];
});
}

void SymbolTableBaseSection::addSymbol(Symbol *B) {
Expand Down
8 changes: 4 additions & 4 deletions lld/ELF/Writer.cpp
Expand Up @@ -1673,15 +1673,15 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
} while (Changed);
}

// createThunks may have added local symbols to the static symbol table
applySynthetic({InX::SymTab},
[](SyntheticSection *SS) { SS->postThunkContents(); });

// Fill other section headers. The dynamic table is finalized
// at the end because some tags like RELSZ depend on result
// of finalizing other sections.
for (OutputSection *Sec : OutputSections)
Sec->finalize<ELFT>();

// createThunks may have added local symbols to the static symbol table
applySynthetic({InX::SymTab},
[](SyntheticSection *SS) { SS->postThunkContents(); });
}

// The linker is expected to define SECNAME_start and SECNAME_end
Expand Down
26 changes: 18 additions & 8 deletions lld/test/ELF/local-symbols-order.s
@@ -1,22 +1,32 @@
# REQUIRES: x86

# RUN: echo '.file "file2"; foo2:; .global bar2; .hidden bar2; bar2:' > %t2.s
# RUN: echo '.data; .file "file2"; foo2:; .global bar2; .hidden bar2; bar2:' > %t2.s
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t2.s -o %t2.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o

# RUN: ld.lld -o %t %t1.o %t2.o
# RUN: llvm-readobj -symbols -elf-output-style=GNU %t | FileCheck %s
# RUN: ld.lld -o %t %t1.o %t2.o --emit-relocs
# RUN: llvm-readobj -symbols -sections -elf-output-style=GNU %t | FileCheck %s

## Show the order of the local symbols produced currently by LLD.
## Check we sort local symbols to match the following order:
## file1, local1, section1, hidden1, file2, local2, section2, hidden2 ...

# CHECK: Section Headers:
# CHECK: [Nr] Name
# CHECK: [ [[ST:.*]]] .text
# CHECK: [ [[SD:.*]]] .data
# CHECK: [ [[SC:.*]]] .comment

# CHECK: Num: Value Size Type Bind Vis Ndx Name
# CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
# CHECK-NEXT: 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS file1
# CHECK-NEXT: 2: 0000000000201000 0 NOTYPE LOCAL DEFAULT 1 foo1
# CHECK-NEXT: 3: 0000000000000000 0 FILE LOCAL DEFAULT ABS file2
# CHECK-NEXT: 4: 0000000000201000 0 NOTYPE LOCAL DEFAULT 1 foo2
# CHECK-NEXT: 5: 0000000000201000 0 NOTYPE LOCAL HIDDEN 1 bar1
# CHECK-NEXT: 6: 0000000000201000 0 NOTYPE LOCAL HIDDEN 1 bar2
# CHECK-NEXT: 3: 0000000000201000 0 SECTION LOCAL DEFAULT [[ST]]
# CHECK-NEXT: 4: 0000000000201000 0 NOTYPE LOCAL HIDDEN 1 bar1
# CHECK-NEXT: 5: 0000000000000000 0 FILE LOCAL DEFAULT ABS file2
# CHECK-NEXT: 6: 0000000000201000 0 NOTYPE LOCAL DEFAULT 2 foo2
# CHECK-NEXT: 7: 0000000000201000 0 SECTION LOCAL DEFAULT [[SD]]
# CHECK-NEXT: 8: 0000000000201000 0 NOTYPE LOCAL HIDDEN 2 bar2
# CHECK-NEXT: 9: 0000000000000000 0 SECTION LOCAL DEFAULT [[SC]]

foo1:

Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/relocatable-comdat-multiple.s
Expand Up @@ -21,7 +21,7 @@
# CHECK-NEXT: Name: .group
# CHECK-NEXT: Index: 5
# CHECK-NEXT: Link: 8
# CHECK-NEXT: Info: 2
# CHECK-NEXT: Info: 6
# CHECK-NEXT: Type: COMDAT
# CHECK-NEXT: Signature: bbb
# CHECK-NEXT: Section(s) in group [
Expand Down

0 comments on commit c552619

Please sign in to comment.