Skip to content

Commit

Permalink
[llvm-objcopy] Add support of symbol modification flags for MachO (ll…
Browse files Browse the repository at this point in the history
…vm#120895)

This patch adds support of the following llvm-objcopy flags for MachO:

- `--globalize-symbol`, `--globalize-symbols`,
- `--keep-global-symbol`, `-G`, `--keep-global-symbols`,
- `--localize-symbol`, `-L`, `--localize-symbols`,
- `--skip-symbol`, `--skip-symbols`.

Code in `updateAndRemoveSymbols` for MachO
is kept similar to its version for ELF.

Fixes llvm#120894
  • Loading branch information
RIscRIpt authored Dec 24, 2024
1 parent 8e1cb96 commit 334a576
Show file tree
Hide file tree
Showing 10 changed files with 659 additions and 62 deletions.
100 changes: 50 additions & 50 deletions llvm/docs/CommandGuide/llvm-objcopy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,47 @@ multiple file formats.
Enable deterministic mode when copying archives, i.e. use 0 for archive member
header UIDs, GIDs and timestamp fields. On by default.

.. option:: --globalize-symbol <symbol>

Mark any defined symbols named ``<symbol>`` as global symbols in the output.
Can be specified multiple times to mark multiple symbols.

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

Read a list of names from the file ``<filename>`` and mark defined symbols with
those names as global in the output. 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:: --help, -h

Print a summary of command line options.

.. option:: --keep-global-symbol <symbol>, -G

Mark all symbols local in the output, except for symbols with the name
``<symbol>``. Can be specified multiple times to ignore multiple symbols.

.. option:: --keep-global-symbols <filename>

Mark all symbols local in the output, except for symbols named in the file
``<filename>``. 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:: --localize-symbol <symbol>, -L

Mark any defined non-common symbol named ``<symbol>`` as a local symbol in the
output. Can be specified multiple times to mark multiple symbols as local.

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

Read a list of names from the file ``<filename>`` and mark defined non-common
symbols with those names as local in the output. 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:: --only-keep-debug

Produce a debug file as the output that only preserves contents of sections
Expand Down Expand Up @@ -177,6 +214,19 @@ multiple file formats.
flags.
- `share` = add the `IMAGE_SCN_MEM_SHARED` and `IMAGE_SCN_MEM_READ` flags.

.. 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:: --strip-all-gnu

Remove all symbols, debug sections and relocations from the output. This option
Expand Down Expand Up @@ -355,18 +405,6 @@ them.
For binary outputs, fill the gaps between sections with ``<value>`` instead
of zero. The value must be an unsigned 8-bit integer.

.. option:: --globalize-symbol <symbol>

Mark any defined symbols named ``<symbol>`` as global symbols in the output.
Can be specified multiple times to mark multiple symbols.

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

Read a list of names from the file ``<filename>`` and mark defined symbols with
those names as global in the output. 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:: --input-target <format>, -I

Read the input as the specified format. See `SUPPORTED FORMATS`_ for a list of
Expand All @@ -377,18 +415,6 @@ them.

Keep symbols of type `STT_FILE`, even if they would otherwise be stripped.

.. option:: --keep-global-symbol <symbol>, -G

Mark all symbols local in the output, except for symbols with the name
``<symbol>``. Can be specified multiple times to ignore multiple symbols.

.. option:: --keep-global-symbols <filename>

Mark all symbols local in the output, except for symbols named in the file
``<filename>``. 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:: --keep-section <section>

When removing sections from the output, do not remove sections named
Expand All @@ -410,19 +436,6 @@ them.

Mark all symbols with hidden or internal visibility local in the output.

.. option:: --localize-symbol <symbol>, -L

Mark any defined non-common symbol named ``<symbol>`` as a local symbol in the
output. Can be specified multiple times to mark multiple symbols as local.

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

Read a list of names from the file ``<filename>`` and mark defined non-common
symbols with those names as local in the output. 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:: --new-symbol-visibility <visibility>

Specify the visibility of the symbols automatically created when using binary
Expand Down Expand Up @@ -489,19 +502,6 @@ 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
6 changes: 6 additions & 0 deletions llvm/docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,12 @@ Changes to the Debug Info
Changes to the LLVM tools
---------------------------------

* llvm-objcopy now supports the following options for Mach-O:
`--globalize-symbol`, `--globalize-symbols`,
`--keep-global-symbol`, `--keep-global-symbols`,
`--localize-symbol`, `--localize-symbols`,
`--skip-symbol`, `--skip-symbols`.

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

Expand Down
6 changes: 2 additions & 4 deletions llvm/lib/ObjCopy/ConfigManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,9 @@ Expected<const COFFConfig &> ConfigManager::getCOFFConfig() const {

Expected<const MachOConfig &> ConfigManager::getMachOConfig() const {
if (!Common.SplitDWO.empty() || !Common.SymbolsPrefix.empty() ||
!Common.SymbolsPrefixRemove.empty() || !Common.SymbolsToSkip.empty() ||
!Common.SymbolsPrefixRemove.empty() ||
!Common.AllocSectionsPrefix.empty() || !Common.KeepSection.empty() ||
!Common.SymbolsToGlobalize.empty() || !Common.SymbolsToKeep.empty() ||
!Common.SymbolsToLocalize.empty() ||
!Common.SymbolsToKeepGlobal.empty() || !Common.SectionsToRename.empty() ||
!Common.SymbolsToKeep.empty() || !Common.SectionsToRename.empty() ||
!Common.UnneededSymbolsToRemove.empty() ||
!Common.SetSectionAlignment.empty() || !Common.SetSectionFlags.empty() ||
!Common.SetSectionType.empty() || Common.ExtractDWO ||
Expand Down
35 changes: 27 additions & 8 deletions llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,38 @@ static void markSymbols(const CommonConfig &, Object &Obj) {
static void updateAndRemoveSymbols(const CommonConfig &Config,
const MachOConfig &MachOConfig,
Object &Obj) {
for (SymbolEntry &Sym : Obj.SymTable) {
// Weaken symbols first to match ELFObjcopy behavior.
bool IsExportedAndDefined =
(Sym.n_type & llvm::MachO::N_EXT) &&
(Sym.n_type & llvm::MachO::N_TYPE) != llvm::MachO::N_UNDF;
if (IsExportedAndDefined &&
Obj.SymTable.updateSymbols([&](SymbolEntry &Sym) {
if (Config.SymbolsToSkip.matches(Sym.Name))
return;

if (!Sym.isUndefinedSymbol() && Config.SymbolsToLocalize.matches(Sym.Name))
Sym.n_type &= ~MachO::N_EXT;

// Note: these two globalize flags have very similar names but different
// meanings:
//
// --globalize-symbol: promote a symbol to global
// --keep-global-symbol: all symbols except for these should be made local
//
// If --globalize-symbol is specified for a given symbol, it will be
// global in the output file even if it is not included via
// --keep-global-symbol. Because of that, make sure to check
// --globalize-symbol second.
if (!Sym.isUndefinedSymbol() && !Config.SymbolsToKeepGlobal.empty() &&
!Config.SymbolsToKeepGlobal.matches(Sym.Name))
Sym.n_type &= ~MachO::N_EXT;

if (!Sym.isUndefinedSymbol() && Config.SymbolsToGlobalize.matches(Sym.Name))
Sym.n_type |= MachO::N_EXT;

if (Sym.isExternalSymbol() && !Sym.isUndefinedSymbol() &&
(Config.Weaken || Config.SymbolsToWeaken.matches(Sym.Name)))
Sym.n_desc |= llvm::MachO::N_WEAK_DEF;
Sym.n_desc |= MachO::N_WEAK_DEF;

auto I = Config.SymbolsToRename.find(Sym.Name);
if (I != Config.SymbolsToRename.end())
Sym.Name = std::string(I->getValue());
}
});

auto RemovePred = [&Config, &MachOConfig,
&Obj](const std::unique_ptr<SymbolEntry> &N) {
Expand Down
13 changes: 13 additions & 0 deletions llvm/lib/ObjCopy/MachO/MachOObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) {
static_cast<const SymbolTable *>(this)->getSymbolByIndex(Index));
}

void SymbolTable::updateSymbols(function_ref<void(SymbolEntry &)> Callable) {
for (auto &Sym : Symbols)
Callable(*Sym);

// Partition symbols: local < defined external < undefined external.
auto ExternalBegin = std::stable_partition(
std::begin(Symbols), std::end(Symbols),
[](const auto &Sym) { return Sym->isLocalSymbol(); });
std::stable_partition(ExternalBegin, std::end(Symbols), [](const auto &Sym) {
return !Sym->isUndefinedSymbol();
});
}

void SymbolTable::removeSymbols(
function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove) {
llvm::erase_if(Symbols, ToRemove);
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/ObjCopy/MachO/MachOObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ struct SymbolTable {

const SymbolEntry *getSymbolByIndex(uint32_t Index) const;
SymbolEntry *getSymbolByIndex(uint32_t Index);
void updateSymbols(function_ref<void(SymbolEntry &)> Callable);
void removeSymbols(
function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove);
};
Expand Down
134 changes: 134 additions & 0 deletions llvm/test/tools/llvm-objcopy/MachO/globalize-symbol.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# RUN: yaml2obj %s -o %t
# RUN: llvm-objcopy --wildcard --globalize-symbol="*" %t %t.copy
# RUN: llvm-readobj --symbols %t.copy | FileCheck %s

# RUN: echo "*" > %t-star.txt
# RUN: llvm-objcopy --wildcard --globalize-symbols="%t-star.txt" %t %t.copy
# RUN: llvm-readobj --symbols %t.copy | FileCheck %s

# CHECK: Symbols [
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: _PrivateSymbol
# CHECK-NEXT: Extern
# CHECK-NEXT: Type: Section (0xE)
# CHECK-NEXT: Section: __text (0x1)
# CHECK-NEXT: RefType: UndefinedNonLazy (0x0)
# CHECK-NEXT: Flags [ (0x0)
# CHECK-NEXT: ]
# CHECK-NEXT: Value: 0x1
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: _PrivateExternalSymbol
# CHECK-NEXT: PrivateExtern
# CHECK-NEXT: Extern
# CHECK-NEXT: Type: Section (0xE)
# CHECK-NEXT: Section: __text (0x1)
# CHECK-NEXT: RefType: UndefinedNonLazy (0x0)
# CHECK-NEXT: Flags [ (0x0)
# CHECK-NEXT: ]
# CHECK-NEXT: Value: 0x2
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: _CommonSymbol
# CHECK-NEXT: Extern
# CHECK-NEXT: Type: Section (0xE)
# CHECK-NEXT: Section: __text (0x1)
# CHECK-NEXT: RefType: UndefinedNonLazy (0x0)
# CHECK-NEXT: Flags [ (0x0)
# CHECK-NEXT: ]
# CHECK-NEXT: Value: 0x3
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: _UndefinedExternalSymbol
# CHECK-NEXT: Extern
# CHECK-NEXT: Type: Undef (0x0)
# CHECK-NEXT: Section: (0x0)
# CHECK-NEXT: RefType: UndefinedNonLazy (0x0)
# CHECK-NEXT: Flags [ (0x0)
# CHECK-NEXT: ]
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: }
# CHECK-NEXT: ]

--- !mach-o
FileHeader:
magic: 0xFEEDFACF
cputype: 0x100000C
cpusubtype: 0x0
filetype: 0x2
ncmds: 3
sizeofcmds: 328
flags: 0x200085
reserved: 0x0
LoadCommands:
- cmd: LC_SEGMENT_64
cmdsize: 152
segname: __TEXT
vmaddr: 4294967296
vmsize: 4096
fileoff: 0
filesize: 4096
maxprot: 5
initprot: 5
nsects: 1
flags: 0
Sections:
- sectname: __text
segname: __TEXT
addr: 0x100000FF8
size: 8
offset: 0xFF8
align: 2
reloff: 0x0
nreloc: 0
flags: 0x80000400
reserved1: 0x0
reserved2: 0x0
reserved3: 0x0
content: 00008052C0035FD6
- cmd: LC_SEGMENT_64
cmdsize: 72
segname: __LINKEDIT
vmaddr: 4294971392
vmsize: 4096
fileoff: 4096
filesize: 67
maxprot: 1
initprot: 1
nsects: 0
flags: 0
- cmd: LC_SYMTAB
cmdsize: 24
symoff: 4096
nsyms: 4
stroff: 4164
strsize: 79
LinkEditData:
NameList:
- n_strx: 2
n_type: 0x0E
n_sect: 1
n_desc: 0
n_value: 1
- n_strx: 17
n_type: 0x1E
n_sect: 1
n_desc: 0
n_value: 2
- n_strx: 40
n_type: 0x0F
n_sect: 1
n_desc: 0
n_value: 3
- n_strx: 54
n_type: 0x01
n_sect: 0
n_desc: 0
n_value: 0
StringTable:
- ' '
- _PrivateSymbol
- _PrivateExternalSymbol
- _CommonSymbol
- _UndefinedExternalSymbol
...
Loading

0 comments on commit 334a576

Please sign in to comment.