#include <machine/asm.h>
#include <ucontextoffsets.h>
-#ifdef __ACK__
-.text
-begtext:
-#ifdef __ACK__
-.rom
-#else
-.data
-#endif
-begrom:
-.data
-begdata:
-.bss
-begbss:
-#endif
-
-
IMPORT(getuctx)
IMPORT(setuctx)
IMPORT(resumecontext)
+ .globl _C_LABEL(__errno)
/* MCF_MAGIC value from <mcontext.h> */
#define MCF_MAGIC 0xc0ffee
* saving its signal mask, then we can skip the context switch to
* PM and kernel altogether and only save general-purpose registers. */
- mov (%esp), %ecx /* Save return address:
- * When setcontext or swapcontext is called,
- * we jump to this address and continue
- * running. */
-
mov 4(%esp), %edx /* edx = ucp */
/* Check null pointer */
cmp $0, %edx /* edx == NULL? */
jne 3f /* Not null, continue */
- movl $EFAULT, (_C_LABEL(errno))
+ PIC_PROLOGUE
+ call PIC_PLT(_C_LABEL(__errno))
+ PIC_EPILOGUE
+ movl $EFAULT, (%eax)
xor %eax, %eax
dec %eax /* return -1 */
ret
3: /* Check flags */
- push %ecx /* save ecx */
- push %ebx /* save ebx */
- lea UC_FLAGS(%edx), %ebx /* ebx = &(ucp->uc_flags) */
- mov (%ebx), %ecx /* ecx = ucp->uc_flags */
- mov $UCF_IGNFPU, %eax
- or $UCF_IGNSIGM, %eax
- cmp %eax, %ecx /* is UCF_IGNFPU or UCF_IGNSIGM set? */
- pop %ebx /* restore ebx */
- pop %ecx /* restore ecx */
- jz 1f /* Both are set, skip getuctx */
-
-0:
- push %ecx /* Save ecx */
+ mov UC_FLAGS(%edx), %eax /* eax = ucp->uc_flags */
+ xor $[UCF_IGNFPU|UCF_IGNSIGM], %eax /* toggle both flags */
+ jz 5f /* Both were set, skip getuctx */
+ PIC_PROLOGUE
push %edx
- call _C_LABEL(getuctx) /* getuctx(ucp) */
+ call PIC_PLT(_C_LABEL(getuctx)) /* getuctx(ucp) */
pop %edx /* clean up stack and restore edx */
- pop %ecx /* Restore ecx */
+ PIC_EPILOGUE
-1:
+5:
/* Save the context */
- mov 4(%esp), %edx /* edx = ucp */
- pop %eax /* retaddr */
- mov %eax, PC(%edx) /* Save real RTA in mcp struct */
+ pop PC(%edx) /* Save real RTA in mcp struct */
mov %esp, SP(%edx) /* Save stack pointer (now pointing to ucp) */
- /* Save GP registers */
+ /* Save GP registers (except EAX and EDX) */
mov %ebp, BP(%edx) /* Save EBP */
mov %esi, SI(%edx) /* Save ESI */
mov %edi, DI(%edx) /* Save EDI */
mov %ebx, BX(%edx) /* Save EBX */
mov %ecx, CX(%edx) /* Save ECX */
movl $MCF_MAGIC, MAGIC(%edx) /* Set magic value */
- push %eax /* Restore retaddr */
-
xor %eax, %eax /* Return 0 */
-
-2:
- add $4, %esp /* Remove stale (setcontext) RTA */
- jmp *%ecx /* Restore return address */
+ jmp *PC(%edx) /* Return return address */
/* int setcontext(const ucontext_t *ucp)
/* Check null pointer */
cmp $0, %edx /* edx == NULL? */
jnz 3f /* Not null, continue */
- movl $EFAULT, (_C_LABEL(errno))
+ movl $EFAULT, %edx
+0: push %edx /* preserve errno */
+ PIC_PROLOGUE
+ call PIC_PLT(_C_LABEL(__errno))
+ PIC_EPILOGUE
+ pop %edx
+ movl %edx, (%eax)
xor %eax, %eax
dec %eax /* return -1 */
ret
3: /* Check flags */
- push %ebx /* save ebx */
- lea MAGIC(%edx), %ebx /* ebx = &(ucp->mc_context.mc_magic) */
- mov (%ebx), %ecx /* ecx = ucp->mc_context.mc_magic */
- pop %ebx /* restore ebx */
- cmp $MCF_MAGIC, %ecx /* is the magic value set (is context valid)?*/
+ cmpl $MCF_MAGIC, MAGIC(%edx) /* is the magic value set (is context valid)?*/
jz 4f /* is set, proceed */
- movl $EINVAL, (_C_LABEL(errno)) /* not set, return error code */
- xor %eax, %eax
- dec %eax /* return -1 */
- ret
+ movl $EINVAL, %edx /* not set, return error code */
+ jmp 0b
-4: push %ebx /* save ebx */
- lea UC_FLAGS(%edx), %ebx /* ebx = &(ucp->uc_flags) */
- mov (%ebx), %ecx /* ecx = ucp->uc_flags */
- pop %ebx /* restore ebx */
- mov $UCF_IGNFPU, %eax
- or $UCF_IGNSIGM, %eax
- cmp %eax, %ecx /* Are UCF_IGNFPU and UCF_IGNSIGM flags set? */
- jz 1f /* Both are set, so don't bother restoring FPU
+4: mov UC_FLAGS(%edx), %eax /* eax = ucp->uc_flags */
+ xor $[UCF_IGNFPU|UCF_IGNSIGM], %eax /* toggle both flags */
+ jz 5f /* Both are set, so don't bother restoring FPU
* state and signal mask */
-0: push %ecx /* Save ecx */
+ PIC_PROLOGUE
push %edx
- call _C_LABEL(setuctx) /* setuctx(ucp) */
+ call PIC_PLT(_C_LABEL(setuctx)) /* setuctx(ucp) */
pop %edx /* Clean up stack and restore edx */
- pop %ecx /* Restore ecx */
+ PIC_EPILOGUE
-1: /* Restore the registers */
- mov 4(%esp), %edx /* edx = ucp */
+5: /* Restore the registers (except EAX and EDX) */
mov CX(%edx), %ecx /* Restore ECX */
mov BX(%edx), %ebx /* Restore EBX */
mov DI(%edx), %edi /* Restore EDI */
mov SI(%edx), %esi /* Restore ESI */
mov BP(%edx), %ebp /* Restore EBP */
mov SP(%edx), %esp /* Restore stack pointer */
-
-2:
- jmp *PC(%edx) /* Push RTA onto stack so we can return to it */
-
+ jmp *PC(%edx) /* Return to RTA */
/* void ctx_start((void *func)(int arg1, ..., argn), arg1, ..., argn,
* ucontext_t *ucp)
* to ucp on the stack. By setting ESP to ESI, we effectively 'remove' all
* arguments to `func' from the stack. Finally, a call to resumecontext
* will start the next context in the linked list (or exit the program if
- * there is no context). */
+ * there is no context).
+ *
+ * Since PIC needs the EBX register, which is pushed on the stack by
+ * PIC_PROLOGUE, we need an extra of salsa here.
+ */
ENTRY(ctx_start)
/* 0(esp) -> func
* 4(esp) -> arg1
pop %eax /* eax = func */
call *%eax /* func(arg1, ..., argn) */
- mov %esi, %esp /* Clean up stack */
+ PIC_PROLOGUE /* may push %ebx, but we do not care */
+ mov %esi, %esp /* Clean up stack, keep %ebx = &GOT */
/* ucp is now at the top of the stack again */
- call _C_LABEL(resumecontext) /* resumecontext(ucp) */
+ call PIC_PLT(_C_LABEL(resumecontext)) /* resumecontext(ucp) */
ret /* never reached */