如何將一個函數編譯成二進位文件?
例如我想將
//add.func
int add(int a,int b)
{
return a+b;
}
編譯成一個add.func的二進位文件
==============================&>這一步怎麼弄?然後這樣調用它
void function()
{
ifstream fin("add.func",ios::binary);
int len;
fin.seekg(0, ios::end);
len = fin.tellg();
fin.seekg(0, ios::beg);
char *buff = ::new char[len];
fin.read(buff, len);
fin.close();int (*pfunc)(int,int);
pfunc=(int(*)(int, int))buff;
}
以上哪裡有錯?能怎麼改??謝謝
再說明一下,就是說怎麼把一個函數編譯成機器碼文件,然後我手動把這個文件放進內存,然後再用指針指向這個段內存,並調用它。
JIT - λ-calculus(驚愕到手了歐耶,GetBlogPostIds.aspx) - C++博客
這種東西知道就好了。如果是出exe還簡單一點,你這種一定要跟語言交互的,每一種操作系統 X 每一種編譯器 X 每一種CPU 都要寫一遍,太麻煩了,還是不要做了。
剛才又看了一遍自己以前的博客,覺得自己以前居然是也是一個學習什麼就會寫這麼詳細的教程的人,果然人長大就是會變。反正我現在再也不寫了(逃Windows下的 DLL文件 和Linux下的 .so 文件貌似勉強能滿足題主需求。
我理解的是,題主需要把機器碼組成代碼段,放到文件里,然後動態載入並執行,那這個和DLL的距離就只有 add.func 是單個函數 和 DLL可以包含多個函數 的區別了。
真要自己做的話很麻煩的:
首先數據段的內存區域默認不能被執行,所以要先向操作系統申請一個可寫可執行的內存區域,把 add.func 的內容放進去,再跳轉。
然後要注意函數調用的時候的調用約定,比如參數怎麼放、誰負責pop stack等。
再次,還有問題是 add.func 這種純函數體沒法調用別的地方的全局變數/常量,而DLL可以依賴花式重定位來訪問其他代碼的數據。
短版答案:用編譯器就好了。
JIT 幹啥啊,這個明顯只是普通的編譯過程啊
長版:
好好玩啊,來閑得慌試試。在 Linux 上,首先用 gcc 編譯題主代碼得到 func.o,然後閑得慌提取出 .text 來objcopy -O binary --only-section .text func.o func.func
可以看到,成功提取出了機器碼
00000000: 5548 89e5 897d fc89 75f8 8b55 fc8b 45f8 UH...}..u..U..E.
00000010: 01d0 5dc3 ..].
Disassembly of section .text:
0000000000000000 &:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 89 7d fc mov %edi,-0x4(%rbp)
7: 89 75 f8 mov %esi,-0x8(%rbp)
a: 8b 55 fc mov -0x4(%rbp),%edx
d: 8b 45 f8 mov -0x8(%rbp),%eax
10: 01 d0 add %edx,%eax
12: 5d pop %rbp
13: c3 retq
然後來一段代碼來調用一下
我覺得題主遇到的問題,應該在:操作系統為了保護動物(劃掉)保護程序不被黑掉,讓
char *buff = ::new char[len];
得到的 buff 無法執行。從 /proc/&
/maps 可以看到如:
00602000-00623000 rw-p 00000000 00:00 0 [heap]
heap 里的內存是不可執行的(可執行內存的第二列不應該是 rw-p 而應該是 啥啥x啥)
所以我們需要強行把文件內容放到可執行內存里。mmap 就可以。Here:#include &
#include &
#include &
#include &
typedef int (*fptr)(int, int);
int main () {
int fd = open ("func.func", O_RDONLY);
fptr func = mmap (
0,
0x14, // 懶得搞了,手抄 size
PROT_READ | PROT_EXEC,
MAP_PRIVATE,
fd,
0
);
printf ("%d
", (*func)(1, 2));
}
成功輸出 3。在 /proc/.../maps 裡面是這樣的
7ffff7ff6000-7ffff7ff7000 r-xp 00000000 08:05 9847581 [路徑已被手動隱藏]/func.func
等下,題主要玩加殼?
qwq 我是萌新別打我(講道理,這問題可大了去了,qwq 別打我)首先你大概需要讓編譯器生成位置無關代碼 (PIC),否則那段代碼覺得自己應該被載入到某個地址的話就跪了。其次如別人所說的,你這個沒有指針的重定位沒法調用非本可執行 .func 里的別的全局變數/函數第三這個就是個沙茶動態庫 loader。。。
dlopen(3) - Linux manual page
根據題主fstream直接從頭讀到尾的做法,我認為題主應該先學一學編譯原理。
覺得編譯原理的書太厚的話……題主應該至少了解一下動態鏈接庫的原理和意義。
如果你還是想自己手動讀入的話,那就去了解一下win32的dll或者elf格式吧。
如果你想繞過這個,那就重新學一遍編譯原理,然後搞JIT吧。難道不是有個dll或者so還神奇的存在嗎
說真的,你這個需求直接去用 Lua 不就好了么,能編譯成位元組碼、能腳本執行什麼的。
推薦閱讀:
※微軟對 C++ 的影響力有多大?
※為什麼要有堆區和棧區呢?
※如何將一個有序的數組隨機排序?
※從事C#開發兩年,25歲轉Cocos2d-x開發,會不會太晚?
※C/C++ 中 bool 相比於 char 有什麼優勢?為什麼要設立 bool 類型?
TAG:CC |