Skip to content

Commit 27f754e

Browse files
a4lgNelson Chu
authored andcommitted
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 bbac553 commit 27f754e

12 files changed

+214
-6
lines changed

gas/config/tc-riscv.c

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4848,7 +4848,13 @@ 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 (fixP->fx_file, fixP->fx_line,
4854+
_("invalid J-type offset (%+lld)"),
4855+
(long long) delta);
4856+
fixP->fx_done = 1;
4857+
}
48524858
}
48534859
break;
48544860

@@ -4860,7 +4866,13 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
48604866
bfd_vma delta = target - md_pcrel_from (fixP);
48614867
bfd_putl32 (bfd_getl32 (buf) | ENCODE_BTYPE_IMM (delta), buf);
48624868
if (!riscv_opts.relax && S_IS_LOCAL (fixP->fx_addsy))
4863-
fixP->fx_done = 1;
4869+
{
4870+
if (!VALID_BTYPE_IMM (delta))
4871+
as_bad_where (fixP->fx_file, fixP->fx_line,
4872+
_("invalid B-type offset (%+lld)"),
4873+
(long long) delta);
4874+
fixP->fx_done = 1;
4875+
}
48644876
}
48654877
break;
48664878

@@ -4872,7 +4884,13 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
48724884
bfd_vma delta = target - md_pcrel_from (fixP);
48734885
bfd_putl16 (bfd_getl16 (buf) | ENCODE_CBTYPE_IMM (delta), buf);
48744886
if (!riscv_opts.relax && S_IS_LOCAL (fixP->fx_addsy))
4875-
fixP->fx_done = 1;
4887+
{
4888+
if (!VALID_CBTYPE_IMM (delta))
4889+
as_bad_where (fixP->fx_file, fixP->fx_line,
4890+
_("invalid CB-type offset (%+lld)"),
4891+
(long long) delta);
4892+
fixP->fx_done = 1;
4893+
}
48764894
}
48774895
break;
48784896

@@ -4884,7 +4902,13 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
48844902
bfd_vma delta = target - md_pcrel_from (fixP);
48854903
bfd_putl16 (bfd_getl16 (buf) | ENCODE_CJTYPE_IMM (delta), buf);
48864904
if (!riscv_opts.relax && S_IS_LOCAL (fixP->fx_addsy))
4887-
fixP->fx_done = 1;
4905+
{
4906+
if (!VALID_CJTYPE_IMM (delta))
4907+
as_bad_where (fixP->fx_file, fixP->fx_line,
4908+
_("invalid CJ-type offset (%+lld)"),
4909+
(long long) delta);
4910+
fixP->fx_done = 1;
4911+
}
48884912
}
48894913
break;
48904914

@@ -4919,7 +4943,14 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
49194943
| ENCODE_UTYPE_IMM (RISCV_CONST_HIGH_PART (value)),
49204944
buf);
49214945
if (!riscv_opts.relax)
4922-
fixP->fx_done = 1;
4946+
{
4947+
if (xlen > 32
4948+
&& !VALID_UTYPE_IMM (RISCV_CONST_HIGH_PART (value)))
4949+
as_bad_where (fixP->fx_file, fixP->fx_line,
4950+
_("invalid pcrel_hi offset (%+lld)"),
4951+
(long long) value);
4952+
fixP->fx_done = 1;
4953+
}
49234954
}
49244955
relaxable = true;
49254956
break;
@@ -4945,7 +4976,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
49454976
bfd_putl32 (bfd_getl32 (buf) | ENCODE_STYPE_IMM (value), buf);
49464977
else
49474978
bfd_putl32 (bfd_getl32 (buf) | ENCODE_ITYPE_IMM (value), buf);
4948-
/* Relaxations should never be enabled by `.option relax'. */
4979+
/* Relaxations should never be enabled by `.option relax'.
4980+
The offset is checked by corresponding %pcrel_hi entry. */
49494981
if (!riscv_opts.relax)
49504982
fixP->fx_done = 1;
49514983
}
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: invalid J-type offset \(\+1048576\)
3+
.*:5: Error: invalid J-type offset \(-1048578\)
4+
.*:8: Error: invalid J-type offset \(\+1048576\)
5+
.*:10: Error: invalid J-type offset \(-1048578\)
6+
.*:14: Error: invalid J-type offset \(\+1048576\)
7+
.*:17: Error: invalid J-type offset \(-1048578\)
8+
.*:20: Error: invalid CJ-type offset \(\+1\)
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: invalid pcrel_hi offset \(\+2147481600\)
3+
.*:11: Error: invalid pcrel_hi offset \(-2147485697\)
4+
.*:17: Error: invalid pcrel_hi offset \(\+2147481600\)
5+
.*:21: Error: invalid pcrel_hi offset \(-2147485697\)
6+
.*:26: Error: invalid pcrel_hi offset \(\+2147481600\)
7+
.*:30: Error: invalid pcrel_hi offset \(-2147485697\)
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].*)?

0 commit comments

Comments
 (0)