Skip to content

[llvm-objcopy] Add --set-symbol-visibility and --set-symbols-visibility options #80872

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 30 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
af5f188
Add llvm-objcopy option --set-visibility-sym
kuilpd Feb 6, 2024
cc05728
Change --set-visibility-sym test check order and variable
kuilpd Feb 6, 2024
97b1e2d
Move setting the visibility to after localizing hidden symbols
kuilpd Feb 8, 2024
d3104d1
Change code formatting in when parsing the options
kuilpd Feb 8, 2024
524b13f
Add checks for multiple uses of setting visibility
kuilpd Feb 8, 2024
9ec88f2
Adjust and separate tests of setting visibility functionality
kuilpd Feb 8, 2024
450e1f6
Add a test for checking various error cases
kuilpd Feb 8, 2024
20a8c43
Add a test for ingoring SHN_UNDEF symbols
kuilpd Feb 8, 2024
f6b659b
Update the llvm-objcopy documentation
kuilpd Feb 8, 2024
c6faec2
Rename --set-visibility-sym to --set-symbol-visibility
kuilpd Feb 8, 2024
105e335
Apply clang-format
kuilpd Feb 8, 2024
cf0c1e5
Remove checks for multiple uses of setting visibility
kuilpd Feb 14, 2024
88c3cf2
Allow each symbol pattern to have a separate visibility
kuilpd Feb 14, 2024
78cd496
Adjust formatting and wording in tests
kuilpd Feb 15, 2024
4ab67a1
Remove unnecessary --regex option in set-visibility-check-errors.test
kuilpd Feb 15, 2024
17f6c40
Explicitly check the option name in set-visibility-check-errors.test
kuilpd Feb 15, 2024
0b28280
Use %errc_ENOENT for 'No such file or directory' message
kuilpd Feb 15, 2024
62a8bac
Add a test case that uses a wildcard
kuilpd Feb 15, 2024
4f7a5cd
Remove unnecessary SHN_UNDEF in set-visibility-undef-symbol.test
kuilpd Feb 15, 2024
ed84dfd
Merge 2 functionality tests into one; rename test files
kuilpd Feb 16, 2024
2d14e71
Add a test case with a special character without pattern matching
kuilpd Feb 16, 2024
7cd45b4
Add a test case that checks visibility overwriting with multiple options
kuilpd Feb 16, 2024
98e127f
Adjust test formatting
kuilpd Feb 16, 2024
287cf46
Merge all tests into a single file
kuilpd Feb 20, 2024
fe8a2d0
Adjust test formatting
kuilpd Feb 23, 2024
d25332c
Reword option description
kuilpd Feb 23, 2024
72022ae
Adjust description as suggested in #82830
kuilpd Feb 26, 2024
ca26144
Allow the option to change the visibility of hidden symbols
kuilpd Feb 26, 2024
26da9e3
Rename VisibilityType to Visibility
kuilpd Feb 26, 2024
5df01eb
Added the options to release notes
kuilpd Feb 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions llvm/docs/CommandGuide/llvm-objcopy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,15 @@ them.
Set the start address of the output to ``<addr>``. Overrides any previously
specified :option:`--change-start` or :option:`--adjust-start` options.

.. option:: --set-symbol-visibility <symbol>=<visibility>

Change the visibility of a symbol to the specified value.

.. option:: --set-symbols-visibility <filename>=<visibility>

Reads a list of symbols from <filename> and changes their visibility to the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imperative sentence like other options?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I replied in another comment:

I copied this description from other options, localize- globalize- strip- weaken- keep- symbols all use this wording. Should I change it?

Copy link
Member

@MaskRay MaskRay Feb 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, there are ~8 options that are inconsistent with others. Actually there is a larger problem that many help messages are slightly wrong, not synced with the clearer semantics by @jh7370 in https://reviews.llvm.org/D63820

I am working on a patch to fix these help messages.

For the new options, definitely use imperative sentences as llvm/docs/CommandGuide/llvm-objcopy.rst uses.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

specified value. Visibility values: default, internal, hidden, protected.

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

