diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -890,38 +890,6 @@ if (expr == R_NONE) continue; - if (expr == R_SIZE) { - target.relocateNoSym(bufLoc, type, - SignExtend64(sym.getSize() + addend)); - continue; - } - - // R_ABS/R_DTPREL and some other relocations can be used from non-SHF_ALLOC - // sections. - if (expr != R_ABS && expr != R_DTPREL && expr != R_GOTPLTREL && - expr != R_RISCV_ADD) { - std::string msg = getLocation(offset) + - ": has non-ABS relocation " + toString(type) + - " against symbol '" + toString(sym) + "'"; - if (expr != R_PC && expr != R_ARM_PCA) { - error(msg); - return; - } - - // If the control reaches here, we found a PC-relative relocation in a - // non-ALLOC section. Since non-ALLOC section is not loaded into memory - // at runtime, the notion of PC-relative doesn't make sense here. So, - // this is a usage error. However, GNU linkers historically accept such - // relocations without any errors and relocate them as if they were at - // address 0. For bug-compatibilty, we accept them with warnings. We - // know Steel Bank Common Lisp as of 2018 have this bug. - warn(msg); - target.relocateNoSym( - bufLoc, type, - SignExtend64(sym.getVA(addend - offset - outSecOff))); - continue; - } - if (tombstone || (isDebug && (type == target.symbolicRel || expr == R_DTPREL))) { // Resolve relocations in .debug_* referencing (discarded symbols or ICF @@ -961,7 +929,44 @@ continue; } } - target.relocateNoSym(bufLoc, type, SignExtend64(sym.getVA(addend))); + + // For a relocatable link, only tombstone values are applied. + if (config->relocatable) + continue; + + if (expr == R_SIZE) { + target.relocateNoSym(bufLoc, type, + SignExtend64(sym.getSize() + addend)); + continue; + } + + // R_ABS/R_DTPREL and some other relocations can be used from non-SHF_ALLOC + // sections. + if (expr == R_ABS || expr == R_DTPREL || expr == R_GOTPLTREL || + expr == R_RISCV_ADD) { + target.relocateNoSym(bufLoc, type, SignExtend64(sym.getVA(addend))); + continue; + } + + std::string msg = getLocation(offset) + ": has non-ABS relocation " + + toString(type) + " against symbol '" + toString(sym) + + "'"; + if (expr != R_PC && expr != R_ARM_PCA) { + error(msg); + return; + } + + // If the control reaches here, we found a PC-relative relocation in a + // non-ALLOC section. Since non-ALLOC section is not loaded into memory + // at runtime, the notion of PC-relative doesn't make sense here. So, + // this is a usage error. However, GNU linkers historically accept such + // relocations without any errors and relocate them as if they were at + // address 0. For bug-compatibilty, we accept them with warnings. We + // know Steel Bank Common Lisp as of 2018 have this bug. + warn(msg); + target.relocateNoSym( + bufLoc, type, + SignExtend64(sym.getVA(addend - offset - outSecOff))); } } @@ -993,15 +998,15 @@ } auto *sec = cast(this); - if (config->relocatable) { + if (config->relocatable) relocateNonAllocForRelocatable(sec, buf); - } else { - const RelsOrRelas rels = sec->template relsOrRelas(); - if (rels.areRelocsRel()) - sec->relocateNonAlloc(buf, rels.rels); - else - sec->relocateNonAlloc(buf, rels.relas); - } + // For a relocatable link, also call relocateNonAlloc() to rewrite applicable + // locations with tombstone values. + const RelsOrRelas rels = sec->template relsOrRelas(); + if (rels.areRelocsRel()) + sec->relocateNonAlloc(buf, rels.rels); + else + sec->relocateNonAlloc(buf, rels.relas); } void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) { diff --git a/lld/test/ELF/debug-dead-reloc-relocatable.s b/lld/test/ELF/debug-dead-reloc-relocatable.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/debug-dead-reloc-relocatable.s @@ -0,0 +1,36 @@ +# REQUIRES: x86 +## Test we resolve symbolic relocations in .debug_* sections to a tombstone +## value if the referenced symbol is discarded when linking a relocatable object. + +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o +# RUN: ld.lld -r %t1.o %t1.o -o %t2.o +# RUN: llvm-readelf -r -x .debug_ranges %t2.o | FileCheck %s + +## Relocations for a discarded section are changed to R_*_NONE. +# CHECK: Relocation section '.rela.debug_ranges' at offset [[#%#x,]] contains 4 entries: +# CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# CHECK-NEXT: 0000000000000000 [[#%x,]] R_X86_64_64 0000000000000000 .text.foo + 0 +# CHECK-NEXT: 0000000000000008 [[#%x,]] R_X86_64_64 0000000000000000 .text.foo + 1 +# CHECK-NEXT: 0000000000000020 [[#%x,]] R_X86_64_NONE +# CHECK-NEXT: 0000000000000028 [[#%x,]] R_X86_64_NONE + +## References to a discarded section are changed to tombstone values. +# CHECK: Hex dump of section '.debug_ranges': +# CHECK-NEXT: 0x00000000 00000000 00000000 00000000 00000000 +# CHECK-NEXT: 0x00000010 00000000 00000000 00000000 00000000 +# CHECK-NEXT: 0x00000020 01000000 00000000 01000000 00000000 +# CHECK-NEXT: 0x00000030 00000000 00000000 00000000 00000000 + +.weak foo + + .section .text.foo,"axG",@progbits,foo,comdat +.Lfoo: +foo: + ret +.Lfoo_end: + + .section .debug_ranges,"",@progbits + .quad .Lfoo + .quad .Lfoo_end + .quad 0 + .quad 0