Created
July 1, 2011 06:27
-
-
Save karthick18/1057979 to your computer and use it in GitHub Desktop.
An example closure in C that requires MAP_32BIT to work with 64 bit
This file contains hidden or 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> | |
#ifndef MAP_32BIT | |
#error "MAP_32BIT not defined" | |
#endif | |
struct scope | |
{ | |
void *args; | |
}; | |
struct thunk | |
{ | |
unsigned char push_op; /* push rdi */ | |
unsigned char mov_op[2]; /* mov $env, rdi */ | |
struct scope *scope; | |
unsigned char call_op; /* callq */ | |
int call_offset; /*$offset => function - address_of_call_offset*/ | |
unsigned char pop_op; /* popq rdi */ | |
unsigned char ret_op; /* ret */ | |
} __attribute__((packed)); | |
static struct thunk initialize_thunk = { .push_op = 0x57, .mov_op = {0x48, 0xbf}, | |
.call_op = 0xe8, .call_offset = 0, | |
.pop_op = 0x5f, .ret_op = 0xc3 | |
}; | |
typedef void (*closure_t)(void); | |
static void closure_block(struct scope *scope) | |
{ | |
int *acc = scope->args; | |
++*acc; | |
} | |
/* | |
* Take a scope and the function block to be bound to the scope. | |
*/ | |
static closure_t make_closure(void *arg, void *block) | |
{ | |
struct thunk *thunk = (struct thunk *)mmap(0, sizeof(*thunk), PROT_WRITE | PROT_EXEC, | |
MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, | |
-1, 0); | |
if((char*)thunk == MAP_FAILED) | |
return NULL; | |
*thunk = initialize_thunk; | |
thunk->scope = calloc(1, sizeof(*thunk->scope)); | |
if(!thunk->scope) | |
{ | |
goto out_free; | |
} | |
thunk->scope->args = arg; | |
thunk->call_offset = (long)block - (long)&thunk->pop_op; | |
mprotect((void*)thunk, sizeof(*thunk), PROT_EXEC); | |
return (closure_t)thunk; | |
out_free: | |
munmap(thunk, sizeof(*thunk)); | |
return (closure_t)NULL; | |
} | |
static closure_t closure; | |
static void update(int n) | |
{ | |
int i; | |
for(i = 0; i < n; ++i) closure(); | |
} | |
int main(int argc, char **argv) | |
{ | |
int acc = 0, c = 10; | |
closure = make_closure((void*)&acc, (void*)&closure_block); | |
update(argc > 1 ? (c=atoi(argv[1])) : c); | |
printf("Accumulator at [%d]\n", acc); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
[1] 2763 segmentation fault ./a.out