2023年1月7日 星期六

使用 tcc 來動態編譯 c 程式

爾俸爾祿,民膏民脂,下民易虐,上天難欺。

因緣際會知道這個東西, 覺得有趣, 嘗試了一下, tcc 可以把 c source code 放在 c source code 中 (有點繞舌), 即時編譯, 然後執行這段 code, 很神奇吧, 不過知道其原理之後就能理解是怎麼做的。

網路上資訊找的跌跌撞撞, 最後成功嘗試出來, 做個整理, 有幾個難關要處理。

安裝 tcc
apt-get install libtcc-dev

TCC Error: tcc: error: file '/usr/lib/x86_64-linux-gnu/tcc/libtcc1.a' not found

如果執行遇到這訊息, 把路徑改好就可以, 我的 path 如 list 1, 加上 symbolic 即可, 注意 libtcc1.a, libtcc.a 名字差了一點點。

list 1
1 root@u64:tcc# pwd
2 /usr/lib/x86_64-linux-gnu/tcc
3 root@u64:tcc# ls -l
4 total 4
5 drwxr-xr-x  include
6 lrwxrwxrwx  libtcc1.a -> ../libtcc.a

tcc_1.c L23 寫了一個 function abc, 交給 tcc 編譯, 因為有用到 printf, 所以還要 call L21 tcc_add_symbol 加入 printf symbol, 另外 source code 也要加上 printf function prototype, 否則會得到 list 2 的錯誤。

list 2. warning
1 TCC Error: <string>:1: warning: implicit declaration of function 'printf'


tcc_1.c L47 的轉型一定要寫, 要不然取出來的 pointer 是 NULL, 無法拿來執行編好的 function abc, 我在這邊卡好久才找到這問題。

tcc_1.c
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 #include <libtcc.h>
 5 
 6 void error_func(void * user, const char * msg) 
 7 {
 8     printf("TCC Error: %s\n", msg);
 9     exit(1);
10 }
11 
12 int main(int argc, char *argv[])
13 {
14   int (*sqr)(int) = NULL;
15   int size;
16   void *mem;
17 
18   TCCState *s = tcc_new();
19 
20   tcc_set_error_func(s, 0, error_func);
21   tcc_add_symbol(s, "printf", printf);
22   tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
23   if (tcc_compile_string(s, "int printf(const char *format, ...); int abc(int x) { printf(\"xx %d\\n\", x*x); return x*x;}") == -1)
24   {
25     printf("compile fail\n");
26     return -1;
27   }
28   //tcc_add_symbol(s, "squarer", squarer);
29   //tcc_run(s, argc, argv);
30 
31 
32   tcc_relocate(s, TCC_RELOCATE_AUTO);
33 
34 #if 0
35   size = tcc_relocate(s, NULL);
36 
37   if (size == -1)
38   {
39     printf("tcc_relocate fail\n");
40     return 1;
41   }
42 
43  /* allocate memory and copy the code into it */
44     mem = malloc(size);
45     tcc_relocate(s, mem);
46 #endif
47   sqr = (int (*)(int))tcc_get_symbol(s, "abc");
48 
49   if (sqr)
50     printf("%d\n", sqr(7));
51   tcc_delete(s);
52 
53   free(mem);
54   
55   return 0;
56 }

編譯指令:
gcc tcc_1.c -o tcc_1 -ltcc -ldl

沒有留言:

張貼留言

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。