-
Notifications
You must be signed in to change notification settings - Fork 0
/
eval-[mini-simple].c
157 lines (123 loc) · 3.54 KB
/
eval-[mini-simple].c
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
* Предназначен для двух платформ:
* * UNIX-подобные ОС с компилятором cc и функцией dlopen
* * Windows с MVC++
* Протестирован на:
* * Debian GNU/Linux Wheezy amd64, gcc 4.7.2
* * Windows 8 Release Preview x86_64, MVC++ 2010 Express
* * MacOS X (почему-то понадобилось вручную установить макрос __unix__)
* При запуске на Windows cl.exe должен быть в %path%
* Создаёт файлы library.c и library.so (library.dll) в текущем каталоге (в Windows могут быть созданы ещё файлы)
* C89
* Компилировать на GNU/Linux: cc eval.c -ldl
* Компилировать на Windows: cl eval.c
*/
#ifdef __unix__
#elif defined(_WIN32)
# define _UNICODE
# define UNICODE
#else
# error "This is not UNIX-like OS, nor Windows"
#endif
#include <stdio.h>
#include <stdlib.h>
#ifdef __unix__
# include <dlfcn.h>
#else
# include <windows.h>
# include <tchar.h>
#endif
#ifdef __unix__
# define DECLSPEC /* Nothing */
void *library;
void my_dlerror(const char *message)
{
char *error = (char *)dlerror(); /* OpenBSD's dlerror returns "const char *", so we need to convert */
if (error != NULL)
{
fprintf(stderr, "%s: %s\n", message, error);
exit (EXIT_FAILURE);
}
}
void *compile(const char *symbol)
{
void *result;
if (system("cc -Wall -Wextra -shared -O3 -fPIC -o library.so library.c") != 0)
{
fprintf(stderr, "system\n");
exit (EXIT_FAILURE);
}
/* RTLD_NOW, так как я не хочу, чтобы программа падала при undefined symbols */
library = dlopen("./library.so", RTLD_NOW | RTLD_LOCAL);
my_dlerror("dlopen");
result = dlsym(library, symbol);
my_dlerror("dlsym");
return result;
}
void clean_up(void)
{
dlclose(library);
my_dlerror("dlclose");
}
#else
# define DECLSPEC "__declspec(dllexport) "
HMODULE library;
void *compile(const char *symbol)
{
void *result;
if (system("cl /LD /nologo /Felibrary library.c") != 0)
{
fprintf(stderr, "system\n");
exit (EXIT_FAILURE);
}
/* LoadLibrary(LPCTSTR); */
library = LoadLibrary(TEXT(".\\library.dll"));
if (library == 0)
{
fprintf(stderr, "LoadLibrary\n");
exit (EXIT_FAILURE);
}
result = GetProcAddress(library, symbol);
if (result == NULL)
{
fprintf(stderr, "GetProcAddress\n");
exit (EXIT_FAILURE);
}
return result;
}
void clean_up(void)
{
if (!FreeLibrary(library))
{
fprintf(stderr, "FreeLibrary\n");
exit (EXIT_FAILURE);
}
}
#endif
void eval(const char *code)
{
void (*compiled)(void); /* Это объявление переменной типа указатель на функцию */
FILE *fout = fopen("library.c", "w");
if (fout == NULL)
{
perror("fopen");
exit (EXIT_FAILURE);
}
fprintf(fout,
"#include <stdio.h>\n"
DECLSPEC "void compiled(void){\n"
"%s\n"
";\n"
"}\n",
code);
fclose(fout);
/* См. http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html , раздел "Application Usage" */
*(void **)&compiled = compile("compiled"); /* Теперь в переменной compiled лежит указатель на функцию compiled */
(*compiled)(); /* Вызываем функцию, на которую указывает указатель compiled */
clean_up();
}
int main(void)
{
eval("printf(\"Hello, world!\\n\")");
exit (EXIT_SUCCESS);
}