[llvm-objcopy] Fix the behavior of --strip-* and --keep-symbol

If one runs llvm-objcopy --strip-all --keep-symbol foo
and the symbol table indeed contains the symbol "foo"
then it should not be removed.

Test plan: make check-all

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

llvm-svn: 333008
This commit is contained in:
Alexander Shaposhnikov 2018-05-22 18:24:07 +00:00
parent a6e63f176c
commit 6e7814c484
3 changed files with 120 additions and 45 deletions

View File

@ -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:]

View File

@ -365,6 +365,7 @@ public:
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<void(Symbol &)> Callable);

View File

@ -222,6 +222,55 @@ void HandleArgs(const CopyConfig &Config, Object &Obj, const Reader &Reader,
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 @@ void HandleArgs(const CopyConfig &Config, Object &Obj, const Reader &Reader,
};
}
// 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 @@ void HandleArgs(const CopyConfig &Config, Object &Obj, const Reader &Reader,
if (!Config.AddGnuDebugLink.empty())
Obj.addSection<GnuDebugLinkSection>(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<Reader> CreateReader(StringRef InputFilename,