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}