所以我正在尝试编写一些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。
感谢您的任何帮助,以及您认为相关的我可能错过的任何内容。我对组装很陌生。谢谢
结构的大小为12。这两个整数和指针在x86上都是4个字节,因此没有填充,结构的大小为12。如果您不确定类型的大小,您可以使用sizeof
询问编译器。
您在编译时没有进行优化,因此代码的效率似乎有点低。
movl $12, (%esp)
call malloc
movl %eax, -12(%ebp)
这将调用malloc
,然后将在%eax
中返回的值保存到存储在-12(%ebp)
中的局部变量uno
。因此,这三条指令组成了对malloc
的调用:准备堆栈、调用函数、保存返回值。
我们继续下一行。
uno->first = 0;
因为没有优化,编译器没有意识到%eax
已经包含uno
的值,所以它再次加载它,然后将零写入第一个成员
movl -12(%ebp), %eax
movl $0, (%eax)
下一个是
uno->second = 0;
我们再次将uno
的值加载到%eax
中,并写入一个零,这一次写入偏移量为4 的第二个成员中
movl -12(%ebp), %eax
movl $0, 4(%eax)
你明白了,我相信我不需要解释最后的作业。
尝试进行优化编译,结果会大不相同。编译器应该能够将uno
优化为%eax
,而不是将其放在堆栈上。它可以产生这样的代码:
movl $12, (%esp)
call malloc
movl $0, (%eax)
movl $0, 4(%eax)
movl $0, 8(%eax)
我真的不知道你为什么认为堆栈保留应该是16字节。在上面的优化变体中,我只看到需要4个字节,即传递给malloc
的参数。如果没有优化,我想它将是8,自变量为4,局部变量为4。但我不知道为什么函数会为堆栈保留40个字节。也许答案可以在其中一个问题中找到:
- 为什么我的编译器为函数堆栈帧保留了比所需更多的空间
- 为什么gcc4.x在调用方法时默认为linux上的堆栈保留8个字节
- 对齐堆栈意味着什么
最后,查看优化的代码可能会更有效率。如果不进行优化,编译器可能会做出许多看似奇怪的决定。经过优化后,代码将更加简洁,从长远来看,您实际执行的代码可能会得到优化。