大佬教程收集整理的这篇文章主要介绍了NASM 中是否存在未对齐的访问问题? x86 中未对齐访问的唯一问题是性能,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
我知道 C 中的未对齐访问是什么,它可能导致某些处理器 UB。
不知道这样的代码有没有同样的问题,写在NASM程序集上:
section .text
global _start
_start:
mov [arr],word "abcd"
section .data
arr: db 1,2,3,4,5,6,7
通常没问题,x86 允许任何大小的未对齐访问(对 16 字节未对齐有一些限制)。
其他一些 ISA 没有(例如 SPARC、MIPS32r6 之前的 MIPS 等),C 通过在 T*
指针的对齐小于 alignof(T)
时不定义行为来迎合这些。在 GNU C 中,您可以使用 __attribute__((aligned(1)))
对在任何对齐方式下具有明确定义行为的类型进行 typedef。
默认情况下,.data
部分在 Linux 下将至少对齐 4 个字节,因此 2 字节 (word
) 存储到 [arr]
是 一个对齐的商店;地址保证是偶数(除非您使用特殊的链接器选项/链接器脚本告诉它从奇数地址开始 .data
)。您的 arr
从 .data
部分的开头开始。
此外,"abcd"
是一个 4 字节的常量,必须截断以适应 word
。我猜您在测试示例以查看它碰巧在您自己的计算机上运行时错过了这一点,然后再询问它总体上是否安全?
导致某些处理器 UB
不,它总是 ISO C 中的 UB。有关示例和链接,请参见 Why does unaligned access to mmap'ed memory sometimes segfault on AMD64?。请注意,未定义行为并不意味着它确实崩溃,只是优化器可以假设它不会发生并且结果可能无法预测。
这种行为在 x86 中总是明确定义的,就像大多数 ISA 一样。硬件供应商必须准确指定即使在引发异常的情况下会发生什么,因此可以编写操作系统以在用户空间导致故障时保持对机器的控制。 (因此,在 asm 中,您真正要寻找的不是定义行为,而是保证无故障。)
任何不对齐对于 16 字节以外的任何访问大小都没有问题。 (假设 AC 位被清除,这是正常系统中的情况。例如,对于小的未对齐副本,glibc memcpy 会出错,如果你设置它,除非你自己专门设置 AC 来检测无意的未对齐访问,否则你可以假设它已清除。现代 CPU 上还有用于拆分加载和拆分存储的性能计数器,您可以使用它们来检测有问题的计数器。)
对于 16 字节访问,legacy-SSE 访问默认需要自然对齐(例如 SSE2 pxor xmm0,[rdi]
需要对齐),除了 movdqu
未对齐加载/存储等指令.其他大小(如 8 字节)不需要对齐,例如punpckldq mm0,[rdi]
是对齐安全的,因为 MMX 寄存器只有 8 个字节宽,即使 punpck
指令烦人地执行全宽加载,而不是它们拖入目的地的一半。)
使用 AVX / AVX-512 编码 (VEX / EVEX),未对齐是默认值(例如 vaddps xmm0,xmm1,[rdi]
不需要对齐),并且只有特殊的需要对齐的指令,例如 { {1}}-stores 或 vmovntps
load/store 将在未对齐时出错。
即使对于未对齐的地址,需要对齐的访问行为也是明确定义的:SSE/AVX 未对齐的#GP 错误,或者如果您设置了 AC 位并执行了一些需要 2 的操作,则为 #AC 、4 或 8 个字节的对齐方式,但不符合该要求。 (https://xem.github.io/minix86/manual/intel-x86-and-64-manual-vol3/o_fe12b1e2a880e0ce-231.html 摘录英特尔 SDM PDF 的相关页面。)
在 GNU/Linux 下,如果用户空间进程生成 #GF 异常,它将收到 SIGSEGV(分段错误)。 IIRC,#AC 可能会让内核传递 SIGBUS(总线错误)。
(除了旧版 SSE 内存操作数中提到的。)
以上是大佬教程为你收集整理的NASM 中是否存在未对齐的访问问题? x86 中未对齐访问的唯一问题是性能全部内容,希望文章能够帮你解决NASM 中是否存在未对齐的访问问题? x86 中未对齐访问的唯一问题是性能所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。