code wiki / (root) / nx_pe_dll_id3d11.nx

nx_pe_dll_id3d11.nx source

↩ module page · 195 lines · 10886 B

1// nx_pe_dll_id3d11.nx -- DATA-DRIVEN generator for a DLL whose device conforms to Microsoft's REAL ID3D11Device vtable 2// ABI. Resolves compiled IUnknown+device method bodies (nx_dev_qi/addref/release/getfl/notimpl), generates one uniform 3// MS-x64->SysV thunk per distinct method, then builds a 43-slot vtable from a SLOT TABLE (data): slot0=QueryInterface, 4// 1=AddRef, 2=Release, 37=GetFeatureLevel, all others=E_NOTIMPL -- matching d3d11.h exactly. A foreign process using the 5// REAL <d3d11.h> ID3D11Device interface dispatches dev->lpVtbl->AddRef/Release/GetFeatureLevel(dev) and hits OUR slots = 6// ABI-conformance graded against Microsoft (MSU discipline). Method BODIES = sovereign nx_cc-compiled NishiLang; vtable+ 7// thunks+factory = sovereign emitter glue (NO C++ ships). Static vtable baked at fixed base 0x180000000 (⚠add .reloc for 8// ASLR/real-deploy). Input /tmp/nishi_export_lib.s Output knowledge/nishi_id3d11.dll license_tier: ORIGINAL expect_exit: 0 9import "nx_syscalls.nx" 10import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 11import "nxasm_x86.nx" 12import "nx_pe_writer.nx" 13 14const N_SLOTS: i64 = 43 15 16func d11_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 17// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 18// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 19// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 20// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 21func d11_putn(v: i64) -> i64 { nxi_out(v); return 0 } 22func d11_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 } 23 24// resolve `cnt` labels (names[m] = *u8 as i64) -> offs[m]; returns total assembled size. 25func d11_assemble(src: *u8, n: i64, out: *u8, out_cap: i64, names: *i64, offs: *i64, cnt: i64) -> i64 { 26 let lab_off: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 27 let lab_len: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 28 let lab_addr: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 29 let lab_sec: *i64 = sys_mmap(ASM_MAX_LABELS * 8) as *i64 30 let op0: *i64 = sys_mmap(72) as *i64 // 9 slots for SIB (matches nxasm_x86) 31 let op1: *i64 = sys_mmap(72) as *i64 32 let op2: *i64 = sys_mmap(72) as *i64 // API DRIFT FIX: axc_pass gained op2 33 let scratch: *u8 = sys_mmap(64) 34 let posbox: *i64 = sys_mmap(16) as *i64 35 let n_lab_box: *i64 = sys_mmap(16) as *i64 36 n_lab_box[0] = 0 37 let lh: *i64 = sys_mmap(ASM_LH_SIZE * 8) as *i64 38 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) 39 if text_size < 0 { return text_size } 40 let n_lab: i64 = n_lab_box[0] 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 var m: i64 = 0 45 while m < cnt { 46 if axc_tok_is(src, lab_off[k], lab_len[k], names[m] as *u8) == 1 { offs[m] = lab_addr[k] } 47 m = m + 1 48 } 49 k = k + 1 50 } 51 axc_lh_build(src, lab_off, lab_len, n_lab, lh) 52 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) 53 if total < 0 { return total } 54 if total > out_cap { return 0 - 200 } 55 return total 56} 57 58// emit a uniform 30-byte 4-arg MS-x64->SysV thunk at file 0x200+tco calling method at code-offset moff (saves rdi/rsi). 59func d11_thunk(buf: *u8, tco: i64, moff: i64) -> i64 { 60 let t: i64 = 0x200 + tco 61 _w8(buf,t+0,0x57); _w8(buf,t+1,0x56) 62 _w8(buf,t+2,0x48); _w8(buf,t+3,0x89); _w8(buf,t+4,0xCF) // mov rdi,rcx 63 _w8(buf,t+5,0x48); _w8(buf,t+6,0x89); _w8(buf,t+7,0xD6) // mov rsi,rdx 64 _w8(buf,t+8,0x4C); _w8(buf,t+9,0x89); _w8(buf,t+10,0xC2) // mov rdx,r8 65 _w8(buf,t+11,0x4C); _w8(buf,t+12,0x89); _w8(buf,t+13,0xC9) // mov rcx,r9 66 _w8(buf,t+14,0x48); _w8(buf,t+15,0x83); _w8(buf,t+16,0xEC); _w8(buf,t+17,0x08) // sub rsp,8 67 _w8(buf,t+18,0xE8); _w32(buf, t+19, moff - (tco + 23)) // call moff 68 _w8(buf,t+23,0x48); _w8(buf,t+24,0x83); _w8(buf,t+25,0xC4); _w8(buf,t+26,0x08) // add rsp,8 69 _w8(buf,t+27,0x5E); _w8(buf,t+28,0x5F); _w8(buf,t+29,0xC3) // pop rsi;pop rdi;ret 70 return 0 71} 72 73// slot -> distinct-method index (0=qi 1=addref 2=release 3=getfl 4=notimpl), matching d3d11.h ID3D11Device layout. 74func d11_slot_method(slot: i64) -> i64 { 75 if slot == 0 { return 0 } // QueryInterface 76 if slot == 1 { return 1 } // AddRef 77 if slot == 2 { return 2 } // Release 78 if slot == 37 { return 3 } // GetFeatureLevel 79 return 4 // everything else -> E_NOTIMPL stub 80} 81 82// emit the ID3D11Device DLL. offs[0..4] = compiled method offsets. Returns file size or -err. 83func d11_emit(buf: *u8, code: *u8, code_len: i64, offs: *i64) -> i64 { 84 if (buf as i64) == 0 { return 0 - NX_PE_BAD_INPUT } 85 let FF: i64 = code_len + 150 // factory (after 5*30 thunks) 86 let VT: i64 = ((FF + 22 + 7) / 8) * 8 // vtable (8-aligned, after 22-byte factory) 87 let text_used: i64 = VT + N_SLOTS * 8 88 let text_pages: i64 = (text_used + 4095) / 4096 89 let text_raw: i64 = text_pages * 4096 90 let edata_rva: i64 = 0x1000 + text_raw 91 let edata_file: i64 = 0x200 + text_raw 92 let size_of_image: i64 = edata_rva + 0x1000 93 let file_size: i64 = edata_file + 0x200 94 95 _w16(buf, 0, 0x5A4D); _w32(buf, 0x3C, 0x80); _w32(buf, 0x80, 0x00004550) 96 _w16(buf, 0x84 + 0, PE_MACHINE_AMD64); _w16(buf, 0x84 + 2, 2); _w16(buf, 0x84 + 16, 0xF0); _w16(buf, 0x84 + 18, 0x2022) 97 let O: i64 = 0x98 98 _w16(buf, O + 0, PE_OH_MAGIC_PEPLUS); _w8(buf, O + 2, 1) 99 _w32(buf, O + 4, text_raw); _w32(buf, O + 8, 0x200) 100 _w32(buf, O + 16, 0); _w32(buf, O + 20, 0x1000) 101 _w64(buf, O + 24, 0x80000000, 0x1) 102 _w32(buf, O + 32, 0x1000); _w32(buf, O + 36, 0x200) 103 _w16(buf, O + 40, 6); _w16(buf, O + 48, 6) 104 _w32(buf, O + 56, size_of_image); _w32(buf, O + 60, 0x200) 105 _w16(buf, O + 68, PE_SUBSYSTEM_CONSOLE) 106 _w64(buf, O + 72, 0x100000, 0); _w64(buf, O + 80, 0x1000, 0); _w64(buf, O + 88, 0x100000, 0); _w64(buf, O + 96, 0x1000, 0) 107 _w32(buf, O + 108, 16) 108 _w32(buf, O + 112 + 0, edata_rva); _w32(buf, O + 112 + 4, 0x56) 109 110 _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) 111 _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) 112 113 var i: i64 = 0 114 while i < code_len { buf[0x200 + i] = code[i]; i = i + 1 } 115 116 // 5 uniform thunks at code_len + j*30 117 var j: i64 = 0 118 while j < 5 { d11_thunk(buf, code_len + j*30, offs[j]); j = j + 1 } 119 120 // factory @ FF: mov rax,rcx; lea rdx,[rip+dV]; mov [rcx],rdx; mov qword[rcx+8],1; ret (22B) 121 let f: i64 = 0x200 + FF 122 _w8(buf,f+0,0x48); _w8(buf,f+1,0x89); _w8(buf,f+2,0xC8) 123 _w8(buf,f+3,0x48); _w8(buf,f+4,0x8D); _w8(buf,f+5,0x15); _w32(buf, f+6, VT - (FF + 10)) 124 _w8(buf,f+10,0x48); _w8(buf,f+11,0x89); _w8(buf,f+12,0x11) 125 _w8(buf,f+13,0x48); _w8(buf,f+14,0xC7); _w8(buf,f+15,0x41); _w8(buf,f+16,0x08); _w32(buf, f+17, 1) 126 _w8(buf,f+21,0xC3) 127 128 // static vtable @ VT: 43 baked-absolute pointers (0x180000000 + thunk RVA), slot->method from d11_slot_method 129 var s: i64 = 0 130 while s < N_SLOTS { 131 let mj: i64 = d11_slot_method(s) 132 let rva: i64 = 0x1000 + code_len + mj*30 133 _w64(buf, 0x200 + VT + s*8, 0x80000000 + rva, 1) 134 s = s + 1 135 } 136 137 // .edata: 1 export "nishi_d3d_create_device" -> factory @ RVA 0x1000+FF 138 let E: i64 = edata_file 139 _w32(buf, E + 12, edata_rva + 0x4A) 140 _w32(buf, E + 16, 1); _w32(buf, E + 20, 1); _w32(buf, E + 24, 1) 141 _w32(buf, E + 28, edata_rva + 0x28); _w32(buf, E + 32, edata_rva + 0x2C); _w32(buf, E + 36, edata_rva + 0x30) 142 _w32(buf, E + 0x28, 0x1000 + FF) 143 _w32(buf, E + 0x2C, edata_rva + 0x32) 144 _w16(buf, E + 0x30, 0) 145 d11_wstr(buf, E + 0x32, "nishi_d3d_create_device\x00" as *u8) 146 d11_wstr(buf, E + 0x4A, "nishicc.dll\x00" as *u8) 147 return file_size 148} 149 150func main() -> i64 { 151 d11_puts("=== nx_pe_dll_id3d11 -- data-driven DLL conforming to Microsoft ID3D11Device vtable ABI ===\n" as *u8) 152 let lenbox: *i64 = sys_mmap(16) as *i64 153 let src: *u8 = sys_read_file("/tmp/nishi_export_lib.s" as *u8, lenbox) 154 if (src as i64) == 0 { d11_puts("FAIL no /tmp/nishi_export_lib.s\n" as *u8); sys_exit(1); return 1 } 155 let n: i64 = lenbox[0] 156 if n <= 0 { d11_puts("FAIL empty .s\n" as *u8); sys_exit(2); return 2 } 157 158 let names: *i64 = sys_mmap(8*5) as *i64 159 names[0] = "nx_dev_qi" as *u8 as i64 160 names[1] = "nx_dev_addref" as *u8 as i64 161 names[2] = "nx_dev_release" as *u8 as i64 162 names[3] = "nx_dev_getfl" as *u8 as i64 163 names[4] = "nx_dev_notimpl" as *u8 as i64 164 let offs: *i64 = sys_mmap(8*5) as *i64 165 var z: i64 = 0 166 while z < 5 { offs[z] = 0 - 1; z = z + 1 } 167 168 let code: *u8 = sys_mmap(1048576) 169 let code_len: i64 = d11_assemble(src, n, code, 1048576, names, offs, 5) 170 if code_len < 0 { d11_puts("FAIL assemble rc="); d11_putn(code_len); d11_puts("\n" as *u8); sys_exit(3); return 3 } 171 var miss: i64 = 0 172 var q: i64 = 0 173 while q < 5 { if offs[q] < 0 { miss = miss + 1 } q = q + 1 } 174 if miss > 0 { d11_puts("FAIL "); d11_putn(miss); d11_puts(" method(s) not found in .s\n" as *u8); sys_exit(4); return 4 } 175 d11_puts(" code_len="); d11_putn(code_len); d11_puts(" qi@"); d11_putn(offs[0]); d11_puts(" addref@"); d11_putn(offs[1]); d11_puts(" release@"); d11_putn(offs[2]); d11_puts(" getfl@"); d11_putn(offs[3]); d11_puts(" notimpl@"); d11_putn(offs[4]); d11_puts("\n" as *u8) 176 177 let buf: *u8 = sys_mmap(0x20000) 178 let fsz: i64 = d11_emit(buf, code, code_len, offs) 179 if fsz < 0 { d11_puts("FAIL emit rc="); d11_putn(fsz); d11_puts("\n" as *u8); sys_exit(5); return 5 } 180 181 let fd: i64 = sys_openat_wr("knowledge/nishi_id3d11.dll\x00" as *u8, 0x1a4) 182 if fd < 0 { d11_puts("FAIL open output\n" as *u8); sys_exit(6); return 6 } 183 let wrote: i64 = sys_write(fd, buf, fsz) 184 sys_close(fd) 185 d11_puts(" wrote "); d11_putn(wrote); d11_puts(" bytes -> knowledge/nishi_id3d11.dll ("); d11_putn(N_SLOTS); d11_puts("-slot vtable)\n" as *u8) 186 187 var fails: i64 = 0 188 if (buf[0] as i64) != 0x4D { fails=fails+1 } 189 if (buf[0x84+18] as i64) != 0x22 { fails=fails+1 } 190 if wrote != fsz { fails=fails+1 } 191 if fails == 0 { d11_puts("NX-PE-ID3D11 GREEN -- ID3D11Device-conformant DLL emitted; harness must dispatch via real <d3d11.h>\n" as *u8); sys_exit(0); return 0 } 192 d11_puts("NX-PE-ID3D11 RED fails="); d11_putn(fails); d11_puts("\n" as *u8) 193 sys_exit(1) 194 return 1 195}