-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[RISCV] Disable gp relaxation if part of object unreachable #72655
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
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -651,12 +651,39 @@ 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 with different addends. | ||
// If we are relaxing the HI20 relocation, we need to ensure that we only | ||
// relax (and delete the instruction) if all possible LO12 relocations | ||
// that depend on it will be relaxable. 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()); | ||
if (alignAdjust) | ||
alignAdjust--; | ||
|
||
switch (r.type) { | ||
case R_RISCV_HI20: | ||
case R_RISCV_HI20: { | ||
uint64_t hiAddr = r.sym->getVA(r.addend); | ||
// If the addend is zero, the LO12 relocations can only be accessing the | ||
// range [base, base+alignAdjust] (where base == r.sym->getVA()). | ||
if (r.addend == 0 && !isInt<12>(hiAddr + alignAdjust - gp->getVA())) | ||
|
||
return; | ||
|
||
// However, if the addend is non-zero, the LO12 relocations may be accessing | ||
// the range [HI-alignAdjust-1, HI+alignAdjust]. | ||
if (r.addend != 0 && | ||
(!isInt<12>(hiAddr - alignAdjust - 1 - gp->getVA()) || | ||
!isInt<12>(hiAddr + alignAdjust - gp->getVA()))) | ||
return; | ||
|
||
// Remove lui rd, %hi20(x). | ||
sec.relaxAux->relocTypes[i] = R_RISCV_RELAX; | ||
remove = 4; | ||
break; | ||
} | ||
case R_RISCV_LO12_I: | ||
sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_I; | ||
break; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# 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: 000017e0 l .data {{0+}}80 Var1 | ||
# CHECK: 00000ffc g .sdata {{0+}}00 __global_pointer$ | ||
|
||
# CHECK: <_start>: | ||
# CHECK-NEXT: lui a1, 1 | ||
# CHECK-NEXT: lw a0, 2020(gp) | ||
# CHECK-NEXT: lw a1, 2044(a1) | ||
|
||
#--- a.s | ||
.global _start | ||
_start: | ||
lui a1, %hi(Var1) | ||
lw a0, %lo(Var1)(a1) # First part is reachable from gp | ||
lw a1, %lo(Var1+28)(a1) # The second part is not reachable | ||
|
||
.section .sdata,"aw" | ||
.section .data,"aw" | ||
.p2align 5 | ||
Var1: | ||
.quad 0 | ||
.zero 120 | ||
.size Var1, 128 | ||
|
||
#--- lds | ||
SECTIONS { | ||
.text : { } | ||
.sdata 0x07fc : { } | ||
.data 0x17E0 : { } | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# 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: 00001000 l .data {{0+}}08 Var0 | ||
# CHECK: 00001f80 l .data1 {{0+}}80 Var1 | ||
# CHECK: 00001800 g .sdata {{0+}}00 __global_pointer$ | ||
|
||
# CHECK: <_start>: | ||
# CHECK-NEXT: lui a1, 1 | ||
# CHECK-NEXT: lw a0, -2048(gp) | ||
# CHECK-NEXT: lw a1, -2044(gp) | ||
# CHECK-NEXT: lui a1, 2 | ||
# CHECK-NEXT: lw a0, 1920(gp) | ||
# CHECK-NEXT: lw a1, 2044(gp) | ||
|
||
#--- a.s | ||
.global _start | ||
_start: | ||
lui a1, %hi(Var0+4) # Cannot prove that %lo relocs will be reachable | ||
lw a0, %lo(Var0)(a1) # Reachable from GP | ||
lw a1, %lo(Var0+4)(a1) # Reachable from GP | ||
lui a1, %hi(Var1+124) # Cannot prove that %lo relocs will be reachable | ||
lw a0, %lo(Var1)(a1) # Reachable from GP | ||
lw a1, %lo(Var1+124)(a1) # Reachable from GP | ||
|
||
.section .sdata,"aw" | ||
.section .data,"aw" | ||
.p2align 3 | ||
Var0: | ||
.quad 0 | ||
.size Var0, 8 | ||
|
||
.section .data1,"aw" | ||
.p2align 7 | ||
Var1: | ||
.quad 0 | ||
.zero 120 | ||
.size Var1, 128 | ||
|
||
#--- lds | ||
SECTIONS { | ||
.text : { } | ||
.sdata 0x1000 : { } | ||
.data 0x1000 : { } | ||
.data1 0x1f80 : { } | ||
} |
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, 2027(gp) | ||
# 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 { | ||
.text : { } | ||
.rodata : { } | ||
.sdata : { } | ||
.sbss : { } | ||
.data : { } | ||
} |
There was a problem hiding this comment.
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 testedThere was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 tomin(addralign, st_size-addend)
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.