NASM是否存在未对齐访问问题?

Is there unaligned access problem in NASM?

我知道 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))) 对在任何对齐方式下具有明确定义行为的类型进行类型定义。


.data段在Linux下默认至少对齐4个字节,所以一个2字节(word)存储到[arr] 一个对齐的商店;该地址保证是偶数(除非您使用特殊的链接器选项/链接器脚本告诉它从 .data 奇数地址开始)。您的 arr.data 部分的开头开始。

此外,"abcd" 是一个 4 字节常量,必须将其截断以适合 word。我想您在测试您的示例以查看它恰好在您自己的计算机上运行时错过了这一点,然后才问它是否安全?

cause for some processors UB

不,在 ISO C总是 UB。有关示例和链接,请参阅 。请注意,未定义的行为并不意味着它 崩溃,只是优化器可以假定它不会发生并且结果可能无法预测。

与大多数 ISA 一样,x86 中的行为始终定义明确。即使在引发异常的情况下,硬件供应商也必须准确指定会发生什么,因此可以编写操作系统以在 user-space 导致故障时保持对机器的控制。 (所以在 asm 中,您真正要寻找的不是定义的行为,而是保证无故障。)

对于 16 字节以外的任何访问大小,任何未对齐都没有问题。 (假设 AC 位被清除,这在正常系统中是这种情况。例如,如果你设置它,glibc memcpy 会出错,对于小的未对齐的副本。除非你自己专门设置 AC 作为一种检测无意的未对齐访问的方法,你可以假设它已被清除。在现代 CPU 上还有用于拆分加载和拆分存储的性能计数器,您可以使用它们来检测有问题的。)

对于 16 字节访问,legacy-SSE 访问默认需要自然对齐(例如 SSE2 pxor xmm0, [rdi] 需要对齐),除了像 [=22= 这样的指令] 未对齐 load/store。其他大小如 8 字节不需要对齐,例如punpckldq mm0, [rdi] 是对齐安全的,因为 MMX 寄存器只有 8 个字节宽,尽管 punpck 指令烦人地进行全角加载,而不是只加载到目的地的一半。)

对于AVX / AVX-512编码(VEX / EVEX),未对齐是默认值(例如vaddps xmm0, xmm1, [rdi]不需要对齐),只有特殊对齐-需要的指令,如 vmovntps-stores 或 vmovdqa load/store 将在未对齐时出错。

即使对于未对齐的地址,需要对齐的访问行为也是明确定义的:#GP fault for SSE/AVX misalignment,或者如果设置了 AC,则为#AC位并做了一些需要 2、4 或 8 个字节对齐但不满足该要求的事情。 (https://xem.github.io/minix86/manual/intel-x86-and-64-manual-vol3/o_fe12b1e2a880e0ce-231.html 摘录英特尔 SDM PDF 的相关页面。)

在 GNU/Linux 下,用户 space 进程如果生成 #GF 异常,将收到 SIGSEGV(分段错误)。 IIRC,#AC 可能会让内核传递 SIGBUS(总线错误)。


x86 中未对齐访问的唯一问题是性能

(遗留 SSE 内存操作数中提到的除外。)