Index: test/tools/llvm-objcopy/ELF/no-symbol-relocation.test =================================================================== --- test/tools/llvm-objcopy/ELF/no-symbol-relocation.test +++ test/tools/llvm-objcopy/ELF/no-symbol-relocation.test @@ -6,7 +6,7 @@ FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB - Type: ET_EXEC + Type: ET_REL Machine: EM_X86_64 Sections: - Name: .text Index: test/tools/llvm-objcopy/ELF/preserve-segment-contents-ehdr-phdrs.test =================================================================== --- test/tools/llvm-objcopy/ELF/preserve-segment-contents-ehdr-phdrs.test +++ 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 Index: test/tools/llvm-objcopy/ELF/remove-multiple-sections.test =================================================================== --- test/tools/llvm-objcopy/ELF/remove-multiple-sections.test +++ test/tools/llvm-objcopy/ELF/remove-multiple-sections.test @@ -87,34 +87,6 @@ # 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) Index: test/tools/llvm-objcopy/ELF/segment-shift-section-remove.test =================================================================== --- test/tools/llvm-objcopy/ELF/segment-shift-section-remove.test +++ test/tools/llvm-objcopy/ELF/segment-shift-section-remove.test @@ -41,7 +41,7 @@ Sections: - Section: .text3 -#CHECK: SectionHeaderCount: 6 +#CHECK: SectionHeaderCount: 4 # CHECK: Sections [ # CHECK-NEXT: Section { @@ -92,34 +92,6 @@ # 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) Index: test/tools/llvm-objcopy/ELF/segment-test-remove-section.test =================================================================== --- test/tools/llvm-objcopy/ELF/segment-test-remove-section.test +++ test/tools/llvm-objcopy/ELF/segment-test-remove-section.test @@ -46,7 +46,7 @@ # Make sure that when we remove a section we overwrite it with zeros # DATA: 0020000 00 00 00 00 -#CHECK: SectionHeaderCount: 6 +#CHECK: SectionHeaderCount: 4 # CHECK: Sections [ # CHECK: Section { @@ -97,34 +97,6 @@ # 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) Index: test/tools/llvm-objcopy/ELF/strip-unneeded2.test =================================================================== --- test/tools/llvm-objcopy/ELF/strip-unneeded2.test +++ test/tools/llvm-objcopy/ELF/strip-unneeded2.test @@ -0,0 +1,67 @@ +# RUN: yaml2obj %s > %t +# RUN: cp %t %t1 +# RUN: llvm-objcopy --strip-unneeded %t %t2 +# RUN: llvm-readobj --section-headers %t2 | FileCheck %s +# RUN: llvm-readobj --dyn-symbols %t2 | FileCheck %s --check-prefix=DYNSYM + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x1000 + AddressAlign: 0x0000000000000010 + Size: 64 +DynamicSymbols: + - Name: foo + Type: STT_FUNC + Binding: STB_GLOBAL + Section: .text + Value: 0x1000 + Size: 8 +Symbols: + - Name: bar + Type: STT_FUNC + Size: 8 + Section: .text + Value: 0x1008 + - Name: barfoo + Type: STT_FUNC + Size: 8 + Section: .text + Value: 0x1010 + - Name: foo + Type: STT_FUNC + Binding: STB_GLOBAL + Section: .text + Value: 0x1000 + Size: 8 + +# CHECK-NOT: .symtab + +# DYNSYM: DynamicSymbols [ +# DYNSYM-NEXT: Symbol { +# DYNSYM-NEXT: Name: (0) +# DYNSYM-NEXT: Value: 0x0 +# DYNSYM-NEXT: Size: 0 +# DYNSYM-NEXT: Binding: Local (0x0) +# DYNSYM-NEXT: Type: None (0x0) +# DYNSYM-NEXT: Other: 0 +# DYNSYM-NEXT: Section: Undefined (0x0) +# DYNSYM-NEXT: } +# DYNSYM-NEXT: Symbol { +# DYNSYM-NEXT: Name: foo (1) +# DYNSYM-NEXT: Value: 0x1000 +# DYNSYM-NEXT: Size: 8 +# DYNSYM-NEXT: Binding: Global (0x1) +# DYNSYM-NEXT: Type: Function (0x2) +# DYNSYM-NEXT: Other: 0 +# DYNSYM-NEXT: Section: .text (0x1) +# DYNSYM-NEXT: } +# DYNSYM-NEXT: ] + Index: tools/llvm-objcopy/ELF/ELFObjcopy.cpp =================================================================== --- tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -421,7 +421,7 @@ 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. Index: tools/llvm-objcopy/ELF/Object.h =================================================================== --- tools/llvm-objcopy/ELF/Object.h +++ tools/llvm-objcopy/ELF/Object.h @@ -684,6 +684,7 @@ Error removeSymbols(function_ref ToRemove) override; void replaceSectionReferences( const DenseMap &FromTo) override; + bool isTrivial() const; static bool classof(const SectionBase *S) { return S->Type == ELF::SHT_SYMTAB; @@ -978,6 +979,7 @@ Range segments() { return make_pointee_range(Segments); } ConstRange segments() const { return make_pointee_range(Segments); } + Error removeUnneededSections(); Error removeSections(bool AllowBrokenLinks, std::function ToRemove); Error removeSymbols(function_ref ToRemove); @@ -992,6 +994,9 @@ Segments.emplace_back(llvm::make_unique(Data)); return *Segments.back(); } + bool isRelocatable() const { + return Type != ELF::ET_DYN && Type != ELF::ET_EXEC; + } }; } // end namespace elf Index: tools/llvm-objcopy/ELF/Object.cpp =================================================================== --- tools/llvm-objcopy/ELF/Object.cpp +++ tools/llvm-objcopy/ELF/Object.cpp @@ -551,6 +551,16 @@ Sym->Index = Index++; } +static bool isPlaceholder(const Symbol *Sym) { + return Sym->Type == STT_NOTYPE && Sym->Binding == STB_LOCAL && + Sym->Visibility == STV_DEFAULT && Sym->getShndx() == SHN_UNDEF; +} + +bool SymbolTableSection::isTrivial() const { + assert(!Symbols.empty()); + return Symbols.size() == 1 && isPlaceholder(Symbols[0].get()); +} + void SymbolTableSection::addSymbol(Twine Name, uint8_t Bind, uint8_t Type, SectionBase *DefinedIn, uint64_t Value, uint8_t Visibility, uint16_t Shndx, @@ -1577,6 +1587,21 @@ ELFWriter::ELFWriter(Object &Obj, Buffer &Buf, bool WSH) : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs) {} +Error Object::removeUnneededSections() { + // We can remove trivial symbol table from non-relocatable objects + if (isRelocatable() || SymbolTable == nullptr || !SymbolTable->isTrivial()) + return Error::success(); + + // .strtab can be used for section names, in such case we shouldn't + // remove it. + auto *StrTab = SymbolTable->getStrTab() == SectionNames + ? nullptr + : SymbolTable->getStrTab(); + return removeSections(false, [&](const SectionBase &Sec) { + return &Sec == SymbolTable || &Sec == StrTab; + }); +} + Error Object::removeSections(bool AllowBrokenLinks, std::function ToRemove) { @@ -1787,6 +1812,8 @@ "cannot write section header table because " "section header string table was removed"); + if (Error E = Obj.removeUnneededSections()) + return E; Obj.sortSections(); // We need to assign indexes before we perform layout because we need to know