我写了下面的代码。
int main (int argc, char *argv[])
{
char *uargv[3];
uargv[0] = "echo";
uargv[1] = "hello!";
uargv[2] = 0;
exec("echo", uargv);
exit();
}
并使用gcc 5.4进行编译。
下面是上面程序的汇编代码。
0x00: lea 0x4(%esp),%ecx
0x04: and $0xfffffff0,%esp
0x07: pushl -0x4(%ecx)
0x0a: push %ebp
0x0b: mov %esp,%ebp
0x0d: push %ecx
0x0e: sub $0x14,%esp
0x11: movl $0x7c3,-0x14(%ebp)
0x18: movl $0x7c8,-0x10(%ebp)
0x1f: movl $0x0,-0xc(%ebp)
0x26: sub $0x8,%esp
0x29: lea -0x14(%ebp),%eax
0x2c: push %eax
0x2d: push $0x7c3
0x32: call 2ce <exec>
0x37: add $0x10,%esp
0x3a: call 296 <exit>
我不明白上面的汇编代码的三部分。
首先,在0x00、0x04、0x07、0x0a,0x0b,0x0d的代码中,其工作方式如下。
0x00: save ebp+4 to ecx, and it is address of argc.
0x04: align esp with 16 byte
0x07: push ecx-4 to stack, and it is return address.
0x0a ~ 0x0b: setup ebp
0x0d: push ecx to stack, and it is address of argc.
我想知道为什么它再次推送返回地址,为什么还要推送argc地址。
这是我的第一个问题。
其次,它在0x0e指令中为局部变量uargv分配堆栈。
但是,uargv的大小只有12个字节。
但是它分配了20个字节。
如果是由于16字节对齐,为什么将局部变量保存在esp + 4中,而不是esp中(ebp + 0x14与esp + 4相同)。
第三,为什么0x26指令为堆栈分配更多的8个字节?
不需要更多的堆栈空间,因为exec的参数通过push指令保存在堆栈中。
谢谢。