riscv-non-isa / riscv-asm-manual

RISC-V Assembly Programmer's Manual
https://jira.riscv.org/browse/RVG-4
Creative Commons Attribution 4.0 International
1.44k stars 238 forks source link

Linker relaxation ignores .option norvc #84

Open dramforever opened 1 year ago

dramforever commented 1 year ago

Currently, even if .option norvc is in effect, the assembler still generates relaxable instructions and R_RISCV_RELAX relocations, which may end up getting turned into compressed instructions by the linker anyway:

    .section .text

test1:
    .option push
    .option norvc
    lui a0, %hi(data)
    addi a0, a0, %lo(data)
    .option pop

test2:
1:
    .option push
    .option norvc
    jump 1b, t0
    .option pop

    .section .rodata
data:
    .quad 42

If we assemble and link it:

$ riscv64-unknown-linux-gnu-gcc -c -o norvc.o norvc.s
$ riscv64-unknown-linux-gnu-ld -nostdlib -o norvc norvc.o
# This warning is expected
riscv64-unknown-linux-gnu-ld: warning: cannot find entry symbol _start; defaulting to 00000000000100b0
$ riscv64-unknown-linux-gnu-objdump -Mno-aliases -dr norvc

norvc:     file format elf64-littleriscv

Disassembly of section .text:

00000000000100b0 <test1>:
   100b0:       6541                    c.lui   a0,0x10
   100b2:       0b850513                addi    a0,a0,184 # 100b8 <data>

00000000000100b6 <test2>:
   100b6:       a001                    c.j     100b6 <test2>

The generated relaxations can be seen in the intermediate object file:

$ riscv64-unknown-linux-gnu-objdump -Mno-aliases -dr norvc.o

norvc.o:     file format elf64-littleriscv

Disassembly of section .text:

0000000000000000 <test1>:
   0:   00000537                lui     a0,0x0
                        0: R_RISCV_HI20 data
                        0: R_RISCV_RELAX        *ABS*
   4:   00050513                addi    a0,a0,0 # 0 <test1>
                        4: R_RISCV_LO12_I       data
                        4: R_RISCV_RELAX        *ABS*

0000000000000008 <test2>:
   8:   00000297                auipc   t0,0x0
                        8: R_RISCV_CALL .L1^B1
                        8: R_RISCV_RELAX        *ABS*
   c:   00028067                jalr    zero,0(t0) # 8 <test2>

I'm not sure how big of a deal this is. It is certainly unexpected at first glance, but it this even worth doing anything about?

I'm also not sure whether to post it here or post it at https://github.com/riscv-non-isa/riscv-elf-psabi-doc (where linker relaxation is specified), but my idea is that this kind of temporary .option norvc is probably rare enough that this case might not be worth the trouble getting the linker to handle this.

dramforever commented 1 year ago

I ended up filing this here rather than say binutils, because this feels like a specification oversight for me, rather than a problem with any particular assembler. It seems that the assembler is generating code/relaxation correctly as specified. Both binutils and llvm-as seems to behave this way.

nick-knight commented 1 year ago

Related: https://github.com/riscv-collab/riscv-gnu-toolchain/issues/445 https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/116

dramforever commented 1 year ago

That's nice. I hadn't noticed the pull request to psABI before, but it does seem that it would fix this for good.

psherman42 commented 1 year ago

This is critically important for cases of building jump or vector tables on 4-byte boundaries, where each table element must be the full (uncompressed) form of a 'j' instruction.

aswaterman commented 1 year ago

For the jump table case, you can also use .balign 4 on every entry. It’s annoying but is functionally correct.

dramforever commented 1 year ago

@psherman42 My understanding is that if you also have .option norelax in effect this would not be a problem.