From 4c0d6bea6317626e0f85b6bd5b2354f6be657e31 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Wed, 6 Dec 2023 15:02:14 -0800 Subject: [PATCH 1/2] [ELF] Change .debug_names tombstone value to UINT32_MAX/UINT64_MAX `clang -g -gpubnames -fdebug-types-section` now emits .debug_names section with references to local type unit entries defined in COMDAT .debug_info sections. ``` .section .debug_info,"G",@progbits,5657452045627120676,comdat .Ltu_begin0: ... .section .debug_names,"",@progbits ... // DWARF32 .long .Ltu_begin0 # Type unit 0 // DWARF64 // .long .Ltu_begin0 # Type unit 0 ``` When `.Ltu_begin0` is relative to a non-prevailing .debug_info section, the relocation resolves to 0, which is a valid offset within the .debug_info section. ``` cat > a.cc < b.cc < rels) { const TargetInfo &target = *elf::target; const auto emachine = config->emachine; const bool isDebug = isDebugSection(*this); - const bool isDebugLocOrRanges = - isDebug && (name == ".debug_loc" || name == ".debug_ranges"); const bool isDebugLine = isDebug && name == ".debug_line"; - std::optional tombstone; + std::optional tombstone, debugTombstone; + if (isDebug) { + if (name == ".debug_loc" || name == ".debug_ranges") + debugTombstone = 1; + else if (name == ".debug_names") + debugTombstone = UINT64_MAX; // DWARF Issue 231013.1 + else + debugTombstone = 0; + } for (const auto &patAndValue : llvm::reverse(config->deadRelocInNonAlloc)) if (patAndValue.first.match(this->name)) { tombstone = patAndValue.second; @@ -954,8 +960,7 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef rels) { return; } - if (tombstone || - (isDebug && (type == target.symbolicRel || expr == R_DTPREL))) { + if (tombstone || (isDebug && (expr == R_ABS || expr == R_DTPREL))) { // Resolve relocations in .debug_* referencing (discarded symbols or ICF // folded section symbols) to a tombstone value. Resolving to addend is // unsatisfactory because the result address range may collide with a @@ -986,8 +991,13 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef rels) { // value. Enable -1 in a future release. if (!sym.getOutputSection() || (ds && ds->folded && !isDebugLine)) { // If -z dead-reloc-in-nonalloc= is specified, respect it. - const uint64_t value = tombstone ? SignExtend64(*tombstone) - : (isDebugLocOrRanges ? 1 : 0); + uint64_t value; + if (tombstone) + value = SignExtend64(*tombstone); + else if (type == target.symbolicRel) + value = *debugTombstone; + else // .debug_names uses 32-bit local TU offsets for DWARF32 + value = static_cast(*debugTombstone); target.relocateNoSym(bufLoc, type, value); continue; } diff --git a/lld/test/ELF/debug-dead-reloc-32.s b/lld/test/ELF/debug-dead-reloc-32.s index 99335b44f51ce..1aa43148689e9 100644 --- a/lld/test/ELF/debug-dead-reloc-32.s +++ b/lld/test/ELF/debug-dead-reloc-32.s @@ -13,6 +13,8 @@ # CHECK-NEXT: 0000 01000000 # CHECK-NEXT: Contents of section .debug_addr: # CHECK-NEXT: 0000 00000000 +# CHECK-NEXT: Contents of section .debug_names: +# CHECK-NEXT: 0000 ffffffff ## -z dead-reloc-in-nonalloc= can override the tombstone value. # RUN: ld.lld -z dead-reloc-in-nonalloc=.debug_loc=42 -z dead-reloc-in-nonalloc=.debug_addr=0xfffffffffffffffe %t.o -o %t1 @@ -38,3 +40,12 @@ ## Resolved to UINT32_C(0), with the addend ignored. .section .debug_addr .long .text.1+8 + +.section .debug_info,"eG",@progbits,5657452045627120676,comdat +.Ltu_begin0: + +.section .debug_names +## .debug_names may reference a local type unit defined in a COMDAT .debug_info +## section (-g -gpubnames -fdebug-types-section). If the referenced section is +## non-prevailing, resolve to UINT32_MAX. +.long .Ltu_begin0 diff --git a/lld/test/ELF/debug-dead-reloc.s b/lld/test/ELF/debug-dead-reloc.s index cfa41e00eab06..1a8823737ed56 100644 --- a/lld/test/ELF/debug-dead-reloc.s +++ b/lld/test/ELF/debug-dead-reloc.s @@ -21,9 +21,12 @@ # CHECK: Contents of section .debug_addr: # CHECK-NEXT: 0000 {{.*}}00 00000000 {{.*}}00 00000000 # CHECK-NEXT: 0010 00000000 00000000 {{.*}}00 00000000 +# CHECK: Contents of section .debug_names: +# CHECK-NEXT: 0000 00000000 00000000 00000000 ffffffff . +# CHECK-NEXT: 0010 ffffffff ffffffff . # CHECK: Contents of section .debug_foo: -# CHECK-NEXT: 0000 00000000 00000000 08000000 00000000 -# CHECK-NEXT: 0010 00000000 00000000 08000000 00000000 +# CHECK-NEXT: 0000 00000000 00000000 00000000 00000000 +# CHECK-NEXT: 0010 00000000 00000000 00000000 00000000 # REL: Relocations [ # REL-NEXT: .rela.text { @@ -43,6 +46,12 @@ # REL-NEXT: 0x10 R_X86_64_NONE - 0x18 # REL-NEXT: 0x18 R_X86_64_64 group 0x20 # REL-NEXT: } +# REL-NEXT: .rela.debug_names { +# REL-NEXT: 0x0 R_X86_64_32 .debug_info 0x0 +# REL-NEXT: 0x4 R_X86_64_64 .debug_info 0x0 +# REL-NEXT: 0xC R_X86_64_NONE - 0x0 +# REL-NEXT: 0x10 R_X86_64_NONE - 0x0 +# REL-NEXT: } # REL-NEXT: .rela.debug_foo { # REL-NEXT: 0x0 R_X86_64_NONE - 0x8 # REL-NEXT: 0x8 R_X86_64_NONE - 0x8 @@ -82,6 +91,17 @@ group: ## resolved to the prevailing copy. .quad group+32 +.section .debug_info,"G",@progbits,5657452045627120676,comdat +.Ltu_begin0: + +.section .debug_names +## .debug_names may reference a local type unit defined in a COMDAT .debug_info +## section (-g -gpubnames -fdebug-types-section). If the referenced section is +## non-prevailing, resolve to UINT32_MAX. +.long .Ltu_begin0 +## ... or UINT64_MAX for DWARF64. +.quad .Ltu_begin0 + .section .debug_foo .quad .text.1+8 From ee4a389d63f77c3e2186e4fc17f46313168fee5a Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Thu, 7 Dec 2023 10:15:18 -0800 Subject: [PATCH 2/2] simplify --- lld/ELF/InputSection.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 5a62b14f4c973..fb4ef30563cbb 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -899,14 +899,14 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef rels) { const auto emachine = config->emachine; const bool isDebug = isDebugSection(*this); const bool isDebugLine = isDebug && name == ".debug_line"; - std::optional tombstone, debugTombstone; + std::optional tombstone; if (isDebug) { if (name == ".debug_loc" || name == ".debug_ranges") - debugTombstone = 1; + tombstone = 1; else if (name == ".debug_names") - debugTombstone = UINT64_MAX; // DWARF Issue 231013.1 + tombstone = UINT64_MAX; // tombstone value else - debugTombstone = 0; + tombstone = 0; } for (const auto &patAndValue : llvm::reverse(config->deadRelocInNonAlloc)) if (patAndValue.first.match(this->name)) { @@ -960,7 +960,7 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef rels) { return; } - if (tombstone || (isDebug && (expr == R_ABS || expr == R_DTPREL))) { + if (tombstone && (expr == R_ABS || expr == R_DTPREL)) { // Resolve relocations in .debug_* referencing (discarded symbols or ICF // folded section symbols) to a tombstone value. Resolving to addend is // unsatisfactory because the result address range may collide with a @@ -991,13 +991,13 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef rels) { // value. Enable -1 in a future release. if (!sym.getOutputSection() || (ds && ds->folded && !isDebugLine)) { // If -z dead-reloc-in-nonalloc= is specified, respect it. - uint64_t value; - if (tombstone) - value = SignExtend64(*tombstone); - else if (type == target.symbolicRel) - value = *debugTombstone; - else // .debug_names uses 32-bit local TU offsets for DWARF32 - value = static_cast(*debugTombstone); + uint64_t value = SignExtend64(*tombstone); + // For a 32-bit local TU reference in .debug_names, X86_64::relocate + // requires that the unsigned value for R_X86_64_32 is truncated to + // 32-bit. Other 64-bit targets's don't discern signed/unsigned 32-bit + // absolute relocations and do not need this change. + if (emachine == EM_X86_64 && type == R_X86_64_32) + value = static_cast(value); target.relocateNoSym(bufLoc, type, value); continue; }