From 2ee12b66a3a5828ee07d6e68576daea2c2082068 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 1 Nov 2016 21:37:57 -0400 Subject: [PATCH] 16-bit bridging code now protects %es register. Fixes crash with Info-Zip's unzip.exe blowing up calling into ncurses via VioGetMode(). --- lx_loader.c | 13 +++++++++---- lx_loader.h | 3 ++- native/os2native16.h | 13 +++++++++++++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/lx_loader.c b/lx_loader.c index 9f643f3..4dab840 100644 --- a/lx_loader.c +++ b/lx_loader.c @@ -730,8 +730,11 @@ static void *generateMissingTrampoline16(const char *_module, const char *_entry *(ptr++) = 0x66; /* mov cx,0x8888... */ *(ptr++) = 0xB9; /* ...mov cx,0x8888 */ memcpy(ptr, &GLoaderState->original_ds, 2); ptr += 2; - *(ptr++) = 0x8E; /* mov ds,ecx... */ - *(ptr++) = 0xD9; /* ...mov ds,ecx */ + *(ptr++) = 0x66; /* mov cx,0x8888... */ + *(ptr++) = 0xB9; /* ...mov cx,0x8888 */ + memcpy(ptr, &GLoaderState->original_es, 2); ptr += 2; + *(ptr++) = 0x8E; /* mov es,ecx... */ \ + *(ptr++) = 0xC1; /* ...mov es,ecx */ \ // okay, CPU is in a sane state again, call the trampoline. Don't bother cleaning up. *(ptr++) = 0x68; // pushl immediate memcpy(ptr, &entry, sizeof (char *)); @@ -2076,10 +2079,12 @@ int main(int argc, char **argv, char **envp) unsigned int segment = 0; __asm__ __volatile__ ( "movw %%cs, %%ax \n\t" : "=a" (segment) ); GLoaderState->original_cs = segment; - __asm__ __volatile__ ( "movw %%ss, %%ax \n\t" : "=a" (segment) ); - GLoaderState->original_ss = segment; __asm__ __volatile__ ( "movw %%ds, %%ax \n\t" : "=a" (segment) ); GLoaderState->original_ds = segment; + __asm__ __volatile__ ( "movw %%es, %%ax \n\t" : "=a" (segment) ); + GLoaderState->original_es = segment; + __asm__ __volatile__ ( "movw %%ss, %%ax \n\t" : "=a" (segment) ); + GLoaderState->original_ss = segment; const char *envr = getenv("IS_2INE"); GLoaderState->subprocess = (envr != NULL); diff --git a/lx_loader.h b/lx_loader.h index 45d2efc..43c61de 100644 --- a/lx_loader.h +++ b/lx_loader.h @@ -212,8 +212,9 @@ typedef struct LxLoaderState int running; int trace_native; uint16 original_cs; - uint16 original_ss; uint16 original_ds; + uint16 original_es; + uint16 original_ss; uint32 ldt[8192]; char *libpath; uint32 libpathlen; diff --git a/native/os2native16.h b/native/os2native16.h index 2698087..eaca045 100644 --- a/native/os2native16.h +++ b/native/os2native16.h @@ -86,15 +86,21 @@ ADD EAX, 4 ; %eax now points to original function arguments on the stack. PUSH EBX ; save original ss:sp to stack. PUSH DS ; save off the caller's data segment. +PUSH ES ; save off the caller's %es register. + MOV CX, 0x8888 ; restore our linear data segment. MOV DS, CX +MOV CX, 0x9999 ; restore %es register. +MOV ES, CX + PUSH EAX ; make this the sole argument to the bridge function. MOV EAX, 0x55555555 ; absolute address of our 32-bit bridging function in C. CALL [EAX] ; call our 32-bit bridging function in C. ; don't touch EAX anymore, it has the return value now! ADD ESP, 4 ; dump our function argument. +POP ES ; get back caller's %es register. POP DS ; get back our 16-bit data segment. ; Restore 16:16 stack. !!! FIXME: can use LSS if we figure out prefix and DS politics. @@ -152,11 +158,17 @@ RETF 0x22 ; ...and back to the (far) caller, clearing the args (Pascal calling *(ptr++) = 0x04; /* ...add eax,byte +0x4 */ \ *(ptr++) = 0x53; /* push ebx */ \ *(ptr++) = 0x1E; /* push ds */ \ + *(ptr++) = 0x06; /* push es */ \ *(ptr++) = 0x66; /* mov cx,0x8888... */ \ *(ptr++) = 0xB9; /* ...mov cx,0x8888 */ \ memcpy(ptr, &GLoaderState->original_ds, 2); ptr += 2; \ *(ptr++) = 0x8E; /* mov ds,ecx... */ \ *(ptr++) = 0xD9; /* ...mov ds,ecx */ \ + *(ptr++) = 0x66; /* mov cx,0x9999... */ \ + *(ptr++) = 0xB9; /* ...mov cx,0x9999 */ \ + memcpy(ptr, &GLoaderState->original_es, 2); ptr += 2; \ + *(ptr++) = 0x8E; /* mov es,ecx... */ \ + *(ptr++) = 0xC1; /* ...mov es,ecx */ \ *(ptr++) = 0x50; /* push eax */ \ *(ptr++) = 0xB8; /* mov eax,0x55555555... */ \ const uint32 callbridgeaddr = (uint32) bridge16to32_##fn; \ @@ -166,6 +178,7 @@ RETF 0x22 ; ...and back to the (far) caller, clearing the args (Pascal calling *(ptr++) = 0x83; /* add esp,byte +0x4... */ \ *(ptr++) = 0xC4; /* ...add esp,byte +0x4 */ \ *(ptr++) = 0x04; /* ...add esp,byte +0x4 */ \ + *(ptr++) = 0x07; /* pop es */ \ *(ptr++) = 0x1F; /* pop ds */ \ *(ptr++) = 0x66; /* pop bx... */ \ *(ptr++) = 0x5B; /* ...pop bx */ \