Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -1545,16 +1545,33 @@ // 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 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 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 file symbol locations, they are naturally placed first in the group. + 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) { Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -494,7 +494,7 @@ static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName, const Symbol &B) { - if (B.isFile() || B.isSection()) + if (B.isSection()) return false; // If sym references a section in a discarded group, don't keep it. @@ -1658,12 +1658,21 @@ // Fill other section headers. The dynamic table is finalized // at the end because some tags like RELSZ depend on result // of finalizing other sections. + // + // We do not finalize SHT_GROUP here. We can see this type only for + // -r output and it can only be finalized after finalization of the + // symbol table done in postThunkContents() below. for (OutputSection *Sec : OutputSections) - Sec->finalize(); + if (Sec->Type != SHT_GROUP) + Sec->finalize(); // createThunks may have added local symbols to the static symbol table applySynthetic({InX::SymTab}, [](SyntheticSection *SS) { SS->postThunkContents(); }); + + for (OutputSection *Sec : OutputSections) + if (Sec->Type == SHT_GROUP) + Sec->finalize(); } // The linker is expected to define SECNAME_start and SECNAME_end Index: test/ELF/file-sym.s =================================================================== --- test/ELF/file-sym.s +++ test/ELF/file-sym.s @@ -1,12 +0,0 @@ -# Check that we do not keep STT_FILE symbols in the symbol table - -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: ld.lld %t.o -shared -o %t.so -# RUN: llvm-readobj -symbols %t.so | FileCheck %s - -# REQUIRES: x86 - -# CHECK-NOT: Name: xxx - -.file "xxx" -.file "" Index: test/ELF/local-symbol-order.s =================================================================== --- test/ELF/local-symbol-order.s +++ test/ELF/local-symbol-order.s @@ -0,0 +1,28 @@ +# REQUIRES: x86 + +# RUN: echo '.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 + +## Check we sort local symbols to match the +## following order: file1, local1, hidden1, file2, local2, hidden2 ... + +# 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: 0000000000201000 0 NOTYPE LOCAL HIDDEN 1 bar1 +# CHECK-NEXT: 4: 0000000000000000 0 FILE LOCAL DEFAULT ABS file2 +# CHECK-NEXT: 5: 0000000000201000 0 NOTYPE LOCAL DEFAULT 1 foo2 +# CHECK-NEXT: 6: 0000000000201000 0 NOTYPE LOCAL HIDDEN 1 bar2 + +foo1: + +.global bar1 +.hidden bar1 +bar1: + +.file "file1" Index: test/ELF/lto/data-ordering-lto.s =================================================================== --- test/ELF/lto/data-ordering-lto.s +++ test/ELF/lto/data-ordering-lto.s @@ -12,13 +12,14 @@ # Check that the order is tin -> dipsy -> pat. -# CHECK: Symbol table '.symtab' contains 5 entries: +# CHECK: Symbol table '.symtab' contains 6 entries: # CHECK-NEXT: Num: Value Size Type Bind Vis Ndx Name # CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND -# CHECK-NEXT: 1: 0000000000201000 0 NOTYPE GLOBAL DEFAULT 1 _start -# CHECK-NEXT: 2: 0000000000202004 4 OBJECT GLOBAL DEFAULT 2 dipsy -# CHECK-NEXT: 3: 0000000000202008 4 OBJECT GLOBAL DEFAULT 2 pat -# CHECK-NEXT: 4: 0000000000202000 4 OBJECT GLOBAL DEFAULT 2 tin +# CHECK-NEXT: 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS {{.*}}.o +# CHECK-NEXT: 2: 0000000000201000 0 NOTYPE GLOBAL DEFAULT 1 _start +# CHECK-NEXT: 3: 0000000000202004 4 OBJECT GLOBAL DEFAULT 2 dipsy +# CHECK-NEXT: 4: 0000000000202008 4 OBJECT GLOBAL DEFAULT 2 pat +# CHECK-NEXT: 5: 0000000000202000 4 OBJECT GLOBAL DEFAULT 2 tin .globl _start _start: Index: test/ELF/lto/parallel-internalize.ll =================================================================== --- test/ELF/lto/parallel-internalize.ll +++ test/ELF/lto/parallel-internalize.ll @@ -18,6 +18,24 @@ ; CHECK-NEXT: Section: Undefined (0x0) ; CHECK-NEXT: } ; CHECK-NEXT: Symbol { +; CHECK-NEXT: Name: {{.*}}.o +; CHECK-NEXT: Value: 0x0 +; CHECK-NEXT: Size: 0 +; CHECK-NEXT: Binding: Local +; CHECK-NEXT: Type: File +; CHECK-NEXT: Other: 0 +; CHECK-NEXT: Section: Absolute +; CHECK-NEXT: } +; CHECK-NEXT: Symbol { +; CHECK-NEXT: Name: {{.*}}.o +; CHECK-NEXT: Value: 0x0 +; CHECK-NEXT: Size: 0 +; CHECK-NEXT: Binding: Local +; CHECK-NEXT: Type: File +; CHECK-NEXT: Other: 0 +; CHECK-NEXT: Section: Absolute +; CHECK-NEXT: } +; CHECK-NEXT: Symbol { ; CHECK-NEXT: Name: bar ; CHECK-NEXT: Value: 0x201010 ; CHECK-NEXT: Size: 8 Index: test/ELF/lto/relocatable.ll =================================================================== --- test/ELF/lto/relocatable.ll +++ test/ELF/lto/relocatable.ll @@ -14,6 +14,15 @@ ; CHECK-NEXT: Section: Undefined ; CHECK-NEXT: } ; CHECK-NEXT: Symbol { +; CHECK-NEXT: Name: {{.*}}.o +; CHECK-NEXT: Value: 0x0 +; CHECK-NEXT: Size: 0 +; CHECK-NEXT: Binding: Local +; CHECK-NEXT: Type: File +; CHECK-NEXT: Other: 0 +; CHECK-NEXT: Section: Absolute +; CHECK-NEXT: } +; CHECK-NEXT: Symbol { ; CHECK-NEXT: Name: ; CHECK-NEXT: Value: 0x0 ; CHECK-NEXT: Size: 0 Index: test/ELF/lto/symbol-ordering-lto.s =================================================================== --- test/ELF/lto/symbol-ordering-lto.s +++ test/ELF/lto/symbol-ordering-lto.s @@ -12,12 +12,13 @@ # Check that the order is tin -> _start -> pat. -# CHECK: Symbol table '.symtab' contains 4 entries: +# CHECK: Symbol table '.symtab' contains 5 entries: # CHECK-NEXT: Num: Value Size Type Bind Vis Ndx Name # CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND -# CHECK-NEXT: 1: 0000000000201008 0 NOTYPE GLOBAL DEFAULT 1 _start -# CHECK-NEXT: 2: 0000000000201020 6 FUNC GLOBAL DEFAULT 1 pat -# CHECK-NEXT: 3: 0000000000201000 6 FUNC GLOBAL DEFAULT 1 tin +# CHECK-NEXT: 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS {{.*}}.o +# CHECK-NEXT: 2: 0000000000201008 0 NOTYPE GLOBAL DEFAULT 1 _start +# CHECK-NEXT: 3: 0000000000201020 6 FUNC GLOBAL DEFAULT 1 pat +# CHECK-NEXT: 4: 0000000000201000 6 FUNC GLOBAL DEFAULT 1 tin .globl _start _start: Index: test/ELF/relocatable-comdat-multiple.s =================================================================== --- test/ELF/relocatable-comdat-multiple.s +++ test/ELF/relocatable-comdat-multiple.s @@ -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 [