Skip to content

Commit 07d8a45

Browse files
authored
[llvm-objcopy] Add --set-symbol-visibility and --set-symbols-visibility options (#80872)
Add options --set-symbol-visibility and --set-symbols-visibility to manually change the visibility of symbols. There is already an option to set the visibility of newly added symbols via --add-symbol and --new-symbol-visibility. This option will allow to change the visibility of already existing symbols.
1 parent 0a54b36 commit 07d8a45

File tree

7 files changed

+384
-0
lines changed

7 files changed

+384
-0
lines changed

llvm/docs/CommandGuide/llvm-objcopy.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,15 @@ them.
455455
Set the start address of the output to ``<addr>``. Overrides any previously
456456
specified :option:`--change-start` or :option:`--adjust-start` options.
457457

458+
.. option:: --set-symbol-visibility <symbol>=<visibility>
459+
460+
Change the visibility of a symbol to the specified value.
461+
462+
.. option:: --set-symbols-visibility <filename>=<visibility>
463+
464+
Read a list of symbols from <filename> and change their visibility to the
465+
specified value. Visibility values: default, internal, hidden, protected.
466+
458467
.. option:: --split-dwo <dwo-file>
459468

460469
Equivalent to running :program:`llvm-objcopy` with :option:`--extract-dwo` and

llvm/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ Changes to the LLVM tools
147147
if it's not specified with the ``--format`` argument and cannot be inferred from
148148
input files.
149149

150+
* llvm-objcopy now supports ``--set-symbol-visibility`` and
151+
``--set-symbols-visibility`` options for ELF input to change the
152+
visibility of symbols.
153+
150154
Changes to LLDB
151155
---------------------------------
152156

llvm/include/llvm/ObjCopy/ELF/ELFConfig.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef LLVM_OBJCOPY_ELF_ELFCONFIG_H
1010
#define LLVM_OBJCOPY_ELF_ELFCONFIG_H
1111

12+
#include "llvm/ObjCopy/CommonConfig.h"
1213
#include "llvm/Object/ELFTypes.h"
1314

1415
namespace llvm {
@@ -18,6 +19,8 @@ namespace objcopy {
1819
struct ELFConfig {
1920
uint8_t NewSymbolVisibility = (uint8_t)ELF::STV_DEFAULT;
2021

22+
std::vector<std::pair<NameMatcher, uint8_t>> SymbolsToSetVisibility;
23+
2124
// ELF entry point address expression. The input parameter is an entry point
2225
// address in the input ELF file. The entry address in the output file is
2326
// calculated with EntryExpr(input_address), when either --set-start or

llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,10 @@ static Error updateAndRemoveSymbols(const CommonConfig &Config,
300300
Config.SymbolsToLocalize.matches(Sym.Name)))
301301
Sym.Binding = STB_LOCAL;
302302

303+
for (auto &[Matcher, Visibility] : ELFConfig.SymbolsToSetVisibility)
304+
if (Matcher.matches(Sym.Name))
305+
Sym.Visibility = Visibility;
306+
303307
// Note: these two globalize flags have very similar names but different
304308
// meanings:
305309
//
Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
# RUN: yaml2obj --docnum=1 %s -o %t.o
2+
# RUN: echo '.*' > %t.symbols.regex
3+
4+
## Check that the visibility of all symbols is properly set to DEFAULT.
5+
# RUN: llvm-objcopy %t.o %t0.o --set-symbols-visibility=%t.symbols.regex=default --regex
6+
# RUN: llvm-readelf -s %t0.o | FileCheck %s --check-prefix=DEF
7+
8+
# DEF-DAG: DEFAULT 1 default_local
9+
# DEF-DAG: DEFAULT 1 internal_local
10+
# DEF-DAG: DEFAULT 1 hidden_local
11+
# DEF-DAG: DEFAULT 1 protected_local
12+
# DEF-DAG: DEFAULT 1 default_global
13+
# DEF-DAG: DEFAULT 1 default_weak
14+
# DEF-DAG: DEFAULT 1 internal_global
15+
# DEF-DAG: DEFAULT 1 internal_weak
16+
# DEF-DAG: DEFAULT 1 hidden_global
17+
# DEF-DAG: DEFAULT 1 hidden_weak
18+
# DEF-DAG: DEFAULT 1 protected_global
19+
# DEF-DAG: DEFAULT 1 protected_weak
20+
21+
## Check that the visibility of all symbols is properly set to HIDDEN.
22+
# RUN: llvm-objcopy %t.o %t1.o --set-symbols-visibility=%t.symbols.regex=hidden --regex
23+
# RUN: llvm-readelf -s %t1.o | FileCheck %s --check-prefix=HID
24+
25+
# HID-DAG: HIDDEN 1 default_local
26+
# HID-DAG: HIDDEN 1 internal_local
27+
# HID-DAG: HIDDEN 1 hidden_local
28+
# HID-DAG: HIDDEN 1 protected_local
29+
# HID-DAG: HIDDEN 1 default_global
30+
# HID-DAG: HIDDEN 1 default_weak
31+
# HID-DAG: HIDDEN 1 internal_global
32+
# HID-DAG: HIDDEN 1 internal_weak
33+
# HID-DAG: HIDDEN 1 hidden_global
34+
# HID-DAG: HIDDEN 1 hidden_weak
35+
# HID-DAG: HIDDEN 1 protected_global
36+
# HID-DAG: HIDDEN 1 protected_weak
37+
38+
## Check that the visibility of all symbols is properly set to PROTECTED.
39+
# RUN: llvm-objcopy %t.o %t2.o --set-symbols-visibility=%t.symbols.regex=protected --regex
40+
# RUN: llvm-readelf -s %t2.o | FileCheck %s --check-prefix=PRO
41+
42+
# PRO-DAG: PROTECTED 1 default_local
43+
# PRO-DAG: PROTECTED 1 internal_local
44+
# PRO-DAG: PROTECTED 1 hidden_local
45+
# PRO-DAG: PROTECTED 1 protected_local
46+
# PRO-DAG: PROTECTED 1 default_global
47+
# PRO-DAG: PROTECTED 1 default_weak
48+
# PRO-DAG: PROTECTED 1 internal_global
49+
# PRO-DAG: PROTECTED 1 internal_weak
50+
# PRO-DAG: PROTECTED 1 hidden_global
51+
# PRO-DAG: PROTECTED 1 hidden_weak
52+
# PRO-DAG: PROTECTED 1 protected_global
53+
# PRO-DAG: PROTECTED 1 protected_weak
54+
55+
## Check that the visibility of all symbols is properly set to INTERNAL.
56+
# RUN: llvm-objcopy %t.o %t3.o --set-symbols-visibility=%t.symbols.regex=internal --regex
57+
# RUN: llvm-readelf -s %t3.o | FileCheck %s --check-prefix=INT
58+
59+
# INT-DAG: INTERNAL 1 default_local
60+
# INT-DAG: INTERNAL 1 internal_local
61+
# INT-DAG: INTERNAL 1 hidden_local
62+
# INT-DAG: INTERNAL 1 protected_local
63+
# INT-DAG: INTERNAL 1 default_global
64+
# INT-DAG: INTERNAL 1 default_weak
65+
# INT-DAG: INTERNAL 1 internal_global
66+
# INT-DAG: INTERNAL 1 internal_weak
67+
# INT-DAG: INTERNAL 1 hidden_global
68+
# INT-DAG: INTERNAL 1 hidden_weak
69+
# INT-DAG: INTERNAL 1 protected_global
70+
# INT-DAG: INTERNAL 1 protected_weak
71+
72+
## Check that setting the visibility of certain symbols that were read from
73+
## a file does not affect other symbols.
74+
# RUN: echo -e "default_local\ninternal_local" > %t.symbol.list
75+
# RUN: llvm-objcopy %t.o %t4.o --set-symbols-visibility=%t.symbol.list=hidden
76+
# RUN: llvm-readelf -s %t4.o | FileCheck %s --check-prefix=FILE
77+
78+
# FILE-DAG: HIDDEN 1 default_local
79+
# FILE-DAG: HIDDEN 1 internal_local
80+
## Unaffected symbols:
81+
# FILE-DAG: HIDDEN 1 hidden_local
82+
# FILE-DAG: PROTECTED 1 protected_local
83+
# FILE-DAG: DEFAULT 1 default_global
84+
# FILE-DAG: DEFAULT 1 default_weak
85+
# FILE-DAG: INTERNAL 1 internal_global
86+
# FILE-DAG: INTERNAL 1 internal_weak
87+
# FILE-DAG: HIDDEN 1 hidden_global
88+
# FILE-DAG: HIDDEN 1 hidden_weak
89+
# FILE-DAG: PROTECTED 1 protected_global
90+
# FILE-DAG: PROTECTED 1 protected_weak
91+
92+
## Check that the visibility of a single symbol is set correctly,
93+
## and that no other symbols are affected.
94+
# RUN: llvm-objcopy %t.o %t5.o --set-symbol-visibility=default_local=hidden \
95+
# RUN: --set-symbol-visibility=internal_local=protected \
96+
# RUN: --set-symbol-visibility=hidden_local=internal \
97+
# RUN: --set-symbol-visibility=protected_local=default
98+
# RUN: llvm-readelf -s %t5.o | FileCheck %s --check-prefix=SINGLE
99+
100+
# SINGLE-DAG: HIDDEN 1 default_local
101+
# SINGLE-DAG: PROTECTED 1 internal_local
102+
# SINGLE-DAG: INTERNAL 1 hidden_local
103+
# SINGLE-DAG: DEFAULT 1 protected_local
104+
## Unaffected symbols:
105+
# SINGLE-DAG: DEFAULT 1 default_global
106+
# SINGLE-DAG: DEFAULT 1 default_weak
107+
# SINGLE-DAG: INTERNAL 1 internal_global
108+
# SINGLE-DAG: INTERNAL 1 internal_weak
109+
# SINGLE-DAG: HIDDEN 1 hidden_global
110+
# SINGLE-DAG: HIDDEN 1 hidden_weak
111+
# SINGLE-DAG: PROTECTED 1 protected_global
112+
# SINGLE-DAG: PROTECTED 1 protected_weak
113+
114+
## Check that the visibility of symbols specified by a regex are set correctly,
115+
## and that no other symbols are affected.
116+
# RUN: llvm-objcopy %t.o %t6.o --set-symbol-visibility='.*'_local=hidden --regex
117+
# RUN: llvm-readelf -s %t6.o | FileCheck %s --check-prefix=REGEX
118+
119+
# REGEX-DAG: HIDDEN 1 default_local
120+
# REGEX-DAG: HIDDEN 1 internal_local
121+
# REGEX-DAG: HIDDEN 1 hidden_local
122+
# REGEX-DAG: HIDDEN 1 protected_local
123+
## Unaffected symbols:
124+
# REGEX-DAG: DEFAULT 1 default_global
125+
# REGEX-DAG: DEFAULT 1 default_weak
126+
# REGEX-DAG: INTERNAL 1 internal_global
127+
# REGEX-DAG: INTERNAL 1 internal_weak
128+
# REGEX-DAG: HIDDEN 1 hidden_global
129+
# REGEX-DAG: HIDDEN 1 hidden_weak
130+
# REGEX-DAG: PROTECTED 1 protected_global
131+
# REGEX-DAG: PROTECTED 1 protected_weak
132+
133+
## Check that the visibility of symbols specified by a wildcard are set correctly,
134+
## and that no other symbols are affected.
135+
# RUN: llvm-objcopy %t.o %t7.o --set-symbol-visibility='*_local'=hidden --wildcard
136+
# RUN: llvm-readelf -s %t7.o | FileCheck %s --check-prefix=WILDCARD
137+
138+
# WILDCARD-DAG: HIDDEN 1 default_local
139+
# WILDCARD-DAG: HIDDEN 1 internal_local
140+
# WILDCARD-DAG: HIDDEN 1 hidden_local
141+
# WILDCARD-DAG: HIDDEN 1 protected_local
142+
## Unaffected symbols:
143+
# WILDCARD-DAG: DEFAULT 1 default_global
144+
# WILDCARD-DAG: DEFAULT 1 default_weak
145+
# WILDCARD-DAG: INTERNAL 1 internal_global
146+
# WILDCARD-DAG: INTERNAL 1 internal_weak
147+
# WILDCARD-DAG: HIDDEN 1 hidden_global
148+
# WILDCARD-DAG: HIDDEN 1 hidden_weak
149+
# WILDCARD-DAG: PROTECTED 1 protected_global
150+
# WILDCARD-DAG: PROTECTED 1 protected_weak
151+
152+
## Check that the latest option that matches the same symbols as any of the previous
153+
## options overwrites the visibility of these symbols.
154+
# RUN: echo -e '*_weak\n*_local' > %t.symbols.pattern
155+
# RUN: llvm-objcopy %t.o %t8.o --set-symbol-visibility='default_*'=hidden \
156+
# RUN: --set-symbol-visibility='internal_*'=hidden \
157+
# RUN: --set-symbols-visibility=%t.symbols.pattern=protected \
158+
# RUN: --wildcard
159+
# RUN: llvm-readelf -s %t8.o | FileCheck %s --check-prefix=REWRITE
160+
161+
# REWRITE-DAG: PROTECTED 1 default_local
162+
# REWRITE-DAG: HIDDEN 1 default_global
163+
# REWRITE-DAG: PROTECTED 1 default_weak
164+
# REWRITE-DAG: PROTECTED 1 internal_local
165+
# REWRITE-DAG: HIDDEN 1 internal_global
166+
# REWRITE-DAG: PROTECTED 1 internal_weak
167+
# REWRITE-DAG: PROTECTED 1 hidden_local
168+
# REWRITE-DAG: PROTECTED 1 hidden_weak
169+
# REWRITE-DAG: PROTECTED 1 protected_local
170+
# REWRITE-DAG: PROTECTED 1 protected_weak
171+
## Unaffected symbols:
172+
# REWRITE-DAG: HIDDEN 1 hidden_global
173+
# REWRITE-DAG: PROTECTED 1 protected_global
174+
175+
## Check that a symbol name with a special charater is treated as a plain name
176+
## when pattern matching options are not enabled.
177+
# RUN: yaml2obj --docnum=2 %s -o %t9.o
178+
# RUN: llvm-objcopy %t9.o --set-symbol-visibility='f*o'=hidden
179+
# RUN: llvm-readelf -s %t9.o | FileCheck %s --check-prefix=SPECIAL
180+
181+
# SPECIAL-DAG: HIDDEN 1 f*o
182+
## Unaffected symbol:
183+
# SPECIAL-DAG: DEFAULT 1 foo
184+
185+
# RUN: yaml2obj --docnum=3 %s -o %t10.o
186+
187+
## Check that the visibility of undefined symbols can be changed as well.
188+
# RUN: llvm-objcopy %t10.o --set-symbol-visibility=foo=hidden
189+
# RUN: llvm-readelf -s %t10.o | FileCheck %s --check-prefix=UNDEF
190+
# UNDEF: HIDDEN UND foo
191+
192+
## Check that passing an invalid visibility type generates an error message.
193+
# RUN: echo 'foo' > %t.symbols
194+
# RUN: not llvm-objcopy %t10.o --set-symbols-visibility=%t.symbols=invalid-type 2>&1 | \
195+
# RUN: FileCheck %s --check-prefix=TYPE
196+
# RUN: not llvm-objcopy %t10.o --set-symbol-visibility=foo=invalid-type 2>&1 | \
197+
# RUN: FileCheck %s --check-prefix=TYPE
198+
# TYPE: error: 'invalid-type' is not a valid symbol visibility
199+
200+
## Check that omitting the '=' character generates an error.
201+
# RUN: not llvm-objcopy %t10.o --set-symbols-visibility=%t.symbols,hidden 2>&1 | \
202+
# RUN: FileCheck %s --check-prefix=FORMAT -DOPTION=--set-symbols-visibility
203+
# RUN: not llvm-objcopy %t10.o --set-symbol-visibility=foo default 2>&1 | \
204+
# RUN: FileCheck %s --check-prefix=FORMAT -DOPTION=--set-symbol-visibility
205+
# FORMAT: error: bad format for [[OPTION]]
206+
207+
## Check that using an invalid symbol pattern generates an error.
208+
# RUN: echo '*.' > %t.symbols.regex
209+
# RUN: not llvm-objcopy %t10.o --set-symbols-visibility=%t.symbols.regex=hidden --regex 2>&1 | \
210+
# RUN: FileCheck %s --check-prefix=SYMBOL
211+
# RUN: not llvm-objcopy %t10.o --set-symbol-visibility='*.'=default --regex 2>&1 | \
212+
# RUN: FileCheck %s --check-prefix=SYMBOL
213+
# SYMBOL: error: cannot compile regular expression '*.': repetition-operator operand invalid
214+
215+
## Check passing an invalid filename generates an error.
216+
# RUN: not llvm-objcopy %t10.o --set-symbols-visibility=no_file=hidden 2>&1 | \
217+
# RUN: FileCheck %s --check-prefix=NO_FILE -DMSG=%errc_ENOENT
218+
# NO_FILE: error: 'no_file': [[MSG]]
219+
220+
---
221+
!ELF
222+
FileHeader:
223+
Class: ELFCLASS64
224+
Data: ELFDATA2LSB
225+
Type: ET_REL
226+
Machine: EM_X86_64
227+
Sections:
228+
- Name: .text
229+
Type: SHT_PROGBITS
230+
Symbols:
231+
- Name: default_local
232+
Section: .text
233+
Binding: STB_LOCAL
234+
- Name: protected_local
235+
Section: .text
236+
Binding: STB_LOCAL
237+
Other: [ STV_PROTECTED ]
238+
- Name: internal_local
239+
Section: .text
240+
Binding: STB_LOCAL
241+
Other: [ STV_INTERNAL ]
242+
- Name: hidden_local
243+
Section: .text
244+
Binding: STB_LOCAL
245+
Other: [ STV_HIDDEN ]
246+
- Name: default_weak
247+
Section: .text
248+
Binding: STB_WEAK
249+
- Name: internal_weak
250+
Section: .text
251+
Binding: STB_WEAK
252+
Other: [ STV_INTERNAL ]
253+
- Name: hidden_weak
254+
Section: .text
255+
Binding: STB_WEAK
256+
Other: [ STV_HIDDEN ]
257+
- Name: protected_weak
258+
Section: .text
259+
Binding: STB_WEAK
260+
Other: [ STV_PROTECTED ]
261+
- Name: default_global
262+
Section: .text
263+
Binding: STB_GLOBAL
264+
- Name: internal_global
265+
Section: .text
266+
Binding: STB_GLOBAL
267+
Other: [ STV_INTERNAL ]
268+
- Name: hidden_global
269+
Section: .text
270+
Binding: STB_GLOBAL
271+
Other: [ STV_HIDDEN ]
272+
- Name: protected_global
273+
Section: .text
274+
Binding: STB_GLOBAL
275+
Other: [ STV_PROTECTED ]
276+
- Name: ignored_name
277+
Section: .text
278+
Binding: STB_GLOBAL
279+
Other: [ STV_INTERNAL ]
280+
...
281+
282+
---
283+
!ELF
284+
FileHeader:
285+
Class: ELFCLASS64
286+
Data: ELFDATA2LSB
287+
Type: ET_REL
288+
Machine: EM_X86_64
289+
Sections:
290+
- Name: .text
291+
Type: SHT_PROGBITS
292+
Symbols:
293+
- Name: f*o
294+
Section: .text
295+
Binding: STB_LOCAL
296+
- Name: foo
297+
Section: .text
298+
Binding: STB_LOCAL
299+
...
300+
301+
---
302+
!ELF
303+
FileHeader:
304+
Class: ELFCLASS64
305+
Data: ELFDATA2LSB
306+
Type: ET_REL
307+
Machine: EM_X86_64
308+
Symbols:
309+
- Name: foo
310+
Binding: STB_LOCAL
311+
...

0 commit comments

Comments
 (0)