Skip to content

[LLD] Tombstone LocalTU entry in .debug_names #70701

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

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 23 additions & 15 deletions lld/ELF/InputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/xxhash.h"
#include <algorithm>
#include <mutex>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should keep the headers. mutex is used by std::mutex in this file.

#include <optional>
#include <vector>

using namespace llvm;
Expand Down Expand Up @@ -886,16 +885,25 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
const unsigned bits = sizeof(typename ELFT::uint) * 8;
const TargetInfo &target = *elf::target;
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 = std::nullopt;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An optional defaults to std::nullopt. Just default initialize it.

std::optional<uint64_t> tombstoneValueToUse = std::nullopt;
for (const auto &patAndValue : llvm::reverse(config->deadRelocInNonAlloc))
if (patAndValue.first.match(this->name)) {
tombstone = patAndValue.second;
break;
}

const uint64_t debugTombstone = StringSwitch<uint64_t>(name)
.Case(".debug_ranges", 1)
.Case(".debug_loc", 1)
.Case(".debug_names", llvm::maxUIntN(32))
.Default(0);
// If -z dead-reloc-in-nonalloc= is specified, respect it.
if (!tombstone && isDebug)
tombstoneValueToUse = debugTombstone;
else if (tombstone)
tombstoneValueToUse = SignExtend64<bits>(*tombstone);
for (const RelTy &rel : rels) {
RelType type = rel.getType(config->isMips64EL);

Expand All @@ -917,8 +925,9 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
if (expr == R_NONE)
continue;

if (tombstone ||
(isDebug && (type == target.symbolicRel || expr == R_DTPREL))) {
auto *ds = dyn_cast<Defined>(&sym);
if (tombstoneValueToUse &&
(!sym.getOutputSection() || (ds && ds->folded && !isDebugLine))) {
// 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
Expand Down Expand Up @@ -947,14 +956,13 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
//
// TODO To reduce disruption, we use 0 instead of -1 as the tombstone
// value. Enable -1 in a future release.
auto *ds = dyn_cast<Defined>(&sym);
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);
target.relocateNoSym(bufLoc, type, value);
continue;
}

// Extending 32bit MAX value to 64bit MAX value..
// One usage example is in .debug_names LocatTU tombstoning.
if (!tombstone && type == target.symbolicRel)
tombstoneValueToUse = SignExtend64<32>(*tombstoneValueToUse);
target.relocateNoSym(bufLoc, type, *tombstoneValueToUse);
continue;
}

// For a relocatable link, content relocated by RELA remains unchanged and
Expand Down
8 changes: 3 additions & 5 deletions lld/test/ELF/debug-dead-reloc.s
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
# CHECK-NEXT: 0000 {{.*}}000 00000000 {{.*}}000 00000000
# CHECK-NEXT: 0010 00000000 00000000 {{.*}}000 00000000
# 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 {
Expand Down Expand Up @@ -80,8 +80,6 @@ group:
.section .debug_foo
.quad .text.1+8

## We only deal with DW_FORM_addr. Don't special case short-range absolute
## relocations. Treat them like regular absolute relocations referencing
## discarded symbols, which are resolved to the addend.
## Treat short-range absolute relocations the same as DW_FORM_addr.
.long .text.1+8
.long 0
97 changes: 97 additions & 0 deletions lld/test/ELF/x86-64-dwarf5-64-debug-names-type-comdat.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# REQUIRES: x86

# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux --defsym DWARF32=1 %s -o %t.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux --defsym DWARF32=1 %s -o %t1.o
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can do ld.lld %t.o %t.o.

-triple=x86_64 since there is no Linux specific stuff. We omit the OS to essentially say the test is generic to all ELF OSes.

# RUN: ld.lld %t.o %t1.o -o %t1
# RUN: llvm-objdump -s %t1 | FileCheck %s --check-prefix=CHECK32

# Test checks that LLD tombstones TU section that was de-duplicated using COMDAT to the maxium value.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For newer tests we use ## for non-RUN non-CHECK comments.


