Commit fe33867b0dcea3cdbe276402694e15b7166e9a54
1 parent
1cb0661e
Don't rely on ARM tcg_out_goto() generating just a single insn.
Otherwise when tb_exit generates a jump beyond the pc-relative range, tcg_out_goto() spans two/three instructions and we load the tb return value from a wrong address. This is #ifdefed out currently because we take care for the jumps to be local. Problem spotted by Steffen Liebergeld. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5845 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
13 additions
and
8 deletions
tcg/arm/tcg-target.c
... | ... | @@ -1232,19 +1232,24 @@ static inline void tcg_out_op(TCGContext *s, int opc, |
1232 | 1232 | if (args[0] >> 8) |
1233 | 1233 | tcg_out32(s, args[0]); |
1234 | 1234 | #else |
1235 | - if (args[0] >> 8) | |
1236 | - tcg_out_ld32_12(s, COND_AL, 0, 15, 0); | |
1237 | - else | |
1238 | - tcg_out_dat_imm(s, COND_AL, ARITH_MOV, 0, 0, args[0]); | |
1239 | - tcg_out_goto(s, COND_AL, (tcg_target_ulong) tb_ret_addr); | |
1240 | - if (args[0] >> 8) | |
1241 | - tcg_out32(s, args[0]); | |
1235 | + { | |
1236 | + uint8_t *ld_ptr = s->code_ptr; | |
1237 | + if (args[0] >> 8) | |
1238 | + tcg_out_ld32_12(s, COND_AL, 0, 15, 0); | |
1239 | + else | |
1240 | + tcg_out_dat_imm(s, COND_AL, ARITH_MOV, 0, 0, args[0]); | |
1241 | + tcg_out_goto(s, COND_AL, (tcg_target_ulong) tb_ret_addr); | |
1242 | + if (args[0] >> 8) { | |
1243 | + *ld_ptr = (uint8_t) (s->code_ptr - ld_ptr) - 8; | |
1244 | + tcg_out32(s, args[0]); | |
1245 | + } | |
1246 | + } | |
1242 | 1247 | #endif |
1243 | 1248 | break; |
1244 | 1249 | case INDEX_op_goto_tb: |
1245 | 1250 | if (s->tb_jmp_offset) { |
1246 | 1251 | /* Direct jump method */ |
1247 | -#if 1 | |
1252 | +#if defined(USE_DIRECT_JUMP) | |
1248 | 1253 | s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; |
1249 | 1254 | tcg_out_b(s, COND_AL, 8); |
1250 | 1255 | #else | ... | ... |