#include <stdio.h>
static int i = 100;
/* Declard as extern since defined in hello.c */
extern int global;
int function(char *input)
{
printf("%s\n", input);
return global;
};
.file "foo.c"
.data
.align 4
.type i, @object
.size i, 4
i:
.long 100
.text
.globl function
.type function, @function
function:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call puts
movl global, %eax
leave
ret
.size function, .-function
.ident "GCC: (Debian 4.4.5-8) 4.4.5"
.section .note.GNU-stack,"",@progbits
原因是什么:
低于 $24, %esp
为什么他通过将堆栈指针递减 24 个字节来为局部变量在堆栈上腾出空间?函数中没有局部变量。然后他会:
movl %eax, (%esp)
为什么 - 因为存储在 ebp+8 的值(指针 char *input)被移动到 eax 并且现在应该传递给 puts.. 但是他为什么要执行先前的 subl - 来存储 int 的返回值?但那是 4 个字节。我还读到 C 不支持调用函数,必须在堆栈上为返回值腾出空间(重入问题)。请问这里发生了什么:( ??他可能在字边界上对齐指针参数..但是SysV I386 ABI说使用了尾部填充..
还,
movl %esp, %ebp
意味着 esp 和 ebp 都将指向新函数堆栈帧的基础。但是,假设有一个“调用函数”;考虑堆栈:您将拥有:
pushl ptr //push char *ptr call function { pushl ebp So stack contains: ptr ret-value ebp ->with-esp-pointing-to-after-ebp (ESP always points to the top of the stack but after the last pushed element..?)
所以他将ebp设置为esp。但是在 pg36,SysV ABI I386 Architecture Processor Supplement 4E 的 ABI 规范中,他说: 0(%ebp) previous %ebp (optional) 我猜是这样写的: %ebp+0 points to previous ebp 但是你可以看到, ebp+0 实际上指向存储的前一个 ebp 之后..???
在另一个节目中,
andl $-16, %esp subl $32, %esp
所以他首先对esp的最后4位进行了核对。嗯,这给了他多少空间?然后是subl..
有人可以为此推荐一个体面的教程或书籍。我不想掌握汇编,只想知道足够多的知识以了解一些 ABI 规范和对齐以及 GOT/PLT/虚拟寻址和编译器/链接器的东西- symbolTable/relocation 等(我正在使用 Levine 的书,但它很大——虽然很有趣,但 COFF 和 IBM/Sparc 的东西 :( 这就是我从 ABI 规范开始的原因。还有 Ian Wienand 的网站:自下而上的计算机科学.)