Skip to content

Commit

Permalink
[llvm-objcopy] Add --skip-symbol and --skip-symbols options (#80873)
Browse files Browse the repository at this point in the history
Add --skip-symbol and --skip-symbols options that allow to skip symbols
when executing other options that can change the symbol's name, binding
or visibility, similar to an existing option --keep-symbol that keeps a
symbol from being removed by other options.
  • Loading branch information
kuilpd committed Mar 21, 2024
1 parent 2699072 commit 4946cc3
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 4 deletions.
13 changes: 13 additions & 0 deletions llvm/docs/CommandGuide/llvm-objcopy.rst
Expand Up @@ -464,6 +464,19 @@ them.
Read a list of symbols from <filename> and change their visibility to the
specified value. Visibility values: default, internal, hidden, protected.

.. option:: --skip-symbol <symbol>

Do not change the parameters of symbol ``<symbol>`` when executing other
options that can change the symbol's name, binding or visibility.

.. option:: --skip-symbols <filename>

Do not change the parameters of symbols named in the file ``<filename>`` when
executing other options that can change the symbol's name, binding or
visibility. In the file, each line represents a single symbol, with leading
and trailing whitespace ignored, as is anything following a '#'.
Can be specified multiple times to read names from multiple files.

.. option:: --split-dwo <dwo-file>

Equivalent to running :program:`llvm-objcopy` with :option:`--extract-dwo` and
Expand Down
4 changes: 4 additions & 0 deletions llvm/docs/ReleaseNotes.rst
Expand Up @@ -175,6 +175,10 @@ Changes to the LLVM tools
``--set-symbols-visibility`` options for ELF input to change the
visibility of symbols.

* llvm-objcopy now supports ``--skip-symbol`` and ``--skip-symbols`` options
for ELF input to skip the specified symbols when executing other options
that can change a symbol's name, binding or visibility.

Changes to LLDB
---------------------------------

Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/ObjCopy/CommonConfig.h
Expand Up @@ -233,6 +233,7 @@ struct CommonConfig {
NameMatcher UnneededSymbolsToRemove;
NameMatcher SymbolsToWeaken;
NameMatcher SymbolsToKeepGlobal;
NameMatcher SymbolsToSkip;

// Map options
StringMap<SectionRename> SectionsToRename;
Expand Down
8 changes: 4 additions & 4 deletions llvm/lib/ObjCopy/ConfigManager.cpp
Expand Up @@ -15,7 +15,7 @@ namespace objcopy {

Expected<const COFFConfig &> ConfigManager::getCOFFConfig() const {
if (!Common.SplitDWO.empty() || !Common.SymbolsPrefix.empty() ||
!Common.SymbolsPrefixRemove.empty() ||
!Common.SymbolsPrefixRemove.empty() || !Common.SymbolsToSkip.empty() ||
!Common.AllocSectionsPrefix.empty() || !Common.KeepSection.empty() ||
!Common.SymbolsToGlobalize.empty() || !Common.SymbolsToKeep.empty() ||
!Common.SymbolsToLocalize.empty() || !Common.SymbolsToWeaken.empty() ||
Expand All @@ -34,7 +34,7 @@ Expected<const COFFConfig &> ConfigManager::getCOFFConfig() const {

Expected<const MachOConfig &> ConfigManager::getMachOConfig() const {
if (!Common.SplitDWO.empty() || !Common.SymbolsPrefix.empty() ||
!Common.SymbolsPrefixRemove.empty() ||
!Common.SymbolsPrefixRemove.empty() || !Common.SymbolsToSkip.empty() ||
!Common.AllocSectionsPrefix.empty() || !Common.KeepSection.empty() ||
!Common.SymbolsToGlobalize.empty() || !Common.SymbolsToKeep.empty() ||
!Common.SymbolsToLocalize.empty() ||
Expand All @@ -56,7 +56,7 @@ Expected<const MachOConfig &> ConfigManager::getMachOConfig() const {
Expected<const WasmConfig &> ConfigManager::getWasmConfig() const {
if (!Common.AddGnuDebugLink.empty() || Common.ExtractPartition ||
!Common.SplitDWO.empty() || !Common.SymbolsPrefix.empty() ||
!Common.SymbolsPrefixRemove.empty() ||
!Common.SymbolsPrefixRemove.empty() || !Common.SymbolsToSkip.empty() ||
!Common.AllocSectionsPrefix.empty() ||
Common.DiscardMode != DiscardType::None || !Common.SymbolsToAdd.empty() ||
!Common.SymbolsToGlobalize.empty() || !Common.SymbolsToLocalize.empty() ||
Expand All @@ -77,7 +77,7 @@ Expected<const WasmConfig &> ConfigManager::getWasmConfig() const {
Expected<const XCOFFConfig &> ConfigManager::getXCOFFConfig() const {
if (!Common.AddGnuDebugLink.empty() || Common.ExtractPartition ||
!Common.SplitDWO.empty() || !Common.SymbolsPrefix.empty() ||
!Common.SymbolsPrefixRemove.empty() ||
!Common.SymbolsPrefixRemove.empty() || !Common.SymbolsToSkip.empty() ||
!Common.AllocSectionsPrefix.empty() ||
Common.DiscardMode != DiscardType::None || !Common.AddSection.empty() ||
!Common.DumpSection.empty() || !Common.SymbolsToAdd.empty() ||
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
Expand Up @@ -291,6 +291,9 @@ static Error updateAndRemoveSymbols(const CommonConfig &Config,
return Error::success();

Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
if (Config.SymbolsToSkip.matches(Sym.Name))
return;

// Common and undefined symbols don't make sense as local symbols, and can
// even cause crashes if we localize those, so skip them.
if (!Sym.isCommon() && Sym.getShndx() != SHN_UNDEF &&
Expand Down
100 changes: 100 additions & 0 deletions llvm/test/tools/llvm-objcopy/ELF/skip-symbol.test
@@ -0,0 +1,100 @@
## This test checks the functionality of options --skip-symbol and --skip-symbols.
# RUN: yaml2obj %s -o %t.o
# RUN: echo 'foo[2-3]' > %t.skip.regex

## Check --skip-symbol functionality when changing symbol bindings.
# RUN: llvm-objcopy %t.o %t2.o --localize-hidden --skip-symbol=foo3
# RUN: llvm-readelf -s %t2.o | FileCheck %s --check-prefix=LH-SYM
# LH-SYM-DAG: LOCAL HIDDEN 1 foo1
# LH-SYM-DAG: LOCAL HIDDEN 1 foo2
# LH-SYM-DAG: GLOBAL HIDDEN 1 foo3
# LH-SYM-DAG: LOCAL HIDDEN 1 foo4
# LH-SYM-DAG: LOCAL HIDDEN 1 foo5

## Check --skip-symbols functionality when changing symbol bindings.
# RUN: llvm-objcopy %t.o %t1.o --localize-hidden --skip-symbols=%t.skip.regex --regex
# RUN: llvm-readelf -s %t1.o | FileCheck %s --check-prefix=LH-SYMS
# LH-SYMS-DAG: LOCAL HIDDEN 1 foo1
# LH-SYMS-DAG: GLOBAL HIDDEN 1 foo2
# LH-SYMS-DAG: GLOBAL HIDDEN 1 foo3
# LH-SYMS-DAG: LOCAL HIDDEN 1 foo4
# LH-SYMS-DAG: LOCAL HIDDEN 1 foo5

## Check --skip-symbol functionality when changing symbol names.
# RUN: echo -e "foo1 bar1\nfoo2 bar2" > %t.renames.list
# RUN: llvm-objcopy %t.o %t4.o --redefine-syms=%t.renames.list \
# RUN: --skip-symbol='fo*' --wildcard
# RUN: llvm-readelf -s %t4.o | FileCheck %s --check-prefix=RS-SYM
# RS-SYM-DAG: foo1
# RS-SYM-DAG: foo2
# RS-SYM-DAG: foo3
# RS-SYM-DAG: foo4
# RS-SYM-DAG: foo5

## Check --skip-symbols functionality when changing symbol names.
# RUN: llvm-objcopy %t.o %t3.o --redefine-syms=%t.renames.list \
# RUN: --skip-symbols=%t.skip.regex --regex
# RUN: llvm-readelf -s %t3.o | FileCheck %s --check-prefix=RS-SYMS
# RS-SYMS-DAG: bar1
# RS-SYMS-DAG: foo2
# RS-SYMS-DAG: foo3
# RS-SYMS-DAG: foo4
# RS-SYMS-DAG: foo5

## Check the functionality when using skip options multiple times.
# RUN: echo "foo3" > %t.symbol0.list
# RUN: echo "foo4" > %t.symbol1.list
# RUN: llvm-objcopy %t.o %t5.o --set-symbol-visibility='foo*'=internal --wildcard \
# RUN: --skip-symbol=foo1 --skip-symbol=foo2 \
# RUN: --skip-symbols=%t.symbol0.list --skip-symbols=%t.symbol1.list
# RUN: llvm-readelf -s %t5.o | FileCheck %s --check-prefix=BOTH
# BOTH-DAG: GLOBAL HIDDEN 1 foo1
# BOTH-DAG: GLOBAL HIDDEN 1 foo2
# BOTH-DAG: GLOBAL HIDDEN 1 foo3
# BOTH-DAG: GLOBAL HIDDEN 1 foo4
## Only foo5 is not skipped.
# BOTH-DAG: GLOBAL INTERNAL 1 foo5

## Check that using an invalid symbol name regex generates an error.
# RUN: echo '*.' > %t.symbols.regex
# RUN: not llvm-objcopy %t.o --skip-symbols=%t.symbols.regex --regex 2>&1 | \
# RUN: FileCheck %s --check-prefix=SYMBOL
# RUN: not llvm-objcopy %t.o --skip-symbol='*.' --regex 2>&1 | \
# RUN: FileCheck %s --check-prefix=SYMBOL
# SYMBOL: error: cannot compile regular expression '*.': repetition-operator operand invalid

## Check passing an invalid filename generates an error.
# RUN: not llvm-objcopy %t.o --skip-symbols=no_file 2>&1 | \
# RUN: FileCheck %s --check-prefix=FILE -DMSG=%errc_ENOENT
# FILE: error: 'no_file': [[MSG]]

!ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_X86_64
Sections:
- Name: .text
Type: SHT_PROGBITS
Symbols:
- Name: foo1
Section: .text
Binding: STB_GLOBAL
Other: [ STV_HIDDEN ]
- Name: foo2
Section: .text
Binding: STB_GLOBAL
Other: [ STV_HIDDEN ]
- Name: foo3
Section: .text
Binding: STB_GLOBAL
Other: [ STV_HIDDEN ]
- Name: foo4
Section: .text
Binding: STB_GLOBAL
Other: [ STV_HIDDEN ]
- Name: foo5
Section: .text
Binding: STB_GLOBAL
Other: [ STV_HIDDEN ]
9 changes: 9 additions & 0 deletions llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
Expand Up @@ -978,6 +978,15 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc, Arg->getValue(),
SymbolMatchStyle, ErrorCallback))
return std::move(E);
for (auto *Arg : InputArgs.filtered(OBJCOPY_skip_symbol))
if (Error E = Config.SymbolsToSkip.addMatcher(NameOrPattern::create(
Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
return std::move(E);
for (auto *Arg : InputArgs.filtered(OBJCOPY_skip_symbols))
if (Error E =
addSymbolsFromFile(Config.SymbolsToSkip, DC.Alloc, Arg->getValue(),
SymbolMatchStyle, ErrorCallback))
return std::move(E);
for (auto *Arg : InputArgs.filtered(OBJCOPY_add_symbol)) {
Expected<NewSymbolInfo> SymInfo = parseNewSymbolInfo(Arg->getValue());
if (!SymInfo)
Expand Down
14 changes: 14 additions & 0 deletions llvm/tools/llvm-objcopy/ObjcopyOpts.td
Expand Up @@ -206,6 +206,20 @@ defm keep_symbols
"be repeated to read symbols from many files">,
MetaVarName<"filename">;

defm skip_symbol : Eq<"skip-symbol", "Do not change parameters of symbol <symbol> "
"when executing other options that can change the symbol's "
"name, binding or visibility">,
MetaVarName<"symbol">;

defm skip_symbols
: Eq<"skip-symbols",
"Read a list of symbols from <filename> and run as if "
"--skip-symbol=<symbol> is set for each one. <filename> "
"contains one symbol per line and may contain comments beginning with "
"'#'. Leading and trailing whitespace is stripped from each line. May "
"be repeated to read symbols from many files">,
MetaVarName<"filename">;

defm dump_section
: Eq<"dump-section",
"Dump contents of section named <section> into file <file>">,
Expand Down

0 comments on commit 4946cc3

Please sign in to comment.