Skip to content

Commit e28a8ff

Browse files
committed
RISC-V: check offsets when linker relaxation is disabled
The assembler partially relied on the linker to check whether the offset is valid. However, some optimization logic (added later) removes relocations relative to local symbols without checking offsets. For instance, it caused following code to silently emit wrong jumps (to the jump instruction "." itself) without relocations: > .option norelax > j .+0x200000 # J (or JAL) instruction cannot encode this offset. > j .+1 # Jump to odd address is not valid. This commit adds offset checks where necessary. gas/ChangeLog: * config/tc-riscv.c (md_apply_fix): Check offsets when the relocation relative to a local symbol is being optimized out. * testsuite/gas/riscv/no-relax-branch-offset-fail.s: Failure case where the branch offset is invalid. * testsuite/gas/riscv/no-relax-branch-offset-fail.d: Ditto. * testsuite/gas/riscv/no-relax-branch-offset-fail.l: Ditto. * testsuite/gas/riscv/no-relax-branch-offset-ok.s: Border case. * testsuite/gas/riscv/no-relax-branch-offset-ok.d: Ditto. * testsuite/gas/riscv/no-relax-pcrel-offset-fail-64.s: Failure case only on RV64 where the PC-relative offset exceed limits. * testsuite/gas/riscv/no-relax-pcrel-offset-fail-64.d: Ditto. * testsuite/gas/riscv/no-relax-pcrel-offset-fail-64.l: Ditto. * testsuite/gas/riscv/no-relax-pcrel-offset-fail-not-32.d: Test case for RV32 so that no errors occur. * testsuite/gas/riscv/no-relax-pcrel-offset-ok.s: Border case. * testsuite/gas/riscv/no-relax-pcrel-offset-ok.d: Ditto.
1 parent 614806c commit e28a8ff

12 files changed

+219
-6
lines changed

gas/config/tc-riscv.c

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4848,7 +4848,14 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
48484848
bfd_vma delta = target - md_pcrel_from (fixP);
48494849
bfd_putl32 (bfd_getl32 (buf) | ENCODE_JTYPE_IMM (delta), buf);
48504850
if (!riscv_opts.relax && S_IS_LOCAL (fixP->fx_addsy))
4851-
fixP->fx_done = 1;
4851+
{
4852+
if (!VALID_JTYPE_IMM (delta))
4853+
as_bad_where (
4854+
fixP->fx_file, fixP->fx_line,
4855+
_ ("offset (%+lld) is invalid for J-type immediate"),
4856+
(long long) delta);
4857+
fixP->fx_done = 1;
4858+
}
48524859
}
48534860
break;
48544861

@@ -4860,7 +4867,14 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
48604867
bfd_vma delta = target - md_pcrel_from (fixP);
48614868
bfd_putl32 (bfd_getl32 (buf) | ENCODE_BTYPE_IMM (delta), buf);
48624869
if (!riscv_opts.relax && S_IS_LOCAL (fixP->fx_addsy))
4863-
fixP->fx_done = 1;
4870+
{
4871+
if (!VALID_BTYPE_IMM (delta))
4872+
as_bad_where (
4873+
fixP->fx_file, fixP->fx_line,
4874+
_ ("offset (%+lld) is invalid for B-type immediate"),
4875+
(long long) delta);
4876+
fixP->fx_done = 1;
4877+
}
48644878
}
48654879
break;
48664880

@@ -4872,7 +4886,14 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
48724886
bfd_vma delta = target - md_pcrel_from (fixP);
48734887
bfd_putl16 (bfd_getl16 (buf) | ENCODE_CBTYPE_IMM (delta), buf);
48744888
if (!riscv_opts.relax && S_IS_LOCAL (fixP->fx_addsy))
4875-
fixP->fx_done = 1;
4889+
{
4890+
if (!VALID_CBTYPE_IMM (delta))
4891+
as_bad_where (
4892+
fixP->fx_file, fixP->fx_line,
4893+
_ ("offset (%+lld) is invalid for CB-type immediate"),
4894+
(long long) delta);
4895+
fixP->fx_done = 1;
4896+
}
48764897
}
48774898
break;
48784899

@@ -4884,7 +4905,14 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
48844905
bfd_vma delta = target - md_pcrel_from (fixP);
48854906
bfd_putl16 (bfd_getl16 (buf) | ENCODE_CJTYPE_IMM (delta), buf);
48864907
if (!riscv_opts.relax && S_IS_LOCAL (fixP->fx_addsy))
4887-
fixP->fx_done = 1;
4908+
{
4909+
if (!VALID_CJTYPE_IMM (delta))
4910+
as_bad_where (
4911+
fixP->fx_file, fixP->fx_line,
4912+
_ ("offset (%+lld) is invalid for CJ-type immediate"),
4913+
(long long) delta);
4914+
fixP->fx_done = 1;
4915+
}
48884916
}
48894917
break;
48904918

