2
 #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 的网站:自下而上的计算机科学.)

4

0 回答 0