2005-11-11 Gwenole Beauchesne * Check for stack clobbers in functions using GOTO_LABEL_PARAM(). --- qemu-0.7.2/dyngen.c.dyngen-check-stack-clobbers 2005-11-11 16:26:33.000000000 +0100 +++ qemu-0.7.2/dyngen.c 2005-11-11 17:30:29.000000000 +0100 @@ -1414,6 +1414,9 @@ int arm_emit_ldr_info(const char *name, #define FLAG_TARGET (1 << 3) /* This is a magic instruction that needs fixing up. */ #define FLAG_EXIT (1 << 4) +/* This instruction clobbers the stack pointer. */ +/* XXX only supports push, pop, add/sub $imm,%esp */ +#define FLAG_STACK (1 << 5) #define MAX_EXITS 5 static void @@ -1454,6 +1457,7 @@ trace_i386_insn (const char *name, uint8 int is_jmp; int is_exit; int is_pcrel; + int is_stack; int immed; int seen_rexw; int32_t disp; @@ -1476,6 +1480,7 @@ trace_i386_insn (const char *name, uint8 is_exit = 0; seen_rexw = 0; is_pcrel = 0; + is_stack = 0; while (is_prefix) { op = ptr[insn_size]; @@ -1522,6 +1527,7 @@ trace_i386_insn (const char *name, uint8 switch (op & 0x7) { case 0: /* push fs/gs */ case 1: /* pop fs/gs */ + is_stack = 1; case 2: /* cpuid/rsm */ modrm = 0; break; @@ -1594,6 +1600,7 @@ trace_i386_insn (const char *name, uint8 #endif case 5: /* push/pop general register. */ modrm = 0; + is_stack = 1; break; case 6: @@ -1601,6 +1608,7 @@ trace_i386_insn (const char *name, uint8 case 0: /* pusha */ case 1: /* popa */ modrm = 0; + is_stack = 1; break; case 2: /* bound */ case 3: /* arpl */ @@ -1620,10 +1628,12 @@ trace_i386_insn (const char *name, uint8 case 8: /* push immediate */ immed = op_size; modrm = 0; + is_stack = 1; break; case 10: /* push 8-bit immediate */ immed = 1; modrm = 0; + is_stack = 1; break; case 9: /* imul immediate */ immed = op_size; @@ -1653,8 +1663,22 @@ trace_i386_insn (const char *name, uint8 immed = op_size; else immed = 1; + if (op == 0x81 || op == 0x83) { + /* add, sub */ + op = ptr[insn_size]; + switch ((op >> 3) & 7) { + case 0: + case 5: + is_stack = (op & 7) == 4; + break; + } + } } - /* else test, xchg, mov, lea or pop general. */ + else if ((op & 0xf) == 0xf) { + /* pop general. */ + is_stack = 1; + } + /* else test, xchg, mov, lea. */ break; case 9: @@ -1904,6 +1928,9 @@ trace_i386_insn (const char *name, uint8 if (is_exit) flags[insn] |= FLAG_EXIT; + if (is_stack) + flags[insn] |= FLAG_STACK; + if (!(is_jmp || is_ret || is_exit)) flags[insn + insn_size] |= FLAG_INSN; } @@ -1924,6 +1951,7 @@ static int trace_i386_op(const char * na int num_exits; int len; int last_insn; + int stack_clobbered; len = *plen; flags = malloc(len + 1); @@ -1947,6 +1975,7 @@ static int trace_i386_op(const char * na retpos = -1; num_exits = 0; last_insn = 0; + stack_clobbered = 0; for (insn = 0; insn < len; insn++) { if (flags[insn] & FLAG_RET) { /* ??? In theory it should be possible to handle multiple return @@ -1956,6 +1985,8 @@ static int trace_i386_op(const char * na retpos = insn; } if (flags[insn] & FLAG_EXIT) { + if (stack_clobbered) + error("Stack clobbered in %s", name); if (num_exits == MAX_EXITS) error("Too many block exits in %s", name); exit_addrs[num_exits] = insn; @@ -1963,6 +1994,8 @@ static int trace_i386_op(const char * na } if (flags[insn] & FLAG_INSN) last_insn = insn; + if (flags[insn] & FLAG_STACK) + stack_clobbered = 1; } exit_addrs[num_exits] = -1;