我最近一直試圖通過使用不同彙編操作符的緩衝區和RAW十六進制等價物來實現C++中的動態函數。爲了說明一個簡單的跳躍:內聯彙編-cdecl和堆棧準備
byte * buffer = new buffer[5];
*buffer = '0xE9'; // Hex for jump
*(uint*)(buffer + 1) = 'address destination';
我不是在組裝經驗,但我知道足以創造非常簡單的功能。現在我正在原始內存中創建cdecl函數。問題是,我不知道我想用多少sub
來推棧(用於內存)。讓我們以這個功能作爲一個例子:
int MyTest(int x, int y) { return x + y; }
long TheTest(int x, int y)
{
return MyTest(x, 5);
}
08048a20 <_Z6TheTestii>:
_Z6TheTestii():
8048a20: 55 push %ebp
8048a21: 89 e5 mov %esp,%ebp
8048a23: 83 ec 18 sub $0x18,%esp
8048a26: c7 44 24 04 05 00 00 movl $0x5,0x4(%esp)
8048a2d: 00
8048a2e: 8b 45 08 mov 0x8(%ebp),%eax
8048a31: 89 04 24 mov %eax,(%esp)
8048a34: e8 c2 ff ff ff call 80489fb <_Z6MyTestii>
8048a39: c9 leave
8048a3a: c3 ret
正如你所看到的,第一個是C++代碼和下面是「TheTest」功能的ASM。人們可以立即注意到堆棧被壓入24(0x18)字節(如前所述,我沒有經歷使用匯編,因此我可能不會使用正確的術語和/或完全正確)。這對我來說沒有任何意義。當僅使用2個不同的整數時,需要24個字節?使用變量'x',它是4個字節,值'5'也使用4個字節(記住它是cdecl,所以調用函數處理關於函數參數的內存)不能彌補24。 ...
現在,這裏是一個額外的例子讓我真的難怪圍繞組件輸出:
int NewTest(int x, char val) { return x + val; }
long TheTest(int x, int y)
{
return NewTest(x, (char)6);
}
08048a3d <_Z6TheTestiiii>:
_Z6TheTestiiii():
8048a3d: 55 push %ebp
8048a3e: 89 e5 mov %esp,%ebp
8048a40: 83 ec 08 sub $0x8,%esp
8048a43: c7 44 24 04 06 00 00 movl $0x6,0x4(%esp)
8048a4a: 00
8048a4b: 8b 45 08 mov 0x8(%ebp),%eax
8048a4e: 89 04 24 mov %eax,(%esp)
8048a51: e8 ca ff ff ff call 8048a20 <_Z7NewTestic>
8048a56: c9 leave
8048a57: c3 ret
這裏唯一的不同(除了值)是我用一個「字符的事實'(1字節)而不是整數。如果我們再看看彙編代碼,那麼只會將堆棧指針壓入8個字節。這與上例相差字節。作爲一個徹頭徹尾的C++人,我不知道發生了什麼。我真的很感激,如果有人可以啓發我的話題!
注意:之所以我在這裏發佈而不是閱讀ASM書,是因爲我需要使用這個一個函數的程序集。所以,我不想讀一整本書的代碼40行...
編輯:我也不在乎的平臺依賴性,我只照顧關於Linux 32位:)
你爲什麼不只是使用libffi? –
@DavidHeffernan那沒什麼好玩的:) –
@Elliott爲什麼不使用調試器,看看'TheTest'裏的堆棧框架是什麼樣的,看看額外的空間是用來幹什麼的? –