-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[lld-macho] Fix invalid DWARF with --icf=safe_thunks #111097
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
Conversation
@llvm/pr-subscribers-lld-macho @llvm/pr-subscribers-lld Author: None (alx32) ChangesThere is a bug in the current implementation of To fix this we never generate STABS entries for such thunks. Full diff: https://github.com/llvm/llvm-project/pull/111097.diff 2 Files Affected:
diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index 7b0078856c5e22..319e7ec52c1ed4 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -1229,6 +1229,17 @@ void SymtabSection::emitStabs() {
if (defined->isAbsolute())
continue;
+ // Never generate a STABS entry for a symbol that has been ICF'ed using a
+ // thunk - just like we do for fully ICF'ed functions. Otherwise we end up
+ // generating invalid DWARF as dsymutil will think the entire function
+ // body is at that location, when in actuality only the thunk will be
+ // present. This will end up causing overlapping DWARF entries.
+ // TODO: Find an implementation that works in combination with
+ // `--keep-icf-stabs`.
+ if (defined->identicalCodeFoldingKind == Symbol::ICFFoldKind::Thunk) {
+ continue;
+ }
+
// Constant-folded symbols go in the executable's symbol table, but don't
// get a stabs entry unless --keep-icf-stabs flag is specified
if (!config->keepICFStabs &&
diff --git a/lld/test/MachO/icf-safe-thunks.ll b/lld/test/MachO/icf-safe-thunks.ll
index 238e90f952e160..bc014d307d5a24 100644
--- a/lld/test/MachO/icf-safe-thunks.ll
+++ b/lld/test/MachO/icf-safe-thunks.ll
@@ -6,6 +6,19 @@
; RUN: llvm-objdump %t/icf-safe.dylib -d --macho | FileCheck %s --check-prefixes=CHECK-ARM64
; RUN: cat %t/icf-safe.map | FileCheck %s --check-prefixes=CHECK-ARM64-MAP
+;;; Check that we generate valid dSYM and that stabs entries are not created for the ICF'ed functions (thunks)
+; RUN: dsymutil %t/icf-safe.dylib -o %t/icf-safe.dSYM
+; RUN: llvm-dwarfdump --verify %t/icf-safe.dSYM | FileCheck %s --check-prefix=VERIFY-DSYM
+; VERIFY-DSYM: No errors.
+
+;;; Check that we don't generate STABS entries (N_FUN) for ICF'ed functions
+; RUN: dsymutil -s %t/icf-safe.dylib | FileCheck %s --check-prefix=VERIFY-STABS
+; VERIFY-STABS-NOT: N_FUN {{.*}} _func_2identical_v2
+; VERIFY-STABS-NOT: N_FUN {{.*}} _func_3identical_v2
+; VERIFY-STABS-NOT: N_FUN {{.*}} _func_3identical_v3
+; VERIFY-STABS-NOT: N_FUN {{.*}} _func_3identical_v2_canmerge
+; VERIFY-STABS-NOT: N_FUN {{.*}} _func_3identical_v3_canmerge
+
; CHECK-ARM64: (__TEXT,__text) section
; CHECK-ARM64-NEXT: _func_unique_1:
; CHECK-ARM64-NEXT: mov {{.*}}, #0x1
@@ -49,127 +62,179 @@
; CHECK-ARM64-MAP-NEXT: 0x00000004 [ 2] _func_3identical_v2
; CHECK-ARM64-MAP-NEXT: 0x00000004 [ 2] _func_3identical_v3
+; ModuleID = 'icf-safe-thunks.cpp'
+source_filename = "icf-safe-thunks.cpp"
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128-Fn32"
target triple = "arm64-apple-macosx11.0.0"
-
-@g_val = global i8 0, align 1
-@g_ptr = global ptr null, align 8
-
+@g_val = global i8 0, align 1, !dbg !0
+@g_ptr = global ptr null, align 8, !dbg !7
; Function Attrs: mustprogress nofree noinline norecurse nounwind ssp memory(readwrite, argmem: none) uwtable(sync)
-define void @func_unique_1() #0 {
+define void @func_unique_1() #0 !dbg !19 {
entry:
- store volatile i8 1, ptr @g_val, align 1, !tbaa !5
- ret void
+ store volatile i8 1, ptr @g_val, align 1, !dbg !22, !tbaa !23
+ ret void, !dbg !26
}
-
; Function Attrs: mustprogress nofree noinline norecurse nounwind ssp memory(readwrite, argmem: none) uwtable(sync)
-define void @func_unique_2_canmerge() local_unnamed_addr #0 {
+define void @func_unique_2_canmerge() local_unnamed_addr #0 !dbg !27 {
entry:
- store volatile i8 2, ptr @g_val, align 1, !tbaa !5
- ret void
+ store volatile i8 2, ptr @g_val, align 1, !dbg !28, !tbaa !23
+ ret void, !dbg !29
}
-
; Function Attrs: mustprogress nofree noinline norecurse nounwind ssp memory(readwrite, argmem: none) uwtable(sync)
-define void @func_2identical_v1() #0 {
+define void @func_2identical_v1() #0 !dbg !30 {
entry:
- store volatile i8 2, ptr @g_val, align 1, !tbaa !5
- ret void
+ store volatile i8 2, ptr @g_val, align 1, !dbg !31, !tbaa !23
+ ret void, !dbg !32
}
-
; Function Attrs: mustprogress nofree noinline norecurse nounwind ssp memory(readwrite, argmem: none) uwtable(sync)
-define void @func_2identical_v2() #0 {
+define void @func_2identical_v2() #0 !dbg !33 {
entry:
- store volatile i8 2, ptr @g_val, align 1, !tbaa !5
- ret void
+ store volatile i8 2, ptr @g_val, align 1, !dbg !34, !tbaa !23
+ ret void, !dbg !35
}
-
; Function Attrs: mustprogress nofree noinline norecurse nounwind ssp memory(readwrite, argmem: none) uwtable(sync)
-define void @func_3identical_v1() #0 {
+define void @func_3identical_v1() #0 !dbg !36 {
entry:
- store volatile i8 3, ptr @g_val, align 1, !tbaa !5
- ret void
+ store volatile i8 3, ptr @g_val, align 1, !dbg !37, !tbaa !23
+ ret void, !dbg !38
}
-
; Function Attrs: mustprogress nofree noinline norecurse nounwind ssp memory(readwrite, argmem: none) uwtable(sync)
-define void @func_3identical_v2() #0 {
+define void @func_3identical_v2() #0 !dbg !39 {
entry:
- store volatile i8 3, ptr @g_val, align 1, !tbaa !5
- ret void
+ store volatile i8 3, ptr @g_val, align 1, !dbg !40, !tbaa !23
+ ret void, !dbg !41
}
-
; Function Attrs: mustprogress nofree noinline norecurse nounwind ssp memory(readwrite, argmem: none) uwtable(sync)
-define void @func_3identical_v3() #0 {
+define void @func_3identical_v3() #0 !dbg !42 {
entry:
- store volatile i8 3, ptr @g_val, align 1, !tbaa !5
- ret void
+ store volatile i8 3, ptr @g_val, align 1, !dbg !43, !tbaa !23
+ ret void, !dbg !44
}
-
; Function Attrs: mustprogress nofree noinline norecurse nounwind ssp memory(readwrite, argmem: none) uwtable(sync)
-define void @func_3identical_v1_canmerge() local_unnamed_addr #0 {
+define void @func_3identical_v1_canmerge() local_unnamed_addr #0 !dbg !45 {
entry:
- store volatile i8 33, ptr @g_val, align 1, !tbaa !5
- ret void
+ store volatile i8 33, ptr @g_val, align 1, !dbg !46, !tbaa !23
+ ret void, !dbg !47
}
-
; Function Attrs: mustprogress nofree noinline norecurse nounwind ssp memory(readwrite, argmem: none) uwtable(sync)
-define void @func_3identical_v2_canmerge() local_unnamed_addr #0 {
+define void @func_3identical_v2_canmerge() local_unnamed_addr #0 !dbg !48 {
entry:
- store volatile i8 33, ptr @g_val, align 1, !tbaa !5
- ret void
+ store volatile i8 33, ptr @g_val, align 1, !dbg !49, !tbaa !23
+ ret void, !dbg !50
}
-
; Function Attrs: mustprogress nofree noinline norecurse nounwind ssp memory(readwrite, argmem: none) uwtable(sync)
-define void @func_3identical_v3_canmerge() local_unnamed_addr #0 {
+define void @func_3identical_v3_canmerge() local_unnamed_addr #0 !dbg !51 {
entry:
- store volatile i8 33, ptr @g_val, align 1, !tbaa !5
- ret void
+ store volatile i8 33, ptr @g_val, align 1, !dbg !52, !tbaa !23
+ ret void, !dbg !53
}
-
; Function Attrs: mustprogress nofree noinline norecurse nounwind ssp uwtable(sync)
-define void @call_all_funcs() local_unnamed_addr #1 {
+define void @call_all_funcs() local_unnamed_addr #1 !dbg !54 {
entry:
- tail call void @func_unique_1()
- tail call void @func_unique_2_canmerge()
- tail call void @func_2identical_v1()
- tail call void @func_2identical_v2()
- tail call void @func_3identical_v1()
- tail call void @func_3identical_v2()
- tail call void @func_3identical_v3()
- tail call void @func_3identical_v1_canmerge()
- tail call void @func_3identical_v2_canmerge()
- tail call void @func_3identical_v3_canmerge()
- ret void
+ tail call void @func_unique_1(), !dbg !55
+ tail call void @func_unique_2_canmerge(), !dbg !56
+ tail call void @func_2identical_v1(), !dbg !57
+ tail call void @func_2identical_v2(), !dbg !58
+ tail call void @func_3identical_v1(), !dbg !59
+ tail call void @func_3identical_v2(), !dbg !60
+ tail call void @func_3identical_v3(), !dbg !61
+ tail call void @func_3identical_v1_canmerge(), !dbg !62
+ tail call void @func_3identical_v2_canmerge(), !dbg !63
+ tail call void @func_3identical_v3_canmerge(), !dbg !64
+ ret void, !dbg !65
}
-
; Function Attrs: mustprogress nofree noinline norecurse nounwind ssp memory(readwrite, argmem: none) uwtable(sync)
-define void @take_func_addr() local_unnamed_addr #0 {
+define void @take_func_addr() local_unnamed_addr #0 !dbg !66 {
entry:
- store volatile ptr @func_unique_1, ptr @g_ptr, align 8, !tbaa !8
- store volatile ptr @func_2identical_v1, ptr @g_ptr, align 8, !tbaa !8
- store volatile ptr @func_2identical_v2, ptr @g_ptr, align 8, !tbaa !8
- store volatile ptr @func_3identical_v1, ptr @g_ptr, align 8, !tbaa !8
- store volatile ptr @func_3identical_v2, ptr @g_ptr, align 8, !tbaa !8
- store volatile ptr @func_3identical_v3, ptr @g_ptr, align 8, !tbaa !8
- ret void
+ store volatile ptr @func_unique_1, ptr @g_ptr, align 8, !dbg !67, !tbaa !68
+ store volatile ptr @func_2identical_v1, ptr @g_ptr, align 8, !dbg !70, !tbaa !68
+ store volatile ptr @func_2identical_v2, ptr @g_ptr, align 8, !dbg !71, !tbaa !68
+ store volatile ptr @func_3identical_v1, ptr @g_ptr, align 8, !dbg !72, !tbaa !68
+ store volatile ptr @func_3identical_v2, ptr @g_ptr, align 8, !dbg !73, !tbaa !68
+ store volatile ptr @func_3identical_v3, ptr @g_ptr, align 8, !dbg !74, !tbaa !68
+ ret void, !dbg !75
}
-
-attributes #0 = { mustprogress nofree noinline norecurse nounwind ssp memory(readwrite, argmem: none) uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+altnzcv,+ccdp,+complxnum,+crc,+dotprod,+fp-armv8,+fp16fml,+fptoint,+fullfp16,+jsconv,+lse,+neon,+pauth,+perfmon,+predres,+ras,+rcpc,+rdm,+sb,+sha2,+sha3,+specrestrict,+ssbs,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a,+zcm,+zcz" }
-attributes #1 = { mustprogress nofree noinline norecurse nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+altnzcv,+ccdp,+complxnum,+crc,+dotprod,+fp-armv8,+fp16fml,+fptoint,+fullfp16,+jsconv,+lse,+neon,+pauth,+perfmon,+predres,+ras,+rcpc,+rdm,+sb,+sha2,+sha3,+specrestrict,+ssbs,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a,+zcm,+zcz" }
-
-!llvm.module.flags = !{!0, !1, !2, !3}
-!llvm.ident = !{!4}
-
-!0 = !{i32 1, !"wchar_size", i32 4}
-!1 = !{i32 8, !"PIC Level", i32 2}
-!2 = !{i32 7, !"uwtable", i32 1}
-!3 = !{i32 7, !"frame-pointer", i32 1}
-!4 = !{!"clang"}
-!5 = !{!6, !6, i64 0}
-!6 = !{!"omnipotent char", !7, i64 0}
-!7 = !{!"Simple C++ TBAA"}
-!8 = !{!9, !9, i64 0}
-!9 = !{!"any pointer", !6, i64 0}
-
+attributes #0 = { mustprogress nofree noinline norecurse nounwind ssp memory(readwrite, argmem: none) uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+altnzcv,+ccdp,+ccidx,+complxnum,+crc,+dit,+dotprod,+flagm,+fp-armv8,+fp16fml,+fptoint,+fullfp16,+jsconv,+lse,+neon,+pauth,+perfmon,+predres,+ras,+rcpc,+rdm,+sb,+sha2,+sha3,+specrestrict,+ssbs,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a,+zcm,+zcz" }
+attributes #1 = { mustprogress nofree noinline norecurse nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+altnzcv,+ccdp,+ccidx,+complxnum,+crc,+dit,+dotprod,+flagm,+fp-armv8,+fp16fml,+fptoint,+fullfp16,+jsconv,+lse,+neon,+pauth,+perfmon,+predres,+ras,+rcpc,+rdm,+sb,+sha2,+sha3,+specrestrict,+ssbs,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a,+zcm,+zcz" }
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!12, !13, !14, !15, !16, !17}
+!llvm.ident = !{!18}
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "g_val", scope: !2, file: !3, line: 5, type: !10, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 20.0.0git (https://github.com/alx32/llvm-project.git 02d6aad5cc940f17904c1288dfabc3fd2d439279)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: !4, globals: !6, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/")
+!3 = !DIFile(filename: "icf-safe-thunks.cpp", directory: "/tmp/safe_thunks")
+!4 = !{!5}
+!5 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+!6 = !{!0, !7}
+!7 = !DIGlobalVariableExpression(var: !8, expr: !DIExpression())
+!8 = distinct !DIGlobalVariable(name: "g_ptr", scope: !2, file: !3, line: 6, type: !9, isLocal: false, isDefinition: true)
+!9 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !5)
+!10 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !11)
+!11 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!12 = !{i32 7, !"Dwarf Version", i32 4}
+!13 = !{i32 2, !"Debug Info Version", i32 3}
+!14 = !{i32 1, !"wchar_size", i32 4}
+!15 = !{i32 8, !"PIC Level", i32 2}
+!16 = !{i32 7, !"uwtable", i32 1}
+!17 = !{i32 7, !"frame-pointer", i32 1}
+!18 = !{!"clang version 20.0.0git (https://github.com/alx32/llvm-project.git 02d6aad5cc940f17904c1288dfabc3fd2d439279)"}
+!19 = distinct !DISubprogram(name: "func_unique_1", scope: !3, file: !3, line: 8, type: !20, scopeLine: 8, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!20 = !DISubroutineType(types: !21)
+!21 = !{null}
+!22 = !DILocation(line: 9, column: 11, scope: !19)
+!23 = !{!24, !24, i64 0}
+!24 = !{!"omnipotent char", !25, i64 0}
+!25 = !{!"Simple C++ TBAA"}
+!26 = !DILocation(line: 10, column: 1, scope: !19)
+!27 = distinct !DISubprogram(name: "func_unique_2_canmerge", scope: !3, file: !3, line: 12, type: !20, scopeLine: 12, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!28 = !DILocation(line: 13, column: 11, scope: !27)
+!29 = !DILocation(line: 14, column: 1, scope: !27)
+!30 = distinct !DISubprogram(name: "func_2identical_v1", scope: !3, file: !3, line: 16, type: !20, scopeLine: 16, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!31 = !DILocation(line: 17, column: 11, scope: !30)
+!32 = !DILocation(line: 18, column: 1, scope: !30)
+!33 = distinct !DISubprogram(name: "func_2identical_v2", scope: !3, file: !3, line: 20, type: !20, scopeLine: 20, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!34 = !DILocation(line: 21, column: 11, scope: !33)
+!35 = !DILocation(line: 22, column: 1, scope: !33)
+!36 = distinct !DISubprogram(name: "func_3identical_v1", scope: !3, file: !3, line: 24, type: !20, scopeLine: 24, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!37 = !DILocation(line: 25, column: 11, scope: !36)
+!38 = !DILocation(line: 26, column: 1, scope: !36)
+!39 = distinct !DISubprogram(name: "func_3identical_v2", scope: !3, file: !3, line: 28, type: !20, scopeLine: 28, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!40 = !DILocation(line: 29, column: 11, scope: !39)
+!41 = !DILocation(line: 30, column: 1, scope: !39)
+!42 = distinct !DISubprogram(name: "func_3identical_v3", scope: !3, file: !3, line: 32, type: !20, scopeLine: 32, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!43 = !DILocation(line: 33, column: 11, scope: !42)
+!44 = !DILocation(line: 34, column: 1, scope: !42)
+!45 = distinct !DISubprogram(name: "func_3identical_v1_canmerge", scope: !3, file: !3, line: 36, type: !20, scopeLine: 36, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!46 = !DILocation(line: 37, column: 11, scope: !45)
+!47 = !DILocation(line: 38, column: 1, scope: !45)
+!48 = distinct !DISubprogram(name: "func_3identical_v2_canmerge", scope: !3, file: !3, line: 40, type: !20, scopeLine: 40, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!49 = !DILocation(line: 41, column: 11, scope: !48)
+!50 = !DILocation(line: 42, column: 1, scope: !48)
+!51 = distinct !DISubprogram(name: "func_3identical_v3_canmerge", scope: !3, file: !3, line: 44, type: !20, scopeLine: 44, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!52 = !DILocation(line: 45, column: 11, scope: !51)
+!53 = !DILocation(line: 46, column: 1, scope: !51)
+!54 = distinct !DISubprogram(name: "call_all_funcs", scope: !3, file: !3, line: 48, type: !20, scopeLine: 48, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!55 = !DILocation(line: 49, column: 5, scope: !54)
+!56 = !DILocation(line: 50, column: 5, scope: !54)
+!57 = !DILocation(line: 51, column: 5, scope: !54)
+!58 = !DILocation(line: 52, column: 5, scope: !54)
+!59 = !DILocation(line: 53, column: 5, scope: !54)
+!60 = !DILocation(line: 54, column: 5, scope: !54)
+!61 = !DILocation(line: 55, column: 5, scope: !54)
+!62 = !DILocation(line: 56, column: 5, scope: !54)
+!63 = !DILocation(line: 57, column: 5, scope: !54)
+!64 = !DILocation(line: 58, column: 5, scope: !54)
+!65 = !DILocation(line: 59, column: 1, scope: !54)
+!66 = distinct !DISubprogram(name: "take_func_addr", scope: !3, file: !3, line: 61, type: !20, scopeLine: 61, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!67 = !DILocation(line: 62, column: 11, scope: !66)
+!68 = !{!69, !69, i64 0}
+!69 = !{!"any pointer", !24, i64 0}
+!70 = !DILocation(line: 63, column: 11, scope: !66)
+!71 = !DILocation(line: 64, column: 11, scope: !66)
+!72 = !DILocation(line: 65, column: 11, scope: !66)
+!73 = !DILocation(line: 66, column: 11, scope: !66)
+!74 = !DILocation(line: 67, column: 11, scope: !66)
+!75 = !DILocation(line: 68, column: 1, scope: !66)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;; Generate the above LLVM IR with the below script ;;;;;;;;;;;;;;;
@@ -250,5 +315,5 @@ attributes #1 = { mustprogress nofree noinline norecurse nounwind ssp uwtable(sy
; }
; EOF
;
-; $TOOLCHAIN_BIN/clang -target arm64-apple-macos11.0 -S -emit-llvm \
+; $TOOLCHAIN_BIN/clang -target arm64-apple-macos11.0 -S -emit-llvm -g \
; icf-safe-thunks.cpp -O3 -o icf-safe-thunks.ll
|
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
.