- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我试图清楚地了解谁(调用者或被调用者)负责堆栈对齐。 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 之外的函数,如果你好奇的话。
我刚刚更新了 x86 中的 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/
我刚刚开始 iOS 应用程序开发,到目前为止,这是一次很棒的体验。 Apple 文档很棒,但我有一些问题不是技术性的,只有有经验的人才能回答。 我有一堆 UIViewController 处理它们控制
我几天前开始学习 react-redux-immutable,但我仍然对构建我的应用程序感到困惑。我有 php(symfony/laravel MVC 背景),所以要理解一些 javascript 概
每次查看 SharpDX 代码并尝试遵循 DirectX 文档时,我都会遇到困难。有没有一个地方清楚地列出了每个编号的类映射到什么以及它们存在的原因? 我说的是这样的事情: D
我正在使用 Robospice 库 创建应用程序。这是处理互联网连接的绝佳选择,因为库的核心是基于 Android 服务的,所以我们的连接与 Activity 生命周期无关。 我们正在创建我们的请求并
我可能在这里分析过度了,但是根据我对 MVC 的阅读,似乎有很多关于如何做事情的观点。 是否有一个“最佳实践”网站或文档来定义 MVC 各个部分的职责? 请记住,我使用 EF/Repository&U
我是一名优秀的程序员,十分优秀!