code wiki / (root) / nx_pe_writer.nx

nx_pe_writer.nx

buildroot/runtime/nx_pe_writer.nx

37359 B952 linesdepth 3pulls 3 transitivereach 42 importersview sourcekind librarytopic pe
docsdependenciesstructsconstsfunctions

about

nx_pe_writer.nx -- substrate-emitted Windows PE32+ bytes. Arc Step 1 of the nxc2 Windows PE backend. Per cardinal 2026-05-21 ("always do the bits up harder investment"): substrate produces a valid, runnable Windows PE32+ executable from NishiLang source + the substrate's existing byte-writing primitives + sys_openat to flush to disk. No assembler, no linker, no MinGW, no MSVC, no third-party PE writer. What this Step 1 ships: - nx_pe_emit_exit42(buf): writes the bytes of a complete PE32+ executable that calls kernel32!ExitProcess(42) and returns to the Windows loader cleanly - Bytes are byte-for-byte deterministic for this minimal case; subsequent steps generalize (variable .text, multiple imports, real codegen integration with nxc2 x86_64 backend) - sys_openat + sys_write flush bytes to a Windows-visible path (/mnt/c/...) so PowerShell / cmd can execute it What this Step 1 does NOT ship (queued for next steps): Step 2: generalize -- accept (code_bytes, code_len, imports[]) and lay out sections dynamically; supports any kernel32 function the substrate wants to call Step 3: integrate with nxc2 x86_64 backend so a NishiLang program compiles to PE directly (--target pe32plus); emits MS x64 calling convention instead of SysV Step 4: substrate-side .obj+.lib equivalents (still no MS toolchain) Step 5: retire WSL2/qemu/binutils from the Win-native build path Why a minimal PE matters as foundation: - Validates byte layout against the real Windows loader - Establishes import-table mechanics (Import Descriptor + INT + IAT + IMAGE_IMPORT_BY_NAME + dll-name string) - Lets the substrate's HAL gain a Windows shim that calls kernel32 functions (the future NX_HAL_SHIM_WINDOWS sealed-enum option finally has an implementation path) - Proves the substrate doesn't need MinGW/MSVC to produce Windows-native binaries PE32+ layout for this minimal case (file size = 0x600 = 1536 bytes):

dependencies 2 imports · 41 importers

nx_syscalls.nx nx_hal.nx nx_pe_writer.nx nx_pe_compile_win.nx nx_pe_compile_win_call.nx nx_pe_compile_win_dll.nx nx_pe_compile_win_fread.nx nx_pe_compile_win_gui.nx nx_pe_compile_win_halloc.nx nx_pe_compile_win_httpd.nx nx_pe_compile_win_index.nx nx_pe_compile_win_io.nx nx_pe_compile_win_iotcli.nx

diagram shows first 10 each side; +0 more imports, +31 more importers in the complete lists below.

imports: nx_syscalls.nxnx_hal.nx

imported by: nx_pe_compile_win.nxnx_pe_compile_win_call.nxnx_pe_compile_win_dll.nxnx_pe_compile_win_fread.nxnx_pe_compile_win_gui.nxnx_pe_compile_win_halloc.nxnx_pe_compile_win_httpd.nxnx_pe_compile_win_index.nxnx_pe_compile_win_io.nxnx_pe_compile_win_iotcli.nxnx_pe_compile_win_mmap.nxnx_pe_compile_win_nishi.nxnx_pe_compile_win_organ.nxnx_pe_compile_win_sw.nxnx_pe_compile_win_table.nxnx_pe_compile_win_uiserve.nxnx_pe_compile_win_write.nxnx_pe_compile_win_wsa.nxnx_pe_container_datachar.nxnx_pe_container_gen.nxnx_pe_container_httpd.nxnx_pe_container_sdserver.nxnx_pe_container_uiserve.nxnx_pe_container_win.nxnx_pe_container_win_io.nxnx_pe_container_win_ping.nxnx_pe_container_win_sup.nxnx_pe_dll_com_device.nxnx_pe_dll_d3d11.nxnx_pe_dll_d3d11ctx.nxnx_pe_dll_d3d11draw.nxnx_pe_dll_d3d11shade.nxnx_pe_dll_d3d11tex.nxnx_pe_dll_id3d11.nxnx_pe_hello_test.nxnx_pe_job_limit_test.nxnx_pe_job_run_test.nxnx_pe_job_self_test.nxnx_pe_natbw.nxnx_pe_spawn_test.nxnx_pe_writer_test.nx

