gen_callr wrote the link register before consuming the target, so "callr r31" jumped to the new return address instead of the old LR value. Copy the target to a temporary first.
Signed-off-by: Brian Cain <[email protected]> --- target/hexagon/genptr.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index f264bb9d0a0..7ef60244de0 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -1028,9 +1028,13 @@ static void gen_call(DisasContext *ctx, int pc_off) static void gen_callr(DisasContext *ctx, TCGv new_pc) { + TCGv target = tcg_temp_new(); TCGv lr = get_result_gpr(ctx, HEX_REG_LR); + + /* Preserve the target when callr uses LR as its source register. */ + tcg_gen_mov_tl(target, new_pc); tcg_gen_movi_tl(lr, ctx->next_PC); - gen_write_new_pc_addr(ctx, new_pc, TCG_COND_ALWAYS, NULL); + gen_write_new_pc_addr(ctx, target, TCG_COND_ALWAYS, NULL); } static void gen_cond_call(DisasContext *ctx, TCGv pred, -- 2.34.1
