2008-10-23 23 views
59

%AX = (%AH + %AL)¿Por qué no hay un registro que contiene los bytes más altos de EAX?

¿Por qué no %EAX = (%SOME_RESTIER + %AX) por algún registro %SOME_REGISTER?

+1

¿Podría dar más detalles? – BCS

+6

corrección menor, EAX no es igual a AX, más exactamente, AX representa los 16 bits inferiores (mitad) de EAX. del mismo modo, AH y AL son las dos mitades de AX. –

+0

@EvanTeran ¿Es posible obtener la mitad superior de EAX así como la mitad inferior? –

Respuesta

128

Solo por alguna aclaración. En los primeros días del microprocesador de la década de 1970, las CPU tenían solo un pequeño número de registros y un conjunto de instrucciones muy limitado. Típicamente, la unidad aritmética solo podría operar en un único registro de CPU, a menudo denominado "acumulador". El acumulador en los procesadores 8080 & Z80 de 8 bits se denominó "A". Había otros 6 registros de 8 bits de propósito general: B, C, D, E, H & L. Estos seis registros podrían emparejarse para formar 3 registros de 16 bits: BC, DE & HL. Internamente, el acumulador se combinó con el registro de Flags para formar el registro AF de 16 bits.

Cuando Intel desarrolló la familia de 16 bits 8086 que querían ser capaces de portar código 8080, por lo que mantiene la misma estructura de registro básica:

8080/Z80 8086 
A   AX 
BC  BX 
DE  CX 
HL  DX 
IX  SI  
IY  DI 

Debido a la necesidad de portar código de 8 bits que necesitaban poder referirse a las partes individuales de 8 bits de AX, BX, CX & DX. Se llaman AL, AH para los bytes altos & de AX y así sucesivamente para BL/BH, CL/CH & DL/DH. IX & IY en el Z80 solo se usaban como registros de puntero de 16 bits, por lo que no era necesario acceder a las dos mitades de SI & DI.

Cuando el 80386 fue lanzado a mediados de 1980 se creó "extendida" versiones de todos los registros. Entonces, AX se convirtió en EAX, BX se convirtió en EBX, etc. No hubo necesidad de acceder a los 16 bits superiores de estos nuevos registros extendidos, por lo que no crearon un pseudoregistro EAXH.

AMD aplicó el mismo truco cuando se produjeron los primeros procesadores de 64 bits. La versión de 64 bits del registro AX se llama RAX. Así pues, ahora usted tiene algo que se parece a esto:

|63..32|31..16|15-8|7-0| 
       |AH.|AL.| 
       |AX.....| 
     |EAX............| 
|RAX...................| 
+0

Generalmente, no hay ninguna explicación sobre por qué no hay un pseudoregistro. por ejemplo 31..16 porción de EAX. Supongo que no era necesario ... – Calyth

+5

En realidad, hay una 'característica' no documentada en el Z80 (que de hecho no es un chip Intel) que le permite abordar el IX y el IY como bytes altos y bajos. El código de operación es un prefijo + un código de operación HL; si usa un código de operación H o L, obtiene el efecto de media palabra. – ijw

+1

diría, regístrese correspondencia es de la misma familia: 8080/Z80, 8086, 86 Codificación: Un AX 000 aC CX 001 DE DX 010 HL BX 011 IX SI 110 IY DI 111 – noop

25

En los viejos días de 8 bits, estaba el registro A.

En los días de 16 bits, estaba el registro AX de 16 bits, que se dividió en dos partes de 8 bits, AH y AL, para aquellos momentos en los que aún deseaba trabajar con valores de 8 bits.

En los días de 32 bits, se introdujo el registro EAX 32 bits, pero el AX, AH, y los registros se mantienen todos AL. Los diseñadores no consideraron necesario introducir un nuevo registro de 16 bits que abordara los bits 16 a 31 de EAX.

+0

Actualmente continúa con registros de 64 bits, el registro RAX de 64 bits incluye EAX como los 32 bits más bajos. – Ferruccio

+2

'E' y 'X' podrían significar "Extendido", pero ¿qué significa la 'R' en RAX? –

+28

Venganza. La venganza de EAX. –

20

