2011-11-28 11 views
10

Moja wiedza na temat zestawu instrukcji intel jest nieco zardzewiała. Czy możesz mi powiedzieć, dlaczego mógłbym uzyskać błąd segmentacji w zoptymalizowanej wersji mojej funkcji (punkty bonusowe, jeśli możesz mi powiedzieć, dlaczego nie dostaję go w wersji -00 kodu:SIGSEGV w zoptymalizowanej wersji kodu

To kod C skompilowana przez GCC 4.1.2

Oto wynik polecenia w katastrofie gDB za "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 

A oto oryginalne źródło funkcji:

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

Dla odniesienia tu jest zakaz zoptymalizowana wersja kodu:

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

Czy sprawdziłeś różnice z niezoptymalizowanym kodem (wyjście zespołu)?Jeśli tak, czy możesz to opublikować? – Macmade

+0

Czy dane wejściowe są ważne? – sehe

+0

Nie sądzę, że dane wejściowe rzeczywiście mają znaczenie ... – Macmade

Odpowiedz

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

Gdy instrukcja andpd przyjmuje argumentu pamięci, to muszą być wyrównane do granicy 16 bajtów.

Dla adresowania zwrotnego, przesunięcie jest stosowane do adresu poniższej instrukcji. Tak więc operand pamięci jest ustawiony na 0x4263ff + 0x169529 = 0x58f928, który nie jest wyrównany do 16 bajtów. Stąd błąd segfault.

Kompilator generuje bezpośrednio kod dla fabs(), używając AND i z odpowiednią maską bitu, aby wyczyścić bit znaku; wartość stała maski bitowej powinna zostać umieszczona przy odpowiednim przesunięciu w odpowiednio wyrównanej sekcji danych, ale jej nie było. Może to być błąd w tej (starej) wersji GCC, lub może być problem związany z linkerem gdzie indziej.

+0

W następstwie tego, twoja odpowiedź jest trafna, okazało się, że jest to błąd linkera w niestandardowym linkerze, którego używamy. Dziękuję za odpowiedź. – laslowh

1

Wydaje odpoczynku po wywołaniu log funkcję:

callq 0x60f098 <[email protected]> 

więc nie może być problem z realizacją fabs, używając -O0.

Czy próbowałeś:

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

To może generować inny montażowej, i można dostać dodatkowe info o katastrofie.

Jako alternatywę można wymienić połączenia fabs z czymś takim:

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

Możesz mieć problemy precyzja z tym, ale nie o to tu chodzi ...

1

Jestem również stosując gcc (GCC) 4.1.2 20070115 (SUSE Linux), tutaj jest generowane montaż:

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 

wydaje się być prawie takie same, ale nie dostać awarię. Myślę, że musisz dostarczyć nam swoje flagi kompilatorów i szczegóły dotyczące procesora i wersji GLIBC oraz wartości a, b i range, które powodują awarię, ponieważ problem jest prawie na pewno związany z rozmową log.

Powiązane problemy