为什么movaps会导致分段错误?

介绍

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

当我使用该指令时,由于 main 中的分段错误,程序崩溃了movaps。我已经尝试使用 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

要求

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

如果您想自己尝试此代码,这里有一个包含整个列表的 pastebin:https : //paste.debian.net/1194986/

回答

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

来自Intel® 64 和 IA-32 架构软件开发人员手册,MOVAPS规范:

MOVAPS—Move Aligned Packed Single-Precision Floating-Point Values

...
当源或目标操作数是内存操作数时,操作数必须按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: In GAS code, always use `.balign 16` or `.p2align 4`, never the ambiguous `.align`. On some systems (e.g. MacOS), `.align` is an alias for `.p2align` instead of `.balign`, and you don't to align by 64k.

以上是为什么movaps会导致分段错误?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>