This commit is contained in:
Mario Fetka
2026-05-23 17:48:55 +02:00
parent 64ab3a4fab
commit 7f4dd3b429
3 changed files with 79 additions and 59 deletions

2
kern.h
View File

@@ -15,7 +15,7 @@ extern void KERN_CALL xmemmove(void *ziel, void *quelle, UI anz);
extern int KERN_CALL Net_Call(UI func, void *req, void *repl);
extern int KERN_CALL C32_LoadNios_Probe(UI axfunc, void *outbuf);
extern int KERN_CALL C32_GetFunc_Probe(char *name, void *outbuf);
extern int KERN_CALL C32_CallName0_Probe(char *name, void *outbuf);
extern int KERN_CALL C32_CallVersion_Nios_Probe(void *outbuf);
extern int KERN_CALL Net_Call_VLM_Raw(UI ax, UI bx, UI cx, UI dx,
void *req, void *repl,
UI p1, UI p2, UI p3);

View File

@@ -22,7 +22,7 @@ public _xmemmove
public _Net_Call
public _C32_LoadNios_Probe
public _C32_GetFunc_Probe
public _C32_CallName0_Probe
public _C32_CallVersion_Nios_Probe
public _Net_Call_VLM_Raw
_IPXinit proc far
@@ -467,26 +467,34 @@ c32get_store:
_C32_GetFunc_Probe endp
; int C32_CallName0_Probe(char *name, void *outbuf)
; int C32_CallVersion_Nios_Probe(void *outbuf)
;
; Resolve Client32 function by name via NIOS resolver returned by D8C1,
; then call resolved function with zero arguments.
;
; This is safe for CLIENT32GetVersion. Do not use for functions needing args.
; Safe Client32 version call using the exact d32wrap convention:
; 1) INT 2F AX=D8C1
; 2) use ESI resolver to resolve "CLIENT32GetVersion"
; 3) call ECX trampoline, not the function pointer directly:
; push 0
; push 0
; push fn_seg
; push fn_off
; call ECX
; add sp,8
;
; outbuf:
; +00 load AX
; +02 resolver ptr off
; +04 resolver ptr seg
; +06 resolved fn off
; +08 resolved fn seg
; +0A call return AX
; +0C call return DX
; +0E call return FLAGS
_C32_CallName0_Probe proc far
; +02 resolver off
; +04 resolver seg
; +06 trampoline off
; +08 trampoline seg
; +0A fn off
; +0C fn seg
; +0E call AX
; +10 call DX
; +12 flags
_C32_CallVersion_Nios_Probe proc far
push bp
mov bp, sp
sub sp, 8
sub sp, 12
push ds
push es
@@ -501,47 +509,51 @@ _C32_CallName0_Probe proc far
mov ax, 0D8C1h
int 2Fh
; save resolver ESI at [bp-4]
; save ESI resolver at [bp-4]
db 66h, 89h, 76h, 0FCh
; save ECX trampoline at [bp-8]
db 66h, 89h, 4Eh, 0F8h
push ax ; load AX
push ax ; load AX for output
or ax, ax
jne c32call_store_fail
jne c32ver_fail
; resolve function name:
; push name segment, name offset, 0, 0; call resolver; add sp,8
push word ptr [bp+8]
push word ptr [bp+6]
push cs
push offset c32ver_name
push 0
push 0
call dword ptr [bp-4]
add sp, 8
; save resolved function pointer DX:AX at [bp-8]
mov word ptr [bp-8], ax
mov word ptr [bp-6], dx
; resolver returns DX:AX function pointer
mov [bp-12], ax
mov [bp-10], dx
or ax, dx
je c32call_store_fail2
je c32ver_fail
; call resolved function with zero args
; d32wrap _CLIENT32GetVersion convention:
push 0
push 0
push word ptr [bp-10]
push word ptr [bp-12]
call dword ptr [bp-8]
add sp, 8
pushf
push dx
push ax
jmp short c32call_store
jmp short c32ver_store
c32call_store_fail2:
c32ver_fail:
xor dx, dx
xor ax, ax
c32call_store_fail:
pushf
push dx
push ax
c32call_store:
les di, dword ptr [bp+10]
c32ver_store:
les di, dword ptr [bp+6]
pop ax ; call AX
pop dx ; call DX
@@ -557,9 +569,13 @@ c32call_store:
mov es:[di+6], cx
mov cx, word ptr [bp-6]
mov es:[di+8], cx
mov es:[di+10], ax
mov es:[di+12], dx
mov es:[di+14], bx
mov cx, word ptr [bp-12]
mov es:[di+10], cx
mov cx, word ptr [bp-10]
mov es:[di+12], cx
mov es:[di+14], ax
mov es:[di+16], dx
mov es:[di+18], bx
popf
pop di
@@ -570,7 +586,10 @@ c32call_store:
pop bp
xor ah, ah
ret
_C32_CallName0_Probe endp
c32ver_name db 'CLIENT32GetVersion',0
_C32_CallVersion_Nios_Probe endp
end

