On 01/11/19 21:33, Bill Wendling wrote: > Tests may use the stack during execution. It's easy to miss allocating > one, so automatically point %esp to the stack when initializing > "inregs". Also remove the initialization of ".esp" in "test_movzx_movsx" > as it doesn't appear to be required. > > Signed-off-by: Bill Wendling <morbo@xxxxxxxxxx> > --- > x86/realmode.c | 158 +++++++++++++++++++++++++++++-------------------- > 1 file changed, 95 insertions(+), 63 deletions(-) > > diff --git a/x86/realmode.c b/x86/realmode.c > index 629a221..f5967ef 100644 > --- a/x86/realmode.c > +++ b/x86/realmode.c > @@ -11,6 +11,10 @@ typedef unsigned short u16; > typedef unsigned u32; > typedef unsigned long long u64; > > +#ifndef NULL > +#define NULL ((void*)0) > +#endif > + > void realmode_start(void); > void test_function(void); > > @@ -140,8 +144,22 @@ struct insn_desc { > u16 len; > }; > > +struct { > + u32 stack[128]; > + char top[]; > +} tmp_stack; > + > static struct regs inregs, outregs; > > +static inline void init_inregs(struct regs *regs) > +{ > + inregs = (struct regs){ 0 }; > + if (regs) > + inregs = *regs; > + if (!inregs.esp) > + inregs.esp = (unsigned long)&tmp_stack.top; > +} > + > static void exec_in_big_real_mode(struct insn_desc *insn) > { > unsigned long tmp; > @@ -302,7 +320,8 @@ static void test_shld(void) > { > MK_INSN(shld_test, "shld $8,%edx,%eax\n\t"); > > - inregs = (struct regs){ .eax = 0xbe, .edx = 0xef000000 }; > + init_inregs(&(struct regs){ .eax = 0xbe, .edx = 0xef000000 }); > + > exec_in_big_real_mode(&insn_shld_test); > report("shld", ~0, outregs.eax == 0xbeef); > } > @@ -315,7 +334,7 @@ static void test_mov_imm(void) > MK_INSN(mov_r8_imm_2, "mov $0x34, %al"); > MK_INSN(mov_r8_imm_3, "mov $0x12, %ah\n\t" "mov $0x34, %al\n\t"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_mov_r16_imm_1); > report("mov 1", R_AX, outregs.eax == 1234); > @@ -342,7 +361,7 @@ static void test_sub_imm(void) > MK_INSN(sub_r8_imm_1, "mov $0x12, %ah\n\t" "sub $0x10, %ah\n\t"); > MK_INSN(sub_r8_imm_2, "mov $0x34, %al\n\t" "sub $0x10, %al\n\t"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_sub_r16_imm_1); > report("sub 1", R_AX, outregs.eax == 1224); > @@ -366,7 +385,7 @@ static void test_xor_imm(void) > MK_INSN(xor_r8_imm_1, "mov $0x12, %ah\n\t" "xor $0x12, %ah\n\t"); > MK_INSN(xor_r8_imm_2, "mov $0x34, %al\n\t" "xor $0x34, %al\n\t"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_xor_r16_imm_1); > report("xor 1", R_AX, outregs.eax == 0); > @@ -392,7 +411,7 @@ static void test_cmp_imm(void) > MK_INSN(cmp_test3, "mov $0x34, %al\n\t" > "cmp $0x24, %al\n\t"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > /* test cmp imm8 with AL */ > /* ZF: (bit 6) Zero Flag becomes 1 if an operation results > @@ -415,7 +434,7 @@ static void test_add_imm(void) > MK_INSN(add_test2, "mov $0x12, %eax \n\t" > "add $0x21, %al\n\t"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_add_test1); > report("add 1", ~0, outregs.eax == 0x55555555); > @@ -433,7 +452,7 @@ static void test_eflags_insn(void) > MK_INSN(cld, "cld"); > MK_INSN(std, "std"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_clc); > report("clc", ~0, (outregs.eflags & 1) == 0); > @@ -484,7 +503,7 @@ static void test_io(void) > "mov $0x00000000, %eax \n\t" > "in %dx, %eax \n\t"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_io_test1); > report("pio 1", R_AX, outregs.eax == 0xff); > @@ -513,12 +532,8 @@ extern void retf_imm(void); > > static void test_call(void) > { > - u32 esp[16]; > u32 addr; > > - inregs = (struct regs){ 0 }; > - inregs.esp = (u32)&esp[ARRAY_SIZE(esp)]; > - > MK_INSN(call1, "mov $test_function, %eax \n\t" > "call *%eax\n\t"); > MK_INSN(call_near1, "jmp 2f\n\t" > @@ -535,6 +550,8 @@ static void test_call(void) > MK_INSN(ret_imm, "sub $10, %sp; jmp 2f; 1: retw $10; 2: callw 1b"); > MK_INSN(retf_imm, "sub $10, %sp; lcallw $0, $retf_imm"); > > + init_inregs(NULL); > + > exec_in_big_real_mode(&insn_call1); > report("call 1", R_AX, outregs.eax == 0x1234); > > @@ -572,7 +589,7 @@ static void test_jcc_short(void) > "mov $0x1234, %eax\n\t" > "1:\n\t"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_jnz_short1); > report("jnz short 1", ~0, 1); > @@ -595,7 +612,7 @@ static void test_jcc_near(void) > MK_INSN(jmp_near1, ".byte 0xE9, 0x06, 0x00\n\t" > "mov $0x1234, %eax\n\t"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_jnz_near1); > report("jnz near 1", 0, 1); > @@ -609,14 +626,13 @@ static void test_jcc_near(void) > > static void test_long_jmp(void) > { > - u32 esp[16]; > - > - inregs = (struct regs){ 0 }; > - inregs.esp = (u32)&esp[ARRAY_SIZE(esp)]; > MK_INSN(long_jmp, "call 1f\n\t" > "jmp 2f\n\t" > "1: jmp $0, $test_function\n\t" > "2:\n\t"); > + > + init_inregs(NULL); > + > exec_in_big_real_mode(&insn_long_jmp); > report("jmp far 1", R_AX, outregs.eax == 0x1234); > } > @@ -658,7 +674,7 @@ static void test_push_pop(void) > "xor $0x12340000, %esp \n\t" > "pop %bx"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_push32); > report("push/pop 1", R_AX|R_BX, > @@ -691,17 +707,12 @@ static void test_null(void) > { > MK_INSN(null, ""); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_null); > report("null", 0, 1); > } > > -struct { > - char stack[500]; > - char top[]; > -} tmp_stack; > - > static void test_pusha_popa(void) > { > MK_INSN(pusha, "pusha\n\t" > @@ -726,7 +737,7 @@ static void test_pusha_popa(void) > "popa\n\t" > ); > > - inregs = (struct regs){ .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6, .esp = (unsigned long)&tmp_stack.top }; > + init_inregs(&(struct regs){ .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6 }); > > exec_in_big_real_mode(&insn_pusha); > report("pusha/popa 1", 0, 1); > @@ -774,7 +785,7 @@ static void test_iret(void) > "1: iretw\n\t" > "2:\n\t"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_iret32); > report("iret 1", 0, 1); > @@ -792,7 +803,7 @@ static void test_iret(void) > > static void test_int(void) > { > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > *(u32 *)(0x11 * 4) = 0x1000; /* Store a pointer to address 0x1000 in IDT entry 0x11 */ > *(u8 *)(0x1000) = 0xcf; /* 0x1000 contains an IRET instruction */ > @@ -829,7 +840,7 @@ static void test_imul(void) > "mov $4, %ecx\n\t" > "imul %ecx\n\t"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_imul8_1); > report("imul 1", R_AX | R_CX | R_DX, (outregs.eax & 0xff) == (u8)-8); > @@ -866,7 +877,7 @@ static void test_mul(void) > "mov $4, %ecx\n\t" > "imul %ecx\n\t"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_mul8); > report("mul 1", R_AX | R_CX | R_DX, (outregs.eax & 0xff) == 8); > @@ -892,7 +903,7 @@ static void test_div(void) > "mov $5, %ecx\n\t" > "div %ecx\n\t"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_div8); > report("div 1", R_AX | R_CX | R_DX, outregs.eax == 384); > @@ -920,7 +931,7 @@ static void test_idiv(void) > "mov $-2, %ecx\n\t" > "idiv %ecx\n\t"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_idiv8); > report("idiv 1", R_AX | R_CX | R_DX, outregs.eax == (u8)-128); > @@ -939,7 +950,7 @@ static void test_cbw(void) > MK_INSN(cwde, "mov $0xFFFE, %eax \n\t" > "cwde\n\t"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_cbw); > report("cbq 1", ~0, outregs.eax == 0xFFFE); > @@ -964,7 +975,7 @@ static void test_loopcc(void) > "1: dec %eax\n\t" > "loopne 1b\n\t"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_loop); > report("LOOPcc short 1", R_AX, outregs.eax == 10); > @@ -1243,7 +1254,7 @@ static void test_das(void) > > MK_INSN(das, "das"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > for (i = 0; i < 1024; ++i) { > unsigned tmp = test_cases[i]; > @@ -1278,7 +1289,7 @@ static void test_cwd_cdq(void) > MK_INSN(cdq_2, "mov $0x10000000, %eax\n\t" > "cdq\n\t"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_cwd_1); > report("cwd 1", R_AX | R_DX, > @@ -1307,7 +1318,7 @@ static struct { > > static void test_lds_lss(void) > { > - inregs = (struct regs){ .ebx = (unsigned long)&desc }; > + init_inregs(&(struct regs){ .ebx = (unsigned long)&desc }); > > MK_INSN(lds, "push %ds\n\t" > "lds (%ebx), %eax\n\t" > @@ -1376,7 +1387,7 @@ static void test_jcxz(void) > "mov $0, %ecx\n\t" > "1:\n\t"); > > - inregs = (struct regs){ 0 }; > + init_inregs(NULL); > > exec_in_big_real_mode(&insn_jcxz1); > report("jcxz short 1", 0, 1); > @@ -1400,8 +1411,10 @@ static void test_cpuid(void) > unsigned function = 0x1234; > unsigned eax, ebx, ecx, edx; > > - inregs.eax = eax = function; > - inregs.ecx = ecx = 0; > + init_inregs(&(struct regs){ .eax = function }); > + > + eax = inregs.eax; > + ecx = inregs.ecx; > asm("cpuid" : "+a"(eax), "=b"(ebx), "+c"(ecx), "=d"(edx)); > exec_in_big_real_mode(&insn_cpuid); > report("cpuid", R_AX|R_BX|R_CX|R_DX, > @@ -1415,10 +1428,11 @@ static void test_ss_base_for_esp_ebp(void) > MK_INSN(ssrel2, "mov %ss, %ax; mov %bx, %ss; movl (%ebp,%edi,8), %ebx; mov %ax, %ss"); > static unsigned array[] = { 0x12345678, 0, 0, 0, 0x87654321 }; > > - inregs.ebx = 1; > - inregs.ebp = (unsigned)array; > + init_inregs(&(struct regs){ .ebx = 1, .ebp = (unsigned)array }); > + > exec_in_big_real_mode(&insn_ssrel1); > report("ss relative addressing (1)", R_AX | R_BX, outregs.ebx == 0x87654321); > + > inregs.ebx = 1; > inregs.ebp = (unsigned)array; > inregs.edi = 0; > @@ -1434,7 +1448,8 @@ static void test_sgdt_sidt(void) > MK_INSN(sidt, "sidtw (%eax)"); > struct table_descr x, y; > > - inregs.eax = (unsigned)&y; > + init_inregs(&(struct regs){ .eax = (unsigned)&y }); > + > asm volatile("sgdtw %0" : "=m"(x)); > exec_in_big_real_mode(&insn_sgdt); > report("sgdt", 0, x.limit == y.limit && x.base == y.base); > @@ -1449,7 +1464,8 @@ static void test_sahf(void) > { > MK_INSN(sahf, "sahf; pushfw; mov (%esp), %al; popfw"); > > - inregs.eax = 0xfd00; > + init_inregs(&(struct regs){ .eax = 0xfd00 }); > + > exec_in_big_real_mode(&insn_sahf); > report("sahf", R_AX, outregs.eax == (inregs.eax | 0xd7)); > } > @@ -1458,7 +1474,8 @@ static void test_lahf(void) > { > MK_INSN(lahf, "pushfw; mov %al, (%esp); popfw; lahf"); > > - inregs.eax = 0xc7; > + init_inregs(&(struct regs){ .eax = 0xc7 }); > + > exec_in_big_real_mode(&insn_lahf); > report("lahf", R_AX, (outregs.eax >> 8) == inregs.eax); > } > @@ -1470,8 +1487,8 @@ static void test_movzx_movsx(void) > MK_INSN(movzsah, "movsx %ah, %ebx"); > MK_INSN(movzxah, "movzx %ah, %ebx"); > > - inregs.eax = 0x1234569c; > - inregs.esp = 0xffff; > + init_inregs(&(struct regs){ .eax = 0x1234569c }); > + > exec_in_big_real_mode(&insn_movsx); > report("movsx", R_BX, outregs.ebx == (signed char)inregs.eax); > exec_in_big_real_mode(&insn_movzx); > @@ -1486,7 +1503,8 @@ static void test_bswap(void) > { > MK_INSN(bswap, "bswap %ecx"); > > - inregs.ecx = 0x12345678; > + init_inregs(&(struct regs){ .ecx = 0x12345678 }); > + > exec_in_big_real_mode(&insn_bswap); > report("bswap", R_CX, outregs.ecx == 0x78563412); > } > @@ -1495,7 +1513,8 @@ static void test_aad(void) > { > MK_INSN(aad, "aad"); > > - inregs.eax = 0x12345678; > + init_inregs(&(struct regs){ .eax = 0x12345678 }); > + > exec_in_big_real_mode(&insn_aad); > report("aad", R_AX, outregs.eax == 0x123400d4); > } > @@ -1504,7 +1523,8 @@ static void test_aam(void) > { > MK_INSN(aam, "aam"); > > - inregs.eax = 0x76543210; > + init_inregs(&(struct regs){ .eax = 0x76543210 }); > + > exec_in_big_real_mode(&insn_aam); > report("aam", R_AX, outregs.eax == 0x76540106); > } > @@ -1519,8 +1539,8 @@ static void test_xlat(void) > table[i] = i + 1; > } > > - inregs.eax = 0x89abcdef; > - inregs.ebx = (u32)table; > + init_inregs(&(struct regs){ .eax = 0x89abcdef, .ebx = (u32)table }); > + > exec_in_big_real_mode(&insn_xlat); > report("xlat", R_AX, outregs.eax == 0x89abcdf0); > } > @@ -1530,7 +1550,8 @@ static void test_salc(void) > MK_INSN(clc_salc, "clc; .byte 0xd6"); > MK_INSN(stc_salc, "stc; .byte 0xd6"); > > - inregs.eax = 0x12345678; > + init_inregs(&(struct regs){ .eax = 0x12345678 }); > + > exec_in_big_real_mode(&insn_clc_salc); > report("salc (1)", R_AX, outregs.eax == 0x12345600); > exec_in_big_real_mode(&insn_stc_salc); > @@ -1542,8 +1563,7 @@ static void test_fninit(void) > u16 fcw = -1, fsw = -1; > MK_INSN(fninit, "fninit ; fnstsw (%eax) ; fnstcw (%ebx)"); > > - inregs.eax = (u32)&fsw; > - inregs.ebx = (u32)&fcw; > + init_inregs(&(struct regs){ .eax = (u32)&fsw, .ebx = (u32)&fcw }); > > exec_in_big_real_mode(&insn_fninit); > report("fninit", 0, fsw == 0 && (fcw & 0x103f) == 0x003f); > @@ -1576,7 +1596,8 @@ static u32 cycles_in_big_real_mode(struct insn_desc *insn) > { > u64 start, end; > > - inregs.ecx = PERF_COUNT; > + init_inregs(&(struct regs){ .ecx = PERF_COUNT }); > + > exec_in_big_real_mode(insn); > start = ((u64)outregs.esi << 32) | outregs.ebx; > end = ((u64)outregs.edx << 32) | outregs.eax; > @@ -1624,7 +1645,9 @@ static void test_perf_memory_load(void) > u32 cyc, tmp; > > MK_INSN_PERF(perf_memory_load, "cmp $0, (%edi)"); > - inregs.edi = (u32)&tmp; > + > + init_inregs(&(struct regs){ .edi = (u32)&tmp }); > + > cyc = cycles_in_big_real_mode(&insn_perf_memory_load); > print_serial_u32((cyc - perf_baseline) / PERF_COUNT); > print_serial(" cycles/emulated memory load instruction\n"); > @@ -1635,7 +1658,9 @@ static void test_perf_memory_store(void) > u32 cyc, tmp; > > MK_INSN_PERF(perf_memory_store, "mov %ax, (%edi)"); > - inregs.edi = (u32)&tmp; > + > + init_inregs(&(struct regs){ .edi = (u32)&tmp }); > + > cyc = cycles_in_big_real_mode(&insn_perf_memory_store); > print_serial_u32((cyc - perf_baseline) / PERF_COUNT); > print_serial(" cycles/emulated memory store instruction\n"); > @@ -1646,7 +1671,9 @@ static void test_perf_memory_rmw(void) > u32 cyc, tmp; > > MK_INSN_PERF(perf_memory_rmw, "add $1, (%edi)"); > - inregs.edi = (u32)&tmp; > + > + init_inregs(&(struct regs){ .edi = (u32)&tmp }); > + > cyc = cycles_in_big_real_mode(&insn_perf_memory_rmw); > print_serial_u32((cyc - perf_baseline) / PERF_COUNT); > print_serial(" cycles/emulated memory RMW instruction\n"); > @@ -1656,8 +1683,9 @@ static void test_dr_mod(void) > { > MK_INSN(drmod, "movl %ebx, %dr0\n\t" > ".byte 0x0f \n\t .byte 0x21 \n\t .byte 0x0\n\t"); > - inregs.eax = 0xdead; > - inregs.ebx = 0xaced; > + > + init_inregs(&(struct regs){ .eax = 0xdead, .ebx = 0xaced }); > + > exec_in_big_real_mode(&insn_drmod); > report("mov dr with mod bits", R_AX | R_BX, outregs.eax == 0xaced); > } > @@ -1670,7 +1698,9 @@ static void test_smsw(void) > "movl %ebx, %cr0\n\t" > "smswl %eax\n\t" > "movl %ecx, %cr0\n\t"); > - inregs.eax = 0x12345678; > + > + init_inregs(&(struct regs){ .eax = 0x12345678 }); > + > exec_in_big_real_mode(&insn_smsw); > report("smsw", R_AX | R_BX | R_CX, outregs.eax == outregs.ebx); > } > @@ -1678,7 +1708,9 @@ static void test_smsw(void) > static void test_xadd(void) > { > MK_INSN(xadd, "xaddl %eax, %eax\n\t"); > - inregs.eax = 0x12345678; > + > + init_inregs(&(struct regs){ .eax = 0x12345678 }); > + > exec_in_big_real_mode(&insn_xadd); > report("xadd", R_AX, outregs.eax == inregs.eax * 2); > } > Applied, thanks. Paolo