[lld] [ELF] Change .debug_names tombstone value to UINT32_MAX/UINT64_MAX (PR #74686)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 7 10:54:22 PST 2023
https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/74686
>From 4c0d6bea6317626e0f85b6bd5b2354f6be657e31 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
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", at progbits,5657452045627120676,comdat
.Ltu_begin0:
...
.section .debug_names,"", at 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 <<e
struct A { int x; };
inline A foo() { return {1}; }
int main() { foo(); }
e
cat > b.cc <<e
struct A { int x; };
inline A foo() { return {1}; }
void use() { foo(); }
e
clang++ -g -gpubnames -fdebug-types-section -fuse-ld=lld a.cc b.cc -o old
```
```
% llvm-dwarfdump old
...
Local Type Unit offsets [
LocalTU[0]: 0x00000000
]
...
Local Type Unit offsets [
LocalTU[0]: 0x00000000 // indistinguishable from a valid offset within .debug_info
]
```
https://dwarfstd.org/issues/231013.1.html proposes that we use a
tombstone value instead to inform consumers. This patch implements the
idea. The second LocalTU entry will now use 0xffffffff.
https://reviews.llvm.org/D84825 has a TODO that we should switch the
tombstone value for most `.debug_*` sections to UINT64_MAX. We have
postponed the change for more than three years for consumers to migrate.
At some point we shall make the change, so that .debug_names is no long
different from other debug section that is not .debug_loc/.debug_ranges.
---
lld/ELF/InputSection.cpp | 24 +++++++++++++++++-------
lld/test/ELF/debug-dead-reloc-32.s | 11 +++++++++++
lld/test/ELF/debug-dead-reloc.s | 24 ++++++++++++++++++++++--
3 files changed, 50 insertions(+), 9 deletions(-)
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 145d55d9a0a4b..5a62b14f4c973 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -898,10 +898,16 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> 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<uint64_t> tombstone;
+ std::optional<uint64_t> 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<RelTy> 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<RelTy> 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<bits>(*tombstone)
- : (isDebugLocOrRanges ? 1 : 0);
+ uint64_t value;
+ if (tombstone)
+ value = SignExtend64<bits>(*tombstone);
+ else if (type == target.symbolicRel)
+ value = *debugTombstone;
+ else // .debug_names uses 32-bit local TU offsets for DWARF32
+ value = static_cast<uint32_t>(*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", at 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", at 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 <i at maskray.me>
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<RelTy> rels) {
const auto emachine = config->emachine;
const bool isDebug = isDebugSection(*this);
const bool isDebugLine = isDebug && name == ".debug_line";
- std::optional<uint64_t> tombstone, debugTombstone;
+ std::optional<uint64_t> 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<RelTy> 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<RelTy> 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<bits>(*tombstone);
- else if (type == target.symbolicRel)
- value = *debugTombstone;
- else // .debug_names uses 32-bit local TU offsets for DWARF32
- value = static_cast<uint32_t>(*debugTombstone);
+ uint64_t value = SignExtend64<bits>(*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<uint32_t>(value);
target.relocateNoSym(bufLoc, type, value);
continue;
}
More information about the llvm-commits
mailing list