2010-12-20 6 views
5

Cuando compilo el código C o C++ con las optimizaciones habilitadas, d GCC alinea las funciones a un límite de 16 bytes (en IA-32). Si la función es menor que 16 bytes, CCG pastillas con un poco de bytes, que no parecen ser al azar en absoluto:Valor de relleno de función de GCC

19: c3      ret 
1a: 8d b6 00 00 00 00  lea 0x0(%esi),%esi 

Siempre parece ser 8d b6 00 00 00 00 ... o 8d 74 26 00.

¿Los bytes de relleno de función tienen algún significado?

+0

Mi comprensión es/fue que GCC usa 0s para el relleno de alineación de funciones, pero como no puedo indicarle una fuente que probablemente no sea muy útil ... – William

Respuesta

6

El relleno está creado por el ensamblador, no por gcc. Simplemente ve una directiva .align (o equivalente) y no sabe si el espacio que debe rellenarse está dentro de una función (por ejemplo, alineación de bucle) o entre funciones, por lo que debe insertar NOP de algún tipo. Los ensambladores x86 modernos usan los códigos de operación NOP más grandes posibles con la intención de pasar el menor número posible de ciclos si el relleno es para la alineación del lazo.

Personalmente, soy extremadamente escéptico de la alineación como una técnica de optimización. Nunca lo he visto de mucha ayuda, y definitivamente puede doler al aumentar enormemente el tamaño total del código (y la utilización de la memoria caché). Si usa el nivel de optimización -Os, está desactivado de manera predeterminada, por lo que no hay nada de qué preocuparse. De lo contrario, puede deshabilitar todas las alineaciones con las opciones apropiadas de -f.

+0

Parece que eso es correcto. La salida '-S' no tiene operaciones de relleno no-ops. –

2

La instrucción lea 0x0(%esi),%esi simplemente carga el valor en %esi en %esi - es no-operación (o NOP), lo que significa que si se ejecuta no tendrá ningún efecto.

Esto simplemente es una instrucción única, NOP de 6 bytes. 8d 74 26 00 es solo una codificación de 4 bytes de la misma instrucción.

+0

Pero no es una instrucción alcanzable (después de 'ret') , ¿Lo es? –

+0

@Alex B: no es directamente alcanzable (pero se podría saltar a). A menudo hay razones para producir un relleno ejecutable dentro de las funciones, por lo que es probable que GCC simplemente reutilice el mismo algoritmo de relleno para el final de las funciones. – caf

1

El ensamblador primero ve una directiva .align. Como no sabe si esta dirección está dentro de un cuerpo de función o no, no puede generar NULL 0x00 bytes, y debe generar NOP s (0x90).

Sin embargo:

lea esi,[esi+0x0] ; does nothing, psuedocode: ESI = ESI + 0 

ejecuta en un menor número de ciclos de reloj que

nop 
nop 
nop 
nop 
nop 
nop 

Si este código pasó a caer dentro de un cuerpo de la función (por ejemplo, la alineación de bucle), la versión lea sería mucho más rápido, sin dejar de "hacer nada".

Cuestiones relacionadas