2009-12-14 22 views
18

Como dice el título, ¿por qué se usaría "movl $ 1,% eax" en lugar de, por ejemplo, " movb $ 1,% eax ", me dijeron que movl pondría a cero los bits de orden alto de% eax, pero ¿no es un registro equivalente al tamaño del tamaño de palabras del sistema? lo que significa que movl es en realidad una operación entera (¿y no es mucho?)

Estoy claramente un poco confundido acerca de todo esto; Gracias.

Respuesta

3

long era originalmente de 32 bits, mientras que int y short eran 16. Y los nombres de los códigos de operación no cambian cada vez que alguien sale con un nuevo sistema operativo.

+1

¿Qué tiene que ver el lanzamiento de un sistema operativo con las convenciones de nomenclatura de los tipos? –

+0

Era una forma de hablar. La intención era indicar que una vez publicada, la especificación del conjunto de instrucciones no cambia de forma destructiva. –

+0

Es por eso que prefiero la sintaxis Intel a la sintaxis GAS. Intel: mov dword eax, ecx GAS: movl eax, ecx El operando de tamaño "l" confunde a las personas. Más personas entienden que 'dword' significa 32 bits. – Jason

5

%eax es un registro de 32 bits. Para usar un ancho menor, necesita %ax para 16 bits. %ax se puede dividir además en %ah para el byte alto de %ax, y %al para el byte inferior. Lo mismo ocurre con los otros GPR x86.

Si observamos la instrucción del conjunto de instrucciones Intel para la instrucción mov, no veo una variante que pueda mover un solo byte en un registro de 32 bits; probablemente se interprete como un movimiento en %al.

Desde movl es una instrucción de 32 bits, los valores de los bytes superiores corresponderán a ceros en el caso de un valor inmediato. Si se estuviera moviendo de la memoria, estaría moviendo una palabra completa de 32 bits.

%eax no se pone a cero a menos que sea movl $0, %eax, o si xorl %eax, %eax. De lo contrario, contiene cualquier valor que haya estado allí anteriormente. Cuando movl $1, %eax, terminará con 0x00000001 en el registro porque la instrucción de 32 bits mueve un valor inmediato de 32 bits en el registro.

+0

Que movl es una instrucción de 32 bits es en parte la respuesta que estaba buscando, pero otra respuesta que estoy preguntando es si% eax de forma predeterminada no está "a cero" o no está declarado? –

+1

% eax nunca se pone a cero a menos que explícitamente lo haga. Si usa movb para simplemente escribir en uno de los bytes, los otros bytes no cambian. –

7

En una máquina de 32 bits,% eax es un registro de 4 bytes (32 bits). movl escribirá en los 4 bytes. En su ejemplo, pondrá a cero los 3 bytes superiores y colocará 1 en el byte más bajo. La movb solo cambiará el byte de orden bajo.

+0

¿Entonces movl es una operación de 4 bytes? –

+0

No estoy seguro de qué ensamblador es, pero ¿no es la única diferencia el tamaño de la constante? – peterchen

+2

Sí. En la arquitectura IA32 (generalmente llamada x86), "largo" significa 4 bytes, y movl significa "mover largo". –

1

%eax es 32 bits en máquinas de 32 bits. %ax es de 16 bits, y %ah y %al son sus componentes altos y bajos de 8 bits.

Por lo tanto, movl es perfectamente válido aquí. Efficiency-wise, movl será tan rápido como movb, y poner a cero los 3 bytes altos de %eax es a menudo una propiedad deseable. Es posible que desee utilizarlo como un valor de 32 bits más tarde, por lo que movb no es una buena manera de mover un byte allí.

36

diferencia de, digamos, "movb $ 1,% eax"

Esta instrucción no es válida. No puedes usar eax con la instrucción movb. En su lugar, utilizaría un registro de 8 bits. Por ejemplo:

movb $ 1, $ al

pero no es% eax un registro que es equivalente al tamaño de wordsize del sistema?

No. EAX siempre tendrá un valor de 32 bits, independientemente del tamaño de registro del sistema.

Está confundiendo tamaños de variable C con tamaños de registro. Los tamaños variables C pueden cambiar dependiendo de su sistema y compilador.

El montaje es más simple que C. En el ensamblaje GAS, las instrucciones tienen las letras "b", "s", "w", "l", "q" o "t" para determinar el tamaño del operando. manipulado.

* b = byte (8 bit) 
* s = short (16 bit integer) or single (32-bit floating point) 
* w = word (16 bit) 
* l = long (32 bit integer or 64-bit floating point) 
* q = quad (64 bit) 
* t = ten bytes (80-bit floating point) 

Estos tamaños son constantes. Ellos nunca serán cambiados. al es siempre de 8 bits y eax siempre es de 32 bits.

+0

¡Buena respuesta, gracias! –

2

Su segunda opción producirá un error, x86 no tiene esa instrucción. X86 es un poco único con respecto a cargar bytes en ciertos registros. Sí, en la mayoría de las arquitecturas de conjuntos de instrucciones, el operando es cero o extendido, pero x86 le permite escribir solo el byte inferior o 16 bits más bajos de algunos de ellos.

Ciertamente hay otras opciones, como la limpieza del registro y luego incrementarlo, pero aquí hay tres opciones inicialmente razonables de aspecto tiene:

0: b8 01 00 00 00   movl $0x1,%eax 

    5: 31 c0     xorl %eax,%eax 
    7: b0 01     movb $0x1,%al 

    9: b0 01     movb $0x1,%al 
    b: 0f b6 c0    movzbl %al,%eax 

La primera es de 5 bytes, el segundo 4, el tercer 5. Por lo tanto, el segundo es la mejor opción para optimizar el espacio; de lo contrario, supongo que el que corre más rápido es el primero. En la actualidad, el X86 está profundamente canalizado, de modo que las dos instrucciones se entrelazarán y la máquina puede necesitar bastantes estados de espera dependiendo de los detalles del hardware de la tubería.

Por supuesto, estas operaciones x86 se están traduciendo en formas específicas de la CPU en CPU micro-ops, y por lo que sabe lo que sucederá.

+0

Muy buena respuesta, muy explicativa. Gracias –

Cuestiones relacionadas