Hay una gran cantidad de respuestas publicadas aquí, pero ninguno realmente responden a la pregunta dada: ¿Por qué no hay un registro que codifica directamente las altas de 16 bits EAX, o los 32 bits altos de RAX? La respuesta se reduce a las limitaciones de la codificación de la instrucción x86.

16-Bit lección de historia

Cuando Intel diseñó el 8086, se utilizó un esquema de codificación de longitud variable para muchas de las instrucciones. Esto significaba que ciertas instrucciones extremadamente comunes, como POP AX, podrían representarse como un solo byte (58), mientras que las instrucciones raras (pero potencialmente útiles) como MOV CX, [BX*4+BP+1023] podrían representarse, incluso si se necesitaron varios bytes para almacenarlas (en este ejemplo, 8B 8C FF 03).

Esto puede parecer una solución razonable, pero cuando lo diseñaron, llenaron la mayor parte del espacio disponible. Así, por ejemplo, hubo ocho POP instrucciones para los ocho registros individuales (AX, CX, DX, BX, SP, BP, SI, DI), y completaron códigos de operación 58 a 5F, y código de operación 60 era algo completamente distinto (PUSHA), al igual que el código de operación 57 (PUSH DI). No queda espacio para nada después o antes de eso. Incluso empujar y hacer estallar los registros del segmento, que es conceptualmente casi idéntico a empujar y hacer estallar los registros de propósito general, tuvo que codificarse en una ubicación diferente (alrededor de 06/0E/16/1E) simplemente porque no había espacio al lado el resto de las instrucciones push/pop.

Del mismo modo, el byte "mod r/m" utilizado para una instrucción compleja como MOV CX, [BX*4+BP+1023] solo tiene tres bits para codificar el registro, lo que significa que solo puede representar ocho registros en total. Eso está bien si solo tienes ocho registros, pero presenta un problema real si quieres tener más.

