| /* |
| * Copyright Robert J. Amstadt, 1993 |
| */ |
| #ifdef linux |
| #define UDATASEL 0x2b |
| #endif |
| #if defined(__NetBSD__) || defined(__FreeBSD__) |
| #define UDATASEL 0x27 |
| #endif |
| .data |
| jump_target: |
| return_value: |
| .long 0 |
| |
| /********************************************************************** |
| * Places to keep info about the current 32-bit stack frame. |
| */ |
| .globl _IF1632_Saved32_esp,_IF1632_Saved32_ebp,_IF1632_Saved32_ss |
| _IF1632_Saved32_esp: |
| .long 0 |
| _IF1632_Saved32_ebp: |
| .long 0 |
| _IF1632_Saved32_ss: |
| .word 0 |
| |
| /********************************************************************** |
| * Places to keep info about the current 16-bit stack frame. |
| */ |
| .globl _IF1632_Saved16_esp,_IF1632_Saved16_ebp,_IF1632_Saved16_ss |
| _IF1632_Saved16_esp: |
| .long 0 |
| _IF1632_Saved16_ebp: |
| .long 0 |
| _IF1632_Saved16_ss: |
| .word 0 |
| |
| nbytes: |
| .word 0 |
| selector: |
| .word 0 |
| offset: |
| .word 0 |
| |
| .text |
| |
| /********************************************************************** |
| * int CallToInit16(unsigned long csip, unsigned long sssp, |
| * unsigned short ds) |
| * |
| * Stack: 0 ebp |
| * 4 eip |
| * 8 target ip |
| * 10 target cs |
| * 12 target sp |
| * 14 target ss |
| * 16 target ds |
| */ |
| .align 4 |
| .globl _CallToInit16 |
| _CallToInit16: |
| pushl %ebp |
| movl %esp,%ebp |
| |
| /* |
| * Save our registers |
| */ |
| pushal |
| pushl _IF1632_Saved32_esp |
| pushl _IF1632_Saved32_ebp |
| pushw _IF1632_Saved32_ss |
| |
| /* |
| * Get target address. |
| */ |
| movl 8(%ebp),%eax |
| movl %eax,jump_target |
| lea jump_target,%edx |
| |
| /* |
| * Put stack registers where we can get them after stack switch. |
| */ |
| movw %ss,_IF1632_Saved32_ss |
| movl %esp,_IF1632_Saved32_esp |
| movl %ebp,_IF1632_Saved32_ebp |
| |
| /* |
| * Load initial registers |
| */ |
| movw _WIN_StackSize,%bx |
| movw _WIN_HeapSize,%cx |
| movl $0,%esi |
| xorl %eax,%eax |
| movw _PSPSelector,%ax |
| movw %ax,%es |
| movw 16(%ebp),%ax |
| movw %ax,%ds |
| movl %eax,%edi |
| xorl %eax,%eax |
| movw 12(%ebp),%ax |
| movl %eax,%esp |
| movw 14(%ebp),%ax |
| movw %ax,%ss |
| movl %esp,%eax |
| movl %eax,%ebp |
| movw $UDATASEL,%ax |
| movw %ax,%fs |
| movw %ax,%gs |
| /* movw %ds,%ax */ |
| |
| /* |
| * Call entry point |
| */ |
| .byte 0x66 |
| lcall %fs:(%edx) |
| |
| /* |
| * Restore old stack and segment registers. |
| * |
| * Two choices here: |
| * 1. Trust that fs or gs hasn't changed. |
| * 2. Rely on knowledge of Linux use of segments. |
| * |
| * I'll opt for choice 2 because who knows what programs we |
| * going to run. Linux should be fairly stable in terms of |
| * GDT usage. |
| */ |
| pushl %eax |
| movw $UDATASEL,%ax |
| movw %ax,%ds |
| movw %ax,%es |
| movw %ax,%fs |
| movw %ax,%gs |
| popl %eax |
| movw _IF1632_Saved32_ss,%ss |
| movl _IF1632_Saved32_esp,%esp |
| movl _IF1632_Saved32_ebp,%ebp |
| |
| /* |
| * Restore registers, but do not destroy return value. |
| */ |
| popw _IF1632_Saved32_ss |
| popl _IF1632_Saved32_ebp |
| popl _IF1632_Saved32_esp |
| movl %eax,return_value |
| popal |
| movl return_value,%eax |
| .align 2,0x90 |
| leave |
| ret |
| |
| /********************************************************************** |
| * int CallTo16(unsigned long csip, unsigned short ds) |
| * |
| * Stack: 0 ebp |
| * 4 eip |
| * 8 target ip |
| * 10 target cs |
| * 12 target ds |
| */ |
| .align 4 |
| .globl _CallTo16 |
| _CallTo16: |
| pushl %ebp |
| movl %esp,%ebp |
| |
| /* |
| * Get target address and new ds |
| */ |
| movl 8(%ebp),%eax |
| movl %eax,jump_target |
| lea jump_target,%edx |
| movw 12(%ebp),%ax |
| |
| /* |
| * Switch to 16-bit stack |
| */ |
| pushl _IF1632_Saved32_esp |
| pushl _IF1632_Saved32_ebp |
| pushw _IF1632_Saved32_ss |
| |
| movw %ss,_IF1632_Saved32_ss |
| movl %esp,_IF1632_Saved32_esp |
| movl %ebp,_IF1632_Saved32_ebp |
| |
| movw _IF1632_Saved16_ss,%ss |
| movl _IF1632_Saved16_esp,%esp |
| movl _IF1632_Saved16_ebp,%ebp |
| |
| /* |
| * Call entry point |
| */ |
| movw %ax,%ds |
| .byte 0x66 |
| lcall %fs:(%edx) |
| |
| /* |
| * Restore old stack and segment registers. |
| * |
| * Two choices here: |
| * 1. Trust that fs or gs hasn't changed. |
| * 2. Rely on knowledge of Linux use of segments. |
| * |
| * I'll opt for choice 2 because who knows what programs we |
| * going to run. Linux should be fairly stable in terms of |
| * GDT usage. |
| */ |
| pushl %eax |
| movw $UDATASEL,%ax |
| movw %ax,%ds |
| movw %ax,%es |
| movw %ax,%fs |
| movw %ax,%gs |
| popl %eax |
| |
| movw %ss,_IF1632_Saved16_ss |
| movl %esp,_IF1632_Saved16_esp |
| movl %ebp,_IF1632_Saved16_ebp |
| |
| movw _IF1632_Saved32_ss,%ss |
| movl _IF1632_Saved32_esp,%esp |
| movl _IF1632_Saved32_ebp,%ebp |
| |
| popw _IF1632_Saved32_ss |
| popl _IF1632_Saved32_ebp |
| popl _IF1632_Saved32_esp |
| |
| movl %eax,return_value |
| movw return_value+2,%dx |
| .align 2,0x90 |
| leave |
| ret |
| |
| /********************************************************************** |
| * CallTo32() |
| * |
| * This function is called as a relay point to the built function |
| * handler. KERNEL, USER and GDI calls are dealt with by this |
| * handler. Calls to these DLLs will be mapped to a call handler |
| * which will set EAX to a number indicating which DLL and which |
| * function within that DLL. |
| * |
| * This function will pass to the function handler two arguments. |
| * The first argument will be the contents of EAX, the second |
| * argument will be a segment:offset pair that points to the |
| * 16-bit stack. |
| */ |
| .align 4 |
| .globl _CallTo32 |
| _CallTo32: |
| pushl %ebp |
| movl %esp,%ebp |
| |
| /* |
| * Save registers. 286 mode does not have fs or gs. |
| */ |
| pushw %ds |
| pushw %es |
| |
| /* |
| * Restore segment registers. |
| */ |
| pushl %eax |
| movw $UDATASEL,%ax |
| movw %ax,%ds |
| movw %ax,%es |
| popl %eax |
| |
| /* |
| * Save old stack save variables, save stack registers, reload |
| * stack registers. |
| */ |
| pushl _IF1632_Saved16_esp |
| pushl _IF1632_Saved16_ebp |
| pushw _IF1632_Saved16_ss |
| |
| movw %ss,_IF1632_Saved16_ss |
| movl %esp,_IF1632_Saved16_esp |
| movl %ebp,_IF1632_Saved16_ebp |
| |
| movw _IF1632_Saved32_ss,%ss |
| movl _IF1632_Saved32_esp,%esp |
| movl _IF1632_Saved32_ebp,%ebp |
| |
| /* |
| * Call entry point |
| */ |
| pushw _IF1632_Saved16_ss |
| pushw _IF1632_Saved16_esp |
| pushl %eax |
| call _DLLRelay |
| |
| /* |
| * Restore registers, but do not destroy return value. |
| */ |
| movw _IF1632_Saved16_ss,%ss |
| movl _IF1632_Saved16_esp,%esp |
| movl _IF1632_Saved16_ebp,%ebp |
| |
| popw _IF1632_Saved16_ss |
| popl _IF1632_Saved16_ebp |
| popl _IF1632_Saved16_esp |
| |
| popw %es |
| popw %ds |
| |
| .align 2,0x90 |
| leave |
| /* |
| * Now we need to ditch the parameter bytes that were left on the |
| * stack. We do this by effectively popping the number of bytes, |
| * and the return address, removing the parameters and then putting |
| * the return address back on the stack. |
| * Normally this field is filled in by the relevant function in |
| * the emulation library, since it should know how many bytes to |
| * expect. |
| */ |
| popw %gs:nbytes |
| cmpw $0,%gs:nbytes |
| je noargs |
| popw %gs:offset |
| popw %gs:selector |
| addw %gs:nbytes,%esp |
| pushw %gs:selector |
| pushw %gs:offset |
| noargs: |
| |
| /* |
| * Last, but not least we need to move the high word from eax to dx |
| */ |
| pushl %eax |
| popw %dx |
| popw %dx |
| |
| .byte 0x66 |
| lret |
| |
| /********************************************************************** |
| * ReturnFromRegisterFunc() |
| */ |
| .globl _ReturnFromRegisterFunc |
| _ReturnFromRegisterFunc: |
| /* |
| * Restore 16-bit stack |
| */ |
| movw _IF1632_Saved16_ss,%ss |
| movl _IF1632_Saved16_esp,%esp |
| movl _IF1632_Saved16_ebp,%ebp |
| |
| popw _IF1632_Saved16_ss |
| popl _IF1632_Saved16_ebp |
| popl _IF1632_Saved16_esp |
| |
| popw %es |
| popw %ds |
| |
| .align 2,0x90 |
| leave |
| /* |
| * This leaves us with a stack that has number of arguments, |
| * the return address, the saved registers, and the return |
| * address again. |
| */ |
| add $6,%esp /* argument count, return address */ |
| #include "pop.h" /* restore context */ |
| |
| /* |
| * Return to original caller. |
| */ |
| .byte 0x66 |
| lret |
| |