標籤:

如何將一個函數編譯成二進位文件?

例如我想將

//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 |