Issue 184854
Summary riscv assembly operand using label arithmetic with relaxation enabled produces spurious reloc
Labels backend:RISC-V
Assignees
Reporter frobtech
    Assembling the following input file (e.g. `clang --target=riscv64-fuchsia -c foo.s`):
```
  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.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to