@@ -4919,7 +4947,15 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
49194947
| ENCODE_UTYPE_IMM (RISCV_CONST_HIGH_PART (value)),
49204948
buf);
49214949
if (!riscv_opts.relax)
4922-
fixP->fx_done = 1;
4950+
{
4951+
if (xlen > 32
4952+
&& !VALID_UTYPE_IMM (RISCV_CONST_HIGH_PART (value)))
4953+
as_bad_where (
4954+
fixP->fx_file, fixP->fx_line,
4955+
_ ("offset (%+lld) too large for PC-relative offset"),
4956+
(long long) value);
4957+
fixP->fx_done = 1;
4958+
}
49234959
}
49244960
relaxable = true;
49254961
break;
@@ -4945,7 +4981,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
49454981
bfd_putl32 (bfd_getl32 (buf) | ENCODE_STYPE_IMM (value), buf);
49464982
else
49474983
bfd_putl32 (bfd_getl32 (buf) | ENCODE_ITYPE_IMM (value), buf);
4948-
/* Relaxations should never be enabled by `.option relax'. */
4984+
/* Relaxations should never be enabled by `.option relax'.
4985+
The offset is checked by corresponding %pcrel_hi entry. */
49494986
if (!riscv_opts.relax)
49504987
fixP->fx_done = 1;
49514988
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#as: -march=rv32ic
2+
#error_output: no-relax-branch-offset-fail.l
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.*Assembler messages:
2+
.*:4: Error: offset \(\+1048576\) is invalid for J-type immediate
3+
.*:5: Error: offset \(-1048578\) is invalid for J-type immediate
4+
.*:8: Error: offset \(\+1048576\) is invalid for J-type immediate
5+
.*:10: Error: offset \(-1048578\) is invalid for J-type immediate
6+
.*:14: Error: offset \(\+1048576\) is invalid for J-type immediate
7+
.*:17: Error: offset \(-1048578\) is invalid for J-type immediate
8+
.*:20: Error: offset \(\+1\) is invalid for CJ-type immediate
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
.option norelax
2+
3+
# Relative to the current instruction.
4+
j .+0x0ffffe+2
5+
j .-0x100000-2
6+
7+
# Relative to local labels (make sure that all instructions except "c.j" occupy 4-bytes).
8+
j 1f+0x0ffffe-4+2
9+
1:
10+
j 2f-0x100000-4-2
11+
2:
12+
3:
13+
lui t0, 0x12345
14+
j 3b+0x0ffffe+4+2
15+
4:
16+
lui t0, 0x2abcd
17+
j 4b-0x100000+4-2
18+
19+
# Jump to odd address (violates instruction alignment).
20+
c.j .+1
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#as: -march=rv32ic
2+
#objdump: -dr
3+
4+
.*: file format .*
5+
6+
7+
Disassembly of section \.text:
8+
9+
0+ <\.text>:
10+
[ ]+0:[ ]+7ffff06f[ ]+j[ ][0-9a-f]+.*
11+
[ ]+4:[ ]+8000006f[ ]+j[ ][0-9a-f]+.*
12+
[ ]+8:[ ]+7ffff06f[ ]+j[ ][0-9a-f]+.*
13+
[ ]+c:[ ]+8000006f[ ]+j[ ][0-9a-f]+.*
14+
[ ]+10:[ ]+123452b7[ ]+lui[ ]t0,0x12345
15+
[ ]+14:[ ]+7ffff06f[ ]+j[ ][0-9a-f]+.*
16+
[ ]+18:[ ]+2abcd2b7[ ]+lui[ ]t0,0x2abcd
17+
[ ]+1c:[ ]+8000006f[ ]+j[ ][0-9a-f]+.*
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
.option norelax
2+
3+
# Relative to the current instruction.
4+
j .+0x0ffffe
5+
j .-0x100000
6+
7+
# Relative to local labels (make sure that all instructions occupy 4-bytes).
8+
j 1f+0x0ffffe-4
9+
1:
10+
j 2f-0x100000-4
11+
2:
12+
3:
13+
lui t0, 0x12345
14+
j 3b+0x0ffffe+4
15+
4:
16+
lui t0, 0x2abcd
17+
j 4b-0x100000+4
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#as: -march=rv64i
2+
#error_output: no-relax-pcrel-offset-fail-64.l
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.*Assembler messages:
2+
.*:8: Error: offset \(\+2147481600\) too large for PC-relative offset
3+
.*:11: Error: offset \(-2147485697\) too large for PC-relative offset
4+
.*:17: Error: offset \(\+2147481600\) too large for PC-relative offset
5+
.*:21: Error: offset \(-2147485697\) too large for PC-relative offset
6+
.*:26: Error: offset \(\+2147481600\) too large for PC-relative offset
7+
.*:30: Error: offset \(-2147485697\) too large for PC-relative offset
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
.option norelax
2+
3+
## Fail on RV64, wrap without errors on RV32.
4+
5+
# Relative to the current instruction.
6+
7+
1:
8+
auipc a0, %pcrel_hi(.+0x7ffff7ff+1)
9+
addi a0, a0, %pcrel_lo(1b)
10+
2:
11+
auipc a0, %pcrel_hi(.-0x80000800-1)
12+
addi a0, a0, %pcrel_lo(2b)
13+
14+
# Relative to local labels (all instructions occupy 4-bytes).
15+
16+
3:
17+
auipc a0, %pcrel_hi(4f+0x7ffff7ff-4+1)
18+
4:
19+
addi a0, a0, %pcrel_lo(3b)
20+
5:
21+
auipc a0, %pcrel_hi(6f-0x80000800-4-1)
22+
6:
23+
addi a0, a0, %pcrel_lo(5b)
24+
25+
7:
26+
auipc a0, %pcrel_hi(6b+0x7ffff7ff+4+1)
27+
8:
28+
addi a0, a0, %pcrel_lo(7b)
29+
9:
30+
auipc a0, %pcrel_hi(8b-0x80000800+4-1)
31+
addi a0, a0, %pcrel_lo(9b)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#as: -march=rv32i
2+
#source: no-relax-pcrel-offset-fail-64.s
3+
#objdump: -dr
4+
5+
.*: file format .*
6+
7+
8+
Disassembly of section \.text:
9+
10+
0+ <\.text>:
11+
[ ]+0:[ ]+80000517[ ]+auipc[ ]a0,0x80000
12+
[ ]+4:[ ]+80050513[ ]+addi[ ]a0,a0,-2048([^0-9].*)?
13+
[ ]+8:[ ]+7ffff517[ ]+auipc[ ]a0,0x7ffff
14+
[ ]+c:[ ]+7ff50513[ ]+addi[ ]a0,a0,2047([^0-9].*)?
15+
[ ]+10:[ ]+80000517[ ]+auipc[ ]a0,0x80000
16+
[ ]+14:[ ]+80050513[ ]+addi[ ]a0,a0,-2048([^0-9].*)?
17+
[ ]+18:[ ]+7ffff517[ ]+auipc[ ]a0,0x7ffff
18+
[ ]+1c:[ ]+7ff50513[ ]+addi[ ]a0,a0,2047([^0-9].*)?
19+
[ ]+20:[ ]+80000517[ ]+auipc[ ]a0,0x80000
20+
[ ]+24:[ ]+80050513[ ]+addi[ ]a0,a0,-2048([^0-9].*)?
21+
[ ]+28:[ ]+7ffff517[ ]+auipc[ ]a0,0x7ffff
22+
[ ]+2c:[ ]+7ff50513[ ]+addi[ ]a0,a0,2047([^0-9].*)?
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#as: -march=rv64i
2+
#objdump: -dr
3+
4+
.*: file format .*
5+
6+
7+
Disassembly of section \.text:
8+
9+
0+ <\.text>:
10+
[ ]+0:[ ]+7ffff517[ ]+auipc[ ]a0,0x7ffff
11+
[ ]+4:[ ]+7ff50513[ ]+addi[ ]a0,a0,2047([^0-9].*)?
12+
[ ]+8:[ ]+80000517[ ]+auipc[ ]a0,0x80000
13+
[ ]+c:[ ]+80050513[ ]+addi[ ]a0,a0,-2048([^0-9].*)?
14+
[ ]+10:[ ]+7ffff517[ ]+auipc[ ]a0,0x7ffff
15+
[ ]+14:[ ]+7ff50513[ ]+addi[ ]a0,a0,2047([^0-9].*)?
16+
[ ]+18:[ ]+80000517[ ]+auipc[ ]a0,0x80000
17+
[ ]+1c:[ ]+80050513[ ]+addi[ ]a0,a0,-2048([^0-9].*)?
18+
[ ]+20:[ ]+7ffff517[ ]+auipc[ ]a0,0x7ffff
19+
[ ]+24:[ ]+7ff50513[ ]+addi[ ]a0,a0,2047([^0-9].*)?
20+
[ ]+28:[ ]+80000517[ ]+auipc[ ]a0,0x80000
21+
[ ]+2c:[ ]+80050513[ ]+addi[ ]a0,a0,-2048([^0-9].*)?
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
.option norelax
2+
3+
# Relative to the current instruction.
4+
5+
1:
6+
auipc a0, %pcrel_hi(.+0x7ffff7ff)
7+
addi a0, a0, %pcrel_lo(1b)
8+
2:
9+
auipc a0, %pcrel_hi(.-0x80000800)
10+
addi a0, a0, %pcrel_lo(2b)
11+
12+
# Relative to local labels (all instructions occupy 4-bytes).
13+
14+
3:
15+
auipc a0, %pcrel_hi(4f+0x7ffff7ff-4)
16+
4:
17+
addi a0, a0, %pcrel_lo(3b)
18+
5:
19+
auipc a0, %pcrel_hi(6f-0x80000800-4)
20+
6:
21+
addi a0, a0, %pcrel_lo(5b)
22+
23+
7:
24+
auipc a0, %pcrel_hi(6b+0x7ffff7ff+4)
25+
8:
26+
addi a0, a0, %pcrel_lo(7b)
27+
9:
28+
auipc a0, %pcrel_hi(8b-0x80000800+4)
29+
addi a0, a0, %pcrel_lo(9b)

0 commit comments

Comments
 (0)