我最近一直试图通过使用不同汇编操作符的缓冲区和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'里的堆栈框架是什么样的,看看额外的空间是用来干什么的? –