X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fruntime%2Fx86-assem.S;h=1afa6eefd8c7cab751a1bb014c5ca78b65ba39b6;hb=c1aa8b6b5b870f21bc8c81da85708e9d71d4eb93;hp=630e81f411ecc745bd3dea73078d3ca43995d661;hpb=afe9091b25da5799f7bfd71c5497cbbd71045012;p=sbcl.git diff --git a/src/runtime/x86-assem.S b/src/runtime/x86-assem.S index 630e81f..1afa6ee 100644 --- a/src/runtime/x86-assem.S +++ b/src/runtime/x86-assem.S @@ -88,7 +88,6 @@ #endif .text - .globl GNAME(foreign_function_call_active) .globl GNAME(all_threads) /* @@ -101,14 +100,15 @@ * floats. * * This should work for Lisp calls C calls Lisp calls C.. + * + * FIXME & OAOOM: This duplicates call-out in src/compiler/x86/c-call.lisp, + * so if you tweak this, change that too! */ .text .align align_16byte,0x90 .globl GNAME(call_into_c) TYPE(GNAME(call_into_c)) GNAME(call_into_c): - movl $1,GNAME(foreign_function_call_active) - /* Save the return Lisp address in ebx. */ popl %ebx @@ -122,16 +122,11 @@ GNAME(call_into_c): fstp %st(0) fstp %st(0) -#ifdef LISP_FEATURE_WIN32 - cld -#endif - -#ifdef LISP_FEATURE_DARWIN - andl $0xfffffff0,%esp # align stack to 16-byte boundary before calling C -#endif - call *%eax # normal callout using Lisp stack + cld # clear out DF: Darwin, Solaris and Win32 at + # least need this, and it should not hurt others - movl %eax,%ecx # remember integer return value + call *%eax # normal callout using Lisp stack + movl %eax,%ecx # remember integer return value /* Check for a return FP value. */ fxam @@ -154,7 +149,6 @@ GNAME(call_into_c): /* Restore the return value. */ movl %ecx,%eax # maybe return value - movl $0,GNAME(foreign_function_call_active) /* Return. */ jmp *%ebx @@ -172,8 +166,7 @@ Lfp_rtn_value: /* We don't need to restore eax, because the result is in st(0). */ - movl $0,GNAME(foreign_function_call_active) -/* Return. */ +/* Return. FIXME: It would be nice to restructure this to use RET. */ jmp *%ebx SIZE(GNAME(call_into_c)) @@ -252,8 +245,6 @@ Lstack: xorl %esi,%esi # third arg /* no longer in function call */ - movl %eax, GNAME(foreign_function_call_active) - movl %esp,%ebx # remember current stack pushl %ebx # Save entry stack on (maybe) new stack. @@ -274,6 +265,19 @@ Lstack: Ldone: /* Registers eax, ecx, edx, edi, and esi are now live. */ +#ifdef LISP_FEATURE_WIN32 + /* Establish an SEH frame. */ +#ifdef LISP_FEATURE_SB_THREAD + /* FIXME: need to save BSP here. */ +#error "need to save BSP here, but don't know how yet." +#else + pushl BINDING_STACK_POINTER + SYMBOL_VALUE_OFFSET +#endif + pushl $GNAME(exception_handler_wrapper) + pushl %fs:0 + movl %esp, %fs:0 +#endif + /* Alloc new frame. */ mov %esp,%ebx # The current sp marks start of new frame. push %ebp # fp in save location S0 @@ -289,6 +293,12 @@ Ldone: LsingleValue: /* A singled value function returns here */ +#ifdef LISP_FEATURE_WIN32 + /* Remove our SEH frame. */ + popl %fs:0 + add $8, %esp +#endif + /* Restore the stack, in case there was a stack change. */ popl %esp # c-sp @@ -412,9 +422,7 @@ GNAME(do_pending_interrupt): ret SIZE(GNAME(do_pending_interrupt)) - -/* - * Allocate bytes and return the start of the allocated space +/* Allocate bytes and return the start of the allocated space * in the specified destination register. * * In the general case the size will be in the destination register. @@ -422,315 +430,128 @@ GNAME(do_pending_interrupt): * All registers must be preserved except the destination. * The C conventions will preserve ebx, esi, edi, and ebp. * So only eax, ecx, and edx need special care here. + * + * ALLOC factors out the logic of calling alloc(): stack alignment, etc. + * + * DEFINE_ALLOC_TO_FOO defines an alloction routine. */ - - .globl GNAME(alloc_to_eax) - TYPE(GNAME(alloc_to_eax)) - .align align_4byte,0x90 -GNAME(alloc_to_eax): - pushl %ecx # Save ecx and edx as C could destroy them. - pushl %edx - pushl %eax # Push the size. - call GNAME(alloc) - addl $4,%esp # Pop the size arg. - popl %edx # Restore ecx and edx. - popl %ecx - ret - SIZE(GNAME(alloc_to_eax)) - .globl GNAME(alloc_8_to_eax) - TYPE(GNAME(alloc_8_to_eax)) - .align align_4byte,0x90 -GNAME(alloc_8_to_eax): - pushl %ecx # Save ecx and edx as C could destroy them. - pushl %edx - pushl $8 # Push the size. - call GNAME(alloc) - addl $4,%esp # Pop the size arg. - popl %edx # Restore ecx and edx. - popl %ecx - ret - SIZE(GNAME(alloc_8_to_eax)) - - .globl GNAME(alloc_8_to_eax) - TYPE(GNAME(alloc_8_to_eax)) - .align align_4byte,0x90 - - .globl GNAME(alloc_16_to_eax) - TYPE(GNAME(alloc_16_to_eax)) - .align align_4byte,0x90 -GNAME(alloc_16_to_eax): - pushl %ecx # Save ecx and edx as C could destroy them. - pushl %edx - pushl $16 # Push the size. - call GNAME(alloc) - addl $4,%esp # Pop the size arg. - popl %edx # Restore ecx and edx. - popl %ecx - ret - SIZE(GNAME(alloc_16_to_eax)) - - .globl GNAME(alloc_to_ecx) - TYPE(GNAME(alloc_to_ecx)) - .align align_4byte,0x90 -GNAME(alloc_to_ecx): - pushl %eax # Save eax and edx as C could destroy them. - pushl %edx - pushl %ecx # Push the size. - call GNAME(alloc) - addl $4,%esp # Pop the size arg. - movl %eax,%ecx # Set up the destination. - popl %edx # Restore eax and edx. - popl %eax - ret - SIZE(GNAME(alloc_to_ecx)) - - .globl GNAME(alloc_8_to_ecx) - TYPE(GNAME(alloc_8_to_ecx)) - .align align_4byte,0x90 -GNAME(alloc_8_to_ecx): - pushl %eax # Save eax and edx as C could destroy them. - pushl %edx - pushl $8 # Push the size. - call GNAME(alloc) - addl $4,%esp # Pop the size arg. - movl %eax,%ecx # Set up the destination. - popl %edx # Restore eax and edx. - popl %eax - ret - SIZE(GNAME(alloc_8_to_ecx)) - - .globl GNAME(alloc_16_to_ecx) - TYPE(GNAME(alloc_16_to_ecx)) - .align align_4byte,0x90 -GNAME(alloc_16_to_ecx): - pushl %eax # Save eax and edx as C could destroy them. - pushl %edx - pushl $16 # Push the size. - call GNAME(alloc) - addl $4,%esp # Pop the size arg. - movl %eax,%ecx # Set up the destination. - popl %edx # Restore eax and edx. - popl %eax - ret - SIZE(GNAME(alloc_16_to_ecx)) - - - .globl GNAME(alloc_to_edx) - TYPE(GNAME(alloc_to_edx)) - .align align_4byte,0x90 -GNAME(alloc_to_edx): - pushl %eax # Save eax and ecx as C could destroy them. - pushl %ecx - pushl %edx # Push the size. - call GNAME(alloc) - addl $4,%esp # Pop the size arg. - movl %eax,%edx # Set up the destination. - popl %ecx # Restore eax and ecx. - popl %eax - ret - SIZE(GNAME(alloc_to_edx)) - - .globl GNAME(alloc_8_to_edx) - TYPE(GNAME(alloc_8_to_edx)) - .align align_4byte,0x90 -GNAME(alloc_8_to_edx): - pushl %eax # Save eax and ecx as C could destroy them. - pushl %ecx - pushl $8 # Push the size. - call GNAME(alloc) - addl $4,%esp # Pop the size arg. - movl %eax,%edx # Set up the destination. - popl %ecx # Restore eax and ecx. - popl %eax - ret - SIZE(GNAME(alloc_8_to_edx)) - - .globl GNAME(alloc_16_to_edx) - TYPE(GNAME(alloc_16_to_edx)) - .align align_4byte,0x90 -GNAME(alloc_16_to_edx): - pushl %eax # Save eax and ecx as C could destroy them. - pushl %ecx - pushl $16 # Push the size. - call GNAME(alloc) - addl $4,%esp # Pop the size arg. - movl %eax,%edx # Set up the destination. - popl %ecx # Restore eax and ecx. - popl %eax - ret - SIZE(GNAME(alloc_16_to_edx)) - - - - .globl GNAME(alloc_to_ebx) - TYPE(GNAME(alloc_to_ebx)) - .align align_4byte,0x90 -GNAME(alloc_to_ebx): - pushl %eax # Save eax, ecx, and edx as C could destroy them. - pushl %ecx - pushl %edx - pushl %ebx # Push the size. - call GNAME(alloc) - addl $4,%esp # Pop the size arg. - movl %eax,%ebx # Set up the destination. - popl %edx # Restore eax, ecx and edx. - popl %ecx - popl %eax - ret - SIZE(GNAME(alloc_to_ebx)) - - .globl GNAME(alloc_8_to_ebx) - TYPE(GNAME(alloc_8_to_ebx)) - .align align_4byte,0x90 -GNAME(alloc_8_to_ebx): - pushl %eax # Save eax, ecx, and edx as C could destroy them. - pushl %ecx - pushl %edx - pushl $8 # Push the size. - call GNAME(alloc) - addl $4,%esp # Pop the size arg. - movl %eax,%ebx # Set up the destination. - popl %edx # Restore eax, ecx and edx. - popl %ecx - popl %eax - ret - SIZE(GNAME(alloc_8_to_ebx)) - - .globl GNAME(alloc_16_to_ebx) - TYPE(GNAME(alloc_16_to_ebx)) - .align align_4byte,0x90 -GNAME(alloc_16_to_ebx): - pushl %eax # Save eax, ecx, and edx as C could destroy them. - pushl %ecx - pushl %edx - pushl $16 # Push the size - call GNAME(alloc) - addl $4,%esp # pop the size arg. - movl %eax,%ebx # setup the destination. - popl %edx # Restore eax, ecx and edx. - popl %ecx - popl %eax - ret - SIZE(GNAME(alloc_16_to_ebx)) - - - - .globl GNAME(alloc_to_esi) - TYPE(GNAME(alloc_to_esi)) - .align align_4byte,0x90 -GNAME(alloc_to_esi): - pushl %eax # Save eax, ecx, and edx as C could destroy them. - pushl %ecx - pushl %edx - pushl %esi # Push the size - call GNAME(alloc) - addl $4,%esp # pop the size arg. - movl %eax,%esi # setup the destination. - popl %edx # Restore eax, ecx and edx. - popl %ecx - popl %eax - ret - SIZE(GNAME(alloc_to_esi)) - - .globl GNAME(alloc_8_to_esi) - TYPE(GNAME(alloc_8_to_esi)) - .align align_4byte,0x90 -GNAME(alloc_8_to_esi): - pushl %eax # Save eax, ecx, and edx as C could destroy them. - pushl %ecx - pushl %edx - pushl $8 # Push the size - call GNAME(alloc) - addl $4,%esp # pop the size arg. - movl %eax,%esi # setup the destination. - popl %edx # Restore eax, ecx and edx. - popl %ecx - popl %eax - ret - SIZE(GNAME(alloc_8_to_esi)) - - .globl GNAME(alloc_16_to_esi) - TYPE(GNAME(alloc_16_to_esi)) - .align align_4byte,0x90 -GNAME(alloc_16_to_esi): - pushl %eax # Save eax, ecx, and edx as C could destroy them. - pushl %ecx - pushl %edx - pushl $16 # Push the size - call GNAME(alloc) - addl $4,%esp # pop the size arg. - movl %eax,%esi # setup the destination. - popl %edx # Restore eax, ecx and edx. - popl %ecx - popl %eax - ret - SIZE(GNAME(alloc_16_to_esi)) - - - .globl GNAME(alloc_to_edi) - TYPE(GNAME(alloc_to_edi)) - .align align_4byte,0x90 -GNAME(alloc_to_edi): - pushl %eax # Save eax, ecx, and edx as C could destroy them. - pushl %ecx - pushl %edx - pushl %edi # Push the size - call GNAME(alloc) - addl $4,%esp # pop the size arg. - movl %eax,%edi # setup the destination. - popl %edx # Restore eax, ecx and edx. - popl %ecx - popl %eax - ret - SIZE(GNAME(alloc_to_edi)) - - .globl GNAME(alloc_8_to_edi) - TYPE(GNAME(alloc_8_to_edi)) - .align align_4byte,0x90 -GNAME(alloc_8_to_edi): - pushl %eax # Save eax, ecx, and edx as C could destroy them. - pushl %ecx - pushl %edx - pushl $8 # Push the size - call GNAME(alloc) - addl $4,%esp # pop the size arg. - movl %eax,%edi # setup the destination. - popl %edx # Restore eax, ecx and edx. - popl %ecx - popl %eax - ret - SIZE(GNAME(alloc_8_to_edi)) +#ifdef LISP_FEATURE_DARWIN +#define ALLOC(size) \ + pushl %ebp; /* Save EBP */ \ + movl %esp,%ebp; /* Save ESP to EBP */ \ + andl $0xfffffff0,%esp; /* Align stack */ \ + pushl $0; /* Padding */ \ + pushl size; /* Argument to alloc */ \ + cld; /* Clear DF */ \ + call GNAME(alloc); \ + movl %ebp,%esp; /* Restore ESP from EBP */ \ + popl %ebp; /* Restore EBP */ +#else +#define ALLOC(size) \ + pushl size; /* Argument to alloc */ \ + cld; /* Clear DF */ \ + call GNAME(alloc); \ + addl $4,%esp; /* Pop argument */ +#endif - .globl GNAME(alloc_16_to_edi) - TYPE(GNAME(alloc_16_to_edi)) - .align align_4byte,0x90 -GNAME(alloc_16_to_edi): - pushl %eax # Save eax, ecx, and edx as C could destroy them. - pushl %ecx - pushl %edx - pushl $16 # Push the size - call GNAME(alloc) - addl $4,%esp # pop the size arg. - movl %eax,%edi # setup the destination. - popl %edx # Restore eax, ecx and edx. - popl %ecx - popl %eax - ret - SIZE(GNAME(alloc_16_to_edi)) +#define DEFINE_ALLOC_TO_EAX(name,size) \ + .globl GNAME(name); \ + TYPE(GNAME(name)); \ + .align align_4byte,0x90; \ +GNAME(name): \ + pushl %ecx; /* Save ECX and EDX */ \ + pushl %edx; \ + ALLOC(size) \ + popl %edx; /* Restore ECX and EDX */ \ + popl %ecx; \ + ret; \ + SIZE(GNAME(name)) + +#define DEFINE_ALLOC_TO_ECX(name,size) \ + .globl GNAME(name); \ + TYPE(GNAME(name)); \ + .align align_4byte,0x90; \ +GNAME(name): \ + pushl %eax; /* Save EAX and EDX */ \ + pushl %edx; \ + ALLOC(size) \ + movl %eax,%ecx; /* Result to destination */ \ + popl %edx; \ + popl %eax; \ + ret; \ + SIZE(GNAME(name)) + +#define DEFINE_ALLOC_TO_EDX(name,size) \ + .globl GNAME(name); \ + TYPE(GNAME(name)); \ + .align align_4byte,0x90; \ +GNAME(name): \ + pushl %eax; /* Save EAX and ECX */ \ + pushl %ecx; \ + ALLOC(size) \ + movl %eax,%edx; /* Restore EAX and ECX */ \ + popl %ecx; \ + popl %eax; \ + ret; \ + SIZE(GNAME(name)) + +#define DEFINE_ALLOC_TO_REG(name,reg,size) \ + .globl GNAME(name); \ + TYPE(GNAME(name)); \ + .align align_4byte,0x90; \ +GNAME(name): \ + pushl %eax; /* Save EAX, ECX, and EDX */ \ + pushl %ecx; \ + pushl %edx; \ + ALLOC(size) \ + movl %eax,reg; /* Restore them */ \ + popl %edx; \ + popl %ecx; \ + popl %eax; \ + ret; \ + SIZE(GNAME(name)) + +DEFINE_ALLOC_TO_EAX(alloc_to_eax,%eax) +DEFINE_ALLOC_TO_EAX(alloc_8_to_eax,$8) +DEFINE_ALLOC_TO_EAX(alloc_16_to_eax,$16) + +DEFINE_ALLOC_TO_ECX(alloc_to_ecx,%ecx) +DEFINE_ALLOC_TO_ECX(alloc_8_to_ecx,$8) +DEFINE_ALLOC_TO_ECX(alloc_16_to_ecx,$16) + +DEFINE_ALLOC_TO_EDX(alloc_to_edx,%edx) +DEFINE_ALLOC_TO_EDX(alloc_8_to_edx,$8) +DEFINE_ALLOC_TO_EDX(alloc_16_to_edx,$16) + +DEFINE_ALLOC_TO_REG(alloc_to_ebx,%ebx,%ebx) +DEFINE_ALLOC_TO_REG(alloc_8_to_ebx,%ebx,$8) +DEFINE_ALLOC_TO_REG(alloc_16_to_ebx,%ebx,$16) + +DEFINE_ALLOC_TO_REG(alloc_to_esi,%esi,%esi) +DEFINE_ALLOC_TO_REG(alloc_8_to_esi,%esi,$8) +DEFINE_ALLOC_TO_REG(alloc_16_to_esi,%esi,$16) + +DEFINE_ALLOC_TO_REG(alloc_to_edi,%edi,%edi) +DEFINE_ALLOC_TO_REG(alloc_8_to_edi,%edi,$8) +DEFINE_ALLOC_TO_REG(alloc_16_to_edi,%edi,$16) - /* Called from lisp when an inline allocation overflows. - Every register except the result needs to be preserved. - We depend on C to preserve ebx, esi, edi, and ebp. - But where necessary must save eax, ecx, edx. */ + * Every register except the result needs to be preserved. + * We depend on C to preserve ebx, esi, edi, and ebp. + * But where necessary must save eax, ecx, edx. */ #ifdef LISP_FEATURE_SB_THREAD #define START_REGION %fs:THREAD_ALLOC_REGION_OFFSET #else #define START_REGION GNAME(boxed_region) #endif - + +#define ALLOC_OVERFLOW(size) \ + /* Calculate the size for the allocation. */ \ + subl START_REGION,size; \ + ALLOC(size) + /* This routine handles an overflow with eax=crfp+size. So the size=eax-crfp. */ .align align_4byte @@ -739,11 +560,7 @@ GNAME(alloc_16_to_edi): GNAME(alloc_overflow_eax): pushl %ecx # Save ecx pushl %edx # Save edx - /* Calculate the size for the allocation. */ - subl START_REGION,%eax - pushl %eax # Push the size - call GNAME(alloc) - addl $4,%esp # pop the size arg. + ALLOC_OVERFLOW(%eax) popl %edx # Restore edx. popl %ecx # Restore ecx. ret @@ -755,11 +572,7 @@ GNAME(alloc_overflow_eax): GNAME(alloc_overflow_ecx): pushl %eax # Save eax pushl %edx # Save edx - /* Calculate the size for the allocation. */ - subl START_REGION,%ecx - pushl %ecx # Push the size - call GNAME(alloc) - addl $4,%esp # pop the size arg. + ALLOC_OVERFLOW(%ecx) movl %eax,%ecx # setup the destination. popl %edx # Restore edx. popl %eax # Restore eax. @@ -772,11 +585,7 @@ GNAME(alloc_overflow_ecx): GNAME(alloc_overflow_edx): pushl %eax # Save eax pushl %ecx # Save ecx - /* Calculate the size for the allocation. */ - subl START_REGION,%edx - pushl %edx # Push the size - call GNAME(alloc) - addl $4,%esp # pop the size arg. + ALLOC_OVERFLOW(%edx) movl %eax,%edx # setup the destination. popl %ecx # Restore ecx. popl %eax # Restore eax. @@ -792,11 +601,7 @@ GNAME(alloc_overflow_ebx): pushl %eax # Save eax pushl %ecx # Save ecx pushl %edx # Save edx - /* Calculate the size for the allocation. */ - subl START_REGION,%ebx - pushl %ebx # Push the size - call GNAME(alloc) - addl $4,%esp # pop the size arg. + ALLOC_OVERFLOW(%ebx) movl %eax,%ebx # setup the destination. popl %edx # Restore edx. popl %ecx # Restore ecx. @@ -813,11 +618,7 @@ GNAME(alloc_overflow_esi): pushl %eax # Save eax pushl %ecx # Save ecx pushl %edx # Save edx - /* Calculate the size for the allocation. */ - subl START_REGION,%esi - pushl %esi # Push the size - call GNAME(alloc) - addl $4,%esp # pop the size arg. + ALLOC_OVERFLOW(%esi) movl %eax,%esi # setup the destination. popl %edx # Restore edx. popl %ecx # Restore ecx. @@ -832,11 +633,7 @@ GNAME(alloc_overflow_edi): pushl %eax # Save eax pushl %ecx # Save ecx pushl %edx # Save edx - /* Calculate the size for the allocation. */ - subl START_REGION,%edi - pushl %edi # Push the size - call GNAME(alloc) - addl $4,%esp # pop the size arg. + ALLOC_OVERFLOW(%edi) movl %eax,%edi # setup the destination. popl %edx # Restore edx. popl %ecx # Restore ecx. @@ -845,6 +642,43 @@ GNAME(alloc_overflow_edi): SIZE(GNAME(alloc_overflow_edi)) +#ifdef LISP_FEATURE_WIN32 + /* The guts of the exception-handling system doesn't use + * frame pointers, which manages to throw off backtraces + * rather badly. So here we grab the (known-good) EBP + * and EIP from the exception context and use it to fake + * up a stack frame which will skip over the system SEH + * code. */ + .align align_4byte + .globl GNAME(exception_handler_wrapper) + TYPE(GNAME(exception_handler_wrapper)) +GNAME(exception_handler_wrapper): + /* Context layout is: */ + /* 7 dwords before FSA. (0x1c) */ + /* 8 dwords and 0x50 bytes in the FSA. (0x70/0x8c) */ + /* 4 dwords segregs. (0x10/0x9c) */ + /* 6 dwords non-stack GPRs. (0x18/0xb4) */ + /* EBP (at 0xb4) */ + /* EIP (at 0xb8) */ +#define CONTEXT_EBP_OFFSET 0xb4 +#define CONTEXT_EIP_OFFSET 0xb8 + /* some other stuff we don't care about. */ + pushl %ebp + movl 0x10(%esp), %ebp /* context */ + pushl CONTEXT_EIP_OFFSET(%ebp) + pushl CONTEXT_EBP_OFFSET(%ebp) + movl %esp, %ebp + pushl 0x1c(%esp) + pushl 0x1c(%esp) + pushl 0x1c(%esp) + pushl 0x1c(%esp) + call GNAME(handle_exception) + lea 8(%ebp), %esp + popl %ebp + ret + SIZE(GNAME(exception_handler_wrapper)) +#endif + #ifdef LISP_FEATURE_DARWIN .align align_4byte .globl GNAME(call_into_lisp_tramp) @@ -1053,4 +887,3 @@ Lend_base: END() - \ No newline at end of file