code wiki / (root) / nx_x86_64_call_test.nx

nx_x86_64_call_test.nx source

↩ module page · 82 lines · 2676 B

1// nx_x86_64_call_test.nx -- session 5 smoke for call / return. 2// 3// Builds a program with two functions: 4// 5// func writer(): 6// write(1, "K", 1) ; emits 'K' to stdout (side effect) 7// return 7 ; returns 7 in rax 8// 9// func main(): 10// call writer ; rax = 7 after return 11// rax += 0x30 ; rax = 0x37 ('7') 12// write(1, &rax_byte, 1) ; emits '7' 13// ret 0 14// 15// Expected stdout: "K7" (hex 4B 37) -- proves: 16// - call dispatches to writer 17// - writer's write side effect happens 18// - writer's return value (7) propagates via rax 19// - main consumes the return value and uses it 20 21import "syscalls.nx" 22import "nx_outbuf.nx" 23import "nx_x86_64.nx" 24 25func main() -> i64 { 26 let o: *OutBuf = out_new(8192) 27 28 let main_name: *u8 = "main" as *u8 29 let _start_name: *u8 = "_start" as *u8 30 let writer_name: *u8 = "writer" as *u8 31 let l_str: *u8 = ".Lkstr" as *u8 32 33 out_str(o, "# Emitted by nx_x86_64.nx session 5 (call/return)\n") 34 out_str(o, " .att_syntax prefix\n") 35 36 // _start trampoline. 37 x86_emit_function_start(o, _start_name) 38 x86_emit_call_label(o, main_name) 39 x86_emit_movabsq(o, "rax" as *u8, NX_X64_SYS_EXIT) 40 x86_emit_movabsq(o, "rdi" as *u8, 0) 41 x86_emit_syscall(o) 42 x86_emit_function_end(o, _start_name) 43 44 // writer: write(1, .Lkstr, 1); return 7 45 x86_emit_function_start(o, writer_name) 46 x86_emit_prologue(o, 0) 47 x86_emit_movabsq(o, "rdi" as *u8, 1) 48 x86_emit_leaq_rip(o, l_str, "rsi" as *u8) 49 x86_emit_movabsq(o, "rdx" as *u8, 1) 50 x86_emit_movabsq(o, "rax" as *u8, NX_X64_SYS_WRITE) 51 x86_emit_syscall(o) 52 x86_emit_movabsq(o, "rax" as *u8, 7) 53 x86_emit_epilogue(o) 54 x86_emit_function_end(o, writer_name) 55 56 // main: call writer; rax += 0x30; write that byte; ret 0 57 x86_emit_function_start(o, main_name) 58 x86_emit_prologue(o, 16) 59 x86_emit_call_label(o, writer_name) 60 // rax = 7 from writer 61 x86_emit_movabsq(o, "rcx" as *u8, 0x30) 62 x86_emit_addq_rr(o, "rcx" as *u8, "rax" as *u8) // rax = 0x37 63 x86_emit_store_byte(o, "rax" as *u8, "rbp" as *u8, 0 - 1) 64 x86_emit_movabsq(o, "rdi" as *u8, 1) 65 x86_emit_lea_disp(o, "rbp" as *u8, 0 - 1, "rsi" as *u8) 66 x86_emit_movabsq(o, "rdx" as *u8, 1) 67 x86_emit_movabsq(o, "rax" as *u8, NX_X64_SYS_WRITE) 68 x86_emit_syscall(o) 69 x86_emit_movabsq(o, "rax" as *u8, 0) 70 x86_emit_epilogue(o) 71 x86_emit_function_end(o, main_name) 72 73 // .rodata: "K" 74 x86_emit_section_rodata(o) 75 x86_emit_label(o, l_str) 76 x86_emit_asciz(o, "K" as *u8, 1) 77 78 x86_emit_gnu_stack_note(o) 79 80 sys_write(1, o.buf, o.pos) 81 return 0 82}