我最近一直在尝试通过使用缓冲区和不同汇编运算符的原始十六进制等效项来实现 C++ 中的动态函数。为了说明一个简单的跳转:
byte * buffer = new buffer[5];
*buffer = '0xE9'; // Hex for jump
*(uint*)(buffer + 1) = 'address destination';
我没有组装经验,但我知道足以创造very简单的功能。现在我正在原始内存中创建 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....
现在这是一个额外的例子,这让我really想知道汇编输出:
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
这里唯一的区别(除了值)是我使用“char”(1 个字节)而不是整数。如果我们查看汇编代码,就会发现堆栈指针仅占 8 个字节。这是一个区别16上一个示例中的字节。作为一个不折不扣的C++人,我不知道发生了什么。如果有人能在这个问题上启发我,我将非常感激!
注意:我之所以在这里发帖而不是阅读 ASM 书籍,是因为我需要使用汇编来实现此目的one功能。所以我不想为了 40 行代码而读整本书......
编辑:我也不关心平台依赖性,我only关心 Linux 32 位:)