2011-11-28 57 views
10

我對intel指令集的瞭解有點生疏。你能告訴我爲什麼我可能會在我的函數的優化版本中得到一個分割錯誤(獎勵分,如果你能告訴我爲什麼我沒有在-O0版本的代碼中得到它)SIGSEGV中的代碼優化版本

這是C代碼通過GCC 4.1.2編譯

這裏是在崩潰GDB的 「disas」 命令的結果:

0x00000000004263e5 <+0>:  sub $0x8,%rsp 
    0x00000000004263e9 <+4>:  movsd %xmm2,(%rsp) 
    0x00000000004263ee <+9>:  divsd %xmm1,%xmm0 
    0x00000000004263f2 <+13>: callq 0x60f098 <[email protected]> 
=> 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 <[email protected]> 
    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 
+1

您是否檢查過與非優化代碼(程序集輸出)的差異?如果是這樣,你可以發佈它嗎? – Macmade

+0

輸入是否重要? – sehe

+0

我不認爲輸入實際上很重要... – Macmade

回答

6
=> 0x00000000004263f7 <+18>: andpd 0x169529(%rip),%xmm0   
    0x00000000004263ff <+26>: movsd (%rsp),%xmm1 

andpd指令需要一個內存操作數時,它需要對齊到一個16字節的邊界。

對於%rip相對尋址,偏移量應用於下一條指令的地址。所以,在這裏,內存操作數是0x4263ff + 0x169529 = 0x58f928,它不是16字節對齊的。因此段錯誤。

編譯器直接爲fabs()生成代碼,使用帶有適當位掩碼的AND來清除符號位;位掩碼常量值應該放置在一個足夠對齊的數據段中的適當偏移處,但尚未。這可能是GCC(舊)版本中的一個錯誤,或者可能是其他地方的鏈接器相關問題。

+0

跟進這個,是你的答案是現貨,它竟然是我們使用的非標準鏈接器中的鏈接器錯誤。感謝你的回答。 – laslowh

1

看來調用log功能後崩潰:

callq 0x60f098 <[email protected]> 

因此,有可能與fabs實施問題,用-O0

你試過:

double logRatio = log(ratio); 
logRatio = fabs(logRatio); 

這可能會產生不同的裝配輸出,並且你可能會得到關於崩潰的其他相關信息。

double logRatio = log(ratio); 
logRatio = (logRatio < 0) -logRatio : logRatio; 

您可能必須與精度的問題,但在這裏,這不是問題的關鍵...

1

我也:

作爲替代方案,你可能會喜歡的東西取代fabs電話使用gcc (GCC) 4.1.2 20070115 (SUSE Linux),這裏的生成的程序集:

Dump of assembler code for function is_within_range: 
0x0000000000400580 <is_within_range+0>: divsd %xmm1,%xmm0 
0x0000000000400584 <is_within_range+4>: sub $0x8,%rsp 
0x0000000000400588 <is_within_range+8>: movsd %xmm2,(%rsp) 
0x000000000040058d <is_within_range+13>:  callq 0x400498 <[email protected]> 
0x0000000000400592 <is_within_range+18>:  andpd 358(%rip),%xmm0  # 0x400700 
0x000000000040059a <is_within_range+26>:  xor %eax,%eax 
0x000000000040059c <is_within_range+28>:  movsd (%rsp),%xmm1 
0x00000000004005a1 <is_within_range+33>:  ucomisd %xmm0,%xmm1 
0x00000000004005a5 <is_within_range+37>:  seta %al 
0x00000000004005a8 <is_within_range+40>:  add $0x8,%rsp 
0x00000000004005ac <is_within_range+44>:  retq 

這似乎是幾乎相同的,但我沒有得到一個崩潰。我認爲您需要向我們提供您的編譯器標誌以及處理器和GLIBC版本的詳細信息,以及a,brange的值會讓您崩潰,因爲問題幾乎肯定與log調用有關。