llvm / llvm/llvm-project

riscv assembly operand using label arithmetic with relaxation enabled produces spurious reloc

Open
#184,854 1 comment 0 reactions 0 assignees View on GitHub
backend:RISC-V
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

Assembling the following input file (e.g. `clang --target=riscv64-fuchsia -c foo.s`):
```asm
li t0, (9f - 0f)
sd t0, (a0)
lla t0, 0f
sd t0, (a0)
0:lw t1, (a0)
1:j 1b
9:ret
```
produces:
```
Disassembly of section .text:

0000000000000000 <.text>:
0: 00000293 li t0, 0x0
0000000000000000: R_RISCV_NONE .Ltmp0
4: 00553023 sd t0, 0x0(a0)

0000000000000008 <.Lpcrel_hi0>:
8: 00000297 auipc t0, 0x0
0000000000000008: R_RISCV_PCREL_HI20 .Ltmp1
0000000000000008: R_RISCV_RELAX *ABS*
c: 00028293 mv t0, t0
000000000000000c: R_RISCV_PCREL_LO12_I .Lpcrel_hi0
000000000000000c: R_RISCV_RELAX *ABS*
10: 00553023 sd t0, 0x0(a0)

0000000000000014 <.Ltmp1>:
14: 00052303 lw t1, 0x0(a0)
18: a001 j 0x18 <.Ltmp1+0x4>
0000000000000018: R_RISCV_PCREL_LO12_S .Ltmp1

000000000000001a <.Ltmp0>:
1a: 8082 ret
```

The reloc at .text+0x18 is spurious, and the NONE reloc at .text+0 is highly suspect. It seems to be the result of some confusion that arises when label arithmetic is used across a range that includes relaxable sequences.

With `.option norelax`, this input produces no relocs at all, as expected.

The GNU assembler simply refuses to accept _any_ label arithmetic in an operand for riscv, AFAICT: `illegal operands `li t0,(9f-0f)'`. In fact, it refuses even with `.option norelax` and `.option norvc`, which ISTM are enough to make even a simple-minded assembler able to ensure this particular case of label arithmetic is OK. (The `norvc` seems relevant because the `j` at .text+0x18 could in the general case be relaxable between 16-bit and 32-bit forms based on the jump distance. Here it doesn't take much for a slightly savvy assembler to see that this particular jump distance is immediately known and cannot change so the assembler's first pass could actually tell that it can use the shorter instruction.) Not only that, GAS even rejects label arithmetic when the labels are both in the same other non-code section (and fragment) where no relocation is possible.

So it seems that the LLVM assembler could be quite extreme in rejecting all cases of label arithmetic as the GNU assembler does. It would be nice at least to use a better error message than just "illegal operand", such as "label arithmetic not permitted here" or whatever.

If we want to go beyond what GNU supports, then it at least seems easily safe to accept a case like this when `norelax` and `norvc` are in force, to keep it really simple. It doesn't seem all that involved to determine that the span in question has nothing relaxable (including possible RVC instruction choice), and it could get arbitrarily fancy with analysis to determine when a particular expression is actually safely constant through possible relaxation stages (assembly and link time).

But it seems the only real mandate is just to error out reliably rather than produce bogus relocs. Note there could be existing users who are working around (intentionally or otherwise) via `.option norelax` if they've only ever used LLVM and not the GNU assembler, but I think it should not be controversial to break those cases that were never supported by GNU.

Contributor guide

Open the contributing guide

Research direction

Reproduce the issue with clang --target=riscv64-fuchsia -c foo.s using the assembly shown, then inspect the RISC-V integrated assembler's operand and relocation handling. The fix should reject unsupported label arithmetic reliably, or otherwise avoid emitting the spurious R_RISCV_NONE and R_RISCV_PCREL_LO12_S relocations; verify the behavior with and without .option norelax and .option norvc.

Written by the indexing model from the issue text.

Assessment

Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.