View File

@@ -1218,42 +1218,43 @@ static int tests_c32getfunc(void)
}
static int tests_c32callver(void)
static int tests_c32callver2(void)
{
uint8 out[32];
uint16 load_ax;
uint16 res_off, res_seg;
uint16 tramp_off, tramp_seg;
uint16 fn_off, fn_seg;
uint16 call_ax, call_dx, flags;
memset(out, 0, sizeof(out));
fprintf(stdout, "TEST C32CALLVER\n");
fprintf(stdout, "Resolve and call CLIENT32GetVersion with zero args\n\n");
fprintf(stdout, "TEST C32CALLVER2\n");
fprintf(stdout, "Call CLIENT32GetVersion through ECX NIOS trampoline\n\n");
C32_CallName0_Probe("CLIENT32GetVersion", out);
C32_CallVersion_Nios_Probe(out);
load_ax = tests_get_word_lh(out + 0);
res_off = tests_get_word_lh(out + 2);
res_seg = tests_get_word_lh(out + 4);
fn_off = tests_get_word_lh(out + 6);
fn_seg = tests_get_word_lh(out + 8);
call_ax = tests_get_word_lh(out + 10);
call_dx = tests_get_word_lh(out + 12);
flags = tests_get_word_lh(out + 14);
load_ax = tests_get_word_lh(out + 0);
res_off = tests_get_word_lh(out + 2);
res_seg = tests_get_word_lh(out + 4);
tramp_off = tests_get_word_lh(out + 6);
tramp_seg = tests_get_word_lh(out + 8);
fn_off = tests_get_word_lh(out + 10);
fn_seg = tests_get_word_lh(out + 12);
call_ax = tests_get_word_lh(out + 14);
call_dx = tests_get_word_lh(out + 16);
flags = tests_get_word_lh(out + 18);
fprintf(stdout, "Load AX=%04X\n", load_ax);
fprintf(stdout, "Resolver=%04X:%04X\n", res_seg, res_off);
fprintf(stdout, "Resolver=%04X:%04X Trampoline=%04X:%04X\n",
res_seg, res_off, tramp_seg, tramp_off);
fprintf(stdout, "Function=%04X:%04X\n", fn_seg, fn_off);
fprintf(stdout, "Call returned DX:AX=%04X:%04X FLAGS=%04X\n",
call_dx, call_ax, flags);
tests_dump_bytes("RAW:", out, 16);
if (fn_off || fn_seg)
fprintf(stdout, "\nFunction pointer resolved.\n");
if (call_ax || call_dx)
fprintf(stdout, "Call returned non-zero version value.\n");
tests_dump_bytes("RAW:", out, 20);
if (load_ax == 0 && (fn_off || fn_seg))
fprintf(stdout, "\nNIOS trampoline path resolved successfully.\n");
return(0);
}
@@ -1273,8 +1274,8 @@ int func_tests(int argc, char *argv[], int mode)
if (tests_same_arg(argv[1], "C32GETFUNC"))
return tests_c32getfunc();
if (tests_same_arg(argv[1], "C32CALLVER"))
return tests_c32callver();
if (tests_same_arg(argv[1], "C32CALLVER2"))
return tests_c32callver2();
if (tests_same_arg(argv[1], "NWREQ87"))
return tests_nwreq87(argc, argv);