forked from yulon/clofn
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathclofn.h
135 lines (116 loc) · 3.95 KB
/
clofn.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#ifndef _CLOFN_H
#define _CLOFN_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#define CLOFN_PHSIZE_MAX 1024
#define _CLOFN_SCIENCE_NUMBER 0x58ffffbffdffffafULL
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#include <sys/mman.h>
#include <sys/user.h>
static inline bool _clofn_active_memory(void *ptr, size_t size) {
return mprotect((void *)(((size_t)ptr >> PAGE_SHIFT) << PAGE_SHIFT), size, PROT_READ | PROT_EXEC | PROT_WRITE) == 0;
}
#elif defined(_WIN32)
#include <windows.h>
static inline bool _clofn_active_memory(void *ptr, size_t size) {
DWORD old_protect;
return VirtualProtect(ptr, size, PAGE_EXECUTE_READWRITE, &old_protect);
}
#else
#error Clofn: not support this OS!
#endif
#define def_clofn(result_type, name, closure_type /* size equal to machine word */, closure_name, args, body) \
static result_type _clofn__##name args { \
volatile closure_type closure_name = (closure_type)_CLOFN_SCIENCE_NUMBER; \
body \
} \
static size_t _clofn__##name##__phsize = 0; \
static size_t _clofn__##name##__phhash = 0;
static void *_new_clofn(void *prototype, size_t *phsize, void *data) {
#ifdef CLOFN_PRINT_HEADER
printf("Clofn: prototype header (%08X) { ", prototype);
#endif
size_t offset = *phsize;
if (!offset) {
for (; offset < CLOFN_PHSIZE_MAX; offset++) {
if (*(size_t *)((uintptr_t)prototype + offset) == (size_t)_CLOFN_SCIENCE_NUMBER) {
if (!*phsize) {
*phsize = offset;
}
#ifdef CLOFN_PRINT_HEADER
printf("} @%u+%u\n", offset, sizeof(uintptr_t));
#endif
goto mk;
}
#ifdef CLOFN_PRINT_HEADER
else printf("%02X ", *(uint8_t *)(prototype + offset));
#endif
}
#ifdef CLOFN_PRINT_HEADER
puts("...");
#endif
printf("Clofn: could't find closure declaration at prototype function (%08X)!\n", prototype);
return NULL;
}
#ifdef CLOFN_PRINT_HEADER
else {
printf("Clofn: prototype header (%08X) { ", prototype);
for (size_t i = 0; i < phsize; i++) {
printf("%02X ", *(uint8_t *)(prototype + i));
}
printf("} @%u+%u\n", offset, sizeof(uintptr_t));
}
#endif
mk:;
#if defined(__x86_64__) || defined(__x86_64) || defined(__amd64) || defined(__amd64__) || defined(_WIN64)
size_t ihsize = offset + sizeof(void *) * 2 + 5;
#elif defined(i386) || defined(__i386__) || defined(_X86_) || defined(__i386) || defined(__i686__) || defined(__i686) || defined(_WIN32)
size_t ihsize = offset + sizeof(void *) * 2 + 1;
#else
#error Clofn: not support this arch!
#endif
void *instance = malloc(ihsize);
if (!_clofn_active_memory(instance, ihsize)) {
puts("Clofn: could't change memory type of C.malloc allocated!");
free(instance);
return NULL;
}
memcpy(instance, prototype, offset);
uintptr_t current = (uintptr_t)instance + offset;
*(void **)current = data;
current += sizeof(void *);
#if defined(__x86_64__) || defined(__x86_64) || defined(__amd64) || defined(__amd64__) || defined(_WIN64)
*(uint8_t *)current = 0x50;
current++;
*(uint8_t *)current = 0x48;
current++;
*(uint8_t *)current = 0xB8;
current++;
*(uintptr_t *)current = (uintptr_t)prototype + offset + sizeof(uintptr_t) - 1; // 0x58 in _CLOFN_SCIENCE_NUMBER
current += sizeof(uintptr_t);
*(uint16_t *)current = 0xE0FF;
#elif defined(i386) || defined(__i386__) || defined(_X86_) || defined(__i386) || defined(__i686__) || defined(__i686) || defined(_WIN32)
*(uint8_t *)current = 0xE9;
current++;
*(uintptr_t *)current = ((uintptr_t)prototype + offset + sizeof(uintptr_t)) - ((uintptr_t)instance + ihsize);
#endif
#ifdef CLOFN_PRINT_HEADER
printf("Clofn: instance header (%08X) { ", instance);
for (size_t i = 0; i < ihsize; i++) {
printf("%02X ", *(uint8_t *)(instance + i));
}
printf("}\n");
#endif
return instance;
}
#define new_clofn(name, closure_value) _new_clofn(_clofn__##name, &_clofn__##name##__phsize, (void *)closure_value)
#ifdef __cplusplus
}
#endif
#endif // !_CLOFN_H