#include #include #include // force using the section based init #define __libnix__ 1 #include "stabs.h" extern struct ExecBase *SysBase; extern UWORD *__SaveSP; register UWORD *a7 __asm("sp"); #if defined(__KICK13__) extern void * AllocVec(unsigned, int); extern void FreeVec(void *); #endif #undef StackSwap #define StackSwap __StackSwap #pragma GCC push_options #pragma GCC optimize ("-Os") #pragma GCC optimize ("-fomit-frame-pointer") // keeps d0/d1/a0/a1 free for local use. void __stkswap() { register struct StackSwapStruct *newStack asm("a2"); register struct ExecBase *SysBase asm("a6"); register UWORD *tmp, *upper asm("a1"), *sp; struct Task *task = SysBase->ThisTask; Disable(); tmp = (UWORD*) newStack->stk_Lower; newStack->stk_Lower = task->tc_SPLower; task->tc_SPLower = tmp; tmp = (UWORD*) newStack->stk_Upper; newStack->stk_Upper = (ULONG) task->tc_SPUpper; task->tc_SPUpper = tmp; // copy stack sp = (UWORD*) newStack->stk_Upper; upper = tmp; while (sp != a7) *--upper = *--sp; task->tc_SPReg = a7 = upper; Enable(); } // performs no push/pop of a2/a6, it's not necessary... __attribute((noinline)) void StackSwap(volatile struct StackSwapStruct *newStack) { asm("move.l %0,a2"::"r" (newStack)); asm("move.l %0,a6"::"r" (SysBase)); __stkswap(); } /* * swapstack.c * * A libnix startup module to swap to a new stack if the old one is not * big enough (minimum value set by the value of the __stack variable). * * Code derived from a stackswap module by Kriton Kyrimis (kyrimis@theseas.ntua.gr) * * Fixed by Bebbo. * * Usage: put this snippet into your main: extern void __stkinit(void); void * __x = __stkinit; unsigned long __stack = YOUR_STACK_SIZE; */ extern unsigned long __stack; void __request(const char *text); static volatile struct StackSwapStruct stack; static char *newstack; void __stkinit() { ULONG size, needed = __stack; struct Task *task; char *new; register UWORD *upper asm("a2"), *to asm("a0"), *sp; /* Determine original stack size */ task = SysBase->ThisTask; #if defined(__KICK13__) task->tc_SPUpper = __SaveSP + 6; #else size = (char*) task->tc_SPUpper - (char*) task->tc_SPLower; if (needed <= size) return; #endif /* Round size to next long word */ needed = (needed + (sizeof(LONG) - 1)) & ~(sizeof(LONG) - 1); /* Allocate new stack */ newstack = new = AllocVec(needed, MEMF_PUBLIC); if (!new) { __request("Couldn't allocate new stack!"); exit(RETURN_FAIL); } /* Build new stack structure */ stack.stk_Lower = new; stack.stk_Upper = (ULONG) (new + needed); /* Copy required parts of old stack */ to = upper = (UWORD*) stack.stk_Upper; sp = __SaveSP; while (sp != a7) *--to = *--sp; stack.stk_Pointer = to; /* Switch to new stack */ StackSwap(&stack); __SaveSP += upper - (UWORD*) stack.stk_Upper; } void __stkexit() { ULONG size; register UWORD *upper asm("a2"), *to asm("a0"), *sp; if (!newstack) return; /* Copy required parts of old stack */ to = upper = (UWORD*) stack.stk_Upper; sp = __SaveSP; while (sp != a7) *--to = *--sp; stack.stk_Pointer = to; /* Switch back to old stack */ StackSwap(&stack); __SaveSP += upper - (UWORD*) stack.stk_Upper; /* And clean up */ FreeVec(newstack); } /* The same priority as the detach module - you cannot use them both */ ADD2INIT(__stkinit, -70); ADD2EXIT(__stkexit, -70);