在NASM中调用函数之前,%rsp是否应与16字节边界对齐? [英] Should %rsp be aligned to 16-byte boundary before calling a function in NASM?

查看:49
本文介绍了在NASM中调用函数之前,%rsp是否应与16字节边界对齐?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I saw the following rules from NASM's document:

在进行调用之前,堆栈指针%rsp必须与16字节边界对齐.很好,但是进行调用的过程会将返回地址(8个字节)压入堆栈,因此当函数获得控制权时,%rsp未对齐.您必须通过推动某些东西或从%rsp减去8来自己腾出额外的空间.

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汇编代码,如下所示:

And I have a snippet of NASM assembly code as below:

在我调用函数"inc"之前,%rsp应该位于8字节的边界.在"_start"中这违反了NASM文档中描述的规则.但是实际上,一切进展顺利.那么,我怎么理解呢?

The %rsp should be at the boundary of 8-bytes before I call the function "inc" in "_start" which violates the rules described in NASM's document. But actually, everything is going on well. So, how can I understand this?

我是在Ubuntu 20.04 LTS(x86_64)下构建的.

I built this under 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字节对齐的堆栈来调用该特定函数.

The ABI is a set of rules for how functions should behave to be interoperable with each other. Each of the rules on one side are paired with allowed assumptions on the other. In this case, the rule about stack alignment for the caller is an allowed assumption about stack alignment for the callee. Since your inc function doesn't depend on 16-byte stack alignment, it's fine to call that particular function with a stack that's only 8-byte aligned.

如果您想知道为什么在启用AC时它没有中断,那是因为您只从堆栈中加载8字节值,而堆栈仍是8字节对齐的.如果您执行了 sub rsp,4 或其他破坏8字节对齐的操作,则将出现总线错误.

If you're wondering why it didn't break when you enabled AC, that's because you're only loading 8-byte values from the stack, and the stack is still 8-byte aligned. If you did sub rsp, 4 or something to break 8-byte alignment too, then you would get a bus error.

当情况不是您在汇编中编写的一个函数调用在汇编中编写的另一个函数时,ABI变得重要的地方.他人的库(包括C标准库)中的功能,或从C而不是用汇编语言编写的功能,在执行 movaps [rsp-24],xmm0 等操作的权限之内,如果您在调用之前没有正确对齐堆栈,则会中断.

Where the ABI becomes important is when the situation isn't one function you wrote yourself in assembly calling another function you wrote yourself in assembly. A function in someone else's library (including the C standard library), or one that you compiled from C instead of writing in assembly, is within its rights to do movaps [rsp - 24], xmm0 or something, which would break if you didn't properly align the stack before calling it.

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

Side note: the ABI also says how you're supposed to pass parameters (the calling convention), but you're just kind of passing them wherever. Again, fine from your own assembly, but they'll definitely break if you try to call them from C.

这篇关于在NASM中调用函数之前,%rsp是否应与16字节边界对齐?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