code wiki / (root) / nx_pe_dll_com_device.nx

nx_pe_dll_com_device.nx source

↩ module page · 187 lines · 11611 B

1// nx_pe_dll_com_device.nx -- THE CONVERGENCE RUNG: emit a sovereign DLL exporting a D3D11CreateDevice-shaped factory 2// that returns a COM object whose vtable methods run REAL nx_cc-compiled rasterizer code. Fuses the two proven halves: 3// (COM object + vtable dispatch) x (compiled render fn) = a foreign Windows process does 4// dev = nishi_d3d_create_device(mem); dev->lpVtbl->Render(dev, buf, w, h) -> compiled rasterizer -> pixels. 5// Method BODIES (nx_dev_render/nx_dev_get_info) = sovereign nx_cc-compiled NishiLang. COM PLUMBING (per-method MS-x64-> 6// SysV ABI thunks + a factory that builds the vtable in the CALLER-PROVIDED buffer via RIP-relative LEA) = generated by 7// THIS sovereign emitter (toolchain ABI glue, like a C++ compiler's vtables+thiscall adapters -- NO C++ ships). 8// Position-independent (no .reloc). Input /tmp/nishi_export_lib.s Output knowledge/nishi_com_device.dll 9// license_tier: ORIGINAL expect_exit: 0 10import "nx_syscalls.nx" 11import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 12import "nxasm_x86.nx" 13import "nx_pe_writer.nx" 14 15func cdv_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 16// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 17// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 18// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 19// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 20func cdv_putn(v: i64) -> i64 { nxi_out(v); return 0 } 21func cdv_wstr(buf: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){ buf[off+i]=s[i]; i=i+1 } buf[off+i]=0 as u8; return i+1 } 22 23func cdv_assemble(src: *u8, n: i64, out: *u8, out_cap: i64, p0: *i64, l0: *u8, p1: *i64, l1: *u8) -> i64 { 24 let lab_off: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 25 let lab_len: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 26 let lab_addr: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 27 let lab_sec: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 28 let op0: *i64 = sys_mmap(72) as *i64 // 9 slots for SIB (matches nxasm_x86) 29 let op1: *i64 = sys_mmap(72) as *i64 30 let op2: *i64 = sys_mmap(72) as *i64 // API DRIFT FIX: axc_pass gained op2 31 let scratch: *u8 = sys_mmap(64) 32 let posbox: *i64 = sys_mmap(16) as *i64 33 let n_lab_box: *i64 = sys_mmap(16) as *i64 34 n_lab_box[0] = 0 35 let lh: *i64 = sys_mmap(ASM_LH_SIZE * 8) as *i64 36 let text_size: i64 = axc_pass(src, n, out, 0, 0, lab_off, lab_len, lab_addr, lab_sec, n_lab_box, lh, op0, op1, op2, scratch, posbox) 37 if text_size < 0 { return text_size } 38 let n_lab: i64 = n_lab_box[0] 39 var a0: i64 = 0 - 1 40 var a1: i64 = 0 - 1 41 var k: i64 = 0 42 while k < n_lab { 43 if lab_sec[k] == 1 { lab_addr[k] = lab_addr[k] + text_size } 44 if axc_tok_is(src, lab_off[k], lab_len[k], l0) == 1 { a0 = lab_addr[k] } 45 if axc_tok_is(src, lab_off[k], lab_len[k], l1) == 1 { a1 = lab_addr[k] } 46 k = k + 1 47 } 48 axc_lh_build(src, lab_off, lab_len, n_lab, lh) 49 let total: i64 = axc_pass(src, n, out, text_size, 1, lab_off, lab_len, lab_addr, lab_sec, n_lab_box, lh, op0, op1, op2, scratch, posbox) 50 if total < 0 { return total } 51 if total > out_cap { return 0 - 200 } 52 p0[0] = a0 53 p1[0] = a1 54 return total 55} 56 57// emit the COM-device DLL. getinfo_off/render_off = code offsets of the compiled methods. Returns file size or -err. 58func cdv_emit(buf: *u8, code: *u8, code_len: i64, getinfo_off: i64, render_off: i64) -> i64 { 59 if (buf as i64) == 0 { return 0 - NX_PE_BAD_INPUT } 60 // glue layout in .text (relative offsets): [code][thunk_getinfo 21][thunk_render 30][factory 41] 61 let G: i64 = code_len // thunk_getinfo 62 let R: i64 = G + 21 // thunk_render 63 let F: i64 = R + 30 // factory (exported) 64 let text_used: i64 = F + 41 65 let text_pages: i64 = (text_used + 4095) / 4096 66 let text_raw: i64 = text_pages * 4096 67 let edata_rva: i64 = 0x1000 + text_raw 68 let edata_file: i64 = 0x200 + text_raw 69 let size_of_image: i64 = edata_rva + 0x1000 70 let file_size: i64 = edata_file + 0x200 71 72 _w16(buf, 0, 0x5A4D); _w32(buf, 0x3C, 0x80); _w32(buf, 0x80, 0x00004550) 73 _w16(buf, 0x84 + 0, PE_MACHINE_AMD64); _w16(buf, 0x84 + 2, 2); _w16(buf, 0x84 + 16, 0xF0); _w16(buf, 0x84 + 18, 0x2022) 74 let O: i64 = 0x98 75 _w16(buf, O + 0, PE_OH_MAGIC_PEPLUS); _w8(buf, O + 2, 1) 76 _w32(buf, O + 4, text_raw); _w32(buf, O + 8, 0x200) 77 _w32(buf, O + 16, 0); _w32(buf, O + 20, 0x1000) 78 _w64(buf, O + 24, 0x80000000, 0x1) // ImageBase 0x180000000 79 _w32(buf, O + 32, 0x1000); _w32(buf, O + 36, 0x200) 80 _w16(buf, O + 40, 6); _w16(buf, O + 48, 6) 81 _w32(buf, O + 56, size_of_image); _w32(buf, O + 60, 0x200) 82 _w16(buf, O + 68, PE_SUBSYSTEM_CONSOLE) 83 _w64(buf, O + 72, 0x100000, 0); _w64(buf, O + 80, 0x1000, 0); _w64(buf, O + 88, 0x100000, 0); _w64(buf, O + 96, 0x1000, 0) 84 _w32(buf, O + 108, 16) 85 _w32(buf, O + 112 + 0, edata_rva); _w32(buf, O + 112 + 4, 0x56) 86 87 _emit_section_header(buf, FOFF_SECT_TBL, 46, 116, 101, 120, 116, 0, 0, 0, text_used, 0x1000, text_raw, 0x200, PE_SECT_CODE_X_R) 88 _emit_section_header(buf, FOFF_SECT_TBL + 40, 46, 101, 100, 97, 116, 97, 0, 0, 0x56, edata_rva, 0x200, edata_file, PE_SECT_DATA_R) 89 90 // .text: compiled code 91 var i: i64 = 0 92 while i < code_len { buf[0x200 + i] = code[i]; i = i + 1 } 93 94 // thunk_getinfo @ 0x200+G (1-arg: self RCX->RDI; saves rdi/rsi): 95 // push rdi;push rsi;mov rdi,rcx;sub rsp,8;call nx_dev_get_info;add rsp,8;pop rsi;pop rdi;ret (21B) 96 let tg: i64 = 0x200 + G 97 _w8(buf,tg+0,0x57); _w8(buf,tg+1,0x56) 98 _w8(buf,tg+2,0x48); _w8(buf,tg+3,0x89); _w8(buf,tg+4,0xCF) 99 _w8(buf,tg+5,0x48); _w8(buf,tg+6,0x83); _w8(buf,tg+7,0xEC); _w8(buf,tg+8,0x08) 100 _w8(buf,tg+9,0xE8); _w32(buf, tg+10, getinfo_off - (G + 14)) 101 _w8(buf,tg+14,0x48); _w8(buf,tg+15,0x83); _w8(buf,tg+16,0xC4); _w8(buf,tg+17,0x08) 102 _w8(buf,tg+18,0x5E); _w8(buf,tg+19,0x5F); _w8(buf,tg+20,0xC3) 103 104 // thunk_render @ 0x200+R (4-arg: RCX->RDI RDX->RSI R8->RDX R9->RCX; saves rdi/rsi): 105 // push rdi;push rsi;mov rdi,rcx;mov rsi,rdx;mov rdx,r8;mov rcx,r9;sub rsp,8;call nx_dev_render;add rsp,8;pop rsi;pop rdi;ret (30B) 106 let tr: i64 = 0x200 + R 107 _w8(buf,tr+0,0x57); _w8(buf,tr+1,0x56) 108 _w8(buf,tr+2,0x48); _w8(buf,tr+3,0x89); _w8(buf,tr+4,0xCF) 109 _w8(buf,tr+5,0x48); _w8(buf,tr+6,0x89); _w8(buf,tr+7,0xD6) 110 _w8(buf,tr+8,0x4C); _w8(buf,tr+9,0x89); _w8(buf,tr+10,0xC2) 111 _w8(buf,tr+11,0x4C); _w8(buf,tr+12,0x89); _w8(buf,tr+13,0xC9) 112 _w8(buf,tr+14,0x48); _w8(buf,tr+15,0x83); _w8(buf,tr+16,0xEC); _w8(buf,tr+17,0x08) 113 _w8(buf,tr+18,0xE8); _w32(buf, tr+19, render_off - (R + 23)) 114 _w8(buf,tr+23,0x48); _w8(buf,tr+24,0x83); _w8(buf,tr+25,0xC4); _w8(buf,tr+26,0x08) 115 _w8(buf,tr+27,0x5E); _w8(buf,tr+28,0x5F); _w8(buf,tr+29,0xC3) 116 117 // factory @ 0x200+F (MS-ABI, mem in RCX). Builds object+vtable in the caller's buffer; returns mem. (41B) 118 // mov rax,rcx; lea rdx,[rip+d1]; mov [rcx+16],rdx; lea rdx,[rip+d2]; mov [rcx+24],rdx; lea rdx,[rcx+16]; mov [rcx],rdx; 119 // mov qword[rcx+8],0xC86432; ret (d1=-61 -> thunk_getinfo, d2=-51 -> thunk_render; both fixed by glue deltas) 120 let tf: i64 = 0x200 + F 121 _w8(buf,tf+0,0x48); _w8(buf,tf+1,0x89); _w8(buf,tf+2,0xC8) // mov rax,rcx 122 _w8(buf,tf+3,0x48); _w8(buf,tf+4,0x8D); _w8(buf,tf+5,0x15); _w32(buf, tf+6, G - (F + 10)) // lea rdx,[rip+d1]->getinfo thunk 123 _w8(buf,tf+10,0x48); _w8(buf,tf+11,0x89); _w8(buf,tf+12,0x51); _w8(buf,tf+13,0x10) // mov [rcx+16],rdx 124 _w8(buf,tf+14,0x48); _w8(buf,tf+15,0x8D); _w8(buf,tf+16,0x15); _w32(buf, tf+17, R - (F + 21))// lea rdx,[rip+d2]->render thunk 125 _w8(buf,tf+21,0x48); _w8(buf,tf+22,0x89); _w8(buf,tf+23,0x51); _w8(buf,tf+24,0x18) // mov [rcx+24],rdx 126 _w8(buf,tf+25,0x48); _w8(buf,tf+26,0x8D); _w8(buf,tf+27,0x51); _w8(buf,tf+28,0x10) // lea rdx,[rcx+16] 127 _w8(buf,tf+29,0x48); _w8(buf,tf+30,0x89); _w8(buf,tf+31,0x11) // mov [rcx],rdx 128 _w8(buf,tf+32,0x48); _w8(buf,tf+33,0xC7); _w8(buf,tf+34,0x41); _w8(buf,tf+35,0x08); _w32(buf, tf+36, 0xC86432) // mov qword[rcx+8],0xC86432 129 _w8(buf,tf+40,0xC3) // ret 130 131 // .edata @ edata_file (RVA edata_rva): 1 export "nishi_d3d_create_device" -> factory @ RVA 0x1000+F 132 let E: i64 = edata_file 133 _w32(buf, E + 12, edata_rva + 0x4A) // Name -> dllname 134 _w32(buf, E + 16, 1) 135 _w32(buf, E + 20, 1) 136 _w32(buf, E + 24, 1) 137 _w32(buf, E + 28, edata_rva + 0x28) // AddressOfFunctions 138 _w32(buf, E + 32, edata_rva + 0x2C) // AddressOfNames 139 _w32(buf, E + 36, edata_rva + 0x30) // AddressOfNameOrdinals 140 _w32(buf, E + 0x28, 0x1000 + F) // func[0] = factory 141 _w32(buf, E + 0x2C, edata_rva + 0x32) // name[0] RVA 142 _w16(buf, E + 0x30, 0) // ordinal[0] 143 cdv_wstr(buf, E + 0x32, "nishi_d3d_create_device\x00" as *u8) 144 cdv_wstr(buf, E + 0x4A, "nishicc.dll\x00" as *u8) 145 return file_size 146} 147 148func main() -> i64 { 149 cdv_puts("=== nx_pe_dll_com_device -- COM device (compiled methods behind an ID3D11-shaped vtable) ===\n" as *u8) 150 let lenbox: *i64 = sys_mmap(16) as *i64 151 let src: *u8 = sys_read_file("/tmp/nishi_export_lib.s" as *u8, lenbox) 152 if (src as i64) == 0 { cdv_puts("FAIL no /tmp/nishi_export_lib.s\n" as *u8); sys_exit(1); return 1 } 153 let n: i64 = lenbox[0] 154 if n <= 0 { cdv_puts("FAIL empty .s\n" as *u8); sys_exit(2); return 2 } 155 156 let code: *u8 = sys_mmap(1048576) 157 let gb: *i64 = sys_mmap(16) as *i64 158 let rb: *i64 = sys_mmap(16) as *i64 159 gb[0] = 0 - 1; rb[0] = 0 - 1 160 let code_len: i64 = cdv_assemble(src, n, code, 1048576, gb, "nx_dev_get_info" as *u8, rb, "nx_dev_render" as *u8) 161 if code_len < 0 { cdv_puts("FAIL assemble rc="); cdv_putn(code_len); cdv_puts("\n" as *u8); sys_exit(3); return 3 } 162 let getinfo_off: i64 = gb[0] 163 let render_off: i64 = rb[0] 164 if getinfo_off < 0 { cdv_puts("FAIL nx_dev_get_info not found\n" as *u8); sys_exit(4); return 4 } 165 if render_off < 0 { cdv_puts("FAIL nx_dev_render not found\n" as *u8); sys_exit(4); return 4 } 166 cdv_puts(" code_len="); cdv_putn(code_len); cdv_puts(" get_info@"); cdv_putn(getinfo_off); cdv_puts(" render@"); cdv_putn(render_off) 167 cdv_puts(" factory@"); cdv_putn(code_len + 51); cdv_puts("\n" as *u8) 168 169 let buf: *u8 = sys_mmap(0x10000) 170 let fsz: i64 = cdv_emit(buf, code, code_len, getinfo_off, render_off) 171 if fsz < 0 { cdv_puts("FAIL emit rc="); cdv_putn(fsz); cdv_puts("\n" as *u8); sys_exit(5); return 5 } 172 173 let fd: i64 = sys_openat_wr("knowledge/nishi_com_device.dll\x00" as *u8, 0x1a4) 174 if fd < 0 { cdv_puts("FAIL open output\n" as *u8); sys_exit(6); return 6 } 175 let wrote: i64 = sys_write(fd, buf, fsz) 176 sys_close(fd) 177 cdv_puts(" wrote "); cdv_putn(wrote); cdv_puts(" bytes -> knowledge/nishi_com_device.dll\n" as *u8) 178 179 var fails: i64 = 0 180 if (buf[0] as i64) != 0x4D { fails=fails+1 } 181 if (buf[0x84+18] as i64) != 0x22 { fails=fails+1 } 182 if wrote != fsz { fails=fails+1 } 183 if fails == 0 { cdv_puts("NX-PE-COM-DEVICE GREEN -- compiled methods behind a COM vtable; harness must create device + dispatch\n" as *u8); sys_exit(0); return 0 } 184 cdv_puts("NX-PE-COM-DEVICE RED fails="); cdv_putn(fails); cdv_puts("\n" as *u8) 185 sys_exit(1) 186 return 1 187}