2011-11-28 22 views
10

Mi conocimiento del conjunto de instrucciones intel está un poco oxidado. ¿Puede decirme por qué podría obtener un error de segmentación en la versión optimizada de mi función (puntos de bonificación si puede decirme por qué no lo obtengo en la compilación -O0 del código.SIGSEGV en la versión optimizada del código

Es código C compilado por GCC 4.1.2

Este es el resultado del comando "DISA" del BGF en el accidente:.

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 

Y aquí está la fuente original de la función:

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

Como referencia aquí es la versión no optimizada del código:

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

¿Ha comprobado las diferencias con el código no optimizado (salida de conjunto)?Si es así, ¿puedes publicarlo también? – Macmade

+0

¿Importa la entrada? – sehe

+0

No creo que la entrada realmente importe ... – Macmade

Respuesta

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

Cuando la instrucción andpd toma un operando de memoria, que se requiere para estar alineados con un límite de 16 bytes.

Para %rip -dirección relativa, el desplazamiento se aplica a la dirección de las siguientes instrucciones. Entonces, aquí, el operando de memoria está en 0x4263ff + 0x169529 = 0x58f928, que no está alineado con 16 bytes. De ahí el segfault.

El compilador genera directamente el código para fabs(), usando AND con una máscara de bits apropiada para borrar el bit de signo; el valor constante de la máscara de bits debería haberse colocado en un desplazamiento apropiado en una sección de datos suficientemente alineada, pero no lo ha sido. Esto podría ser un error en esa (antigua) versión de GCC, o podría ser un problema relacionado con el enlazador en otro lugar.

+0

El seguimiento de esto, es que su respuesta es perfecta, resultó ser un error del enlazador en un enlazador no estándar que estamos usando. Gracias por la respuesta. – laslowh

1

Parece para descansar después de la llamada a la función log:

callq 0x60f098 <[email protected]> 

Así que hay tal vez un problema con la implementación fabs, usando -O0.

Ha intentado:

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

Esto puede generar una salida de montaje distinto, y es posible obtener informaciones adicionales sobre el accidente.

Como alternativa, puede reemplazar la llamada fabs con algo como:

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

Es posible que tenga problemas de precisión con eso, pero ese no es el punto aquí ...

1

También soy utilizando gcc (GCC) 4.1.2 20070115 (SUSE Linux), aquí está el ensamblado generado:

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 

parece ser casi lo mismo, pero no consigo un accidente. Creo que deberá proporcionarnos los indicadores del compilador y los detalles de su procesador y la versión GLIBC, y los valores de a, b y range que se bloquean, ya que el problema se debe casi exclusivamente a la llamada log.

Cuestiones relacionadas