所以我正在尝试编写一些x86来为结构分配内存。我的c代码看起来像这样......
struc *uno = malloc(sizeof(struc));
uno->first = 0;
uno->second = 0;
uno->third = 0;
//And the struct
struct struc {
int first;
int second;
int *third;
}
反汇编看起来像......
pushl %ebp
movl %esp, %ebp
subl $40, %esp
movl $12, (%esp)
call malloc
movl %eax, -12(%ebp)
movl -12(%ebp), %eax
movl $0, (%eax)
movl -12(%ebp), %eax
movl $0, 4(%eax)
movl -12(%ebp), %eax
movl $0, 8(%eax)
movl $0, %eax
所以我有几个问题......
1)结构的大小是16,但为什么程序集只显示它分配12?
2)
的含义是什么? movl %eax, -12(%ebp)
movl -12(%ebp), %eax
是不是只是将eax的内容放入ebp-12的地址中。那么第二个语句是多余的?
3)当没有其他局部变量或参数被推入堆栈时,为什么esp会减少40?我以为它只需要递减16。
感谢任何帮助,以及我认为您认为相关的任何内容。我对装配很新。感谢。
答案 0 :(得分:10)
结构的大小为12.两个整数和指针在x86上都是4个字节,因此没有填充,结构的大小为12.您可以随时使用{{1如果你不确定类型的大小。
您正在编译而没有进行优化,因此代码似乎效率不高。
sizeof
这会调用movl $12, (%esp)
call malloc
movl %eax, -12(%ebp)
,然后将malloc
中返回的值保存到存储在%eax
的局部变量uno
。因此,这三条指令组成了对-12(%ebp)
的调用:准备堆栈,调用函数,保存返回值。
我们继续前行。
malloc
因为没有优化,编译器没有意识到uno->first = 0;
已经包含%eax
的值,所以它再次加载它,然后将零写入第一个成员
uno
接下来是
movl -12(%ebp), %eax
movl $0, (%eax)
我们再次将uno->second = 0;
的值加载到uno
,然后写入零,这次写入偏移量为4的第二个成员
%eax
你明白了,我确定我不需要解释最后的任务。
尝试使用优化进行编译,输出看起来会非常不同。编译器应该能够将movl -12(%ebp), %eax
movl $0, 4(%eax)
优化为uno
,而不是将其放在堆栈中。它可以产生这个代码:
%eax
我不确定为什么你认为堆栈保留应该是16个字节。在上面的优化变体中,我只看到需要4个字节,参数传递给movl $12, (%esp)
call malloc
movl $0, (%eax)
movl $0, 4(%eax)
movl $0, 8(%eax)
。如果没有优化,我猜测是8,参数是4,局部变量是4。但我不知道为什么函数为堆栈保留了40个字节。也许答案可以在其中一个问题中找到:
最后,查看优化代码可能会更有效率。如果没有优化,编译器可能会采取许多看似奇怪的决策优化后代码将更加简洁,从长远来看,您为真实执行的代码可能已经过优化。