gpt4 book ai didi

linux - 32 位 x86 汇编中堆栈对齐的职责

转载 作者:IT王子 更新时间:2023-10-29 00:19:27 27 4
gpt4 key购买 nike

我试图清楚地了解谁(调用者或被调用者)负责堆栈对齐。 64 位汇编的情况很清楚,它是由caller 完成的。

引用 System V AMD64 ABI,第 3.2.2 节堆栈框架:

The end of the input argument area shall be aligned on a 16 (32, if __m256 is passed on stack) byte boundary.

换句话说,应该安全地假设,对于被调用函数的每个入口点:

16 | (%rsp + 8)

持有(额外八个是因为call 隐含地将返回地址压入堆栈)。


它在 32 位世界中看起来如何(假设 cdecl)?我注意到 gcc 使用以下构造将对齐放在被调用函数中:

and esp, -16

这似乎表明,这是被调用者的责任。

为了更清楚,请考虑以下 NASM 代码:

global main
extern printf
extern scanf
section .rodata
s_fmt db "%d %d", 0
s_res db `%d with remainder %d\n`, 0
section .text
main:
start 0, 0
sub esp, 8
mov DWORD [ebp-4], 0 ; dividend
mov DWORD [ebp-8], 0 ; divisor

lea eax, [ebp-8]
push eax
lea eax, [ebp-4]
push eax
push s_fmt
call scanf
add esp, 12

mov eax, [ebp-4]
cdq
idiv DWORD [ebp-8]

push edx
push eax
push s_res
call printf

xor eax, eax
leave
ret

调用scanf前是否需要对齐栈?如果是这样,那么这将需要在将这两个参数推送到 scanf 之前将 %esp 减少四个字节:

4 bytes (return address)
4 bytes (%ebp of previous stack frame)
8 bytes (for two variables)
12 bytes (three arguments for scanf)
= 28

最佳答案

GCC main 中执行此额外的堆栈对齐;该函数很特殊。如果您查看任何其他函数的代码生成,您将看不到它,除非您有一个带有 alignas(32) 或其他东西的本地文件。

GCC 只是对 -m32 采取防御性方法,不假设 main 是使用正确的 16B 对齐堆栈调用的。或者这种特殊处理是 -mpreferred-stack-boundary=4 只是一个好主意,而不是法律时遗留下来的。

i386 System V ABI 多年来一直保证/要求 ESP+4 在函数入口处是 16B 对齐的。 (即 ESP 在 CALL 指令之前必须是 16B 对齐的,因此堆栈上的参数从 16B 边界开始。这与 x86-64 System V 相同。)

ABI 还保证新的 32 位进程以在 16B 边界上对齐的 ESP 开始(例如,在 _start,ELF 入口点,其中 ESP 指向 argc,而不是返回地址), glibc CRT 代码保持这种对齐。

就调用约定而言,EBP 只是另一个调用保留寄存器。但是,是的,带有 -fno-omit-frame-pointer 的编译器输出确实会在其他调用保留寄存器(如 EBX)之前注意 push ebp,因此保存的 EBP 值形成一个链表。 (因为它还在推送之后设置帧指针的 mov ebp, esp 部分。)


也许 gcc 是防御性的,因为一个非常古老的 Linux 内核(从 i386 ABI 的修订版之前,当所需的对齐仅为 4B 时)可能违反该假设,并且它只是在生命中运行一次的额外指令 -进程时间(假设程序不递归调用 main)。


与 gcc 不同,clang 假定堆栈在进入 main 时正确对齐。 (clang 也是 assumes that narrow args have been sign or zero-extended to 32 bits ,即使当前的 ABI 修订版还没有指定该行为。gcc 和 clang 都发出在调用方执行的代码,但只有 clang 在被调用方依赖它。这发生在 64位代码,但我没有检查 32 位。)

查看 http://gcc.godbolt.org/ 上的编译器输出对于 main 和除 main 之外的函数,如果你好奇的话。


我刚刚更新了 中的 ABI 链接前几天标记 wiki。 http://x86-64.org/仍然死了,似乎不会回来,所以我更新了 System V 链接以指向 HJ Lu 的 github 存储库中当前修订版的 PDF,和 his page with links .

请注意 last version on SCO's site 不是当前修订版,并且不包括 16B 堆栈对齐要求。

我认为某些 BSD 版本仍然不需要/保持 16 字节堆栈对齐。

关于linux - 32 位 x86 汇编中堆栈对齐的职责,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40307193/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com