2011-11-28 2 views
10

La mia conoscenza del set di istruzioni Intel è un po 'arrugginita. Puoi dirmi perché potrei avere un errore di segmentazione nella versione ottimizzata della mia funzione (punti bonus se puoi dirmi perché non lo ottengo nella build del codice -O0SIGSEGV in versione ottimizzata del codice

È il codice C compilato da GCC 4.1.2

Ecco il risultato del comando di GDB "disas" presso l'incidente:.

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 

Ed ecco la fonte originale della funzione:

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

Per avere un riferimento qui è la versione non ottimizzata del codice:

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

Avete controllato le differenze con il codice non ottimizzato (uscita di montaggio)?Se è così, puoi pubblicarlo anche tu? – Macmade

+0

L'input è importante? – sehe

+0

Non penso che l'input sia effettivamente importante ... – Macmade

risposta

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

Quando l'istruzione andpd prende un operando di memoria, è necessario essere allineati ad un limite di 16 byte.

Per indirizzo %rip, l'offset viene applicato all'indirizzo della seguente istruzione. Quindi, qui, l'operando della memoria è a 0x4263ff + 0x169529 = 0x58f928, che non è allineato a 16 byte. Da qui il segfault.

Il compilatore genera direttamente il codice per fabs(), utilizzando un AND con una maschera bit appropriata per cancellare il bit di segno; il valore costante della maschera di bit avrebbe dovuto essere posizionato in un offset appropriato in una sezione di dati sufficientemente allineata, ma non lo è stato. Questo potrebbe essere un bug in quella (vecchia) versione di GCC, o potrebbe essere probabilmente un problema legato al linker da qualche altra parte.

+0

Il seguito di questo, è che la tua risposta è azzeccata, si è rivelato un bug del linker in un linker non standard che stiamo usando. Grazie per la risposta. – laslowh

1

Sembra per dormire dopo la chiamata alla funzione log:

callq 0x60f098 <[email protected]> 

Quindi c'è forse un problema con il fabs implementazione, utilizzando -O0.

Hai provato:

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

Questo può generare un'uscita completamento diverso, e si possono ottenere ulteriori informazioni riguardo l'incidente.

In alternativa, è possibile sostituire la chiamata fabs con qualcosa di simile:

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

Si possono avere problemi di precisione con quello, ma non è questo il punto qui ...

1

Sono anche utilizzando gcc (GCC) 4.1.2 20070115 (SUSE Linux), ecco l'assembly generato:

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 

sembra essere quasi lo stesso, ma non ottengo un incidente. Penso che dovrai fornirci i flag del compilatore, i dettagli del processore e la versione GLIBC ei valori di a, e range che si bloccano per te, poiché il problema è quasi sicuramente con la chiamata log.