Skip to content

Instantly share code, notes, and snippets.

@lbiaggi
Forked from vidarh/closures-basic.c
Created July 16, 2021 14:16
Show Gist options
  • Save lbiaggi/b663f5bf94f6d5f7f5602ac64c760d50 to your computer and use it in GitHub Desktop.
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
#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 = &block;
return closure;
}
int main() {
struct closure * c = foo(5);
c->call(c);
c->call(c);
}
#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);
}
#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);
}
#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