Skip to content

Instantly share code, notes, and snippets.

@nelix
Forked from simonask/gist:143200
Created July 9, 2009 19:26
Show Gist options
  • Save nelix/143924 to your computer and use it in GitHub Desktop.
Save nelix/143924 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdarg.h>
#define NOINLINE __attribute__((noinline))
typedef unsigned char byte;
typedef struct Continuation {
void* rip;
void* rsp;
void* rbp;
byte* stack;
struct Continuation* return_to;
void** args;
size_t num_args;
} Continuation;
NOINLINE void resume(Continuation* cc)
{
__asm__ __volatile__(
// restore registers
"movq %0, %%rdi\n"
"movq %1, %%rsp\n"
"movq %2, %%rbp\n"
// indicate to function being resumed that it was resumed
"movq $1, %%rax\n"
// resume!
"movq %3, %%r8\n"
"jmpq *%%r8\n"
:
: "r"(cc), "m"(cc->rsp), "m"(cc->rbp), "m"(cc->rip)
: "%rax", "%rdi", "%rsi", "%rsp", "%r8"
);
}
NOINLINE bool save(Continuation* cc)
{
__asm__ __volatile__(
// rsp is rsp, since the stack size of this function is 0
"movq %%rsp, %0\n"
// rbp stored on the stack
"movq (%%rsp), %%rax\n"
"movq %%rax, %1\n"
// read instruction pointer for calling function from the stack
"movq %%rbp, %%r8\n"
"movq 8(%%r8), %%rax\n"
"movq %%rax, %2\n"
: "=m"(cc->rsp), "=m"(cc->rbp), "=m"(cc->rip)
:
: "%rax"
);
return false;
}
void init_continuation(Continuation* cc, void* func, size_t num_args)
{
cc->rip = func;
cc->stack = (byte*)malloc(1024);
cc->rbp = cc->rsp = cc->stack;
cc->num_args = num_args;
cc->args = malloc(sizeof(void*)*num_args);
}
void start_continuation(Continuation* cc, Continuation* return_to, ...) {
cc->return_to = return_to;
va_list ap;
va_start(ap, return_to);
size_t i;
for (i = 0; i < cc->num_args; ++i) {
cc->args[i] = va_arg(ap, void*);
}
va_end(ap);
resume(cc);
}
void continuation(Continuation* cc) {
int a = (int)cc->args[0];
int b = (int)cc->args[1];
int c = a + b;
printf("hello from continuation: %d\n", c);
if (!save(cc))
{
resume(cc->return_to);
}
else
{
printf("continuation was resumed... %d\n", c);
printf("stack var c is at 0x%llx\n", &c);
}
resume(cc->return_to);
}
int main (int argc, char const *argv[])
{
Continuation return_here;
Continuation sub;
printf("return_here is at 0x%llx\n", &return_here);
printf("before\n");
if (!save(&return_here)) {
printf("returning directly\n");
init_continuation(&sub, continuation, 2);
start_continuation(&sub, &return_here, (void*)5, (void*)4);
printf("after resume -- should never be reached!\n");
} else {
printf("returned from continuation!\n");
if (!save(&return_here)) {
resume(&sub);
} else {
printf("returned from continuation for the second time\n");
}
}
printf("exiting\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment