【问题标题】:x86 Assembly Stack Reservationx86 程序集堆栈预留
【发布时间】:2012-03-05 11:25:33
【问题描述】:

考虑一下这个简单的 C 程序

#include <stdio.h>

int func()
{
    printf("Hello World\n");
    return 0;
}

int main()
{
    printf("Hello World\n");
    return 0;
}

这是由 gcc 编译的对应的 32 位程序集

    .file   "a.c"
        .section        .rodata
    .LC0:
        .string "Hello World"
        .text
    .globl func
        .type   func, @function
    func:
         pushl   %ebp
         movl    %esp, %ebp
         subl    $24, %esp
         movl    $.LC0, (%esp)
         call    puts
         movl    $0, %eax
         leave
         ret
         .size   func, .-func
    .globl main
         .type   main, @function
    main:
          pushl   %ebp
          movl    %esp, %ebp
          andl    $-16, %esp
          subl    $16, %esp
          movl    $.LC0, (%esp)
          call    puts
          movl    $0, %eax
          leave
          ret
          .size   main, .-main
          .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
          .section        .note.GNU-stack,"",@progbits

为什么 gcc 在函数 'func()' 中为字符串 "Hello World" 保留 24 个字节,而在主函数中为同一字符串保留 16 个字节?

【问题讨论】:

  • 它与字符串没有任何关系,它永远不会被加载到堆栈上。主函数序言中的 $16 用于使堆栈指针对齐。注意 andl 指令。
  • Hans,你说的是 main 中的 andl 指令。它是将堆栈指针与页面边界对齐的 andl 指令。我在询问主函数中的 subl $16, (%esp) 和 func 中的 subl $24, (%esp)

标签: x86


【解决方案1】:

编译器正在尝试为这两个函数分配 16B(它是否需要那么多是值得怀疑的)。

在“main”中,它只是分配 16B 并调用 puts。请注意,堆栈在调用之前与 0 mod 16 对齐,因为这在 ABI 中是必需的(也就是说,在调用之前,您的堆栈通常总是 0 mod 16)。

在 func 中,堆栈以 12 mod 16 对齐(由于返回地址)。然后我们压入 ebp,使其为 8 mod 16。现在,我们要在堆栈上分配 16B(类似于 main),但我们还希望堆栈在调用 put 之前为 0 mod 16 字节对齐,因此,我们需要减去 8 + 16 个字节,即 24。

【讨论】:

    猜你喜欢
    • 2015-09-03
    • 1970-01-01
    • 1970-01-01
    • 2014-10-03
    • 2013-12-31
    • 1970-01-01
    • 2011-01-26
    • 2016-09-27
    • 1970-01-01
    相关资源
    最近更新 更多