]> git.lizzy.rs Git - cclosure.git/commitdiff
Initial commit
authorElias Fleckenstein <eliasfleckenstein@web.de>
Mon, 16 May 2022 09:55:06 +0000 (11:55 +0200)
committerElias Fleckenstein <eliasfleckenstein@web.de>
Mon, 16 May 2022 09:55:06 +0000 (11:55 +0200)
Makefile [new file with mode: 0644]
closure.c [new file with mode: 0644]
closure.h [new file with mode: 0644]
main.c [new file with mode: 0644]
player.c [new file with mode: 0644]
player.h [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
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 (file)
index 0000000..9487716
--- /dev/null
+++ b/closure.c
@@ -0,0 +1,53 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#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 (file)
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 (file)
index 0000000..998eed0
--- /dev/null
+++ b/main.c
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#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 (file)
index 0000000..bbf2896
--- /dev/null
+++ b/player.c
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <stdlib.h>
+#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 (file)
index 0000000..90a7c78
--- /dev/null
+++ b/player.h
@@ -0,0 +1,20 @@
+#ifndef _PLAYER_H_
+#define _PLAYER_H_
+
+#include <stdbool.h>
+
+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