Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 为什么ESP被0xFFFFF0屏蔽?_Assembly_X86_Elf - Fatal编程技术网

Assembly 为什么ESP被0xFFFFF0屏蔽?

Assembly 为什么ESP被0xFFFFF0屏蔽?,assembly,x86,elf,Assembly,X86,Elf,我已经反汇编了一个程序。我在开头看到一条和指令,其中包含ESP和0xfffff0 这个面具是什么意思?这是一个对齐问题吗 它是32位x86的ELF可执行文件。gcc for i386 Linux默认为。(其他非Linux系统也使用ELF可执行文件,但它们也具有相同的堆栈对齐默认值和SysV ABI。) 与clang不同,gcc不假定堆栈在进入main时对齐,因此它使用和指令屏蔽堆栈指针的低位。这是在堆栈上保留足够的填充以到达下一个对齐边界的最便宜的方法 堆栈对齐与您将看到调用另一个函数的函数在堆

我已经反汇编了一个程序。我在开头看到一条
指令,其中包含
ESP
0xfffff0

这个面具是什么意思?这是一个对齐问题吗


它是32位x86的ELF可执行文件。

gcc for i386 Linux默认为。(其他非Linux系统也使用ELF可执行文件,但它们也具有相同的堆栈对齐默认值和SysV ABI。)

与clang不同,gcc不假定堆栈在进入
main
时对齐,因此它使用
指令屏蔽堆栈指针的低位。这是在堆栈上保留足够的填充以到达下一个对齐边界的最便宜的方法

堆栈对齐与您将看到调用另一个函数的函数在堆栈上保留一些不用于任何用途的空间的原因相同:

extern内部条(void);
intfoo(intx){返回x+bar();}
gcc 5.3-O3
子esp,12#为另一个调用对齐堆栈
呼叫栏
添加eax,DWORD PTR[esp+16]#将参数(从堆栈)添加到bar()的返回值(在eax中)
添加esp,12
ret
,您可以在其中尝试不同的编译器和选项

-mincoming stack boundary=3
(或更少)会将堆栈对齐样板文件添加到每个函数(而不仅仅是main)
-mstackrealign
-mno stackrealign
foo()
main()
没有影响,无论是否有小的
-mincoming堆栈边界
。基于,我认为它可以为main以外的函数或main启用或禁用对齐


过去仅保证4字节堆栈对齐,但调用约定现在保证
%esp
调用
指令之前的16字节对齐

第2.2.2节堆叠框架

。。。换句话说,值(
%esp+4
)总是 当控制转移到功能入口点时,16的倍数。(当通过值传递32字节ymm向量时为32)

因此,gcc的
-mprefered stack boundary=4
不仅是一个好主意,而且是法律(在Linux等系统上,包含这种更强大保证的更新版ABI是官方标准)。这使得除
main
之外的函数在使用对齐的SSE存储/加载到堆栈之前可以安全地省略该对齐步骤。这些指令(如)将在未对齐的地址上出错。因此,对齐是正确性所必需的,而不仅仅是性能


现在实际上并不需要
指令
32位ABI的当前版本确实保证新执行的32位进程将以16字节对齐的方式启动。(第2.3.1节初始堆栈和寄存器状态,请参见关于
%esp
本身初始状态的要点,而不是堆栈内容。)

这意味着gcc在main开头对齐堆栈的行为现在已经过时,假设调用
main
的CRT启动代码没有使堆栈对齐

clang确实假设堆栈在main的开头对齐,就像64位gcc一样

16B对齐从一开始就是x86-64 SysV ABI的一部分,不是后来添加的,因此它始终是一个安全的假设,并且没有旧内核在进程启动时不提供这一点


tag wiki有到其他ABI的链接,等等。

没有上下文很难说清楚,但堆栈对齐是您这样做的原因之一。它将堆栈指针对齐到16字节(内存中向下,堆栈中向上)什么平台?什么建筑?什么编译器?什么语言?您的问题缺少关键信息,无法按原样回答。是的,大多数现代x86或x64编译器都将使用SSE2指令。它们需要与16对齐。@HansPassant要清楚,有SSE2+指令需要对齐,但也有等效指令不需要对齐(即:
movapd
vs
movupd
)。在早期的芯片上,指令的未对齐版本会受到严重的惩罚,但在较新的芯片(即:Haswell+)上,实际上已经没有太大的区别了。不幸的是,ABI的更改无缘无故地向后兼容地破坏了ABI。这也是“法律”,只不过是考虑到GNU版本的文件正式取代了实际系统V ABI文档。@ RossRidge:好捕获,我错过了部分的答案时,使它不是纯粹的Linux特定的,在认识到OP的声明的ELF 32位X86没有缩小到只有Linux。我做了一次编辑,指出一些系统可能不使用那个版本的ABI文档。x86标记wiki确实包含到旧版本的链接。我不清楚是谁参与了更广泛的向量更新ABI,但不仅仅是FSF/GNU。IDK,如果有*BSD或Solaris人员参与……即使在Linux上,也不清楚是什么让它“正式”。Linux内核本身并不使用16字节的堆栈对齐方式,并且每个Linux发行版都是免费的,可以自行决定他们所考虑的官方内容。大多数人在升级用于构建其用户区域的编译器时,都会默默地(可能是不知不觉地)采用经过此更改的更新ABI。。。有趣的是,尽管Linux内核ELF加载器无条件地使用16字节对齐,而不管体系结构如何(或者至少当前版本是这样),但在Linux机器上,
crt1.o
的32位和64位版本都使用手动对齐堆栈。@RossRidge这可能是为了向后兼容较旧的内核?