structs

none

consts

91const PE_FILE_SIZE: i64 = 0x600
92const PE_MACHINE_AMD64: i64 = 0x8664
93const PE_OH_MAGIC_PEPLUS: i64 = 0x020B
94const PE_SUBSYSTEM_CONSOLE: i64 = 3
95const PE_CHAR_EXEC: i64 = 0x0002
96const PE_CHAR_LARGE_ADDR: i64 = 0x0020
97const PE_SECT_CODE_X_R: i64 = 0x60000020
98const PE_SECT_DATA_R: i64 = 0x40000040
99const PE_SECT_DATA_RW: i64 = 0xC0000040 // INITIALIZED_DATA | READ | WRITE
102const FOFF_PE_SIG: i64 = 0x80
103const FOFF_COFF: i64 = 0x84
104const FOFF_OPT: i64 = 0x98
105const FOFF_SECT_TBL: i64 = 0x188
106const FOFF_TEXT: i64 = 0x200
107const FOFF_IDATA: i64 = 0x400
110const RVA_TEXT: i64 = 0x1000
111const RVA_IDATA: i64 = 0x2000
112const RVA_IMP_DESC: i64 = 0x2000
113const RVA_INT: i64 = 0x2028
114const RVA_IAT: i64 = 0x2038
115const RVA_IMP_NAME: i64 = 0x2048
116const RVA_DLL_STR: i64 = 0x2056
119const IMG_BASE_LO: i64 = 0x40000000
120const IMG_BASE_HI: i64 = 0x1
123const NX_PE_OK: i64 = 0
124const NX_PE_BAD_INPUT: i64 = 1
125const NX_PE_FAULT: i64 = 2
126const NX_PE_N_VERDICTS: i64 = 3
332const PE_HELLO_FILE_SIZE: i64 = 0x800 // 2048 bytes
333const PE_HELLO_FOFF_TEXT: i64 = 0x200
334const PE_HELLO_FOFF_RDATA: i64 = 0x400
335const PE_HELLO_FOFF_IDATA: i64 = 0x600
336const PE_HELLO_RVA_TEXT: i64 = 0x1000
337const PE_HELLO_RVA_RDATA: i64 = 0x2000
338const PE_HELLO_RVA_IDATA: i64 = 0x3000
600const PE_SPAWN_FILE_SIZE: i64 = 0x800

functions

67func _w8(buf: *u8, off: i64, v: i64) -> i64
71func _w16(buf: *u8, off: i64, v: i64) -> i64
76func _w32(buf: *u8, off: i64, v: i64) -> i64
83func _w64(buf: *u8, off: i64, lo32: i64, hi32: i64) -> i64
128func nx_pe_verdict_is_valid(v: i64) -> i64
135func _emit_section_header(buf: *u8, off: i64, name0: i64, name1: i64, name2: i64, name3: i64, name4: i64, name5: i64, name6: i64, name7: i64, vsize: i64, vaddr: i64, rawsize: i64, rawptr: i64, chars: i64) -> i64
159func nx_pe_emit_exit42(buf: *u8) -> i64
340func nx_pe_emit_hello(buf: *u8) -> i64
602func nx_pe_emit_spawn42(buf: *u8) -> i64
942func nx_pe_write_to_file(path: *u8, buf: *u8, n_bytes: i64) -> i64