From: Elias Fleckenstein Date: Mon, 16 May 2022 09:55:06 +0000 (+0200) Subject: Initial commit X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=bea82c0615e64efef7ec8c9a4041e88a6cbd64dc;p=cclosure.git Initial commit --- bea82c0615e64efef7ec8c9a4041e88a6cbd64dc diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a1ad555 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +test: main.c closure.c closure.h player.c player.h + cc -g main.c closure.c player.c -o test -Wall -Wextra diff --git a/closure.c b/closure.c new file mode 100644 index 0000000..9487716 --- /dev/null +++ b/closure.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include "closure.h" + +typedef struct __attribute__((packed)) { + uint16_t opcode_0; + void *operand_0; + + uint16_t opcode_1; + void *operand_1; + + uint16_t opcode_2; +} Closure; + +// rdi, rsi, rdx, rcx, r8, r9 +static const uint16_t mov[6] = {0xbf48, 0xbe48, 0xba48, 0xb948, 0xb849, 0xb949}; +static size_t size; + +__attribute__((constructor)) static void init() +{ + size = sysconf(_SC_PAGESIZE); +} + +void *closure_create(void *self, ClosureParam *param, size_t num) +{ + Closure *block = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + + for (size_t i = 0; i < num; i++) { + if (param[i].arg > 6) + abort(); // TODO + + block[i].opcode_0 = 0xb848; + block[i].operand_0 = param[i].fun; + + block[i].opcode_1 = mov[param[i].arg]; + block[i].operand_1 = self; + + block[i].opcode_2 = 0xe0ff; + + *((void **) param[i].ptr) = &block[i]; + } + + mprotect(block, size, PROT_READ | PROT_EXEC); + return block; +} + +void closure_destroy(void *closure) +{ + munmap(closure, size); +} diff --git a/closure.h b/closure.h new file mode 100644 index 0000000..9cb3611 --- /dev/null +++ b/closure.h @@ -0,0 +1,13 @@ +#ifndef _CLOSURE_H_ +#define _CLOSURE_H_ + +typedef struct { + void *fun; + void *ptr; + unsigned int arg; +} ClosureParam; + +void *closure_create(void *self, ClosureParam *params, size_t num); +void closure_destroy(void *closure); + +#endif diff --git a/main.c b/main.c new file mode 100644 index 0000000..998eed0 --- /dev/null +++ b/main.c @@ -0,0 +1,22 @@ +#include +#include "player.h" + +int main() +{ + Player *p1 = player("Fleckenstein"); + p1->age = 16; + + Player *p2 = player("lizzy22"); + p2->age = 22; + + p1->print(); + printf("age diff = %d; adult = %d\n", p1->compare(p2), p1->adult()); + + for (int i = 0; i < 10; i++) + p1->birthday(); + + printf("age diff = %d; adult = %d\n", p1->compare(p2), p1->adult()); + + p1->delete(); + p2->delete(); +} diff --git a/player.c b/player.c new file mode 100644 index 0000000..bbf2896 --- /dev/null +++ b/player.c @@ -0,0 +1,47 @@ +#include +#include +#include "closure.h" +#include "player.h" + +static bool player_adult(Player *self) +{ + return self->age >= 18; +} + +static void player_print(Player *self) +{ + printf("Name: %s\nAge: %d\n", self->name, self->age); +} + +static void player_birthday(Player *self) +{ + self->age++; +} + +static int player_compare(Player *other, Player *self) +{ + return self->age - other->age; +} + +static void player_delete(Player *self) +{ + closure_destroy(self->closure); + free(self); +} + +Player *player(char *name) +{ + Player *self = malloc(sizeof *self); + self->name = name; + self->age = 0; + + self->closure = closure_create(self, (ClosureParam[5]) { + {&player_adult, &self->adult, 0}, + {&player_print, &self->print, 0}, + {&player_birthday, &self->birthday, 0}, + {&player_compare, &self->compare, 1}, + {&player_delete, &self->delete, 0}, + }, 5); + + return self; +} diff --git a/player.h b/player.h new file mode 100644 index 0000000..90a7c78 --- /dev/null +++ b/player.h @@ -0,0 +1,20 @@ +#ifndef _PLAYER_H_ +#define _PLAYER_H_ + +#include + +typedef struct Player { + int age; + char *name; + + void *closure; + bool (*adult)(); + void (*print)(); + void (*birthday)(); + int (*compare)(struct Player *other); + void (*delete)(); +} Player; + +Player *player(char *name); + +#endif