Index: llvm/trunk/test/tools/llvm-objcopy/strip-all-and-keep-symbol.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/strip-all-and-keep-symbol.test +++ llvm/trunk/test/tools/llvm-objcopy/strip-all-and-keep-symbol.test @@ -0,0 +1,57 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy --strip-all --keep-symbol foo %t %t2 +# RUN: llvm-readobj -sections -symbols %t2 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x1000 + AddressAlign: 0x0000000000000010 + Size: 64 + - Name: .gnu.warning.foo + Type: SHT_PROGBITS + - Name: .debug_bar + Type: SHT_PROGBITS +Symbols: + Local: + - Name: foo + Type: STT_FUNC + Section: .text + Value: 0x1000 + Size: 8 + - Name: bar + Type: STT_FUNC + Section: .text + Value: 0x1008 + Size: 8 + - Name: baz + Type: STT_FUNC + Section: .text + Value: 0x1010 + Size: 8 + +# CHECK: Name: .text +# CHECK: Name: .gnu.warning.foo +# CHECK: Name: .symtab +# CHECK: Name: .strtab +# CHECK: Name: .shstrtab +# CHECK-NOT: Name: .debug_bar + +#CHECK: Symbols [ +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: foo +#CHECK-NEXT: Value: 0x1000 +#CHECK-NEXT: Size: 8 +#CHECK-NEXT: Binding: Local +#CHECK-NEXT: Type: Function +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: .text +#CHECK-NEXT: } +#CHECK-NEXT:] Index: llvm/trunk/tools/llvm-objcopy/Object.h =================================================================== --- llvm/trunk/tools/llvm-objcopy/Object.h +++ llvm/trunk/tools/llvm-objcopy/Object.h @@ -365,6 +365,7 @@ SectionBase *DefinedIn, uint64_t Value, uint8_t Visibility, uint16_t Shndx, uint64_t Sz); void addSymbolNames(); + bool empty() const { return Symbols.empty(); } const SectionBase *getStrTab() const { return SymbolNames; } const Symbol *getSymbolByIndex(uint32_t Index) const; void updateSymbols(function_ref Callable); Index: llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp =================================================================== --- llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp +++ llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp @@ -222,6 +222,55 @@ if (!Config.SplitDWO.empty()) { SplitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType); } + + // TODO: update or remove symbols only if there is an option that affects them. + if (Obj.SymbolTable) { + Obj.SymbolTable->updateSymbols([&](Symbol &Sym) { + if ((Config.LocalizeHidden && + (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) || + (!Config.SymbolsToLocalize.empty() && + is_contained(Config.SymbolsToLocalize, Sym.Name))) + Sym.Binding = STB_LOCAL; + + if (!Config.SymbolsToGlobalize.empty() && + is_contained(Config.SymbolsToGlobalize, Sym.Name)) + Sym.Binding = STB_GLOBAL; + + if (!Config.SymbolsToWeaken.empty() && + is_contained(Config.SymbolsToWeaken, Sym.Name) && + Sym.Binding == STB_GLOBAL) + Sym.Binding = STB_WEAK; + + if (Config.Weaken && Sym.Binding == STB_GLOBAL && + Sym.getShndx() != SHN_UNDEF) + Sym.Binding = STB_WEAK; + + const auto I = Config.SymbolsToRename.find(Sym.Name); + if (I != Config.SymbolsToRename.end()) + Sym.Name = I->getValue(); + }); + + Obj.removeSymbols([&](const Symbol &Sym) { + if (!Config.SymbolsToKeep.empty() && + is_contained(Config.SymbolsToKeep, Sym.Name)) + return false; + + if (Config.DiscardAll && Sym.Binding == STB_LOCAL && + Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE && + Sym.Type != STT_SECTION) + return true; + + if (Config.StripAll || Config.StripAllGNU) + return true; + + if (!Config.SymbolsToRemove.empty() && + is_contained(Config.SymbolsToRemove, Sym.Name)) { + return true; + } + + return false; + }); + } SectionPred RemovePred = [](const SectionBase &) { return false; }; @@ -327,6 +376,19 @@ }; } + // This has to be the last predicate assignment. + // If the option --keep-symbol has been specified + // and at least one of those symbols is present + // (equivalently, the updated symbol table is not empty) + // the symbol table and the string table should not be removed. + if (!Config.SymbolsToKeep.empty() && !Obj.SymbolTable->empty()) { + RemovePred = [&Obj, RemovePred](const SectionBase &Sec) { + if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab()) + return false; + return RemovePred(Sec); + }; + } + Obj.removeSections(RemovePred); if (!Config.AddSection.empty()) { @@ -347,51 +409,6 @@ if (!Config.AddGnuDebugLink.empty()) Obj.addSection(Config.AddGnuDebugLink); - - if (Obj.SymbolTable) { - Obj.SymbolTable->updateSymbols([&](Symbol &Sym) { - if ((Config.LocalizeHidden && - (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) || - (!Config.SymbolsToLocalize.empty() && - is_contained(Config.SymbolsToLocalize, Sym.Name))) - Sym.Binding = STB_LOCAL; - - if (!Config.SymbolsToGlobalize.empty() && - is_contained(Config.SymbolsToGlobalize, Sym.Name)) - Sym.Binding = STB_GLOBAL; - - if (!Config.SymbolsToWeaken.empty() && - is_contained(Config.SymbolsToWeaken, Sym.Name) && - Sym.Binding == STB_GLOBAL) - Sym.Binding = STB_WEAK; - - if (Config.Weaken && Sym.Binding == STB_GLOBAL && - Sym.getShndx() != SHN_UNDEF) - Sym.Binding = STB_WEAK; - - const auto I = Config.SymbolsToRename.find(Sym.Name); - if (I != Config.SymbolsToRename.end()) - Sym.Name = I->getValue(); - }); - - Obj.removeSymbols([&](const Symbol &Sym) { - if (!Config.SymbolsToKeep.empty() && - is_contained(Config.SymbolsToKeep, Sym.Name)) - return false; - - if (Config.DiscardAll && Sym.Binding == STB_LOCAL && - Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE && - Sym.Type != STT_SECTION) - return true; - - if (!Config.SymbolsToRemove.empty() && - is_contained(Config.SymbolsToRemove, Sym.Name)) { - return true; - } - - return false; - }); - } } std::unique_ptr CreateReader(StringRef InputFilename,