nx_x86_64_test.nx source
↩ module page · 67 lines · 2332 B
1// nx_x86_64_test.nx -- foundation smoke for the x86_64 emit library.
2//
3// Hand-sequences nx_x86_64 primitives to build a write+exit program
4// asm file, prints it to stdout. The companion bash wrapper then
5// assembles + links + runs the produced binary natively on x86_64.
6//
7// Two layers verified by this smoke:
8// 1. Each emit primitive produces the expected asm text (this file).
9// 2. The asm assembles + runs natively (bench/nx_x86_64_smoke.sh).
10//
11// The hand-built asm is the canonical "hello world" + sys_exit(0).
12
13import "syscalls.nx"
14import "nx_outbuf.nx"
15import "nx_x86_64.nx"
16
17func main() -> i64 {
18 let o: *OutBuf = out_new(4096)
19
20 let main_name: *u8 = "main" as *u8
21 let _start_name: *u8 = "_start" as *u8
22 let msg_label: *u8 = ".Lhello" as *u8
23 let msg: *u8 = "x86 native hello via nx_x86_64\n" as *u8
24 let msg_len: i64 = 31
25
26 // Header comment.
27 out_str(o, "# Emitted by nx_x86_64.nx (foundation session 1)\n")
28 out_str(o, " .intel_syntax noprefix\n")
29 out_str(o, " .att_syntax prefix\n")
30
31 // _start: call main; mov rax, 60; mov rdi, 0; syscall
32 x86_emit_function_start(o, _start_name)
33 out_str(o, " call main\n")
34 x86_emit_movabsq(o, "rax" as *u8, NX_X64_SYS_EXIT)
35 x86_emit_movabsq(o, "rdi" as *u8, 0)
36 x86_emit_syscall(o)
37 x86_emit_function_end(o, _start_name)
38
39 // main: write(1, .Lhello, len); ret
40 x86_emit_function_start(o, main_name)
41 x86_emit_prologue(o, 16)
42 x86_emit_syscall_imm(o, NX_X64_SYS_WRITE, 3,
43 1, 0, msg_len, 0, 0, 0)
44 // patch rsi to the leaq result (overwrites the movabsq above)
45 // -- for V1 simplicity, just emit a second leaq + redo the
46 // syscall. Cleaner pattern in session 2.
47 x86_emit_leaq_rip(o, msg_label, "rsi" as *u8)
48 x86_emit_movabsq(o, "rdi" as *u8, 1)
49 x86_emit_movabsq(o, "rdx" as *u8, msg_len)
50 x86_emit_movabsq(o, "rax" as *u8, NX_X64_SYS_WRITE)
51 x86_emit_syscall(o)
52 // Return 0.
53 x86_emit_movabsq(o, "rax" as *u8, 0)
54 x86_emit_epilogue(o)
55 x86_emit_function_end(o, main_name)
56
57 // .rodata: .Lhello:.asciz "..."
58 x86_emit_section_rodata(o)
59 x86_emit_label(o, msg_label)
60 x86_emit_asciz(o, msg, msg_len)
61
62 x86_emit_gnu_stack_note(o)
63
64 // Write the buffer to stdout.
65 sys_write(1, o.buf, o.pos)
66 return 0
67}