Skip to content

Commit 651ecfb

Browse files
committed
[lld][MachO] ICF functions with calls to thunks
1 parent c3316b4 commit 651ecfb

3 files changed

Lines changed: 245 additions & 17 deletions

File tree

‎lld/MachO/ICF.cpp‎

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,22 @@ static bool compareData(const ConcatInputSection *ia,
142142
return bufA == bufB;
143143
}
144144

145+
static Defined *getDirectCallTarget(const Relocation &r) {
146+
if (r.getAddend() != 0 || !target->hasAttr(r.type, RelocAttrBits::BRANCH))
147+
return nullptr;
148+
auto *defined =
149+
dyn_cast_or_null<Defined>(dyn_cast_if_present<Symbol *>(r.referent));
150+
if (!defined || defined->value != 0 || !defined->originalIsec ||
151+
!isCodeSection(defined->originalIsec) || needsBinding(defined))
152+
return nullptr;
153+
return defined;
154+
}
155+
156+
static bool canIgnoreTargetAddresses(const Relocation &a, const Relocation &b) {
157+
return config->icfLevel == ICFLevel::safe_thunks && getDirectCallTarget(a) &&
158+
getDirectCallTarget(b);
159+
}
160+
145161
// Compare "non-moving" parts of two ConcatInputSections, namely everything
146162
// except references to other ConcatInputSections.
147163
bool ICF::equalsConstant(const ConcatInputSection *ia,
@@ -197,15 +213,12 @@ bool ICF::equalsConstant(const ConcatInputSection *ia,
197213
isecB = cast<InputSection *>(rb.referent);
198214
}
199215

200-
// Typically, we should not encounter sections marked with `keepUnique` at
201-
// this point as they would have resulted in different hashes and therefore
202-
// no need for a full comparison.
203-
// However, in `safe_thunks` mode, it's possible for two different
204-
// relocations to reference identical `keepUnique` functions that will be
205-
// distinguished later via thunks - so we need to handle this case
206-
// explicitly.
207-
if ((isecA != isecB) && ((isecA->keepUnique && isCodeSection(isecA)) ||
208-
(isecB->keepUnique && isCodeSection(isecB))))
216+
// Keep address-taking references distinct; direct calls to equivalent
217+
// bodies are safe to fold.
218+
if (isecA != isecB &&
219+
((isecA->keepUnique && isCodeSection(isecA)) ||
220+
(isecB->keepUnique && isCodeSection(isecB))) &&
221+
!canIgnoreTargetAddresses(ra, rb))
209222
return false;
210223

211224
if (isecA->parent != isecB->parent)
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
# REQUIRES: aarch64
2+
3+
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %s -o %t.o
4+
# RUN: %lld -arch arm64 -dylib --icf=safe_thunks -interposable %t.o -map - -o %t.dylib | FileCheck %s
5+
# RUN: llvm-objdump --macho --disassemble %t.dylib | FileCheck %s --check-prefix=DISASM
6+
7+
## Taking the leaves' addresses must still produce different code. A caller of
8+
## a thunk leading to a different body must also keep its own body.
9+
# CHECK-DAG: 0x0000000C {{.*}} _address_a
10+
# CHECK-DAG: 0x0000000C {{.*}} _address_b
11+
# CHECK-DAG: 0x00000008 {{.*}} _leaf_c
12+
# CHECK-DAG: 0x00000004 {{.*}} _leaf_d
13+
# CHECK-DAG: 0x00000004 {{.*}} _interposable_leaf
14+
# CHECK-DAG: 0x00000018 {{.*}} _call_c
15+
16+
## Calls and tail branches to equivalent bodies allow their callers to fold.
17+
# CHECK-DAG: [[CALL:0x[0-9A-Fa-f]+]] 0x00000018 {{.*}} _call_a
18+
# CHECK-DAG: [[CALL]] 0x00000000 {{.*}} _call_b
19+
# CHECK-DAG: [[TAIL:0x[0-9A-Fa-f]+]] 0x00000008 {{.*}} _tail_a
20+
# CHECK-DAG: [[TAIL]] 0x00000000 {{.*}} _tail_b
21+
22+
## Address-significant callers must retain unique entrypoints too.
23+
# CHECK-DAG: 0x00000018 {{.*}} _unique_a
24+
# CHECK-DAG: 0x00000004 {{.*}} _unique_b
25+
26+
## Recursive bodies can be equivalent while their entrypoints remain distinct.
27+
# CHECK-DAG: 0x00000010 {{.*}} _recursive_a
28+
# CHECK-DAG: 0x00000004 {{.*}} _recursive_b
29+
30+
## Address-significant leaves share a body through a unique entry thunk.
31+
# DISASM-LABEL: _leaf_a:
32+
# DISASM-NEXT: [[#%x,LEAF_A:]]:
33+
34+
## Folded callers share a callsite; distinct callees keep distinct callers.
35+
# DISASM-LABEL: _call_b:
36+
# DISASM: {{.*}} bl _leaf_a
37+
# DISASM-LABEL: _call_c:
38+
# DISASM: {{.*}} bl _leaf_d
39+
40+
# DISASM-LABEL: _call_only_b:
41+
# DISASM: {{.*}} bl _leaf_b
42+
43+
# DISASM-LABEL: _address_a:
44+
# DISASM: add x0, x0, #0x[[#%x,LEAF_A]]
45+
# DISASM-LABEL: _address_b:
46+
# DISASM: add x0, x0, #0x[[#%x,LEAF_B:]]
47+
## Direct and indirect calls to a thunk preserve the same entrypoint.
48+
# DISASM-LABEL: _call_direct_and_indirect_b:
49+
# DISASM: add x8, x8, #0x[[#%x,LEAF_B]]
50+
# DISASM: {{.*}} bl _leaf_b
51+
# DISASM: blr x8
52+
53+
## Runtime-bound direct calls still resolve the original symbol.
54+
# DISASM-LABEL: _call_interposable:
55+
# DISASM: {{.*}} bl {{.*}}symbol stub for: _interposable_leaf
56+
57+
# DISASM-LABEL: _leaf_d:
58+
# DISASM-NEXT: {{.*}} b _leaf_c
59+
# DISASM-LABEL: _leaf_b:
60+
# DISASM-NEXT: [[#%x,LEAF_B]]: {{.*}} b _leaf_a
61+
# DISASM-LABEL: _unique_b:
62+
# DISASM-NEXT: {{.*}} b _unique_a
63+
64+
.subsections_via_symbols
65+
.text
66+
.p2align 2
67+
.globl _leaf_a, _leaf_b, _leaf_c, _leaf_d
68+
.globl _call_a, _call_b, _call_c, _call_only_b, _tail_a, _tail_b
69+
.globl _unique_a, _unique_b, _address_a, _address_b
70+
.globl _recursive_a, _recursive_b
71+
.globl _call_direct_and_indirect_b
72+
.private_extern _leaf_a, _leaf_b, _leaf_c, _leaf_d
73+
.private_extern _unique_a, _unique_b, _recursive_a, _recursive_b
74+
.globl _interposable_leaf, _call_interposable
75+
76+
_leaf_a:
77+
add w0, w0, #7
78+
ret
79+
80+
_leaf_b:
81+
add w0, w0, #7
82+
ret
83+
84+
_leaf_c:
85+
add w0, w0, #9
86+
ret
87+
88+
_leaf_d:
89+
add w0, w0, #9
90+
ret
91+
92+
_call_a:
93+
stp x29, x30, [sp, #-16]!
94+
mov x29, sp
95+
bl _leaf_a
96+
add w0, w0, #3
97+
ldp x29, x30, [sp], #16
98+
ret
99+
100+
_call_b:
101+
stp x29, x30, [sp, #-16]!
102+
mov x29, sp
103+
bl _leaf_b
104+
add w0, w0, #3
105+
ldp x29, x30, [sp], #16
106+
ret
107+
108+
_call_c:
109+
stp x29, x30, [sp, #-16]!
110+
mov x29, sp
111+
bl _leaf_d
112+
add w0, w0, #3
113+
ldp x29, x30, [sp], #16
114+
ret
115+
116+
_call_only_b:
117+
stp x29, x30, [sp, #-16]!
118+
mov x29, sp
119+
bl _leaf_b
120+
add w0, w0, #11
121+
ldp x29, x30, [sp], #16
122+
ret
123+
124+
_tail_a:
125+
eor w0, w0, #1
126+
b _leaf_a
127+
128+
_tail_b:
129+
eor w0, w0, #1
130+
b _leaf_b
131+
132+
_unique_a:
133+
stp x29, x30, [sp, #-16]!
134+
mov x29, sp
135+
bl _leaf_a
136+
add w0, w0, #5
137+
ldp x29, x30, [sp], #16
138+
ret
139+
140+
_unique_b:
141+
stp x29, x30, [sp, #-16]!
142+
mov x29, sp
143+
bl _leaf_b
144+
add w0, w0, #5
145+
ldp x29, x30, [sp], #16
146+
ret
147+
148+
_recursive_a:
149+
subs w0, w0, #1
150+
b.eq Lrecursive_done_a
151+
b _recursive_step_a
152+
Lrecursive_done_a:
153+
ret
154+
155+
_recursive_b:
156+
subs w0, w0, #1
157+
b.eq Lrecursive_done_b
158+
b _recursive_step_b
159+
Lrecursive_done_b:
160+
ret
161+
162+
_recursive_step_a:
163+
b _recursive_a
164+
nop
165+
166+
_recursive_step_b:
167+
b _recursive_b
168+
nop
169+
170+
_address_a:
171+
adrp x0, _leaf_a@PAGE
172+
add x0, x0, _leaf_a@PAGEOFF
173+
ret
174+
175+
_address_b:
176+
adrp x0, _leaf_b@PAGE
177+
add x0, x0, _leaf_b@PAGEOFF
178+
ret
179+
180+
_call_direct_and_indirect_b:
181+
stp x29, x30, [sp, #-32]!
182+
mov x29, sp
183+
adrp x8, _leaf_b@PAGE
184+
add x8, x8, _leaf_b@PAGEOFF
185+
str x8, [sp, #16]
186+
bl _leaf_b
187+
ldr x8, [sp, #16]
188+
blr x8
189+
ldp x29, x30, [sp], #32
190+
ret
191+
192+
_interposable_leaf:
193+
add w0, w0, #7
194+
ret
195+
196+
_call_interposable:
197+
stp x29, x30, [sp, #-16]!
198+
bl _interposable_leaf
199+
ldp x29, x30, [sp], #16
200+
ret
201+
202+
.data
203+
.p2align 3
204+
.globl _addresses
205+
_addresses:
206+
.quad _leaf_a, _leaf_b, _leaf_c, _leaf_d, _unique_a, _unique_b, _recursive_a, _recursive_b
207+
208+
.addrsig
209+
.addrsig_sym _leaf_a
210+
.addrsig_sym _leaf_b
211+
.addrsig_sym _leaf_c
212+
.addrsig_sym _leaf_d
213+
.addrsig_sym _unique_a
214+
.addrsig_sym _unique_b
215+
.addrsig_sym _recursive_a
216+
.addrsig_sym _recursive_b
217+
.addrsig_sym _recursive_step_a
218+
.addrsig_sym _recursive_step_b
219+
.addrsig_sym _interposable_leaf

‎lld/test/MachO/icf-safe-thunks.ll‎

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,7 @@
3232
; CHECK-ARM64: mov {{.*}}, #0x21
3333
;
3434
; CHECK-ARM64: _func_call_thunked_1_nomerge:
35-
; CHECK-ARM64-NEXT: stp x29
36-
;
37-
; CHECK-ARM64: _func_call_thunked_2_nomerge:
35+
; CHECK-ARM64-NEXT: _func_call_thunked_2_nomerge:
3836
; CHECK-ARM64-NEXT: _func_call_thunked_2_merge:
3937
; CHECK-ARM64-NEXT: stp x29
4038
;
@@ -69,9 +67,7 @@
6967
; CHECK-LTO: mov {{.*}}, #0x21
7068
;
7169
; CHECK-LTO: _func_call_thunked_1_nomerge:
72-
; CHECK-LTO-NEXT: stp x29
73-
;
74-
; CHECK-LTO: _func_call_thunked_2_nomerge:
70+
; CHECK-LTO-NEXT: _func_call_thunked_2_nomerge:
7571
; CHECK-LTO-NEXT: _func_call_thunked_2_merge:
7672
; CHECK-LTO-NEXT: stp x29
7773
;
@@ -96,7 +92,7 @@
9692
; CHECK-LTO-MAP-NEXT: 0x00000000 [ 2] _func_3identical_v2_canmerge
9793
; CHECK-LTO-MAP-NEXT: 0x00000000 [ 2] _func_3identical_v3_canmerge
9894
; CHECK-LTO-MAP-NEXT: 0x00000020 [ 2] _func_call_thunked_1_nomerge
99-
; CHECK-LTO-MAP-NEXT: 0x00000020 [ 2] _func_call_thunked_2_nomerge
95+
; CHECK-LTO-MAP-NEXT: 0x00000000 [ 2] _func_call_thunked_2_nomerge
10096
; CHECK-LTO-MAP-NEXT: 0x00000000 [ 2] _func_call_thunked_2_merge
10197
; CHECK-LTO-MAP-NEXT: 0x00000034 [ 2] _call_all_funcs
10298
; CHECK-LTO-MAP-NEXT: 0x00000050 [ 2] _take_func_addr
@@ -112,7 +108,7 @@
112108
; CHECK-ARM64-MAP-NEXT: 0x00000000 [ 2] _func_3identical_v2_canmerge
113109
; CHECK-ARM64-MAP-NEXT: 0x00000000 [ 2] _func_3identical_v3_canmerge
114110
; CHECK-ARM64-MAP-NEXT: 0x00000020 [ 2] _func_call_thunked_1_nomerge
115-
; CHECK-ARM64-MAP-NEXT: 0x00000020 [ 2] _func_call_thunked_2_nomerge
111+
; CHECK-ARM64-MAP-NEXT: 0x00000000 [ 2] _func_call_thunked_2_nomerge
116112
; CHECK-ARM64-MAP-NEXT: 0x00000000 [ 2] _func_call_thunked_2_merge
117113
; CHECK-ARM64-MAP-NEXT: 0x00000034 [ 2] _call_all_funcs
118114
; CHECK-ARM64-MAP-NEXT: 0x00000050 [ 2] _take_func_addr

0 commit comments

Comments
 (0)