movaps指令引起的复位

博客介绍了在升级GCC编译器后,由于添加了-ftree-slp-vectorize选项,程序在执行movaps指令时挂掉。问题源于malloc分配的内存未按16字节对齐,导致SEE指令执行失败。解决方案是使用16字节对齐的内存分配函数。通过gdb调试,验证了内存对齐问题确实导致了程序崩溃,并通过修改rax寄存器值实现了临时修复。
摘要由CSDN通过智能技术生成

最近项目升级了gcc编译器,需要增加编译选项-ftree-slp-vectorize,加了后发现程序莫名其妙挂掉,使用gdb挂起也没看到有内存错误,使用disassemble才看到当程序运行到movaps指令时挂掉了。上网搜索发现这是SEE指令,movaps要求操作地址是16字节对齐。但是由于项目使用的并不是glibc的malloc,而是自己研发的malloc,这个malloc并不像是glibc一样在64位系统下16字节对齐,而是4字节对齐,所以当申请的地址不能被16整除时,movaps指令异常,程序挂掉。

修改方法:使用类似align_malloc的接口申请16字节对齐的内存。

下面我尝试在虚拟机上复现该问题,由于我的系统是64位的,malloc函数申请内存地址都是16字节对齐,这里使用汇编模拟这个问题。

int main()
{
    int a = 0;
    __asm__ __volatile__ ("movaps 0x04(%rax), %xmm0");
    return 0;
}
(gdb) b main 
Breakpoint 1 at 0x400478: file movtest.c, line 3.
(gdb) i r
The program has no registers now.
(gdb) r
Starting program: /home/luogf/20210213/a.out 

Breakpoint 1, main () at movtest.c:3
3       int a = 0; 
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.212.el6_10.3.x86_64
(gdb) i r
rax            0x7ffff7dd8f80   140737351880576
rbx            0x0      0
rcx            0x400474 4195444
rdx            0x7fffffffe668   140737488348776
rsi            0x7fffffffe658   140737488348760
rdi            0x1      1
rbp            0x7fffffffe570   0x7fffffffe570
rsp            0x7fffffffe570   0x7fffffffe570
r8             0x7ffff7dd7ba0   140737351875488
r9             0x7ffff7deae20   140737351953952
r10            0x7fffffffe3c0   140737488348096
r11            0x7ffff7a66c20   140737348267040
r12            0x400390 4195216
r13            0x7fffffffe650   140737488348752
r14            0x0      0
r15            0x0      0
rip            0x400478 0x400478 <main+4>
eflags         0x246    [ PF ZF IF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0
(gdb) disassemble 
Dump of assembler code for function main:
   0x0000000000400474 <+0>:     push   %rbp
   0x0000000000400475 <+1>:     mov    %rsp,%rbp
=> 0x0000000000400478 <+4>:     movl   $0x0,-0x4(%rbp)
   0x000000000040047f <+11>:    movaps 0x4(%rax),%xmm0
   0x0000000000400483 <+15>:    mov    $0x0,%eax
   0x0000000000400488 <+20>:    leaveq 
   0x0000000000400489 <+21>:    retq   
End of assembler dump.

 

可以看到rax寄存器是0x7ffff7dd8f80,movaps 0x4(%rax),%xmm0操作0x7ffff7dd8f80+0x04不是16字节对齐,所以会出现下面的错误:

(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
main () at movtest.c:4
4       __asm__ __volatile__ (  
(gdb) disassemble 
Dump of assembler code for function main:
   0x0000000000400474 <+0>:     push   %rbp
   0x0000000000400475 <+1>:     mov    %rsp,%rbp
   0x0000000000400478 <+4>:     movl   $0x0,-0x4(%rbp)
=> 0x000000000040047f <+11>:    movaps 0x4(%rax),%xmm0
   0x0000000000400483 <+15>:    mov    $0x0,%eax
   0x0000000000400488 <+20>:    leaveq 
   0x0000000000400489 <+21>:    retq   
End of assembler dump.

没错,出现了coredump,清晰的看到挂在了movaps上,如果我们该给rax寄存器减去4,使得0x04(%rax) 即:%rax+4刚好16字节对齐:

(gdb) set $rax=$rax-4
(gdb) i r
rax            0x7ffff7dd8f7c   140737351880572
rbx            0x0      0
rcx            0x400474 4195444
rdx            0x7fffffffe668   140737488348776
rsi            0x7fffffffe658   140737488348760
rdi            0x1      1
rbp            0x7fffffffe570   0x7fffffffe570
rsp            0x7fffffffe570   0x7fffffffe570
r8             0x7ffff7dd7ba0   140737351875488
r9             0x7ffff7deae20   140737351953952
r10            0x7fffffffe3c0   140737488348096
r11            0x7ffff7a66c20   140737348267040
r12            0x400390 4195216
r13            0x7fffffffe650   140737488348752
r14            0x0      0
r15            0x0      0
rip            0x400478 0x400478 <main+4>
eflags         0x246    [ PF ZF IF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0
(gdb) c
Continuing.

Program exited normally.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值