【问题标题】:Why movaps causes segmentation fault?为什么movaps会导致分段错误?
【发布时间】:2021-07-18 10:45:56
【问题描述】:

简介

我试图让自己熟悉 AES 指令,然后使用更自觉地利用这些技术的库。但是,我不经常用汇编编程,所以我对这门语言有一定的信心,但我不认为自己是专家。我已经编写了大约 150 条装配线的清单,以尝试使用英特尔提供的文档来使用这些功能。但是我没有成功地向前迈出很多步。

当我使用指令movaps 时,程序由于main 中的分段错误而崩溃。我已经尝试使用 gdb 和 valgrind 进行调试,但似乎一切都应该工作,但事实并非如此。以下是导致问题的行。

代码

main:
start_f

    printstr

    movaps (string), %xmm15
==> movaps (key), %xmm0
    call   aes_encript

    movaps %xmm15, string
    printstr

end_f

start_f 和end_f 只是用于启动和结束函数的宏。我还提供了 .data 部分的代码,以显示应该没有问题:

    .data
string:
    .string "string"
    .fill   (128 - (.-string)), 1, 0

newline:
    .byte   0x0a

key:
    .fill   128, 1, 0

    .text
    .global _start

调试信息

至于错误,我无法通过静态反汇编或在 gdb 中获得任何有用的信息。 Valgrind 也没有任何帮助,这是可以预料的,因为我根本不接触堆。 我展示了在 gdb 中反汇编的部分清单:

   0x0000000000401022 <+0>:     push   %rbp
   0x0000000000401023 <+1>:     mov    %rsp,%rbp
   0x0000000000401026 <+4>:     mov    $0x402000,%rsi
   0x000000000040102d <+11>:    call   0x401156 <write_long>
   0x0000000000401032 <+16>:    mov    $0x1,%rax
   0x0000000000401039 <+23>:    mov    $0x1,%rbp
   0x0000000000401040 <+30>:    mov    $0x402080,%rsi
   0x0000000000401047 <+37>:    mov    $0x1,%rdx
   0x000000000040104e <+44>:    syscall 
   0x0000000000401050 <+46>:    movaps 0x402000,%xmm15
=> 0x0000000000401059 <+55>:    movaps 0x402081,%xmm0
   0x0000000000401061 <+63>:    call   0x4010b6 <aes_encript>
   0x0000000000401066 <+68>:    movaps %xmm15,0x402000
   0x000000000040106f <+77>:    mov    $0x402000,%rsi
   0x0000000000401076 <+84>:    call   0x401156 <write_long>

这里是地址0x402081的内容(完全可以访问):

(gdb) x/32x 0x402081
0x402081:       0x00000000      0x00000000      0x00000000      0x00000000
0x402091:       0x00000000      0x00000000      0x00000000      0x00000000
0x4020a1:       0x00000000      0x00000000      0x00000000      0x00000000
0x4020b1:       0x00000000      0x00000000      0x00000000      0x00000000
0x4020c1:       0x00000000      0x00000000      0x00000000      0x00000000
0x4020d1:       0x00000000      0x00000000      0x00000000      0x00000000
0x4020e1:       0x00000000      0x00000000      0x00000000      0x00000000
0x4020f1:       0x00000000      0x00000000      0x00000000      0x00000000

请求

我不排除错误是愚蠢的微不足道:我有一段时间没有使用 as 了。无论如何,如果你能给我一个小费,我将不胜感激。

如果您想自己尝试这段代码,这里有一个包含整个清单的粘贴箱:https://paste.debian.net/1194986/

【问题讨论】:

  • 要么对齐 16 字节内存地址上的数据,要么使用 movups 进行非对齐访问。
  • 这是 64 位代码,因此您应该像编译器一样使用 RIP 相对寻址模式(如 movaps string(%rip), %xmm15)来寻址静态数据。更喜欢使用 XMM0..7,这样机器代码可以更紧凑(不需要 REX 前缀)。另外,错字:加密不是加密。

标签: assembly segmentation-fault sse memory-alignment att


【解决方案1】:

key 的0x402081 内存地址未与 16 字节对齐。

来自Intel® 64 and IA-32 architectures software developer’s manual,MOVAPS specification:

MOVAPS—移动对齐压缩单精度浮点值
...
当源或目标操作数是内存操作数时,操作数必须在 16 字节(128 位 版本)、32 字节(VEX.256 编码版本)或 64 字节(EVEX.512 编码版本)边界或一般保护异常 (#GP)。

您可以使用movups,但通常最好对齐常量。

在上一行 0x402000 对齐到 16 个字节,所以上一行没有段错误。

key 可以定义如下以对齐到 16 个字节:

    .balign 16
key:
    .fill   128, 1, 0

另外请注意,这是 128 个字节 的零,而不是 128 位。既然都是零,你可以把它放在.bss而不是.data。

(把newline: .byte '\n'放在之后这个,这样你就不会在对齐上浪费15个字节。或者更好的是,在.rodata中加入换行符,或者让write_long在输出中包含一个换行符它写道。)

【讨论】:

  • 哦,是的,我真的没看到。非常比你。
  • @Renat:在 GAS 代码中,始终使用 .balign 16 或 .p2align 4,切勿使用模棱两可的 .align。在某些系统(例如 MacOS)上,.align 是 .p2align 而不是 .balign 的别名,并且您不能按 64k 对齐。
猜你喜欢
  • 2020-04-15
  • 1970-01-01
  • 2020-10-28
  • 1970-01-01
  • 2017-08-18
  • 1970-01-01
  • 2021-04-18
  • 2021-11-06
  • 2016-09-24
相关资源
最近更新 更多