Skip to content

Instantly share code, notes, and snippets.

@ks888
Last active May 30, 2018 14:39
Show Gist options
  • Save ks888/f05ca9542b1e3539a64a4ddd6e7f8965 to your computer and use it in GitHub Desktop.
Save ks888/f05ca9542b1e3539a64a4ddd6e7f8965 to your computer and use it in GitHub Desktop.
closure in C, inspired by libffcall
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include "mycallback.h"
static uint8_t codes[] = {
0x48, 0xc7, 0xc0, 0x00, 0x00, 0x00, 0x00, /* mov $0x00000000,%rax */
0x48, 0x89, 0xfe, /* mov %rdi, %rsi */
0x48, 0xc7, 0xc7, 0x00, 0x00, 0x00, 0x00, /* mov $0x00000000,%rdi */
0xff, 0xe0, /* jmpq *%rax */
};
void *alloc_callback(void *func, void *data) {
const size_t codes_len = sizeof(codes);
const long pageSize = sysconf(_SC_PAGESIZE);
uint8_t *callback = mmap(NULL, codes_len, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
if (callback == MAP_FAILED) {
perror("mmap");
return NULL;
}
memcpy(callback, codes, codes_len);
callback[3] = (uintptr_t)func&0xFFu;
callback[4] = ((uintptr_t)func>>8)&0xFFu;
callback[5] = ((uintptr_t)func>>16)&0xFFu;
callback[6] = ((uintptr_t)func>>24)&0xFFu;
callback[13] = (uintptr_t)data&0xFFu;
callback[14] = ((uintptr_t)data>>8)&0xFFu;
callback[15] = ((uintptr_t)data>>16)&0xFFu;
callback[16] = ((uintptr_t)data>>24)&0xFFu;
if (mprotect((void*)((uintptr_t)callback&~(pageSize-1)), pageSize, PROT_READ|PROT_EXEC) < 0) {
perror("mprotect");
return NULL;
}
return callback;
}
void free_callback(void *func) {
if (munmap(func, sizeof(codes)) < 0) {
perror("munmap");
}
}
#ifndef _CALLBACK_H
#define _CALLBACK_H
extern void *alloc_callback(void *func, void *data);
extern void free_callback(void *func);
#endif /* _CALLBACK_H */
#include <stdio.h>
#include <stdlib.h>
#include "mycallback.h"
static int sum(int *data, int arg) {
*data += arg;
return *data;
}
int main() {
int *data1 = (int *)malloc(sizeof(*data1));
*data1 = 1;
int *data2 = (int *)malloc(sizeof(*data2));
*data2 = 1;
int (*mysum1)(int) = alloc_callback(sum, data1);
if (mysum1 == NULL) {
printf("failed to allocate callback.\n");
return 1;
}
int (*mysum2)(int) = alloc_callback(sum, data2);
if (mysum2 == NULL) {
printf("failed to allocate callback.\n");
return 1;
}
mysum1(2);
mysum1(3);
int sum1 = mysum1(4);
mysum2(2);
mysum2(4);
int sum2 = mysum2(8);
printf("sum1: %d\n", sum1);
printf("sum2: %d\n", sum2);
free_callback(mysum1);
free_callback(mysum2);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment