https://sourceware.org/bugzilla/show_bug.cgi?id=33538

            Bug ID: 33538
           Summary: [RISC-V] Missed opportunities to relax PC-relative to
                    GP-relative
           Product: binutils
           Version: 2.45
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: binutils
          Assignee: unassigned at sourceware dot org
          Reporter: davidegrayson at gmail dot com
  Target Milestone: ---

The GNU linker is capable of relaxing a pair of instructions using the
R_RISCV_PCREL_HI20 and R_RISCV_PCREL_LO12_[I,S] relocations into a single
`addi _,gp,offset` instruction if the target is near the value of the special
symbol `__global_pointer$`.  The allowed values for the offset are
-2048 to 2047.

However, it seems like there are some cases where the linker fails to do it,
for variables that are near the edge of the range and for symbols defined
in the linker script.

Here is an assembly file and linker script that reproduces these issues:

----

    .text
    .global _start
_start:
    .option norelax
    la gp, __global_pointer$
    .option relax
    la a1, _var1          # should get relaxed but doesn't (gp offset -2048)
    la a2, _var2          # should get relaxed but doesn't (.balign)
    la a3, _var3          # should get relaxed but doesn't (.size)
    la a7, __idata_end    # gp offset is within range, but doesn't get relaxed
(absolute)

    .data
_var1:
    .byte 1
_var2:
    .byte 2
    .byte 0
    .byte 0
_var3:
    .word 3
    .size _var3, . - _var3
    .balign 4

----

MEMORY
{
  ROM : ORIGIN = 0x10000000, LENGTH = 64K
  RAM : ORIGIN = 0x20000000, LENGTH = 64K
}
SECTIONS
{
  .text : { *(.text) } >ROM
  .data : { *(.data); __idata_end = .; *(.bss); } >RAM
}
__global_pointer$ = 0x20000800;

-----

I ran these commands with binutil 2.45:

riscv64-unknown-elf-as -march=rv32i -mabi=ilp32 test.asm -o test.o
riscv64-unknown-elf-ld --relax --relax-gp --no-pie -m elf32lriscv -T test.ld
test.o -o test.elf
riscv64-unknown-elf-objdump -d test.elf

The output from objdump showed that nothing was relaxed.  The output of
objdump also shows the offsets of all the variables involved, so you can
see they were all within range of the __global_pointer$.

10000000 <_start>:
10000000:       10001197                auipc   gp,0x10001
10000004:       80018193                addi    gp,gp,-2048 # 20000800
<__global_pointer$>
10000008:       10000597                auipc   a1,0x10000
1000000c:       ff858593                addi    a1,a1,-8 # 20000000 <_var1>
10000010:       10000617                auipc   a2,0x10000
10000014:       ff160613                addi    a2,a2,-15 # 20000001 <_var2>
10000018:       10000697                auipc   a3,0x10000
1000001c:       fec68693                addi    a3,a3,-20 # 20000004 <_var3>
10000020:       10000897                auipc   a7,0x10000
10000024:       fe888893                addi    a7,a7,-24 # 20000008
<__idata_end>

If you remove the `.balign 4` directive AND decrease `__global_pointer$` by 1
in the linker script, then the `_var1` relocations are relaxed properly.

If you remove the `.balign 4` directive, then the `_var2` relocations are
relaxed properly.  I know that `.balign 4` introduces some uncertainty about
the size of the section, so maybe the linker is misinterpreting that and
thinking that `_var2` might get moved out of range.  Once all of the
addresses in RAM have been determined, it is in principle possible to
accurately relax the code in ROM that references them, even if the
addresses were initially uncertain.

If you remove the `.size` directive, then the _var3 relocations are
relaxed properly.  I have no idea why that happens; the symbol size is just
metadata for the debuggers as far as I know.

I suspect `__idata_end` doesn't get relaxed simply because it is defined
in the linker script, so the toolchain treats it as an "absolute" symbol.
It doesn't get relaxed even if I move it closer to the GP by adding
1024 bytes of data to the .data section.

I believe the code responsible for this relaxation is
`_bfd_riscv_relax_pc` in `bfd/elfnn-riscv.c`.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

Reply via email to