From: Max Chou <[email protected]>
reloc_call splits a PC-relative offset into a signed 12-bit low
immediate and an AUIPC contribution. When the low immediate carries
into bit 31, the existing 32-bit arithmetic can accept an unencodable
positive 0x80000000 AUIPC contribution.
Keep the split in pointer-width arithmetic and reject it unless the
rounded upper contribution is representable as signed 32-bit. Factor
this validation into split_auipc_offset so reloc_call retains its
existing failure contract.
Fixes: dfa8e74f9463 ("tcg/riscv: Add the relocation functions")
Reviewed-by: Philippe Mathieu-Daudé <[email protected]>
Signed-off-by: Max Chou <[email protected]>
[rth: Pass target as intptr_t to split_auipc_offset.]
Signed-off-by: Richard Henderson <[email protected]>
---
tcg/riscv64/tcg-target.c.inc | 24 +++++++++++++++++++-----
1 file changed, 19 insertions(+), 5 deletions(-)
diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc
index c167ff5237a..7754bcf39f2 100644
--- a/tcg/riscv64/tcg-target.c.inc
+++ b/tcg/riscv64/tcg-target.c.inc
@@ -643,14 +643,28 @@ static bool reloc_jimm20(tcg_insn_unit *src_rw, const
tcg_insn_unit *target)
return encode_jimm20(src_rw, offset);
}
-static bool reloc_call(tcg_insn_unit *src_rw, const tcg_insn_unit *target)
+static bool split_auipc_offset(tcg_insn_unit *src_rw, intptr_t target,
+ int32_t *ret_hi, int32_t *ret_lo)
{
const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw);
- intptr_t offset = (intptr_t)target - (intptr_t)src_rx;
- int32_t lo = sextreg(offset, 0, 12);
- int32_t hi = offset - lo;
+ intptr_t offset = target - (intptr_t)src_rx;
+ int32_t lo = sextract32(offset, 0, 12);
+ intptr_t hi = offset - lo;
- if (offset == hi + lo) {
+ /* AUIPC sign-extends its 20-bit immediate after shifting by 12. */
+ if (hi == (int32_t)hi) {
+ *ret_lo = lo;
+ *ret_hi = hi;
+ return true;
+ }
+ return false;
+}
+
+static bool reloc_call(tcg_insn_unit *src_rw, const tcg_insn_unit *target)
+{
+ int32_t lo, hi;
+
+ if (split_auipc_offset(src_rw, (intptr_t)target, &hi, &lo)) {
src_rw[0] |= encode_uimm20(hi);
src_rw[1] |= encode_imm12(lo);
return true;
--
2.53.0