-
-
Save lbiaggi/b663f5bf94f6d5f7f5602ac64c760d50 to your computer and use it in GitHub Desktop.
A number of ways to implement closures in C, in preparation of an upcoming blog post
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
struct closure { | |
void (* call)(struct closure *); | |
int x; | |
}; | |
void block(struct closure * env) { | |
env->x += 1; | |
printf ("block: x is %d\n", env->x); | |
} | |
struct closure * foo(int x) | |
{ | |
struct closure * closure = (struct closure *)malloc(sizeof(struct closure *)); | |
closure->x = x; | |
printf ("x is %d\n",closure->x); | |
closure->call = █ | |
return closure; | |
} | |
int main() { | |
struct closure * c = foo(5); | |
c->call(c); | |
c->call(c); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
struct env { | |
int x; | |
}; | |
struct closure { | |
void (* call)(struct env *); | |
struct env * env; | |
}; | |
void block(struct env * env) { | |
env->x += 1; | |
printf ("block: x is %d\n", env->x); | |
} | |
struct closure foo(int x) | |
{ | |
struct env * env = (struct env *)malloc(sizeof(struct env)); | |
env->x = x; | |
printf ("x is %d\n",env->x); | |
struct closure closure; | |
closure.env = env; | |
closure.call = block; | |
return closure; | |
} | |
int main() { | |
struct closure c = foo(5); | |
c.call(c.env); | |
c.call(c.env); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
struct env { | |
int x; | |
}; | |
struct closure { | |
void (* call)(struct env *); | |
struct env * env; | |
}; | |
void block(struct env * env) { | |
env->x += 1; | |
printf ("block: x is %d\n", env->x); | |
} | |
struct closure * foo(int x) | |
{ | |
struct env * env = (struct env *)malloc(sizeof(struct env)); | |
env->x = x; | |
printf ("x is %d\n",env->x); | |
struct closure * closure = (struct closure *)malloc(sizeof(struct closure *)); | |
closure->env = env; | |
closure->call = block; | |
return closure; | |
} | |
int main() { | |
struct closure * c = foo(5); | |
c->call(c->env); | |
c->call(c->env); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <sys/mman.h> | |
struct env { | |
int x; | |
}; | |
struct __attribute__((packed)) thunk { | |
unsigned char push; | |
struct env * env_addr; | |
unsigned char call; | |
signed long call_offset; | |
unsigned char add_esp[3]; | |
unsigned char ret; | |
}; | |
struct thunk default_thunk = {0x68, 0, 0xe8, 0, {0x83, 0xc4, 0x04}, 0xc3}; | |
typedef void (* cfunc)(); | |
struct thunk * make_thunk(struct env * env, void * code) | |
{ | |
struct thunk * thunk = (struct thunk *)mmap(0,sizeof(struct thunk), PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
*thunk = default_thunk; | |
thunk->env_addr = env; | |
thunk->call_offset = code - (void *)&thunk->add_esp[0]; // Pretty! | |
mprotect(thunk,sizeof(struct thunk), PROT_EXEC); | |
return thunk; | |
} | |
void block(struct env * env) { | |
env->x += 1; | |
printf ("block: x is %d\n", env->x); | |
} | |
cfunc foo (int x) | |
{ | |
struct env * env = (struct env *)malloc(sizeof(struct env)); | |
env->x = x; | |
printf ("x is %d\n",env->x); | |
return (cfunc)make_thunk(env,(void *)&block); | |
} | |
int main() { | |
cfunc c = foo(5); | |
c(); | |
c(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment