热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

为什么SystemV/AMD64ABI要求16字节堆栈对齐?

如何解决《为什么SystemV/AMD64ABI要求16字节堆栈对齐?》经验,为你挑选了1个好方法。

我读过的,因为它是为"业绩原因"做不同的地方,但我仍然不知道什么是在性能得到这个16字节对齐提高了特殊情况.或者,无论如何,选择这个的原因是什么.

编辑:我想我以误导的方式写了这个问题.我没有询问为什么处理器使用16字节对齐的内存更快地处理事情,这在文档中随处可见.我想要知道的是,强制执行16字节对齐比仅让程序员在需要时自己对齐堆栈更好.我问这个是因为根据我的汇编经验,堆栈实施有两个问题:只有少于1%的执行代码才有用(所以其他99%实际上是开销); 它也是一个非常常见的错误来源.所以我想知道它最终是如何得到回报的.虽然我对此仍有疑问,但我接受了彼得的回答,因为它包含了我原来问题的最详细答案.



1> Peter Cordes..:

请注意,Linux上使用的当前版本的i386 System V ABI也需要16字节堆栈对齐1.有关历史,请参阅https://sourceforge.net/p/fbc/bugs/659/.


SSE2是x86-64的基线__m128,我认为使ABI对类型和编译器自动矢量化等类型有效是设计目标之一.ABI必须定义如何将这些args作为函数args或通过引用传递.

16字节对齐有时对堆栈上的局部变量(尤其是数组)很有用,并且保证16字节对齐意味着编译器可以在任何有用的时候免费获取它,即使源没有明确请求它.

如果相对于16字节边界的堆栈对齐未知,则每个需要对齐本地的函数都需要一个and rsp, -16,并且rsp在未知偏移rsp(0或者-8)之后保存/恢复的额外指令. 例如,rbp用于帧指针.

没有AVX,内存源操作数必须是16字节对齐的.例如,paddd xmm0, [rsp+rdi]如果内存操作数未对齐,则会出现故障.因此,如果未知对齐,则必须使用movups xmm1, [rsp+rdi]/ paddd xmm0, xmm1,或编写循环序言/结尾来处理未对齐的元素.对于编译器想要自动向量化的本地数组,它可以简单地选择将它们对齐16.

另请注意,早期的x86 CPU(在Nehalem/Bulldozer之前)的movups指令速度比movaps指针确实对齐时要慢.(即对齐数据上的未对齐加载/存储特别慢,以及防止将折叠加载到ALU指令中).(有关上述所有内容的更多信息,请参阅Agner Fog的优化指南,微指南和指令表.)

这些因素是保证比"通常"保持堆栈对齐更有用的原因. 被允许制作实际上在未对齐堆栈上出错的代码允许更多优化机会.

排列阵列也加快了矢量memcpy/ strcmp/什么不能职能承担对齐,而是检查它,可以直接跳到他们的整个矢量循环.

从最新版本的x86-64 System V ABI(r252):

数组使用与其元素相同的对齐方式,除了长度至少为16个字节的本地或全局数组变量或C99可变长度数组变量始终具有至少16个字节的对齐方式.4

4对齐要求允许在阵列上操作时使用SSE指令.编译器通常不能计算可变长度数组(VLA)的大小,但预计大多数VLA将需要至少16个字节,因此要求VLA至少具有16字节对齐是合乎逻辑的.

这有点过于激进,并且大多数只有在自动向量化的函数可以内联时才有用,但通常还有其他本地编译器可以填充到任何间隙中,因此它不会浪费堆栈空间.只要有已知的堆栈对齐,就不会浪费指令.(显然,如果他们决定不要求16字节堆栈对齐,那么ABI设计人员就可以将其排除在外.)


溢出/重装 __m128

当然,它可以自由地执行alignas(16) char buf[1024];源或请求 16字节对齐的其他情况.

还有__m128/ __m128d/ __m128i本地人.编译器可能无法将所有向量局部保留在寄存器中(例如,溢出函数调用,或者没有足够的寄存器),因此它需要能够使用movaps或作为ALU指令的内存源操作数来溢出/重新加载它们,出于效率原因,上面讨论了

实际上分布在缓存行边界(64字节)上的加载/存储具有显着的延迟惩罚,并且对现代CPU也有轻微的吞吐量惩罚.加载需要来自2个独立缓存行的数据,因此需要对缓存进行两次访问.(可能还有2次缓存未命中,但堆栈内存很少见).

我认为movups已经为那些价格昂贵的旧CPU上的矢量带来了成本,但它仍然很糟糕.跨越4k页面边界差得多(在Skylake之前的CPU上),如果它接触4k边界两侧的字节,则加载或存储需要约100个周期.(还需要2次TLB检查). 自然对齐使得跨越任何更宽边界的分裂变得不可能,因此16字节对齐对于您可以使用SSE2做的一切就足够了.


max_align_t在x86-64 System V ABI中有16字节对齐,因为long double(10字节/ 80位x87).由于某些奇怪的原因,它被定义为填充到16个字节,这与32位代码不同sizeof(long double) == 10.的x87 10字节加载/存储是相当缓慢反正(如1/3的负载吞吐量doublefloat对酷睿2,在P4 1/6,或K8 1/8),但也许缓存线和页面拆分的处罚是如此糟糕在较旧的CPU上,他们决定以这种方式定义它.我认为在现代CPU(甚至可能是Core2)上循环遍历数组long double并不会因打包10字节而变慢,因为这fld m80将比每个~64个元素的缓存行分割更大的瓶颈.

实际上,ABI是在硅可用于基准测试之前定义的(早在2000年),但那些K8数字与K7相同(32位/ 64位模式在这里无关紧要).使用long double16字节可以复制单个字节movaps,即使您在XMM寄存器中无法对其进行任何操作.(除了用xorps/ andps/ 操作符号位orps)

