code assembler asm c gcc assembly x86 stack

asm - use assembler in c



AsignaciĆ³n de pila, relleno y alineaciĆ³n (6)

He intentado obtener una comprensión más profunda de cómo los compiladores generan códigos de máquina, y más específicamente cómo GCC trata con la pila. Al hacerlo, he estado escribiendo simples programas en C, compilándolos para ensamblar y haciendo todo lo posible por comprender el resultado. Aquí hay un programa simple y la salida que genera:

asmtest.c :

void main() { char buffer[5]; }

asmtest.s :

pushl %ebp movl %esp, %ebp subl $24, %esp leave ret

Lo que me desconcierta es por qué se están asignando 24 bytes para la pila. Sé que debido a la forma en que el procesador aborda la memoria, la pila debe asignarse en incrementos de 4, pero si este fuera el caso, solo deberíamos mover el puntero de la pila en 8 bytes, no en 24. Como referencia, un buffer de 17 los bytes producen un puntero de pila movido 40 bytes y ningún búfer en absoluto mueve el puntero de pila 8. Un búfer entre 1 y 16 bytes inclusive mueve ESP 24 bytes.

Ahora suponiendo que los 8 bytes son una constante necesaria (¿para qué se necesita?), Esto significa que estamos asignando en fragmentos de 16 bytes. ¿Por qué el compilador se estaría alineando de esa manera? Estoy usando un procesador x86_64, pero incluso una palabra de 64 bits solo debería requerir una alineación de 8 bytes. ¿Por qué la discrepancia?

Como referencia, estoy compilando esto en una Mac con 10.5 con gcc 4.0.1 y sin optimizaciones habilitadas.


El Mac OS X / Darwin x86 ABI requiere una alineación de la pila de 16 bytes. Este no es el caso en otras plataformas x86 como Linux, Win32, FreeBSD ...


Encontré este sitio , que tiene una explicación decente en la parte inferior de la página sobre por qué la pila podría ser más grande. Escale el concepto hasta una máquina de 64 bits y podría explicar lo que está viendo.


Es una característica de gcc controlada por -mpreferred-stack-boundary=n donde el compilador intenta mantener elementos en la pila alineados a 2^n . Si cambiaras n a 2 , solo asignaría 8 bytes en la pila. El valor predeterminado para n es 4 es decir, intentará alinearse con los límites de 16 bytes.

¿Por qué hay 8 bytes "por defecto" y luego 24 = 8 + 16 bytes porque la pila ya contiene 8 bytes para leave y ret , por lo que el código compilado debe ajustar la pila primero en 8 bytes para alinearlo a 2 ^ 4 = dieciséis.


La familia de instrucciones SSEx REQUIERE que los vectores empaquetados de 128 bits se alineen con 16 bytes; de lo contrario, obtendrá un segfault tratando de cargarlos / almacenarlos. Es decir, si desea pasar con seguridad vectores de 16 bytes para usarlos con SSE en la pila, la pila debe mantenerse constantemente alineada con 16. GCC lo cuenta de manera predeterminada.


Los 8 bytes están ahí porque la primera instrucción empuja el valor inicial de% ebp en la pila (suponiendo que sea de 64 bits).