YHS*_*SPY 3 linux assembly x86-64 calling-convention memory-alignment
我从 NASM 的文档中看到了以下规则:
在进行调用之前,堆栈指针 %rsp 必须与 16 字节边界对齐。很好,但是进行调用的过程会将返回地址(8 个字节)压入堆栈,因此当函数获得控制权时,%rsp 未对齐。你必须自己创造额外的空间,通过推动某些东西或从 %rsp 中减去 8。
我有一段 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
Run Code Online (Sandbox Code Playgroud)
ABI 是一组关于函数应该如何表现才能相互操作的规则。一侧的每条规则都与另一侧的允许假设配对。在这种情况下,调用者堆栈对齐的规则是被调用者堆栈对齐的允许假设。由于您的inc函数不依赖于 16 字节堆栈对齐,因此可以使用仅 8 字节对齐的堆栈调用该特定函数。
如果您想知道为什么启用 AC 时它没有中断,那是因为您只从堆栈中加载 8 字节的值,并且堆栈仍然是 8 字节对齐的。如果您这样做sub rsp, 4或也破坏了 8 字节对齐,那么您将收到总线错误。
ABI 变得重要的地方是,当情况不是您自己在汇编中编写的一个函数调用您在汇编中自己编写的另一个函数时。其他人的库(包括 C 标准库)中的函数,或者您从 C 编译而不是用汇编编写的函数,在其权限范围内执行movaps [rsp - 24], xmm0或执行某些操作,如果您在调用之前没有正确对齐堆栈,则会中断它。
旁注:ABI 还说明了您应该如何传递参数(调用约定),但您只是将它们传递到任何地方。同样,从您自己的程序集来看很好,但是如果您尝试从 C 中调用它们,它们肯定会中断。
| 归档时间: |
|
| 查看次数: |
477 次 |
| 最近记录: |