code wiki / (root) / nx_x86_64_branch_test.nx

nx_x86_64_branch_test.nx source

↩ module page · 110 lines · 3660 B

1// nx_x86_64_branch_test.nx -- session 3 smoke for cmp/setcc/branch. 2// 3// Builds a program that exercises every cmp/branch primitive: 4// 5// rax := 5 6// rcx := 5 7// cmpq %rcx, %rax ; rax - rcx == 0 8// sete %al ; al = 1 9// movzbq %al, %rax ; rax = 1 10// testq %rax, %rax ; flags from rax (non-zero) 11// jne .Leq ; branch taken 12// write 'N' and exit (should NOT reach) 13// .Leq: 14// write 'Y' (means: equality compare worked) 15// 16// rax := 3 17// rcx := 7 18// cmpq %rcx, %rax ; rax - rcx == -4 < 0 19// jl .Llt ; signed less-than (cmpq operand order: 20// ; AT&T `cmpq src1, src2` is src2 - src1, 21// ; so jl jumps when src2 < src1 -- here 22// ; rax (3) < rcx (7) yes) 23// write 'B' and exit (should NOT reach) 24// .Llt: 25// write 'L' (means: signed-less-than branch worked) 26// 27// jmp .Ldone 28// .Ldone: 29// exit 0 30// 31// Expected stdout: "YL" (2 bytes hex 59 4C). 32 33import "syscalls.nx" 34import "nx_outbuf.nx" 35import "nx_x86_64.nx" 36 37func emit_write_byte(o: *OutBuf, ch: i64, scratch_disp: i64) -> i64 { 38 // store byte ch at scratch_disp(%rbp); write(1, &scratch, 1) 39 x86_emit_movabsq(o, "rax" as *u8, ch) 40 x86_emit_store_byte(o, "rax" as *u8, "rbp" as *u8, scratch_disp) 41 x86_emit_movabsq(o, "rdi" as *u8, 1) 42 x86_emit_lea_disp(o, "rbp" as *u8, scratch_disp, "rsi" as *u8) 43 x86_emit_movabsq(o, "rdx" as *u8, 1) 44 x86_emit_movabsq(o, "rax" as *u8, NX_X64_SYS_WRITE) 45 x86_emit_syscall(o) 46 return 0 47} 48 49func main() -> i64 { 50 let o: *OutBuf = out_new(8192) 51 52 let main_name: *u8 = "main" as *u8 53 let _start_name: *u8 = "_start" as *u8 54 let l_eq: *u8 = ".Leq" as *u8 55 let l_lt: *u8 = ".Llt" as *u8 56 let l_done: *u8 = ".Ldone" as *u8 57 let l_ne_path: *u8 = ".Lne_path" as *u8 58 let l_ge_path: *u8 = ".Lge_path" as *u8 59 60 out_str(o, "# Emitted by nx_x86_64.nx session 3 (cmp/setcc/branch)\n") 61 out_str(o, " .att_syntax prefix\n") 62 63 // _start trampoline 64 x86_emit_function_start(o, _start_name) 65 out_str(o, " call main\n") 66 x86_emit_movabsq(o, "rax" as *u8, NX_X64_SYS_EXIT) 67 x86_emit_movabsq(o, "rdi" as *u8, 0) 68 x86_emit_syscall(o) 69 x86_emit_function_end(o, _start_name) 70 71 x86_emit_function_start(o, main_name) 72 x86_emit_prologue(o, 16) 73 74 // ---- Block 1: equality compare ---- 75 x86_emit_movabsq(o, "rax" as *u8, 5) 76 x86_emit_movabsq(o, "rcx" as *u8, 5) 77 x86_emit_cmpq_rr(o, "rcx" as *u8, "rax" as *u8) 78 x86_emit_setcc(o, NX_X64_CC_EQ, "al" as *u8) 79 x86_emit_movzbq_rr(o, "al" as *u8, "rax" as *u8) 80 // rax should be 1; testq then jne -> .Leq 81 x86_emit_testq_rr(o, "rax" as *u8, "rax" as *u8) 82 x86_emit_jcc_label(o, NX_X64_CC_NE, l_eq) 83 // unreachable fallthrough: write 'N' + exit 84 emit_write_byte(o, 0x4E, 0 - 1) // 'N' 85 x86_emit_jmp_label(o, l_done) 86 87 x86_emit_label(o, l_eq) 88 emit_write_byte(o, 0x59, 0 - 1) // 'Y' 89 90 // ---- Block 2: signed less-than ---- 91 x86_emit_movabsq(o, "rax" as *u8, 3) 92 x86_emit_movabsq(o, "rcx" as *u8, 7) 93 x86_emit_cmpq_rr(o, "rcx" as *u8, "rax" as *u8) 94 x86_emit_jcc_label(o, NX_X64_CC_LT_S, l_lt) 95 emit_write_byte(o, 0x42, 0 - 1) // 'B' (bad) 96 x86_emit_jmp_label(o, l_done) 97 98 x86_emit_label(o, l_lt) 99 emit_write_byte(o, 0x4C, 0 - 1) // 'L' 100 101 x86_emit_label(o, l_done) 102 x86_emit_movabsq(o, "rax" as *u8, 0) 103 x86_emit_epilogue(o) 104 x86_emit_function_end(o, main_name) 105 106 x86_emit_gnu_stack_note(o) 107 108 sys_write(1, o.buf, o.pos) 109 return 0 110}