Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
14 changes: 14 additions & 0 deletions lld/ELF/Arch/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,20 @@ static void relaxHi20Lo12(const InputSection &sec, size_t i, uint64_t loc,
if (!isInt<12>(r.sym->getVA(r.addend) - gp->getVA()))
return;

// The symbol may be accessed in multiple pieces. We need to make sure that
Copy link
Member

Choose a reason for hiding this comment

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

The symbol may be accessed in multiple pieces with different addends.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed. Thanks.

// all of the possible accesses are relaxed or none are. This prevents
// relaxing the hi relocation and being unable to relax one of the low
// relocations. The compiler will only access multiple pieces of an object
// with low relocations on the memory op if the alignment allows it.
// Therefore it should suffice to check that the smaller of the alignment
// and size can be reached from GP.
uint32_t alignAdjust =
r.sym->getOutputSection() ? r.sym->getOutputSection()->addralign : 0;
alignAdjust = std::min<uint32_t>(alignAdjust, r.sym->getSize());
Copy link
Member

Choose a reason for hiding this comment

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

alignAdjust = std::min<uint32_t>(alignAdjust, r.sym->getSize()); is not tested

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah yes, I added a test now.

Copy link
Member

Choose a reason for hiding this comment

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

If addend < st_size, it seems that this can be improved to min(addralign, st_size-addend)

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, yes, I think that is indeed the case.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually, this is only true if we assume that the addend on the LO12 will be equal or greater than the addend on the HI20.
Ultimately, we need to ensure that the entire window of
min(st_size, st_align) bytes that contains the relocation is reachable from GP.


if (!isInt<12>(r.sym->getVA() + alignAdjust - gp->getVA()))
Copy link
Member

Choose a reason for hiding this comment

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

This condition guards against

lui     a1, %hi(var)
lw      a0, %lo(var)(a1)
lw      a1, %lo(var+4)(a1)

but not

lui     a1, %hi(var+4)
lw      a0, %lo(var+4)(a1)
lw      a1, %lo(var)(a1)

Copy link
Member Author

Choose a reason for hiding this comment

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

This is absolutely true. If the addend on the HI20 is higher than the addend on the LO12, there is no guarantee whatsoever that we can't get into the same situation (relaxing and removing the HI instruction even though we need it for the LO instruction). Of course, this isn't new with this patch, the issue already existed.
I think that to be on the safe side, we should reject a relaxation of the HI20 if the addend is non-zero. What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

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

I actually opted to just check the range of +/- adjustment since any LO12 relocations that depend on this are only allowed to access this range.

return;

switch (r.type) {
case R_RISCV_HI20:
// Remove lui rd, %hi20(x).
Expand Down
58 changes: 58 additions & 0 deletions lld/test/ELF/riscv-relax-gp-partial.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# REQUIRES: riscv
# RUN: rm -rf %t && split-file %s %t && cd %t

# RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf -mattr=+relax a.s -o rv32.o
# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=+relax a.s -o rv64.o

# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv32.o lds -o rv32
# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv64.o lds -o rv64
# RUN: llvm-objdump -td -M no-aliases --no-show-raw-insn rv32 | FileCheck %s
# RUN: llvm-objdump -td -M no-aliases --no-show-raw-insn rv64 | FileCheck %s

# CHECK: 00000080 l .data {{0+}}08 Var0
# CHECK: 00001000 l .data {{0+}}80 Var1
# CHECK: 00000815 g .sdata {{0+}}00 __global_pointer$

# CHECK: <_start>:
# CHECK-NOT: lui
# CHECK-NEXT: lw a0, -1941(gp)
# CHECK-NEXT: lw a1, -1937(gp)
# CHECK-NEXT: lui a1, 1
# CHECK-NEXT: lw a0, 0(a1)
# CHECK-NEXT: lw a1, 124(a1)

#--- a.s
.global _start
_start:
lui a1, %hi(Var0)
lw a0, %lo(Var0)(a1)
lw a1, %lo(Var0+4)(a1)
lui a1, %hi(Var1)
lw a0, %lo(Var1)(a1) # First part is reachable from gp
lw a1, %lo(Var1+124)(a1) # The second part is not reachable

.section .rodata
foo:
.space 1
.section .sdata,"aw"
.space 1
.section .data,"aw"
.p2align 3
Var0:
.quad 0
.size Var0, 8
.space 3960
.p2align 7
Var1:
.quad 0
.zero 120
.size Var1, 128

#--- lds
SECTIONS {
Copy link
Member

Choose a reason for hiding this comment

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

Place SECTIONS at column 0 and indent the body by 2.

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, yup. Sorry.

.text : { }
.rodata : { }
.sdata : { }
.sbss : { }
.data : { }
}