Skip to content

Commit db1a762

Browse files
authored
[LLD][RISCV] Error on PCREL_LO referencing other Section (#107558)
The RISC-V psABI states that "The `R_RISCV_PCREL_LO12_I` or `R_RISCV_PCREL_LO12_S` relocations contain a label pointing to an instruction in the same section with an `R_RISCV_PCREL_HI20` relocation entry that points to the target symbol." Without this patch, GNU ld errors, but LLD does not -- I think because LLD is doing the right thing, certainly in the testcase provided. Nonetheless, I think an error is good here to bring LLD in line with what GNU ld is doing in showing that the object the user provided is not following the psABI as written. Fixes #107304
1 parent f01364e commit db1a762

File tree

3 files changed

+61
-15
lines changed

3 files changed

+61
-15
lines changed

lld/ELF/InputSection.cpp

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -625,27 +625,40 @@ static uint64_t getARMStaticBase(const Symbol &sym) {
625625
// points the corresponding R_RISCV_PCREL_HI20 relocation, and the target VA
626626
// is calculated using PCREL_HI20's symbol.
627627
//
628-
// This function returns the R_RISCV_PCREL_HI20 relocation from
629-
// R_RISCV_PCREL_LO12's symbol and addend.
630-
static Relocation *getRISCVPCRelHi20(const Symbol *sym, uint64_t addend) {
628+
// This function returns the R_RISCV_PCREL_HI20 relocation from the
629+
// R_RISCV_PCREL_LO12 relocation.
630+
static Relocation *getRISCVPCRelHi20(const InputSectionBase *loSec,
631+
const Relocation &loReloc) {
632+
uint64_t addend = loReloc.addend;
633+
Symbol *sym = loReloc.sym;
634+
631635
const Defined *d = cast<Defined>(sym);
632636
if (!d->section) {
633-
errorOrWarn("R_RISCV_PCREL_LO12 relocation points to an absolute symbol: " +
634-
sym->getName());
637+
errorOrWarn(
638+
loSec->getLocation(loReloc.offset) +
639+
": R_RISCV_PCREL_LO12 relocation points to an absolute symbol: " +
640+
sym->getName());
635641
return nullptr;
636642
}
637-
InputSection *isec = cast<InputSection>(d->section);
643+
InputSection *hiSec = cast<InputSection>(d->section);
644+
645+
if (hiSec != loSec)
646+
errorOrWarn(loSec->getLocation(loReloc.offset) +
647+
": R_RISCV_PCREL_LO12 relocation points to a symbol '" +
648+
sym->getName() + "' in a different section '" + hiSec->name +
649+
"'");
638650

639651
if (addend != 0)
640-
warn("non-zero addend in R_RISCV_PCREL_LO12 relocation to " +
641-
isec->getObjMsg(d->value) + " is ignored");
652+
warn(loSec->getLocation(loReloc.offset) +
653+
": non-zero addend in R_RISCV_PCREL_LO12 relocation to " +
654+
hiSec->getObjMsg(d->value) + " is ignored");
642655

643656
// Relocations are sorted by offset, so we can use std::equal_range to do
644657
// binary search.
645-
Relocation r;
646-
r.offset = d->value;
658+
Relocation hiReloc;
659+
hiReloc.offset = d->value;
647660
auto range =
648-
std::equal_range(isec->relocs().begin(), isec->relocs().end(), r,
661+
std::equal_range(hiSec->relocs().begin(), hiSec->relocs().end(), hiReloc,
649662
[](const Relocation &lhs, const Relocation &rhs) {
650663
return lhs.offset < rhs.offset;
651664
});
@@ -655,8 +668,9 @@ static Relocation *getRISCVPCRelHi20(const Symbol *sym, uint64_t addend) {
655668
it->type == R_RISCV_TLS_GD_HI20 || it->type == R_RISCV_TLS_GOT_HI20)
656669
return &*it;
657670

658-
errorOrWarn("R_RISCV_PCREL_LO12 relocation points to " +
659-
isec->getObjMsg(d->value) +
671+
errorOrWarn(loSec->getLocation(loReloc.offset) +
672+
": R_RISCV_PCREL_LO12 relocation points to " +
673+
hiSec->getObjMsg(d->value) +
660674
" without an associated R_RISCV_PCREL_HI20 relocation");
661675
return nullptr;
662676
}
@@ -825,7 +839,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
825839
return getAArch64Page(val) - getAArch64Page(p);
826840
}
827841
case R_RISCV_PC_INDIRECT: {
828-
if (const Relocation *hiRel = getRISCVPCRelHi20(r.sym, a))
842+
if (const Relocation *hiRel = getRISCVPCRelHi20(this, r))
829843
return getRelocTargetVA(ctx, *hiRel, r.sym->getVA());
830844
return 0;
831845
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# REQUIRES: riscv
2+
3+
# RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.o
4+
# RUN: not ld.lld %t.o 2>&1 | FileCheck %s
5+
6+
# CHECK: error: {{.*}}:(.text.sec_one+0x0): R_RISCV_PCREL_LO12 relocation points to a symbol '.Lpcrel_hi0' in a different section '.text.sec_two'
7+
# CHECK: error: {{.*}}:(.text.sec_one+0x4): R_RISCV_PCREL_LO12 relocation points to a symbol '.Lpcrel_hi1' in a different section '.text.sec_two'
8+
# CHECK-NOT: R_RISCV_PCREL_LO12 relocation points to a symbol '.Lpcrel_hi2'
9+
10+
## This test is checking that we warn the user when the relocations in their
11+
## object don't follow the RISC-V psABI. In particular, the psABI requires
12+
## that PCREL_LO12 relocations are in the same section as the pcrel_hi
13+
## instruction they point to.
14+
15+
.section .text.sec_one,"ax"
16+
addi a0, a0, %pcrel_lo(.Lpcrel_hi0)
17+
sw a0, %pcrel_lo(.Lpcrel_hi1)(a1)
18+
19+
.section .text.sec_two,"ax"
20+
.Lpcrel_hi0:
21+
auipc a0, %pcrel_hi(a)
22+
.Lpcrel_hi1:
23+
auipc a1, %pcrel_hi(a)
24+
25+
.Lpcrel_hi2:
26+
auipc a2, %pcrel_hi(a)
27+
addi a2, a2, %pcrel_lo(.Lpcrel_hi2)
28+
29+
.data
30+
.global a
31+
a:
32+
.word 50

lld/test/ELF/riscv-pcrel-hilo-error.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.o
33
# RUN: not ld.lld %t.o --defsym external=0 2>&1 | FileCheck %s
44

5-
# CHECK: error: R_RISCV_PCREL_LO12 relocation points to an absolute symbol: external
5+
# CHECK: error: {{.*}}:(.text+0x4): R_RISCV_PCREL_LO12 relocation points to an absolute symbol: external
66

77
# We provide a dummy %pcrel_hi referred to by external to appease the
88
# assembler, but make external weak so --defsym can still override it at link

0 commit comments

Comments
 (0)