nx_elf_writer.nx source
↩ module page · 159 lines · 5444 B
1// nx_elf_writer.nx -- sovereign ELF64 binary writer.
2//
3// Pure NishiLang. Takes an exit-code integer; writes a complete
4// static-linked x86_64 ELF binary to a file descriptor. No as. No
5// ld. No gcc. No libc. The output is bytes that Linux execve loads
6// and runs.
7//
8// Today: smallest credible binary -- `_start: mov rdi, N; mov rax,
9// 231; syscall` (exit_group with code N). Total ELF size: 134 bytes.
10//
11// Tomorrow (L19b): take an IR snapshot (nxc2 --target ir > foo.ir),
12// read it, emit the corresponding x86_64 bytes. That closes the
13// "nxc2 emits ELF directly" loop without adding more C to nxc2.
14//
15// Cardinal alignment:
16// feedback-nishilang-mission-displace-cuda-directx-via-patent-clean-
17// absorption: every new substrate file is .nx. This file replaces
18// the temptation to add an ELF emitter to x86_64.c.
19//
20// genealogy_id: elf_specification_v1_2 + linux_kernel_load_elf + sysv_abi
21// lineage_id: sovereign_elf_emit_q10
22
23// nx_safety_envelope:
24// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
25// sil_target: SIL1
26// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
27// verdict: NOT_YET_EVALUATED
28
29import "nx_syscalls_x86_64.nx"
30
31// Sealed verdict for "did the write succeed".
32const NX_ELF_VERDICT_UNKNOWN: i64 = 0
33const NX_ELF_VERDICT_OK: i64 = 1
34const NX_ELF_VERDICT_WRITE_FAIL: i64 = 2
35const NX_ELF_VERDICT_N: i64 = 3
36
37const NX_ELF_BASE_VADDR_LO: i64 = 0x400000
38const NX_ELF_TEXT_OFFSET: i64 = 0x78 // sizeof(Ehdr=64) + sizeof(Phdr=56)
39
40// Write one byte to fd.
41func _wb(fd: i64, b: i64) -> i64 {
42 let one: *u8 = sys_mmap(8)
43 one[0] = b
44 return sys_write(fd, one, 1)
45}
46
47// Write `n` bytes from `buf` to fd.
48func _wn(fd: i64, buf: *u8, n: i64) -> i64 {
49 return sys_write(fd, buf, n)
50}
51
52// Little-endian 16-bit write.
53func _w16(fd: i64, v: i64) -> i64 {
54 let two: *u8 = sys_mmap(8)
55 two[0] = v & 0xff
56 two[1] = (v >> 8) & 0xff
57 return sys_write(fd, two, 2)
58}
59
60// Little-endian 32-bit write.
61func _w32(fd: i64, v: i64) -> i64 {
62 let four: *u8 = sys_mmap(8)
63 four[0] = v & 0xff
64 four[1] = (v >> 8) & 0xff
65 four[2] = (v >> 16) & 0xff
66 four[3] = (v >> 24) & 0xff
67 return sys_write(fd, four, 4)
68}
69
70// Little-endian 64-bit write.
71func _w64(fd: i64, v: i64) -> i64 {
72 let eight: *u8 = sys_mmap(8)
73 eight[0] = v & 0xff
74 eight[1] = (v >> 8) & 0xff
75 eight[2] = (v >> 16) & 0xff
76 eight[3] = (v >> 24) & 0xff
77 eight[4] = (v >> 32) & 0xff
78 eight[5] = (v >> 40) & 0xff
79 eight[6] = (v >> 48) & 0xff
80 eight[7] = (v >> 56) & 0xff
81 return sys_write(fd, eight, 8)
82}
83
84// Write the .text bytes for `_start: mov rdi, code; mov rax, 231;
85// syscall` -- 14 bytes that exit_group with the given code.
86//
87// Encoding:
88// 48 c7 c7 NN NN NN NN mov rdi, imm32 (7 bytes)
89// 48 c7 c0 e7 00 00 00 mov rax, 231 (7 bytes)
90// 0f 05 syscall (2 bytes)
91// Total: 16 bytes (NOT 14 -- my earlier count was off).
92func _emit_text(fd: i64, exit_code: i64) -> i64 {
93 let buf: *u8 = sys_mmap(32)
94 buf[0] = 0x48; buf[1] = 0xc7; buf[2] = 0xc7
95 buf[3] = exit_code & 0xff
96 buf[4] = (exit_code >> 8) & 0xff
97 buf[5] = (exit_code >> 16) & 0xff
98 buf[6] = (exit_code >> 24) & 0xff
99 buf[7] = 0x48; buf[8] = 0xc7; buf[9] = 0xc0
100 buf[10] = 0xe7; buf[11] = 0x00; buf[12] = 0x00; buf[13] = 0x00
101 buf[14] = 0x0f; buf[15] = 0x05
102 return sys_write(fd, buf, 16)
103}
104
105// Total binary size = 64 + 56 + 16 = 136 bytes.
106const NX_ELF_TEXT_LEN: i64 = 16
107const NX_ELF_FILE_SIZE: i64 = 136
108
109// Top-level: write the complete ELF to fd. Returns NX_ELF_VERDICT_OK
110// on success.
111func nx_elf_emit_return_n(fd: i64, exit_code: i64) -> i64 {
112 let entry_vaddr: i64 = NX_ELF_BASE_VADDR_LO + NX_ELF_TEXT_OFFSET
113
114 // ---- ELF64 header (64 bytes) ----
115 _wb(fd, 0x7f); _wb(fd, 0x45); _wb(fd, 0x4c); _wb(fd, 0x46) // \x7fELF
116 _wb(fd, 2) // ELFCLASS64
117 _wb(fd, 1) // ELFDATA2LSB
118 _wb(fd, 1) // EV_CURRENT
119 _wb(fd, 0) // OSABI System V
120 _wb(fd, 0) // ABIVERSION
121 // e_ident padding (7 bytes)
122 _wb(fd, 0); _wb(fd, 0); _wb(fd, 0); _wb(fd, 0)
123 _wb(fd, 0); _wb(fd, 0); _wb(fd, 0)
124 _w16(fd, 2) // e_type = ET_EXEC
125 _w16(fd, 0x3e) // e_machine = EM_X86_64
126 _w32(fd, 1) // e_version
127 _w64(fd, entry_vaddr) // e_entry
128 _w64(fd, 64) // e_phoff
129 _w64(fd, 0) // e_shoff (no sections)
130 _w32(fd, 0) // e_flags
131 _w16(fd, 64) // e_ehsize
132 _w16(fd, 56) // e_phentsize
133 _w16(fd, 1) // e_phnum
134 _w16(fd, 0) // e_shentsize
135 _w16(fd, 0) // e_shnum
136 _w16(fd, 0) // e_shstrndx
137
138 // ---- Program header (56 bytes): PT_LOAD R|X ----
139 _w32(fd, 1) // PT_LOAD
140 _w32(fd, 5) // PF_R | PF_X
141 _w64(fd, 0) // p_offset
142 _w64(fd, NX_ELF_BASE_VADDR_LO)
143 _w64(fd, NX_ELF_BASE_VADDR_LO)
144 _w64(fd, NX_ELF_FILE_SIZE) // p_filesz
145 _w64(fd, NX_ELF_FILE_SIZE) // p_memsz
146 _w64(fd, 0x1000) // p_align
147
148 // ---- .text ----
149 _emit_text(fd, exit_code)
150
151 return NX_ELF_VERDICT_OK
152}
153
154// Sealed-enum validity gate.
155func nx_elf_verdict_is_valid(v: i64) -> i64 {
156 if v < 0 { return 0 }
157 if v >= NX_ELF_VERDICT_N { return 0 }
158 return 1
159}