linux - 在调用 NASM 中的函数之前,%rsp 是否应该与 16 字节边界对齐?

标签 linux assembly x86-64 memory-alignment calling-convention

我从 NASM 的文档中看到了以下规则:

The stack pointer %rsp must be aligned to a 16-byte boundary before making a call. Fine, but the process of making a call pushes the return address (8 bytes) on the stack, so when a function gets control, %rsp is not aligned. You have to make that extra space yourself, by pushing something or subtracting 8 from %rsp.

我有一段 NASM 汇编代码如下:

在我调用“_start”中的函数“inc”之前,%rsp 应该位于 8 字节的边界,这违反了 NASM 文档中描述的规则。但实际上,一切都进行得很顺利。那么,我该如何理解呢?

我在 Ubuntu 20.04 LTS (x86_64) 下构建了这个。

global _start

section .data
init:
    db 0x2

section .rodata
codes: 
    db '0123456789abcdef'

section .text
inc:
    mov rax, [rsp+8]  ; read param from the stack;
    add rax, 0x1
    ret

print:
    lea rsi, [codes + rax]
    mov rax, 1
    mov rdi, 1
    mov rdx, 1
    syscall
    ret

_start:
    ; enable AC check;
    pushf
    or dword [rsp], 1<<18
    popf

    mov rdi, [init]  ; move the first 8 bytes of init to %rdi;
    push rdi  ; %rsp -> 8 bytes;
    call inc
    pop r11  ; clean stack by the caller;
    call print

    mov rax, 60
    xor rdi, rdi
    syscall

最佳答案

ABI 是一组关于函数应如何表现以实现互操作的规则。一侧的每个规则都与另一侧的允许假设配对。在这种情况下,关于调用者堆栈对齐的规则是关于被调用者堆栈对齐的允许假设。由于您的 inc 函数不依赖于 16 字节堆栈对齐,因此可以使用仅 8 字节对齐的堆栈调用该特定函数。

如果您想知道为什么在启用 AC 时它没有中断,那是因为您只从堆栈加载 8 字节值,而堆栈仍然是 8 字节对齐的。如果你也做了 sub rsp, 4 或其他东西来破坏 8 字节对齐,那么你会得到一个总线错误。

ABI 变得重要的地方是,当情况不是您自己在汇编中编写的一个函数调用您自己在汇编中编写的另一个函数时。其他人的库(包括 C 标准库)中的函数,或者您从 C 编译而不是用汇编编写的函数,在其执行 movaps [rsp - 24], xmm0 或其他内容的权利范围内, 如果您在调用它之前没有正确对齐堆栈,它将中断。

旁注:ABI 还说明了您应该如何传递参数(调用约定),但您只是将它们传递到任何地方。同样,从您自己的程序集中很好,但如果您尝试从 C 调用它们,它们肯定会中断。

关于linux - 在调用 NASM 中的函数之前,%rsp 是否应该与 16 字节边界对齐?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62714764/

相关文章:

c++ - 如何使 64 位 dll 与 Windows Server 2008、Windows 7 和 Windows XP 的 64 位版本兼容?

c++ - 体系结构 x86_64 : _memalign: TCMalloc 的 undefined symbol

linux - 检索父 pid

linux - 为什么普通用户不能使用chgrp/chown

assembly - NEG 指令如何影响 x86 上的标志?

c++ - 汇编操作的时间

c++ - Mac OS X 10.9.5 上的 HealPix C++ 链接错误

linux - hexdump 中的迭代次数和字节数是多少?

c++ - Eclipse 报错 127

performance - 在x86汇编中将寄存器设置为零的最佳方法是什么:xor,mov或and?