Skip to content

Commit 9e862ae

Browse files
authored
[lld-macho] Fix invalid DWARF with --icf=safe_thunks (#111097)
There is a bug in the current implementation of `--icf=safe_thunks` where a STABS entry is emitted for generated thunks. This is problematic as we end up generating invalid DWARF as dsymutil will think the entire function body is at the thunk location, when in actuality there will only be a single branch present. This will end up causing overlapping DWARF entries. To fix this we never generate STABS entries for such thunks. The existing `--icf=safe_thunks` test is updated to also generate debug info and we add a check that no corrupt DWARF is generated. As a future TODO we need to make `--keep-icf-stabs` compatible with `--icf=safe_thunks`.
1 parent bf895c7 commit 9e862ae

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

lld/MachO/SyntheticSections.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,6 +1229,16 @@ void SymtabSection::emitStabs() {
12291229
if (defined->isAbsolute())
12301230
continue;
12311231

1232+
// Never generate a STABS entry for a symbol that has been ICF'ed using a
1233+
// thunk, just as we do for fully ICF'ed functions. Otherwise, we end up
1234+
// generating invalid DWARF as dsymutil will assume the entire function
1235+
// body is at that location, when, in reality, only the thunk is
1236+
// present. This will end up causing overlapping DWARF entries.
1237+
// TODO: Find an implementation that works in combination with
1238+
// `--keep-icf-stabs`.
1239+
if (defined->identicalCodeFoldingKind == Symbol::ICFFoldKind::Thunk)
1240+
continue;
1241+
12321242
// Constant-folded symbols go in the executable's symbol table, but don't
12331243
// get a stabs entry unless --keep-icf-stabs flag is specified
12341244
if (!config->keepICFStabs &&
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
; REQUIRES: aarch64
2+
3+
;;; Build the
4+
; RUN: rm -rf %t; mkdir %t
5+
; RUN: llc -filetype=obj %s -O3 -o %t/icf-obj-safe-thunks-dwarf.o -enable-machine-outliner=never -mtriple arm64-apple-macos -addrsig
6+
; RUN: %lld -arch arm64 -lSystem --icf=safe_thunks -dylib -o %t/icf-safe-dwarf.dylib %t/icf-obj-safe-thunks-dwarf.o
7+
8+
;;; Check that we generate valid dSYM
9+
; RUN: dsymutil %t/icf-safe-dwarf.dylib -o %t/icf-safe.dSYM
10+
; RUN: llvm-dwarfdump --verify %t/icf-safe.dSYM | FileCheck %s --check-prefix=VERIFY-DSYM
11+
; VERIFY-DSYM: No errors.
12+
13+
;;; Check that we don't generate STABS entries (N_FUN) for ICF'ed function thunks
14+
; RUN: dsymutil -s %t/icf-safe-dwarf.dylib | FileCheck %s --check-prefix=VERIFY-STABS
15+
; VERIFY-STABS-NOT: N_FUN{{.*}}_func_B
16+
; VERIFY-STABS-NOT: N_FUN{{.*}}_func_C
17+
18+
;;; Check that we do generate STABS entries (N_FUN) for non-ICF'ed functions
19+
; VERIFY-STABS: N_FUN{{.*}}_func_A
20+
; VERIFY-STABS: N_FUN{{.*}}_take_func_addr
21+
22+
23+
; ModuleID = 'icf-safe-thunks-dwarf.cpp'
24+
source_filename = "icf-safe-thunks-dwarf.cpp"
25+
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128-Fn32"
26+
target triple = "arm64-apple-macosx11.0.0"
27+
28+
; Function Attrs: mustprogress noinline nounwind optnone ssp uwtable(sync)
29+
define i32 @func_A() #0 !dbg !13 {
30+
entry:
31+
ret i32 1
32+
}
33+
34+
; Function Attrs: mustprogress noinline nounwind optnone ssp uwtable(sync)
35+
define i32 @func_B() #0 !dbg !18 {
36+
entry:
37+
ret i32 1
38+
}
39+
40+
; Function Attrs: mustprogress noinline nounwind optnone ssp uwtable(sync)
41+
define i32 @func_C() #0 !dbg !20 {
42+
entry:
43+
ret i32 1
44+
}
45+
46+
; Function Attrs: mustprogress noinline nounwind optnone ssp uwtable(sync)
47+
define i64 @take_func_addr() #0 !dbg !22 {
48+
entry:
49+
%val = alloca i64, align 8
50+
store i64 0, ptr %val, align 8
51+
%0 = load i64, ptr %val, align 8
52+
%add = add i64 %0, ptrtoint (ptr @func_A to i64)
53+
store i64 %add, ptr %val, align 8
54+
%1 = load i64, ptr %val, align 8
55+
%add1 = add i64 %1, ptrtoint (ptr @func_B to i64)
56+
store i64 %add1, ptr %val, align 8
57+
%2 = load i64, ptr %val, align 8
58+
%add2 = add i64 %2, ptrtoint (ptr @func_C to i64)
59+
store i64 %add2, ptr %val, align 8
60+
%3 = load i64, ptr %val, align 8
61+
ret i64 %3
62+
}
63+
64+
attributes #0 = { noinline nounwind }
65+
66+
!llvm.dbg.cu = !{!0}
67+
!llvm.module.flags = !{!6, !7, !8, !9, !10, !11}
68+
!llvm.ident = !{!12}
69+
70+
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 20.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/")
71+
!1 = !DIFile(filename: "icf-safe-thunks-dwarf.cpp", directory: "/tmp/test")
72+
!6 = !{i32 7, !"Dwarf Version", i32 4}
73+
!7 = !{i32 2, !"Debug Info Version", i32 3}
74+
!8 = !{i32 1, !"wchar_size", i32 4}
75+
!9 = !{i32 8, !"PIC Level", i32 2}
76+
!10 = !{i32 7, !"uwtable", i32 1}
77+
!11 = !{i32 7, !"frame-pointer", i32 1}
78+
!12 = !{!"clang version 20.0.0"}
79+
!13 = distinct !DISubprogram(name: "func_A", scope: !1, file: !1, line: 4, type: !14, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
80+
!14 = !DISubroutineType(types: !15)
81+
!15 = !{}
82+
!18 = distinct !DISubprogram(name: "func_B", scope: !1, file: !1, line: 5, type: !14, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
83+
!20 = distinct !DISubprogram(name: "func_C", scope: !1, file: !1, line: 6, type: !14, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
84+
!22 = distinct !DISubprogram(name: "take_func_addr", scope: !1, file: !1, line: 8, type: !14, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
85+
86+
87+
88+
89+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
90+
;;;;;;;;;;;;;; Generate the above LLVM IR with the below script ;;;;;;;;;;;;;;;
91+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
92+
; #!/bin/bash
93+
; set -ex
94+
; TOOLCHAIN_BIN="llvm-project/build/Debug/bin"
95+
;
96+
; # Create icf-safe-thunks-dwarf.cpp file
97+
; cat > icf-safe-thunks-dwarf.cpp <<EOF
98+
; #define ATTR __attribute__((noinline)) extern "C"
99+
; typedef unsigned long long ULL;
100+
;
101+
; ATTR int func_A() { return 1; }
102+
; ATTR int func_B() { return 1; }
103+
; ATTR int func_C() { return 1; }
104+
;
105+
; ATTR ULL take_func_addr() {
106+
; ULL val = 0;
107+
; val += (ULL)(void*)func_A;
108+
; val += (ULL)(void*)func_B;
109+
; val += (ULL)(void*)func_C;
110+
; return val;
111+
; }
112+
; EOF
113+
;
114+
; $TOOLCHAIN_BIN/clang -target arm64-apple-macos11.0 -S -emit-llvm -g \
115+
; icf-safe-thunks-dwarf.cpp

0 commit comments

Comments
 (0)