为什么 movaps 会导致分段错误?
Why movaps causes segmentation fault?
简介
我试图让自己熟悉 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 [=12=]x402000,%rsi
0x000000000040102d <+11>: call 0x401156 <write_long>
0x0000000000401032 <+16>: mov [=12=]x1,%rax
0x0000000000401039 <+23>: mov [=12=]x1,%rbp
0x0000000000401040 <+30>: mov [=12=]x402080,%rsi
0x0000000000401047 <+37>: mov [=12=]x1,%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 [=12=]x402000,%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 了。无论如何,如果你能给我小费,我将不胜感激。
如果您想自己尝试此代码,这里有一个包含整个清单的 pastebin:https://paste.debian.net/1194986/
0x402081
key
的内存地址未对齐到 16 字节。
来自 Intel® 64 and IA-32 architectures software developer’s manual, MOVAPS
specification:
MOVAPS—Move Aligned Packed Single-Precision Floating-Point Values
...
When the source or destination operand is a memory operand, the operand must be aligned on a 16-byte (128-bit
version), 32-byte (VEX.256 encoded version) or 64-byte (EVEX.512 encoded version) boundary or a generalprotection exception (#GP) will be generated.
您可以使用 movups
,但通常最好对齐常量。
上一行 0x402000
对齐到 16 字节,所以上一行没有段错误。
key
可以定义如下以对齐到 16 字节:
.balign 16
key:
.fill 128, 1, 0
另请注意,这是 128 字节 的零,而不是 128 位。由于全为零,您可以将其放入 .bss
而不是 .data
.
(将 newline: .byte '\n'
放在 之后,这样你就不会在对齐上浪费 15 个字节。或者更好的是,将换行符放在 .rodata
中,或者write_long
在它写入的输出中包含一个换行符。)
简介
我试图让自己熟悉 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 [=12=]x402000,%rsi
0x000000000040102d <+11>: call 0x401156 <write_long>
0x0000000000401032 <+16>: mov [=12=]x1,%rax
0x0000000000401039 <+23>: mov [=12=]x1,%rbp
0x0000000000401040 <+30>: mov [=12=]x402080,%rsi
0x0000000000401047 <+37>: mov [=12=]x1,%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 [=12=]x402000,%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 了。无论如何,如果你能给我小费,我将不胜感激。
如果您想自己尝试此代码,这里有一个包含整个清单的 pastebin:https://paste.debian.net/1194986/
0x402081
key
的内存地址未对齐到 16 字节。
来自 Intel® 64 and IA-32 architectures software developer’s manual, MOVAPS
specification:
MOVAPS—Move Aligned Packed Single-Precision Floating-Point Values
...
When the source or destination operand is a memory operand, the operand must be aligned on a 16-byte (128-bit version), 32-byte (VEX.256 encoded version) or 64-byte (EVEX.512 encoded version) boundary or a generalprotection exception (#GP) will be generated.
您可以使用 movups
,但通常最好对齐常量。
上一行 0x402000
对齐到 16 字节,所以上一行没有段错误。
key
可以定义如下以对齐到 16 字节:
.balign 16
key:
.fill 128, 1, 0
另请注意,这是 128 字节 的零,而不是 128 位。由于全为零,您可以将其放入 .bss
而不是 .data
.
(将 newline: .byte '\n'
放在 之后,这样你就不会在对齐上浪费 15 个字节。或者更好的是,将换行符放在 .rodata
中,或者write_long
在它写入的输出中包含一个换行符。)