SIGSEGV在优化版本的代码中

前端之家收集整理的这篇文章主要介绍了SIGSEGV在优化版本的代码中前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我对intel指令集的了解有点生锈.你可以告诉我为什么我可能会在我的功能的优化版本中得到一个分段错误(如果你能告诉我为什么我没有在-O0的代码中建立这个代码,那么这个奖励积分).

它是由GCC 4.1.2编译的C代码.

这是GDB在崩溃时的“disas”命令的结果:

0x00000000004263e5 <+0>:     sub    $0x8,%rsp
   0x00000000004263e9 <+4>:     movsd  %xmm2,(%rsp)
   0x00000000004263ee <+9>:     divsd  %xmm1,%xmm0
   0x00000000004263f2 <+13>:    callq  0x60f098 <log@plt>
=> 0x00000000004263f7 <+18>:    andpd  0x169529(%rip),%xmm0        
   0x00000000004263ff <+26>:    movsd  (%rsp),%xmm1
   0x0000000000426404 <+31>:    ucomisd %xmm0,%xmm1
   0x0000000000426408 <+35>:    seta   %al
   0x000000000042640b <+38>:    movzbl %al,%eax
   0x000000000042640e <+41>:    add    $0x8,%rsp
   0x0000000000426412 <+45>:    retq

这里是函数的原始来源:

char is_within_range(double a,double b,double range) {
  double ratio = a / b;
  double logRatio = fabs(log(ratio));
  return logRatio < range;
}

为了参考,这里是非优化版本的代码

0x00000000004263e5 <+0>: push   %rbp
   0x00000000004263e6 <+1>: mov    %rsp,%rbp
   0x00000000004263e9 <+4>: sub    $0x30,%rsp
   0x00000000004263ed <+8>: movsd  %xmm0,-0x18(%rbp)
   0x00000000004263f2 <+13>:    movsd  %xmm1,-0x20(%rbp)
   0x00000000004263f7 <+18>:    movsd  %xmm2,-0x28(%rbp)
   0x00000000004263fc <+23>:    movsd  -0x18(%rbp),%xmm0
   0x0000000000426401 <+28>:    divsd  -0x20(%rbp),%xmm0
   0x0000000000426406 <+33>:    movsd  %xmm0,-0x10(%rbp)
   0x000000000042640b <+38>:    mov    -0x10(%rbp),%rax
   0x000000000042640f <+42>:    mov    %rax,-0x30(%rbp)
   0x0000000000426413 <+46>:    movsd  -0x30(%rbp),%xmm0
   0x0000000000426418 <+51>:    callq  0x610608 <log@plt>
   0x000000000042641d <+56>:    movapd %xmm0,%xmm1
   0x0000000000426421 <+60>:    movsd  0x16b6b7(%rip),%xmm0
   0x0000000000426429 <+68>:    andpd  %xmm1,%xmm0
   0x000000000042642d <+72>:    movsd  %xmm0,-0x8(%rbp)
   0x0000000000426432 <+77>:    movsd  -0x8(%rbp),%xmm1
   0x0000000000426437 <+82>:    movsd  -0x28(%rbp),%xmm0
   0x000000000042643c <+87>:    ucomisd %xmm1,%xmm0
   0x0000000000426440 <+91>:    seta   %al
   0x0000000000426443 <+94>:    movzbl %al,%eax
   0x0000000000426446 <+97>:    leaveq 
   0x0000000000426447 <+98>:    retq

解决方法

=> 0x00000000004263f7 <+18>:    andpd  0x169529(%rip),%xmm1

当andpd指令需要一个内存操作数时,需要对齐一个16字节的边界.

对于%rip相对寻址,偏移量应用于以下指令的地址.所以,这里,内存操作数在0x4263ff 0x169529 = 0x58f928,不是16字节对齐.因此segfault.

编译器直接为fabs()生成代码,使用AND和适当的位掩码来清除符号位;应该将位掩码常数值置于足够对齐的数据段中的适当偏移量上,但尚未.这可能是GCC的旧版本中的一个错误,或者可能是其他地方与链接器相关的问题.

猜你在找的C&C++相关文章