【问题标题】:Why alignment is 16 bytes on 64 bit architecture? [duplicate]为什么在 64 位架构上对齐是 16 字节? [复制]
【发布时间】:2011-04-04 11:54:37
【问题描述】:
(gdb) disas foo
Dump of assembler code for function foo:
0x00000000004004a8 <foo+0>: push   %rbp
0x00000000004004a9 <foo+1>: mov    %rsp,%rbp
0x00000000004004ac <foo+4>: mov    0x13c(%rip),%eax        # 0x4005ee <__dso_handle+30>
0x00000000004004b2 <foo+10>:    mov    %eax,-0x10(%rbp)
0x00000000004004b5 <foo+13>:    lea    -0x10(%rbp),%rax
0x00000000004004b9 <foo+17>:    add    $0x18,%rax
0x00000000004004bd <foo+21>:    mov    %rax,%rdx
0x00000000004004c0 <foo+24>:    mov    $0x400498,%eax
0x00000000004004c5 <foo+29>:    mov    %eax,(%rdx)
0x00000000004004c7 <foo+31>:    leaveq 
0x00000000004004c8 <foo+32>:    retq   
(gdb) l foo
8   void foo() {
9       char overme[4] = "WOW";
10      *(int*)(overme+24) = (int)bad;
11  }

为什么不只有 8 个字节?

【问题讨论】:

标签: c x86-64 memory-alignment


【解决方案1】:

gcc 没有将此空间“分配”给变量。相反,x86_64 abi 要求堆栈指针在函数调用时始终保持 16 字节对齐,以防被调用者使用矢量化 SSE 数学。这是一个非常愚蠢和浪费的要求(如果需要,被调用者应该确保对齐),但这是标准,gcc 遵循标准。您可以使用-mpreferred-stack-boundary=3 修复它(8 字节对齐,64 位的最小值)。

【讨论】:

  • @R,寄存器大小是8字节,为什么是16字节对齐?
  • 你能详细介绍一下vectorized SSE math吗?
  • 显然许多 SSE 指令要么崩溃,要么做错事,要么在给定未对齐的地址时非常缓慢(不确定哪个)。它们一次处理 128 位,可以是单个 128 位浮点值,也可以是许多较小整数或浮点值的向量,因此正确的对齐方式是 16。
【解决方案2】:

它是 8 个字节,而不是 16 个。LEA 指令不显示任何与对齐相关的内容,-0x10 只是应用于 RBP 寄存器值的偏移量。大概是为了生成一个小的本地数组的地址。如果代码生成器使用任何 SIMD 指令,那么 16 可能是相关的。在两行问题中都看不到。

【讨论】:

  • @Hans Passant,我已经更新了代码,mov %eax,-0x10(%rbp) 正在为 char overme[4] 分配 16 个字节
  • 不,EAX 寄存器存储 4 个字节。它正在复制恰好也是 4 个字节长的“WOW”字符串。我猜对了“小型本地数组”。当您使字符串更长时,您将获得非常不同的代码。否则代码是UB。
  • @Hans Passant,你能详细说明为什么“小型本地数组”需要 16 个字节,而不是 8 个字节,如果对齐是 8 个字节?
  • 不知道,gcc 经常吞噬堆栈字节。它也没有通过调整 rsp 为数组腾出空间。尝试关闭代码优化器以减少 RSA 加密。这有什么意义?你是不是故意踩堆栈?
  • @Hans Passant,它已经在优化器关闭的情况下编译,gcc -O0 xxx。是的,我正在尝试踩堆栈,但不明白为什么overme 被分配了 16 个字节...
猜你喜欢
  • 2021-08-22
  • 2011-04-05
  • 1970-01-01
  • 2012-01-28
  • 2016-04-02
  • 2013-05-18
  • 2017-07-05
  • 2012-04-30
  • 2020-05-26
相关资源
最近更新 更多