(Hay un excelente mapa de todas estas asignaciones de bytes en la arquitectura x86 aquí: http://i.imgur.com/xfeWv.png. Observe cómo no queda espacio en el mapa principal, con algunas instrucciones superponiendo bytes, e incluso la cantidad del mapa secundario "0F" se utiliza ahora gracias a las instrucciones MMX y SSE.)

hacia 32 y 64 Bits

lo tanto, para permitir que incluso el diseño de CPU que se extendía desde 16 bits a 32 bits, que ya tenían un problema de diseño , y lo resolvieron con prefijo bytes: Al agregar un byte especial "66" en fro nt de todas las instrucciones estándar de 16 bits, la CPU sabe que desea la misma instrucción, pero la versión de 32 bits (EAX) en lugar de la versión de 16 bits (AX). El resto del diseño permaneció igual: solo había ocho registros generales de propósito general en la arquitectura general de la CPU.

hackery similares tenía que ser hecho de extender la arquitectura de 64-bits (RAX y amigos); de ahí, el problema se resolvió mediante la adición de otro conjunto de códigos de prefijo (REX, 40-4F) que significaba "64-bit" (y efectivamente añadió otros dos bits para el campo "mod r/m"), y también descartar extraño viejas instrucciones que nadie usó nunca y reutilizando sus códigos de bytes para cosas más nuevas.

Un Aparte de 8 bits Registra

Una de las cuestiones más importantes que hacer, entonces, es cómo las cosas Heck como AH y AL jamás trabajaron en el primer lugar si sólo hay realmente habitación en el diseño para ocho registros. La primera parte de la respuesta es que no existe el "PUSH AL": ¡algunas instrucciones simplemente no pueden operar en los registros del tamaño de un byte! Los únicos que pueden están algunas rarezas especiales (como AAD y XLAT) y versiones especiales de las instrucciones de "mod r/m": Al tener un poco muy específico volteado en el byte "mod r/m", los "instrucciones avanzadas "podría voltearse para operar en los registros de 8 bits en lugar de los de 16 bits. Ocurre que también hay exactamente ocho registros de 8 bits: AL, CL, DL, BL, AH, CH, DH y BH (en ese orden), y eso se alinea muy bien con las ocho ranuras de registro disponibles en el byte "mod r/m".

Intel notó en ese momento que se suponía que el diseño 8086 era "compatible con la fuente" con el 8080/8085: había una instrucción equivalente en el 8086 para cada una de las instrucciones 8080/8085, pero no usó los mismos códigos de bytes (ni siquiera están cerca), y tendría que recompilar (volver a montar) su programa para que use los nuevos códigos de bytes. Pero la "fuente compatible" era un camino a seguir para el viejo software, y permitía los A, B, C, etc. individuales del 8085.y combo "BC" y "DE" registra para seguir trabajando en el nuevo procesador, incluso si ahora se llamaran "AL" y "BL" y "BX" y "DX" (o lo que sea que el mapeo fue).

Así que esa es realmente la verdadera respuesta: no es que Intel o AMD intencionalmente "dejen fuera" un registro alto de 16 bits para EAX, o un registro alto de 32 bits para RAX: es que los registros de 8 bits son una extraña anomalía histórica, y replicar su diseño en tamaños de bits más altos sería realmente difícil dado el requisito de que la arquitectura sea compatible con versiones anteriores.

Una consideración acerca del rendimiento

Hay otra consideración de por qué esos "altos registros" no se han añadido ya que, así: Dentro de arquitecturas de procesadores modernos, por razones de rendimiento, los registros de tamaño variable en realidad no se superponen: AH y AL no son parte de AX, y AX no es parte de EAX, y EAX no es parte de RAX: todos son registros separados bajo el capó, y el el procesador establece un indicador de invalidación en los otros cuando manipula uno de ellos para que sepa que deberá copiar los datos cuando lea de los demás.

(Por ejemplo: Si se establece AL = 5, el procesador no actualiza AX Pero si a continuación, se leen de AX, el procesador rápidamente copias que el 5 de AL en bits inferiores de AX..)

Por manteniendo los registros separados, la CPU puede hacer todo tipo de cosas inteligentes como el cambio de nombre de registro invisible para hacer que su código se ejecute más rápido, pero eso significa que su código ejecuta más lento si utiliza el patrón anterior de tratar los registros pequeños como piezas de registros más grandes, porque el procesador deberá detenerlos y actualizarlos. Para evitar que toda esta contabilidad interna se salga de control, los diseñadores de CPU sabiamente optaron por agregar registros separados en los procesadores más nuevos en lugar de agregar más registros superpuestos.

(Y sí, eso significa que lo que realmente es más rápido en los procesadores modernos de forma explícita "MOVZX EAX, value" que hacerlo de la manera antigua, más descuidado de "MOV AX, value/use EAX".)

Conclusión

Con Dicho todo esto, ¿Intel y AMD podrían agregar más registros "superpuestos" si realmente quisieran? Por supuesto. Hay formas de atraparlos si hay suficiente demanda. Pero dado el importante bagaje histórico, las limitaciones arquitectónicas actuales, las notables limitaciones de rendimiento y el hecho de que la mayoría de los códigos actualmente son generados por compiladores optimizados para registros que no se superponen, es muy poco probable que agreguen tales cosas en el corto plazo.

+1

Lectura muy interesante. +1 – Boann

+1

Solo [familias de uarch Intel P6/SnB renombran sub registros por separado] (http://agner.org/optimize/). En las CPU AMD e Intel Atom/Silvermont/P4, escribir a AL tiene una dependencia falsa del contenido anterior de EAX (incluso si nunca lee el registro completo). Sin embargo, no obtiene puestos de registro parcial para escribir AL y luego leer EAX. (Intel IvB elimina las penalizaciones por fusión parcial-reg para mitades bajas (AL/BL/...), mientras que Haswell elimina las penalizaciones incluso para AH/BH/... Así que obtienes el beneficio completo de las cadenas de depósito separadas para escribir reglas parciales sin pagar ningún costo de fusión.) –

+2

Creo que hubiera sido interesante para AMD64 dividir RAX en registros de 8 bytes, en lugar de proporcionar acceso al byte bajo de cada registro. Así que podría 'movzx ecx, eax {5}' o algo así, descomprimir el 5to byte para usarlo como un índice de matriz. Es inusual necesitar una gran cantidad de registros de bytes; Es más común querer desempacar una carga de 64 bits en múltiples bytes. 'setcc' podría haberse cambiado para tomar un operando r/m32, para eliminar la necesidad de xor-zeroing del registro superior y ese caso de uso para la necesidad de escribir el byte inferior de cada registro posible. Difiere del modo compat = más transistores:/ –

Cuestiones relacionadas