【问题标题】:Making a space for local variables in assembly在汇编中为局部变量留出空间
【发布时间】:2017-04-10 11:08:33
【问题描述】:

所以我必须编写一个调用 extern C 函数的汇编程序。所以我写了简单的pow函数,我用这个C代码编译了我的汇编程序。一切正常。但正如我从gcc-S 命令中看到的,编译器为局部变量留出了空间。我以为会是这样的:

int func(int number)
{
    int a = 10;
    int b = 5;
    int c = 0;
}

我们有 3 个局部变量,所以编译器会subl $12, %esp。但它适用于subl $16, %esp。即使我在这里只留下一个数字,它仍然会减少16。现在我有了我的代码:

main.s:

.section .data
.XD:
    msg: .ascii "%d\n"
    msg_len = . - msg

.text
.globl _pow
.globl main

main:
    pushl   %ebp
    movl    %esp, %ebp
    movl $5, %eax #like int a = 5;
    pushl %eax 
    call _pow #_pow(a);
    movl %eax, -8(%ebp)
    pushl -8(%ebp)
    pushl $.XD
    call printf #printf("%d\n", _pow(a));
    movl $0, %eax
    leave
    ret

func.c:

int _pow(int number)
{
    return number * number;
}

它按预期工作,./main 打印出25。但是现在,我没有subl 来自%esp 的任何东西。我的意思是我可以添加这一行,但它不会改变任何东西。我在互联网上搜索过,我发现我的代码可能只是偶然地工作,通常我应该减少%esp。所以我的问题是:我应该在main 中减少%esp 的值是多少?应该是12 还是16

【问题讨论】:

  • 16 的使用很可能使堆栈保持 16 字节对齐。
  • 我猜你是对的,但是我应该让它总是 16 字节对齐,还是应该 subl 特定值?
  • 该要求可能在平台的应用程序二进制接口 (ABI) 文档中指定。由于它是一个规范,因此您应该遵循它以便能够与其他代码进行交互。
  • 这是偶然的,因为有两个原因:1)在movl %eax, -8(%ebp)pushl -8(%ebp)之间没有其他东西会使用你的堆栈空间(32b x86保护模式下的中断在内核级别使用它们自己的堆栈空间)。 2)pushl -8(%ebp) 会将值完全存储在同一位置[ebp-8],因此您正在用自己覆盖该值,因此不会损坏任何东西(如果我在头中正确模拟它,请检查调试器,验证esp 和@ 987654348@ 地址在push 之前/之后,并查看内存视图中的值)。推送其他内容会覆盖本地 var 值。
  • 关于通过sub而不是and对齐堆栈 -> 如果 gcc 可以完全控制上面的函数调用,它知道当前堆栈对齐在特定调用深度,所以它可以产生一个sub esp,imm3216 之类的常量,既为局部变量保留空间,又在未来调用其他函数之前将堆栈再次对齐16B。所以and esp,-16 不是唯一可能的方法(尽管and 更健壮,因为即使在输入此类代码时堆栈状态未知,它也可以工作)。

标签: c linux assembly x86-64 stack-pointer


【解决方案1】:

由于您调用的是 32 位 C 函数,因此您必须遵循 C calling convention。与 64 位系统不同,对齐堆栈没有明确的顺序。我找不到声明何时应该进行这种对齐。推送参数后堆栈可能“未对齐”。

如果你想对齐堆栈,你可以在保存后简单地 AND -16 (movl %esp, %ebp):

andl $-16, %esp                ; Align 16

【讨论】:

  • 这正是 gcc 在编译 C 代码时所做的。嗯,但是我应该 subl 来自 esp 的任何东西,为局部变量腾出空间吗?
  • 首先subl 用于局部变量(如果需要),然后andl 用于对齐。但是,我很确定 32 位 C 不需要 16 字节对齐。
  • 好的,我知道我不需要它。但是gcc 确实有subl 一些值,但是它并没有将它与addliing 对齐。我的意思是它确实 - 使用leave 指令。但这里的问题是 - 我必须 subl 来自 %esp 的任何东西吗?
  • @Frynio:我说:不,您通常不必这样做。是的,如果您使用局部变量。仅使用 4 字节变量 - 用于 4 字节对齐。没有为 32 位程序定义“红色区域”。
  • 好的,如果我有 3 个局部变量,整数,abc。我初始化它们。那么(在使用值推送和初始化它们之前)我必须subl $12, %esp,或者它只是可选的?
猜你喜欢
  • 2015-07-15
  • 2014-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-07
  • 1970-01-01
  • 2022-06-14
  • 1970-01-01
相关资源
最近更新 更多