# CHECK32:Contents of section .debug_names:
# CHECK32-NEXT: 0000 37000000 05000000 00000000 01000000 7...............
# CHECK32-NEXT: 0010 00000000 00000000 00000000 03000000 ................
# CHECK32-NEXT: 0020 08000000 4c4c564d 30373030 00000000 ....LLVM0700....
# CHECK32-NEXT: 0030 00000000 00000000 00000037 00000005 ...........7....
# CHECK32-NEXT: 0040 00000000 00000001 00000000 00000000 ................
# CHECK32-NEXT: 0050 00000000 00000003 00000008 0000004c ...............L
# CHECK32-NEXT: 0060 4c564d30 37303000 000000ff ffffff00 LVM0700.........


# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux --defsym DWARF64=1 %s -o %t.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux --defsym DWARF64=1 %s -o %t1.o
# RUN: ld.lld %t.o %t1.o -o %t1
# RUN: llvm-objdump -s %t1 | FileCheck %s --check-prefix=CHECK64

# Test checks that LLD tombstones TU section that was de-duplicated using COMDAT to the maxium value.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto


# CHECK64: Contents of section .debug_names:
# CHECK64-NEXT: 0000 ffffffff 3f000000 00000000 05000000 ....?...........
# CHECK64-NEXT: 0010 00000000 01000000 00000000 00000000 ................
# CHECK64-NEXT: 0020 00000000 03000000 08000000 4c4c564d ............LLVM
# CHECK64-NEXT: 0030 30373030 00000000 00000000 00000000 0700............
# CHECK64-NEXT: 0040 00000000 00000000 000000ff ffffff3f ...............?
# CHECK64-NEXT: 0050 00000000 00000005 00000000 00000001 ................
# CHECK64-NEXT: 0060 00000000 00000000 00000000 00000003 ................
# CHECK64-NEXT: 0070 00000008 0000004c 4c564d30 37303000 .......LLVM0700.
# CHECK64-NEXT: 0080 00000000 000000ff ffffffff ffffff00 ................

# Test generated with clang++ -g2 -gdwarf-5 -gpubnames -fdebug-types-section -S and then manually reduced.
.ifdef DWARF32
.section .debug_info,"G",@progbits,1175092228111723119,comdat
.Ltu_begin0:
.section .debug_names,"",@progbits
.long .Lnames_end0-.Lnames_start0 # Header: unit length
.Lnames_start0:
.short 5 # Header: version
.short 0 # Header: padding
.long 0 # Header: compilation unit count
.long 1 # Header: local type unit count
.long 0 # Header: foreign type unit count
.long 0 # Header: bucket count
.long 0 # Header: name count
.long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
.long 8 # Header: augmentation string size
.ascii "LLVM0700" # Header: augmentation string
.long 0 # Compilation unit 0
.long .Ltu_begin0 # Type unit 0
.long 0 # Bucket 0

.Lnames_abbrev_start0:
.byte 0 # End of abbrev
.byte 0 # End of abbrev
.byte 0 # End of abbrev list
.Lnames_abbrev_end0:
.Lnames_entries0:
.Lnames_end0:
.endif

# Test generated with clang++ -g2 -gdwarf-5 -gdwarf64 -gpubnames -fdebug-types-section -S and then manually reduced.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a C++ source example.

.ifdef DWARF64
.section .debug_info,"G",@progbits,1175092228111723119,comdat
.Ltu_begin0:
.section .debug_names,"",@progbits
.long 4294967295 # DWARF64 Mark
.quad .Lnames_end0-.Lnames_start0 # Header: unit length
.Lnames_start0:
.short 5 # Header: version
.short 0 # Header: padding
.long 0 # Header: compilation unit count
.long 1 # Header: local type unit count
.long 0 # Header: foreign type unit count
.long 0 # Header: bucket count
.long 0 # Header: name count
.long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
.long 8 # Header: augmentation string size
.ascii "LLVM0700" # Header: augmentation string
.quad 0 # Compilation unit 0
.quad .Ltu_begin0 # Type unit 0
.long 0 # Bucket 0

.Lnames_abbrev_start0:
.byte 0 # End of abbrev
.byte 0 # End of abbrev
.byte 0 # End of abbrev list
.Lnames_abbrev_end0:
.Lnames_entries0:
.Lnames_end0:
.endif