相关:此max_align_t定义意味着malloc始终在x86-64代码中返回16字节对齐的内存.这让你可以将它用于SSE对齐的负载_mm_load_ps,但是这样的代码在编译为32位时可能会中断,其中alignof(max_align_t)只有8 位.(使用aligned_alloc或其他).


其他ABI因素包括__m128在堆栈上传递值(在xmm0-7之后具有前8个浮点数/向量args).对内存中的向量要求16字节对齐是有意义的,因此被调用者可以有效地使用它们,并且由调用者有效地存储它们.始终保持16字节堆栈对齐使得需要将一些arg传递空间对齐16的函数变得容易.

有类似的类型__m128,ABI保证有16字节对齐.如果你定义一个local并获取它的地址,并将该指针传递给其他函数,那么本地需要充分对齐.因此,保持16字节堆栈对齐与提供某些类型的16字节对齐密切相关,这显然是一个好主意.

这些天,它atomic可以廉价地获得16字节对齐,因此lock cmpxchg16b不会跨越缓存行边界.对于极少数情况,你有一个带有自动存储的原子本地,你将指针传递给多个线程......


脚注1:32位Linux

并非所有32位平台都破坏了与现有二进制文件的兼容性,并且像Linux一样手写.有些像i386 NetBSD仍然只使用原始版本的i386 SysV ABI的历史4字节堆栈对齐要求.

历史的4字节堆栈对齐也不足以double在现代CPU上实现高效的8字节.未对齐fld/ fstp通常是高效的,除非它们越过缓存线边界(像其他加载/存储一样),所以它并不可怕,但自然对齐很好.

即使在16字节对齐正式成为ABI的一部分之前,GCC也曾-mpreferred-stack-boundary=4在32位上启用(2 ^ 4 = 16字节).这当前假设传入的堆栈对齐是16个字节(即使对于不会出现故障的情况),以及保留该对齐.我不确定历史gcc版本是否曾经尝试保留堆栈对齐而不依赖于SSE代码或alignas(16)对象的正确性.

ffmpeg是一个众所周知的例子,依赖于编译器给它堆栈对齐:什么是"堆栈对齐"?,例如在32位Windows上.

现代gcc仍然在顶部发出代码main以使堆栈对齐16(即使在Linux上,ABI保证内核以对齐的堆栈启动进程),但不是在任何其他函数的顶部.您可以使用-mincoming-stack-boundary告诉gcc在生成代码时应该如何对齐它.

古代的gcc4.1似乎并没有真正尊重__attribute__((aligned(16)))或者32用于自动存储,也就是说它在Godbolt的这个例子中没有任何额外的对齐堆栈,所以旧的gcc在堆栈对齐方面有一种格格不入的过去.我认为官方Linux ABI到16字节对齐的变化首先发生在事实上的变化,而不是一个精心策划的变更.在变化发生的时候,我还没有发现任何正式的事情,但在2005年到2010年之间的某个地方,我认为,在x86-64变得流行之后,x86-64 System V ABI的16字节堆栈对齐被证明是有用的.

起初,GCC的代码更改是使用比ABI要求更多的对齐(即对gcc编译的代码使用更严格的ABI),但后来它写入了维护在https的i386 System V ABI版本://github.com/hjl-tools/x86-psABI/wiki/X86-psABI(至少是Linux官方版).


@MichaelPetch和@ThomasJager报告说gcc4.5可能是-mpreferred-stack-boundary=432位和64位的第一个版本.Godbolt上的gcc4.1.2和gcc4.4.7似乎表现得那样,所以也许这个改变是向后移植的,或者Matt Godbolt用更现代的配置配置旧的gcc.


推荐阅读
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 本文概述了JNI的原理以及常用方法。JNI提供了一种Java字节码调用C/C++的解决方案,但引用类型不能直接在Native层使用,需要进行类型转化。多维数组(包括二维数组)都是引用类型,需要使用jobjectArray类型来存取其值。此外,由于Java支持函数重载,根据函数名无法找到对应的JNI函数,因此介绍了JNI函数签名信息的解决方案。 ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • ch3中可视化软件pangolin的安装步骤及注意事项
    本文介绍了在ch3中安装可视化软件pangolin的步骤及注意事项。首先提供了pangolin的下载地址,并说明了下载后需要放到与虚拟机交互的文件夹地址。然后详细介绍了安装pangolin所需的依赖项,并提供了在终端进行安装的命令。最后给出了解压pangolin的步骤。 ... [详细]
  • 本文介绍了Linux Shell中括号和整数扩展的使用方法,包括命令组、命令替换、初始化数组以及算术表达式和逻辑判断的相关内容。括号中的命令将会在新开的子shell中顺序执行,括号中的变量不能被脚本余下的部分使用。命令替换可以用于将命令的标准输出作为另一个命令的输入。括号中的运算符和表达式符合C语言运算规则,可以用在整数扩展中进行算术计算和逻辑判断。 ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 说明:主要是基于ghostyu网友整理的《 armmini2440基于v4l2ffmpegx264的视频远程监控》。自己做了一遍,遇到不少问题,就整理记录下来。 1、平台硬件:ar ... [详细]
  • ffmpeg做切片切出来最终是vod的切的过程中是直播的加载G:\MEDIA\HLS\index.m3u8进行播放播放器自己会做HLS多码率的切换。以下的切换日志,证明做了切换:B ... [详细]
  • ffmpeg  spydroid jrtplib
    2019独角兽企业重金招聘Python工程师标准手机上采用Spydroid程序。https:github.comfyhertzspydroid-ipcamera先用libcu ... [详细]
author-avatar
手机用户2502885301
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有