Equivalent to running :program:`llvm-objcopy` with :option:`--extract-dwo` and
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/ObjCopy/ELF/ELFConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LLVM_OBJCOPY_ELF_ELFCONFIG_H
#define LLVM_OBJCOPY_ELF_ELFCONFIG_H

#include "llvm/ObjCopy/CommonConfig.h"
#include "llvm/Object/ELFTypes.h"

namespace llvm {
Expand All @@ -18,6 +19,8 @@ namespace objcopy {
struct ELFConfig {
uint8_t NewSymbolVisibility = (uint8_t)ELF::STV_DEFAULT;

std::vector<std::pair<NameMatcher, uint8_t>> SymbolsToSetVisibility;

// ELF entry point address expression. The input parameter is an entry point
// address in the input ELF file. The entry address in the output file is
// calculated with EntryExpr(input_address), when either --set-start or
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,10 @@ static Error updateAndRemoveSymbols(const CommonConfig &Config,
Config.SymbolsToLocalize.matches(Sym.Name)))
Sym.Binding = STB_LOCAL;

for (auto &[Matcher, VisibilityType] : ELFConfig.SymbolsToSetVisibility)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change VisibilityType to Visibility like elsewhere?

if (Matcher.matches(Sym.Name) && Sym.getShndx() != SHN_UNDEF)
Copy link
Member

@MaskRay MaskRay Feb 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there a special case for undefined symbol? A protected/hidden undefined should be allowed.

The following code generates a hidden undefined symbol.

#pragma GCC visibility push(hidden)
void bar();
void foo() {
  bar();
}

The option should have the ability to change their visibility.

Sym.Visibility = VisibilityType;

// Note: these two globalize flags have very similar names but different
// meanings:
//
Expand Down
311 changes: 311 additions & 0 deletions llvm/test/tools/llvm-objcopy/ELF/set-symbol-visibility.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
# RUN: yaml2obj --docnum=1 %s -o %t.o
# RUN: echo '.*' > %t.symbols.regex

## Check that the visibility of all symbols is properly set to DEFAULT.
# RUN: llvm-objcopy %t.o %t0.o --set-symbols-visibility=%t.symbols.regex=default --regex
# RUN: llvm-readelf -s %t0.o | FileCheck %s --check-prefix=DEF

# DEF-DAG: DEFAULT 1 default_local
# DEF-DAG: DEFAULT 1 internal_local
# DEF-DAG: DEFAULT 1 hidden_local
# DEF-DAG: DEFAULT 1 protected_local
# DEF-DAG: DEFAULT 1 default_global
# DEF-DAG: DEFAULT 1 default_weak
# DEF-DAG: DEFAULT 1 internal_global
# DEF-DAG: DEFAULT 1 internal_weak
# DEF-DAG: DEFAULT 1 hidden_global
# DEF-DAG: DEFAULT 1 hidden_weak
# DEF-DAG: DEFAULT 1 protected_global
# DEF-DAG: DEFAULT 1 protected_weak

## Check that the visibility of all symbols is properly set to HIDDEN.
# RUN: llvm-objcopy %t.o %t1.o --set-symbols-visibility=%t.symbols.regex=hidden --regex
# RUN: llvm-readelf -s %t1.o | FileCheck %s --check-prefix=HID

# HID-DAG: HIDDEN 1 default_local
# HID-DAG: HIDDEN 1 internal_local
# HID-DAG: HIDDEN 1 hidden_local
# HID-DAG: HIDDEN 1 protected_local
# HID-DAG: HIDDEN 1 default_global
# HID-DAG: HIDDEN 1 default_weak
# HID-DAG: HIDDEN 1 internal_global
# HID-DAG: HIDDEN 1 internal_weak
# HID-DAG: HIDDEN 1 hidden_global
# HID-DAG: HIDDEN 1 hidden_weak
# HID-DAG: HIDDEN 1 protected_global
# HID-DAG: HIDDEN 1 protected_weak

## Check that the visibility of all symbols is properly set to PROTECTED.
# RUN: llvm-objcopy %t.o %t2.o --set-symbols-visibility=%t.symbols.regex=protected --regex
# RUN: llvm-readelf -s %t2.o | FileCheck %s --check-prefix=PRO

# PRO-DAG: PROTECTED 1 default_local
# PRO-DAG: PROTECTED 1 internal_local
# PRO-DAG: PROTECTED 1 hidden_local
# PRO-DAG: PROTECTED 1 protected_local
# PRO-DAG: PROTECTED 1 default_global
# PRO-DAG: PROTECTED 1 default_weak
# PRO-DAG: PROTECTED 1 internal_global
# PRO-DAG: PROTECTED 1 internal_weak
# PRO-DAG: PROTECTED 1 hidden_global
# PRO-DAG: PROTECTED 1 hidden_weak
# PRO-DAG: PROTECTED 1 protected_global
# PRO-DAG: PROTECTED 1 protected_weak

## Check that the visibility of all symbols is properly set to INTERNAL.
# RUN: llvm-objcopy %t.o %t3.o --set-symbols-visibility=%t.symbols.regex=internal --regex
# RUN: llvm-readelf -s %t3.o | FileCheck %s --check-prefix=INT

# INT-DAG: INTERNAL 1 default_local
# INT-DAG: INTERNAL 1 internal_local
# INT-DAG: INTERNAL 1 hidden_local
# INT-DAG: INTERNAL 1 protected_local
# INT-DAG: INTERNAL 1 default_global
# INT-DAG: INTERNAL 1 default_weak
# INT-DAG: INTERNAL 1 internal_global
# INT-DAG: INTERNAL 1 internal_weak
# INT-DAG: INTERNAL 1 hidden_global
# INT-DAG: INTERNAL 1 hidden_weak
# INT-DAG: INTERNAL 1 protected_global
# INT-DAG: INTERNAL 1 protected_weak

## Check that setting the visibility of certain symbols that were read from
## a file does not affect other symbols.
# RUN: echo -e "default_local\ninternal_local" > %t.symbol.list
# RUN: llvm-objcopy %t.o %t4.o --set-symbols-visibility=%t.symbol.list=hidden
# RUN: llvm-readelf -s %t4.o | FileCheck %s --check-prefix=FILE

# FILE-DAG: HIDDEN 1 default_local
# FILE-DAG: HIDDEN 1 internal_local
## Unaffected symbols:
# FILE-DAG: HIDDEN 1 hidden_local
# FILE-DAG: PROTECTED 1 protected_local
# FILE-DAG: DEFAULT 1 default_global
# FILE-DAG: DEFAULT 1 default_weak
# FILE-DAG: INTERNAL 1 internal_global
# FILE-DAG: INTERNAL 1 internal_weak
# FILE-DAG: HIDDEN 1 hidden_global
# FILE-DAG: HIDDEN 1 hidden_weak
# FILE-DAG: PROTECTED 1 protected_global
# FILE-DAG: PROTECTED 1 protected_weak

## Check that the visibility of a single symbol is set correctly,
## and that no other symbols are affected.
# RUN: llvm-objcopy %t.o %t5.o --set-symbol-visibility=default_local=hidden \
# RUN: --set-symbol-visibility=internal_local=protected \
# RUN: --set-symbol-visibility=hidden_local=internal \
# RUN: --set-symbol-visibility=protected_local=default
# RUN: llvm-readelf -s %t5.o | FileCheck %s --check-prefix=SINGLE

# SINGLE-DAG: HIDDEN 1 default_local
# SINGLE-DAG: PROTECTED 1 internal_local
# SINGLE-DAG: INTERNAL 1 hidden_local
# SINGLE-DAG: DEFAULT 1 protected_local
## Unaffected symbols:
# SINGLE-DAG: DEFAULT 1 default_global
# SINGLE-DAG: DEFAULT 1 default_weak
# SINGLE-DAG: INTERNAL 1 internal_global
# SINGLE-DAG: INTERNAL 1 internal_weak
# SINGLE-DAG: HIDDEN 1 hidden_global
# SINGLE-DAG: HIDDEN 1 hidden_weak
# SINGLE-DAG: PROTECTED 1 protected_global
# SINGLE-DAG: PROTECTED 1 protected_weak

## Check that the visibility of symbols specified by a regex are set correctly,
## and that no other symbols are affected.
# RUN: llvm-objcopy %t.o %t6.o --set-symbol-visibility='.*'_local=hidden --regex
# RUN: llvm-readelf -s %t6.o | FileCheck %s --check-prefix=REGEX

# REGEX-DAG: HIDDEN 1 default_local
# REGEX-DAG: HIDDEN 1 internal_local
# REGEX-DAG: HIDDEN 1 hidden_local
# REGEX-DAG: HIDDEN 1 protected_local
## Unaffected symbols:
# REGEX-DAG: DEFAULT 1 default_global
# REGEX-DAG: DEFAULT 1 default_weak
# REGEX-DAG: INTERNAL 1 internal_global
# REGEX-DAG: INTERNAL 1 internal_weak
# REGEX-DAG: HIDDEN 1 hidden_global
# REGEX-DAG: HIDDEN 1 hidden_weak
# REGEX-DAG: PROTECTED 1 protected_global
# REGEX-DAG: PROTECTED 1 protected_weak

## Check that the visibility of symbols specified by a wildcard are set correctly,
## and that no other symbols are affected.
# RUN: llvm-objcopy %t.o %t7.o --set-symbol-visibility='*_local'=hidden --wildcard
# RUN: llvm-readelf -s %t7.o | FileCheck %s --check-prefix=WILDCARD

# WILDCARD-DAG: HIDDEN 1 default_local
# WILDCARD-DAG: HIDDEN 1 internal_local
# WILDCARD-DAG: HIDDEN 1 hidden_local
# WILDCARD-DAG: HIDDEN 1 protected_local
## Unaffected symbols:
# WILDCARD-DAG: DEFAULT 1 default_global
# WILDCARD-DAG: DEFAULT 1 default_weak
# WILDCARD-DAG: INTERNAL 1 internal_global
# WILDCARD-DAG: INTERNAL 1 internal_weak
# WILDCARD-DAG: HIDDEN 1 hidden_global
# WILDCARD-DAG: HIDDEN 1 hidden_weak
# WILDCARD-DAG: PROTECTED 1 protected_global
# WILDCARD-DAG: PROTECTED 1 protected_weak

## Check that the latest option that matches the same symbols as any of the previous
## options overwrites the visibility of these symbols.
# RUN: echo -e '*_weak\n*_local' > %t.symbols.pattern
# RUN: llvm-objcopy %t.o %t8.o --set-symbol-visibility='default_*'=hidden \
# RUN: --set-symbol-visibility='internal_*'=hidden \
# RUN: --set-symbols-visibility=%t.symbols.pattern=protected \
# RUN: --wildcard
# RUN: llvm-readelf -s %t8.o | FileCheck %s --check-prefix=REWRITE

# REWRITE-DAG: PROTECTED 1 default_local
# REWRITE-DAG: HIDDEN 1 default_global
# REWRITE-DAG: PROTECTED 1 default_weak
# REWRITE-DAG: PROTECTED 1 internal_local
# REWRITE-DAG: HIDDEN 1 internal_global
# REWRITE-DAG: PROTECTED 1 internal_weak
# REWRITE-DAG: PROTECTED 1 hidden_local
# REWRITE-DAG: PROTECTED 1 hidden_weak
# REWRITE-DAG: PROTECTED 1 protected_local
# REWRITE-DAG: PROTECTED 1 protected_weak
## Unaffected symbols:
# REWRITE-DAG: HIDDEN 1 hidden_global
# REWRITE-DAG: PROTECTED 1 protected_global

## Check that a symbol name with a special charater is treated as a plain name
## when pattern matching options are not enabled.
# RUN: yaml2obj --docnum=2 %s -o %t9.o
# RUN: llvm-objcopy %t9.o --set-symbol-visibility='f*o'=hidden
# RUN: llvm-readelf -s %t9.o | FileCheck %s --check-prefix=SPECIAL

# SPECIAL-DAG: HIDDEN 1 f*o
## Unaffected symbol:
# SPECIAL-DAG: DEFAULT 1 foo

# RUN: yaml2obj --docnum=3 %s -o %t10.o

## Check that symbols with SHN_UNDEF index are ignored when setting visibility.
# RUN: llvm-objcopy %t10.o --set-symbol-visibility=foo=hidden
# RUN: llvm-readelf -s %t10.o | FileCheck %s --check-prefix=UNDEF
# UNDEF: DEFAULT UND foo

## Check that passing an invalid visibility type generates an error message.
# RUN: echo 'foo' > %t.symbols
# RUN: not llvm-objcopy %t10.o --set-symbols-visibility=%t.symbols=invalid-type 2>&1 | \
# RUN: FileCheck %s --check-prefix=TYPE
# RUN: not llvm-objcopy %t10.o --set-symbol-visibility=foo=invalid-type 2>&1 | \
# RUN: FileCheck %s --check-prefix=TYPE
# TYPE: error: 'invalid-type' is not a valid symbol visibility

## Check that omitting the '=' character generates an error.
# RUN: not llvm-objcopy %t10.o --set-symbols-visibility=%t.symbols,hidden 2>&1 | \
# RUN: FileCheck %s --check-prefix=FORMAT -DOPTION=--set-symbols-visibility
# RUN: not llvm-objcopy %t10.o --set-symbol-visibility=foo default 2>&1 | \
# RUN: FileCheck %s --check-prefix=FORMAT -DOPTION=--set-symbol-visibility
# FORMAT: error: bad format for [[OPTION]]

## Check that using an invalid symbol pattern generates an error.
# RUN: echo '*.' > %t.symbols.regex
# RUN: not llvm-objcopy %t10.o --set-symbols-visibility=%t.symbols.regex=hidden --regex 2>&1 | \
# RUN: FileCheck %s --check-prefix=SYMBOL
# RUN: not llvm-objcopy %t10.o --set-symbol-visibility='*.'=default --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 %t10.o --set-symbols-visibility=no_file=hidden 2>&1 | \
# RUN: FileCheck %s --check-prefix=NO_FILE -DMSG=%errc_ENOENT
# NO_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: default_local
Section: .text
Binding: STB_LOCAL
- Name: protected_local
Section: .text
Binding: STB_LOCAL
Other: [ STV_PROTECTED ]
- Name: internal_local
Section: .text
Binding: STB_LOCAL
Other: [ STV_INTERNAL ]
- Name: hidden_local
Section: .text
Binding: STB_LOCAL
Other: [ STV_HIDDEN ]
- Name: default_weak
Section: .text
Binding: STB_WEAK
- Name: internal_weak
Section: .text
Binding: STB_WEAK
Other: [ STV_INTERNAL ]
- Name: hidden_weak
Section: .text
Binding: STB_WEAK
Other: [ STV_HIDDEN ]
- Name: protected_weak
Section: .text
Binding: STB_WEAK
Other: [ STV_PROTECTED ]
- Name: default_global
Section: .text
Binding: STB_GLOBAL
- Name: internal_global
Section: .text
Binding: STB_GLOBAL
Other: [ STV_INTERNAL ]
- Name: hidden_global
Section: .text
Binding: STB_GLOBAL
Other: [ STV_HIDDEN ]
- Name: protected_global
Section: .text
Binding: STB_GLOBAL
Other: [ STV_PROTECTED ]
- Name: ignored_name
Section: .text
Binding: STB_GLOBAL
Other: [ STV_INTERNAL ]
...

---
!ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_X86_64
Sections:
- Name: .text
Type: SHT_PROGBITS
Symbols:
- Name: f*o
Section: .text
Binding: STB_LOCAL
- Name: foo
Section: .text
Binding: STB_LOCAL
...

---
!ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_X86_64
Symbols:
- Name: foo
Binding: STB_LOCAL
...
Loading