From c7e6d14c6c30c6798b14faf2a28e5be642b78ad8 Mon Sep 17 00:00:00 2001 From: Eugene Leviant Date: Tue, 23 Jul 2019 08:03:30 +0000 Subject: [PATCH] [llvm-objcopy] Allow strip symtab in executables and DSOs Re-commit of the patch after addressing -Wl,--emit-relocs case. Differential revision: https://reviews.llvm.org/D61672 llvm-svn: 366787 --- .../preserve-segment-contents-ehdr-phdrs.test | 2 +- .../ELF/remove-multiple-sections.test | 28 ----------------- .../ELF/segment-shift-section-remove.test | 30 +------------------ .../ELF/segment-test-remove-section.test | 30 +------------------ .../ELF/strip-unneeded-all-symbols.test | 21 +++++++++++++ llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp | 2 +- llvm/tools/llvm-objcopy/ELF/Object.cpp | 21 +++++++++++++ llvm/tools/llvm-objcopy/ELF/Object.h | 5 ++++ 8 files changed, 51 insertions(+), 88 deletions(-) create mode 100644 llvm/test/tools/llvm-objcopy/ELF/strip-unneeded-all-symbols.test diff --git a/llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents-ehdr-phdrs.test b/llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents-ehdr-phdrs.test index 9dc63d753f60..3352313c2714 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents-ehdr-phdrs.test +++ b/llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents-ehdr-phdrs.test @@ -13,7 +13,7 @@ # BEFORE: Type: PT_LOAD # BEFORE-NEXT: Offset: 0x240 -# AFTER: SectionHeaderCount: 5 +# AFTER: SectionHeaderCount: 3 # AFTER: Type: PT_LOAD # AFTER-NEXT: Offset: 0x0 # AFTER: Type: PT_LOAD diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-multiple-sections.test b/llvm/test/tools/llvm-objcopy/ELF/remove-multiple-sections.test index 1f1bc4ce1910..a162303ccacf 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/remove-multiple-sections.test +++ b/llvm/test/tools/llvm-objcopy/ELF/remove-multiple-sections.test @@ -87,34 +87,6 @@ Sections: # CHECK: } # CHECK: Section { # CHECK: Index: 4 -# CHECK: Name: .symtab -# CHECK: Type: SHT_SYMTAB (0x2) -# CHECK: Flags [ (0x0) -# CHECK: ] -# CHECK: Address: 0x0 -# CHECK: Offset: -# CHECK: Size: -# CHECK: Link: 5 -# CHECK: Info: 1 -# CHECK: AddressAlignment: 8 -# CHECK: EntrySize: 24 -# CHECK: } -# CHECK: Section { -# CHECK: Index: 5 -# CHECK: Name: .strtab -# CHECK: Type: SHT_STRTAB (0x3) -# CHECK: Flags [ (0x0) -# CHECK: ] -# CHECK: Address: 0x0 -# CHECK: Offset: -# CHECK: Size: -# CHECK: Link: 0 -# CHECK: Info: 0 -# CHECK: AddressAlignment: 1 -# CHECK: EntrySize: 0 -# CHECK: } -# CHECK: Section { -# CHECK: Index: 6 # CHECK: Name: .shstrtab # CHECK: Type: SHT_STRTAB (0x3) # CHECK: Flags [ (0x0) diff --git a/llvm/test/tools/llvm-objcopy/ELF/segment-shift-section-remove.test b/llvm/test/tools/llvm-objcopy/ELF/segment-shift-section-remove.test index 563a9e3f836b..cef783cb9b29 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/segment-shift-section-remove.test +++ b/llvm/test/tools/llvm-objcopy/ELF/segment-shift-section-remove.test @@ -41,7 +41,7 @@ ProgramHeaders: Sections: - Section: .text3 -#CHECK: SectionHeaderCount: 6 +#CHECK: SectionHeaderCount: 4 # CHECK: Sections [ # CHECK-NEXT: Section { @@ -92,34 +92,6 @@ ProgramHeaders: # CHECK-NEXT: } # CHECK-NEXT: Section { # CHECK-NEXT: Index: 3 -# CHECK-NEXT: Name: .symtab -# CHECK-NEXT: Type: SHT_SYMTAB (0x2) -# CHECK-NEXT: Flags [ (0x0) -# CHECK-NEXT: ] -# CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x3000 -# CHECK-NEXT: Size: 24 -# CHECK-NEXT: Link: 4 -# CHECK-NEXT: Info: 1 -# CHECK-NEXT: AddressAlignment: 8 -# CHECK-NEXT: EntrySize: 24 -# CHECK-NEXT: } -# CHECK-NEXT: Section { -# CHECK-NEXT: Index: 4 -# CHECK-NEXT: Name: .strtab -# CHECK-NEXT: Type: SHT_STRTAB (0x3) -# CHECK-NEXT: Flags [ (0x0) -# CHECK-NEXT: ] -# CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x3018 -# CHECK-NEXT: Size: -# CHECK-NEXT: Link: 0 -# CHECK-NEXT: Info: 0 -# CHECK-NEXT: AddressAlignment: 1 -# CHECK-NEXT: EntrySize: 0 -# CHECK-NEXT: } -# CHECK-NEXT: Section { -# CHECK-NEXT: Index: 5 # CHECK-NEXT: Name: .shstrtab # CHECK-NEXT: Type: SHT_STRTAB (0x3) # CHECK-NEXT: Flags [ (0x0) diff --git a/llvm/test/tools/llvm-objcopy/ELF/segment-test-remove-section.test b/llvm/test/tools/llvm-objcopy/ELF/segment-test-remove-section.test index f9a5dd7811e7..60cd5f3483d3 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/segment-test-remove-section.test +++ b/llvm/test/tools/llvm-objcopy/ELF/segment-test-remove-section.test @@ -46,7 +46,7 @@ ProgramHeaders: # Make sure that when we remove a section we overwrite it with zeros # DATA: {{^[^[:blank:]]+}} 00 00 00 00 -#CHECK: SectionHeaderCount: 6 +#CHECK: SectionHeaderCount: 4 # CHECK: Sections [ # CHECK: Section { @@ -97,34 +97,6 @@ ProgramHeaders: # CHECK-NEXT: } # CHECK-NEXT: Section { # CHECK-NEXT: Index: 3 -# CHECK-NEXT: Name: .symtab -# CHECK-NEXT: Type: SHT_SYMTAB (0x2) -# CHECK-NEXT: Flags [ (0x0) -# CHECK-NEXT: ] -# CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: -# CHECK-NEXT: Size: -# CHECK-NEXT: Link: 4 -# CHECK-NEXT: Info: 1 -# CHECK-NEXT: AddressAlignment: 8 -# CHECK-NEXT: EntrySize: 24 -# CHECK-NEXT: } -# CHECK-NEXT: Section { -# CHECK-NEXT: Index: 4 -# CHECK-NEXT: Name: .strtab -# CHECK-NEXT: Type: SHT_STRTAB (0x3) -# CHECK-NEXT: Flags [ (0x0) -# CHECK-NEXT: ] -# CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: -# CHECK-NEXT: Size: -# CHECK-NEXT: Link: 0 -# CHECK-NEXT: Info: 0 -# CHECK-NEXT: AddressAlignment: 1 -# CHECK-NEXT: EntrySize: 0 -# CHECK-NEXT: } -# CHECK-NEXT: Section { -# CHECK-NEXT: Index: 5 # CHECK-NEXT: Name: .shstrtab # CHECK-NEXT: Type: SHT_STRTAB (0x3) # CHECK-NEXT: Flags [ (0x0) diff --git a/llvm/test/tools/llvm-objcopy/ELF/strip-unneeded-all-symbols.test b/llvm/test/tools/llvm-objcopy/ELF/strip-unneeded-all-symbols.test new file mode 100644 index 000000000000..e2fd42021158 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/ELF/strip-unneeded-all-symbols.test @@ -0,0 +1,21 @@ +## Stripping unneeded symbols from execuatble/DSO should +## eliminate the static symbol table, because it's not used +## by the dynamic loader. + +# RUN: yaml2obj %s > %t +# RUN: cp %t %t1 +# RUN: llvm-objcopy --strip-unneeded %t %t2 +# RUN: llvm-readobj --section-headers %t2 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Symbols: + - Name: bar + - Name: foo + Binding: STB_GLOBAL + +# CHECK-NOT: .symtab diff --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp index b366c6e55987..bbaac96f070b 100644 --- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -423,7 +423,7 @@ static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) { if ((Config.StripUnneeded || is_contained(Config.UnneededSymbolsToRemove, Sym.Name)) && - isUnneededSymbol(Sym)) + (!Obj.isRelocatable() || isUnneededSymbol(Sym))) return true; // We want to remove undefined symbols if all references have been stripped. diff --git a/llvm/tools/llvm-objcopy/ELF/Object.cpp b/llvm/tools/llvm-objcopy/ELF/Object.cpp index fa696380e17c..2d85b3ad36f8 100644 --- a/llvm/tools/llvm-objcopy/ELF/Object.cpp +++ b/llvm/tools/llvm-objcopy/ELF/Object.cpp @@ -1995,6 +1995,25 @@ template Error ELFWriter::write() { return Buf.commit(); } +static Error removeUnneededSections(Object &Obj) { + // We can remove an empty symbol table from non-relocatable objects. + // Relocatable objects typically have relocation sections whose + // sh_link field points to .symtab, so we can't remove .symtab + // even if it is empty. + if (Obj.isRelocatable() || Obj.SymbolTable == nullptr || + !Obj.SymbolTable->empty()) + return Error::success(); + + // .strtab can be used for section names. In such a case we shouldn't + // remove it. + auto *StrTab = Obj.SymbolTable->getStrTab() == Obj.SectionNames + ? nullptr + : Obj.SymbolTable->getStrTab(); + return Obj.removeSections(false, [&](const SectionBase &Sec) { + return &Sec == Obj.SymbolTable || &Sec == StrTab; + }); +} + template Error ELFWriter::finalize() { // It could happen that SectionNames has been removed and yet the user wants // a section header table output. We need to throw an error if a user tries @@ -2004,6 +2023,8 @@ template Error ELFWriter::finalize() { "cannot write section header table because " "section header string table was removed"); + if (Error E = removeUnneededSections(Obj)) + return E; Obj.sortSections(); // We need to assign indexes before we perform layout because we need to know diff --git a/llvm/tools/llvm-objcopy/ELF/Object.h b/llvm/tools/llvm-objcopy/ELF/Object.h index f3df93b9662f..3b4f3c7a0d72 100644 --- a/llvm/tools/llvm-objcopy/ELF/Object.h +++ b/llvm/tools/llvm-objcopy/ELF/Object.h @@ -1018,6 +1018,7 @@ public: uint32_t Flags; bool HadShdrs = true; + bool MustBeRelocatable = false; StringTableSection *SectionNames = nullptr; SymbolTableSection *SymbolTable = nullptr; SectionIndexSection *SectionIndexTable = nullptr; @@ -1043,6 +1044,7 @@ public: template T &addSection(Ts &&... Args) { auto Sec = llvm::make_unique(std::forward(Args)...); auto Ptr = Sec.get(); + MustBeRelocatable |= isa(*Ptr); Sections.emplace_back(std::move(Sec)); Ptr->Index = Sections.size(); return *Ptr; @@ -1051,6 +1053,9 @@ public: Segments.emplace_back(llvm::make_unique(Data)); return *Segments.back(); } + bool isRelocatable() const { + return (Type != ELF::ET_DYN && Type != ELF::ET_EXEC) || MustBeRelocatable; + } }; } // end namespace elf