[ELF] Allow absolute relocation referencing symbol index 0 in PIC mode

The value of an absolute relocation, like R_RISCV_HI20 or R_PPC64_LO16,
with a symbol index of 0, the resulting value should be treated as
absolute and permitted in both -pie and -shared links.

This change also resolves an absolute relocation referencing an
undefined symbol in statically-linked executables.

PPC64 has unfortunate exceptions:

* R_PPC64_TOCBASE uses symbol index 0 but it should be treated as
  referencing the linker-defined .TOC.
* R_PPC64_PCREL_OPT (https://reviews.llvm.org/D84360) could no longer
  rely on `isAbsoluteValue` return false.
This commit is contained in:
Fangrui Song 2025-03-28 20:44:07 -07:00
parent 1d4801f22a
commit ba2de8f22d
3 changed files with 16 additions and 6 deletions

View File

@ -178,7 +178,7 @@ static RelType getMipsPairType(RelType type, bool isLocal) {
// True if non-preemptable symbol always has the same value regardless of where
// the DSO is loaded.
static bool isAbsolute(const Symbol &sym) {
if (sym.isUndefWeak())
if (sym.isUndefined())
return true;
if (const auto *dr = dyn_cast<Defined>(&sym))
return dr->section == nullptr; // Absolute symbol.
@ -1005,7 +1005,7 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
// For the target and the relocation, we want to know if they are
// absolute or relative.
bool absVal = isAbsoluteValue(sym);
bool absVal = isAbsoluteValue(sym) && e != RE_PPC64_TOCBASE;
bool relE = isRelExpr(e);
if (absVal && !relE)
return true;
@ -1021,7 +1021,7 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
// calls to such symbols (e.g. glibc/stdlib/exit.c:__run_exit_handlers).
// Normally such a call will be guarded with a comparison, which will load a
// zero from the GOT.
if (sym.isUndefWeak())
if (sym.isUndefined())
return true;
// We set the final symbols values for linker script defined symbols later.
@ -1066,7 +1066,8 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
type == R_HEX_GD_PLT_B22_PCREL_X ||
type == R_HEX_GD_PLT_B32_PCREL_X)))
expr = fromPlt(expr);
} else if (!isAbsoluteValue(sym)) {
} else if (!isAbsoluteValue(sym) ||
(type == R_PPC64_PCREL_OPT && ctx.arg.emachine == EM_PPC64)) {
expr = ctx.target->adjustGotPcExpr(type, addend,
sec->content().data() + offset);
// If the target adjusted the expression to R_RELAX_GOT_PC, we may end up

View File

@ -12,6 +12,8 @@
# CHECK: lui a0, 0x200
# CHECK-NEXT: addi a0, a0, 0x1
# CHECK-NEXT: lui a0, 0x200
# CHECK-NEXT: addi a0, a0, 0x1
# CHECK-NEXT: lw a0, 0x1(a0)
# CHECK-NEXT: sw a0, 0x1(a0)
@ -23,6 +25,11 @@ abs = 0x200001
_start:
lui a0, %hi(abs)
addi a0, a0, %lo(abs)
.reloc ., R_RISCV_HI20, abs
lui a0, 0
.reloc ., R_RISCV_LO12_I, abs
addi a0, a0, 0
lw a0, %lo(abs)(a0)
sw a0, %lo(abs)(a0)

View File

@ -29,10 +29,12 @@
# RUN: ld.lld a.o b.o -o out1 -z undefs
# RUN: llvm-readelf -r -x .data out1 | FileCheck %s --check-prefix=STATIC1
# RUN: ld.lld a.o b.o -o out1.pie -pie -z undefs
# RUN: llvm-readelf -r -x .data out1.pie | FileCheck %s --check-prefix=STATIC2
# RUN: llvm-readelf -r -x .data out1.pie | FileCheck %s --check-prefix=STATIC1
# STATIC1: no relocations
# STATIC2: R_X86_64_RELATIVE
# STATIC1: Hex dump of section '.data':
# STATIC1-NEXT: {{.*}} 00000000 00000000 00000000 00000000 .
# STATIC1-EMPTY:
# RUN: ld.lld a.o b.o c.o -pie -z undefs 2>&1 | count 0