[lld] 9e862ae - [lld-macho] Fix invalid DWARF with --icf=safe_thunks (#111097)

via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 4 21:48:13 PDT 2024


Author: alx32
Date: 2024-10-04T21:48:09-07:00
New Revision: 9e862ae3219b09283971ca0ced52a64b0d6db86b

URL: https://github.com/llvm/llvm-project/commit/9e862ae3219b09283971ca0ced52a64b0d6db86b
DIFF: https://github.com/llvm/llvm-project/commit/9e862ae3219b09283971ca0ced52a64b0d6db86b.diff

LOG: [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`.

Added: 
    lld/test/MachO/icf-safe-thunks-dwarf.ll

Modified: 
    lld/MachO/SyntheticSections.cpp

Removed: 
    


################################################################################
diff  --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index 7b0078856c5e22..eee87b3a6cb4de 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -1229,6 +1229,16 @@ void SymtabSection::emitStabs() {
       if (defined->isAbsolute())
         continue;
 
+      // Never generate a STABS entry for a symbol that has been ICF'ed using a
+      // thunk, just as we do for fully ICF'ed functions. Otherwise, we end up
+      // generating invalid DWARF as dsymutil will assume the entire function
+      // body is at that location, when, in reality, only the thunk is
+      // 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-dwarf.ll b/lld/test/MachO/icf-safe-thunks-dwarf.ll
new file mode 100644
index 00000000000000..74f3fb7a033db8
--- /dev/null
+++ b/lld/test/MachO/icf-safe-thunks-dwarf.ll
@@ -0,0 +1,115 @@
+; REQUIRES: aarch64
+
+;;; Build the
+; RUN: rm -rf %t; mkdir %t
+; RUN: llc -filetype=obj %s -O3 -o %t/icf-obj-safe-thunks-dwarf.o -enable-machine-outliner=never -mtriple arm64-apple-macos -addrsig
+; RUN: %lld -arch arm64 -lSystem --icf=safe_thunks -dylib -o %t/icf-safe-dwarf.dylib %t/icf-obj-safe-thunks-dwarf.o
+
+;;; Check that we generate valid dSYM
+; RUN: dsymutil %t/icf-safe-dwarf.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 function thunks
+; RUN: dsymutil -s %t/icf-safe-dwarf.dylib | FileCheck %s --check-prefix=VERIFY-STABS
+; VERIFY-STABS-NOT:  N_FUN{{.*}}_func_B
+; VERIFY-STABS-NOT:  N_FUN{{.*}}_func_C
+
+;;; Check that we do generate STABS entries (N_FUN) for non-ICF'ed functions
+; VERIFY-STABS:  N_FUN{{.*}}_func_A
+; VERIFY-STABS:  N_FUN{{.*}}_take_func_addr
+
+
+; ModuleID = 'icf-safe-thunks-dwarf.cpp'
+source_filename = "icf-safe-thunks-dwarf.cpp"
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128-Fn32"
+target triple = "arm64-apple-macosx11.0.0"
+
+; Function Attrs: mustprogress noinline nounwind optnone ssp uwtable(sync)
+define i32 @func_A() #0 !dbg !13 {
+entry:
+  ret i32 1
+}
+
+; Function Attrs: mustprogress noinline nounwind optnone ssp uwtable(sync)
+define i32 @func_B() #0 !dbg !18 {
+entry:
+  ret i32 1
+}
+
+; Function Attrs: mustprogress noinline nounwind optnone ssp uwtable(sync)
+define i32 @func_C() #0 !dbg !20 {
+entry:
+  ret i32 1
+}
+
+; Function Attrs: mustprogress noinline nounwind optnone ssp uwtable(sync)
+define i64 @take_func_addr() #0 !dbg !22 {
+entry:
+  %val = alloca i64, align 8
+  store i64 0, ptr %val, align 8
+  %0 = load i64, ptr %val, align 8
+  %add = add i64 %0, ptrtoint (ptr @func_A to i64)
+  store i64 %add, ptr %val, align 8
+  %1 = load i64, ptr %val, align 8
+  %add1 = add i64 %1, ptrtoint (ptr @func_B to i64)
+  store i64 %add1, ptr %val, align 8
+  %2 = load i64, ptr %val, align 8
+  %add2 = add i64 %2, ptrtoint (ptr @func_C to i64)
+  store i64 %add2, ptr %val, align 8
+  %3 = load i64, ptr %val, align 8
+  ret i64 %3
+}
+
+attributes #0 = { noinline nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!6, !7, !8, !9, !10, !11}
+!llvm.ident = !{!12}
+
+!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: "/")
+!1 = !DIFile(filename: "icf-safe-thunks-dwarf.cpp", directory: "/tmp/test")
+!6 = !{i32 7, !"Dwarf Version", i32 4}
+!7 = !{i32 2, !"Debug Info Version", i32 3}
+!8 = !{i32 1, !"wchar_size", i32 4}
+!9 = !{i32 8, !"PIC Level", i32 2}
+!10 = !{i32 7, !"uwtable", i32 1}
+!11 = !{i32 7, !"frame-pointer", i32 1}
+!12 = !{!"clang version 20.0.0"}
+!13 = distinct !DISubprogram(name: "func_A", scope: !1, file: !1, line: 4, type: !14, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
+!14 = !DISubroutineType(types: !15)
+!15 = !{}
+!18 = distinct !DISubprogram(name: "func_B", scope: !1, file: !1, line: 5, type: !14, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
+!20 = distinct !DISubprogram(name: "func_C", scope: !1, file: !1, line: 6, type: !14, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
+!22 = distinct !DISubprogram(name: "take_func_addr", scope: !1, file: !1, line: 8, type: !14, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
+
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;; Generate the above LLVM IR with the below script ;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; #!/bin/bash
+; set -ex
+; TOOLCHAIN_BIN="llvm-project/build/Debug/bin"
+;
+; # Create icf-safe-thunks-dwarf.cpp file
+; cat > icf-safe-thunks-dwarf.cpp <<EOF
+; #define ATTR __attribute__((noinline)) extern "C"
+; typedef unsigned long long ULL;
+;
+; ATTR int func_A() { return 1; }
+; ATTR int func_B() { return 1; }
+; ATTR int func_C() { return 1; }
+;
+; ATTR ULL take_func_addr() {
+;     ULL val = 0;
+;     val += (ULL)(void*)func_A;
+;     val += (ULL)(void*)func_B;
+;     val += (ULL)(void*)func_C;
+;     return val;
+; }
+; EOF
+;
+; $TOOLCHAIN_BIN/clang -target arm64-apple-macos11.0 -S -emit-llvm -g \
+;                      icf-safe-thunks-dwarf.cpp


        


More information about the llvm-commits mailing list