--- cvsroot/libcoro/coro.c 2006/11/30 18:21:14 1.23 +++ cvsroot/libcoro/coro.c 2007/05/02 05:53:26 1.27 @@ -53,7 +53,7 @@ # include #endif -#if CORO_SJLJ || CORO_LOSER || CORO_LINUX || CORO_IRIX +#if CORO_SJLJ || CORO_LOSER || CORO_LINUX || CORO_IRIX || CORO_ASM #include @@ -67,6 +67,12 @@ static volatile void *coro_init_arg; static volatile coro_context *new_coro, *create_coro; +/* what we really want to detect here is wether we use a new-enough version of GAS */ +/* instead, check for gcc 3 and ELF and hope for the best */ +#if __GNUC__ >= 3 && __ELF__ +# define HAVE_CFI 1 +#endif + static void coro_init (void) { @@ -90,7 +96,15 @@ trampoline (int sig) { if (setjmp (((coro_context *)new_coro)->env)) - coro_init (); /* start it */ + { +#if HAVE_CFI + asm (".cfi_startproc"); +#endif + coro_init (); /* start it */ +#if HAVE_CFI + asm (".cfi_endproc"); +#endif + } else trampoline_count++; } @@ -99,6 +113,46 @@ #endif +#if CORO_ASM +void __attribute__((__noinline__, __fastcall__)) +coro_transfer (struct coro_context *prev, struct coro_context *next) +{ + asm volatile ( +#if __amd64 +# define NUM_CLOBBERED 5 + "push %%rbx\n\t" + "push %%r12\n\t" + "push %%r13\n\t" + "push %%r14\n\t" + "push %%r15\n\t" + "mov %%rsp, %0\n\t" + "mov %1, %%rsp\n\t" + "pop %%r15\n\t" + "pop %%r14\n\t" + "pop %%r13\n\t" + "pop %%r12\n\t" + "pop %%rbx\n\t" +#elif __i386 +# define NUM_CLOBBERED 4 + "push %%ebx\n\t" + "push %%esi\n\t" + "push %%edi\n\t" + "push %%ebp\n\t" + "mov %%esp, %0\n\t" + "mov %1, %%esp\n\t" + "pop %%ebp\n\t" + "pop %%edi\n\t" + "pop %%esi\n\t" + "pop %%ebx\n\t" +#else +# error unsupported architecture +#endif + : "=m" (prev->sp) + : "m" (next->sp) + ); +} +#endif + /* initialize a machine state */ void coro_create (coro_context *ctx, coro_func coro, void *arg, @@ -115,7 +169,7 @@ makecontext (&(ctx->uc), (void (*)()) coro, 1, arg); -#elif CORO_SJLJ || CORO_LOSER || CORO_LINUX || CORO_IRIX +#elif CORO_SJLJ || CORO_LOSER || CORO_LINUX || CORO_IRIX || CORO_ASM # if CORO_SJLJ stack_t ostk, nstk; @@ -203,36 +257,41 @@ # elif CORO_LINUX _setjmp (ctx->env); -#if defined(__GLIBC__) && defined(__GLIBC_MINOR__) \ - && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined(JB_PC) && defined(JB_SP) +#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined (JB_PC) && defined (JB_SP) ctx->env[0].__jmpbuf[JB_PC] = (long)coro_init; - ctx->env[0].__jmpbuf[JB_SP] = (long)STACK_ADJUST_PTR (sptr,ssize); -#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) \ - && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined(__mc68000__) + ctx->env[0].__jmpbuf[JB_SP] = (long)STACK_ADJUST_PTR (sptr, ssize); +#elif __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined (__mc68000__) ctx->env[0].__jmpbuf[0].__aregs[0] = (long int)coro_init; ctx->env[0].__jmpbuf[0].__sp = (int *)((char *)sptr + ssize); -#elif defined(__GNU_LIBRARY__) && defined(__i386__) +#elif defined (__GNU_LIBRARY__) && defined (__i386__) ctx->env[0].__jmpbuf[0].__pc = (char *)coro_init; ctx->env[0].__jmpbuf[0].__sp = (void *)((char *)sptr + ssize); -#elif defined(__GNU_LIBRARY__) && defined(__amd64__) +#elif defined (__GNU_LIBRARY__) && defined (__amd64__) ctx->env[0].__jmpbuf[JB_PC] = (long)coro_init; - ctx->env[0].__jmpbuf[JB_RSP] = (long)STACK_ADJUST_PTR (sptr,ssize); + ctx->env[0].__jmpbuf[JB_RSP] = (long)STACK_ADJUST_PTR (sptr, ssize); #else -#error "linux libc or architecture not supported" +# error "linux libc or architecture not supported" #endif # elif CORO_IRIX setjmp (ctx->env); ctx->env[JB_PC] = (__uint64_t)coro_init; - ctx->env[JB_SP] = (__uint64_t)STACK_ADJUST_PTR (sptr,ssize); + ctx->env[JB_SP] = (__uint64_t)STACK_ADJUST_PTR (sptr, ssize); + +# elif CORO_ASM + + ctx->sp = (volatile void **)(ssize + (char *)sptr); + *--ctx->sp = (void *)coro_init; + *--ctx->sp = (void *)coro_init; // this is needed when the prologue saves ebp + ctx->sp -= NUM_CLOBBERED; # endif coro_transfer ((coro_context *)create_coro, (coro_context *)new_coro); #else -error unsupported architecture +# error unsupported architecture #endif }