Arquitectura x86
El procesador Intel x86 usa una arquitectura compleja del equipo del conjunto de instrucciones (CISC), lo que significa que hay un número modesto de registros de propósito especial en lugar de grandes cantidades de registros de uso general. También significa que las instrucciones complejas de propósito especial prevalecerán.
El procesador x86 traza su patrimonio al menos hasta el procesador Intel 8080 de 8 bits. Muchas peculiaridades del conjunto de instrucciones x86 se deben a la compatibilidad con versiones anteriores con ese procesador (y con su variante Zilog Z-80).
Microsoft Win32 usa el procesador x86 en modo plano de 32 bits. Esta documentación solo se centrará en el modo plano.
Registros
La arquitectura x86 consta de los siguientes registros enteros sin privilegios.
eax |
Acumulador |
ebx |
Registro base |
ecx |
Registro de contadores |
edx |
Registro de datos: se puede usar para el acceso a puertos de E/S y funciones aritméticas |
Esi |
Registro de índice de origen |
EDI |
Registro de índice de destino |
ebp |
Registro de puntero base |
Esp |
Puntero de pila |
Todos los registros enteros son de 32 bits. Sin embargo, muchos de ellostienens de 16 o 8 bits.
hacha |
Bajo 16 bits de eax |
Bx |
16 bits bajos de ebx |
cx |
16 bits bajos de ecx |
dx |
16 bits bajos de edx |
si |
16 bits bajos de esi |
di |
16 bits bajos de edi |
BP |
16 bits bajos de ebp |
Sp |
Poco 16 bits de esp |
al |
Bajo 8 bits de eax |
ah |
Alto de 8 bits de ax |
bl |
8 bits bajos de ebx |
Bh |
Alto de 8 bits de bx |
Cl |
8 bits bajos de ecx |
Ch |
Alto de 8 bits de cx |
dl |
8 bits bajos de edx |
Dh |
Alto de 8 bits de dx |
El funcionamiento de un conjunto de datos afecta solo al subsestor y a ninguna de las partes fuera de la colección. Por ejemplo, el almacenamiento en el registro de ejes deja sin cambios los 16 bits altos del registro de eax .
Cuando se usa ? (Evaluar expresión) command, los registros deben tener como prefijo un signo "at" ( @ ). Por ejemplo, debe usar ? @ax en lugar de ? ax. Esto garantiza que el depurador reconozca ax como un registro en lugar de un símbolo.
Sin embargo, el comando (@) no es necesario en el comando r (Registers). Por ejemplo, r ax=5 siempre se interpretará correctamente.
Otros dos registros son importantes para el estado actual del procesador.
eip |
puntero de instrucción |
flags |
flags |
El puntero de instrucción es la dirección de la instrucción que se está ejecutando.
El registro de marcas es una colección de marcas de un solo bit. Muchas instrucciones modifican las marcas para describir el resultado de la instrucción. Estas marcas se pueden probar mediante instrucciones de salto condicional. Consulte marcas x86 para obtener más información.
Convenciones de llamada
La arquitectura x86 tiene varias convenciones de llamada diferentes. Afortunadamente, todos siguen las mismas reglas de devolución de función y conservación de registros:
Las funciones deben conservar todos los registros, excepto eax, ecx y edx, que se pueden cambiar en una llamada de función, y esp, que se deben actualizar según la convención de llamada.
El registro eax recibe valores devueltos de función si el resultado es de 32 bits o menor. Si el resultado es de 64 bits, el resultado se almacena en el par edx:eax .
A continuación se muestra una lista de las convenciones de llamada que se usan en la arquitectura x86:
Win32 (__stdcall)
Los parámetros de función se pasan en la pila, se insertan de derecha a izquierda y el destinatario limpia la pila.
Llamada de método nativa de C++ (también conocida como thiscall)
Los parámetros de función se pasan en la pila, se insertan de derecha a izquierda, el puntero "this" se pasa en el registro ecx y el destinatario limpia la pila.
COM (__stdcall para llamadas de método de C++)
Los parámetros de función se pasan en la pila, se insertan de derecha a izquierda, luego se inserta el puntero "this" en la pila y, a continuación, se llama a la función. El destinatario limpia la pila.
__fastcall
Los dos primeros argumentos DWORD o más pequeños se pasan en los registros ecx y edx . Los parámetros restantes se pasan en la pila, insertados de derecha a izquierda. El destinatario limpia la pila.
__cdecl
Los parámetros de función se pasan en la pila, se insertan de derecha a izquierda y el autor de la llamada limpia la pila. La convención de llamada __cdecl se usa para todas las funciones con parámetros de longitud variable.
Visualización del depurador de registros y marcas
Este es un ejemplo de visualización del registro del depurador:
eax=00000000 ebx=008b6f00 ecx=01010101 edx=ffffffff esi=00000000 edi=00465000
eip=77f9d022 esp=05cffc48 ebp=05cffc54 iopl=0 nv up ei ng nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000286
En la depuración en modo de usuario, puede omitir iopl y toda la última línea de la pantalla del depurador.
Marcas x86
En el ejemplo anterior, los códigos de dos letras al final de la segunda línea son marcas. Estos son registros de un solo bit y tienen una variedad de usos.
En la tabla siguiente se enumeran las marcas x86:
Código de marca | Nombre del marcador | Valor | Estado de marca | Descripción |
---|---|---|---|---|
de | Marca de desbordamiento | 0 1 | nvov | Sin desbordamiento: desbordamiento |
df | Marca de dirección | 0 1 | updn | Dirección hacia arriba: dirección hacia abajo |
if | Marca de interrupción | 0 1 | diei | Interrupciones deshabilitadas: interrupciones habilitadas |
sf | Marca de firma | 0 1 | plng | Positivo (o cero): negativo |
zf | Marca cero | 0 1 | nzzr | Distinto de cero: cero |
af | Marca de transporte auxiliar | 0 1 | naac | Sin transporte auxiliar: transporte auxiliar |
pf | Marca de paridad | 0 1 | Pepo | Paridad impar: paridad |
cf | Marca de transporte | 0 1 | nccy | Sin transporte - Llevar |
tf | Marca de captura | Si tf es igual a 1, el procesador generará una excepción de STATUS_SINGLE_STEP después de la ejecución de una instrucción. Un depurador usa esta marca para implementar el seguimiento de un solo paso. No debe usarse en otras aplicaciones. | ||
iopl | Nivel de privilegios de E/S | Nivel de privilegios de E/S Este es un entero de dos bits, con valores entre cero y 3. El sistema operativo lo usa para controlar el acceso al hardware. Las aplicaciones no deben usarla. |
Cuando los registros se muestran como resultado de algún comando en la ventana Comando del depurador, es el estado de marca que se muestra. Sin embargo, si desea cambiar una marca mediante el comando r (Registers), debe hacer referencia a ella mediante el código de marca.
En la ventana Registros de WinDbg, el código de marca se usa para ver o modificar marcas. No se admite el estado de la marca.
A continuación se muestra un ejemplo: En la presentación del registro anterior, aparece el estado de la marca ng . Esto significa que la marca de signo está establecida actualmente en 1. Para cambiar esto, use el siguiente comando:
r sf=0
Esto establece la marca de signo en cero. Si hace otra presentación de registro, el código de estado ng no aparecerá. En su lugar, se mostrará el código de estado pl .
La marca de signo, la marca cero y la marca de transporte son las marcas más usadas.
Condiciones
Una condición describe el estado de una o varias marcas. Todas las operaciones condicionales de x86 se expresan en términos de condiciones.
El ensamblador usa una o dos abreviaturas de letra para representar una condición. Una condición se puede representar mediante varias abreviaturas. Por ejemplo, AE ("arriba o igual") es la misma condición que NB ("no a continuación"). En la tabla siguiente se enumeran algunas condiciones comunes y su significado.
Nombre de condición | Flags | Significado |
---|---|---|
Z |
ZF=1 |
El resultado de la última operación era cero. |
NZ |
ZF=0 |
El resultado de la última operación no era cero. |
C |
CF=1 |
La última operación requería una operaciones de transporte o préstamo. (Para enteros sin signo, esto indica desbordamiento). |
NC |
CF=0 |
La última operación no requería una operaciones de transporte o préstamo. (Para enteros sin signo, esto indica desbordamiento). |
S |
SF=1 |
El resultado de la última operación tiene su conjunto de bits alto. |
NS |
SF=0 |
El resultado de la última operación tiene su bit alto claro. |
O |
OF=1 |
Cuando se trata como una operación de entero con signo, la última operación provocó un desbordamiento o subflujo. |
NO |
OF=0 |
Cuando se trata como operación de entero con signo, la última operación no provocó un desbordamiento o subflujo. |
Las condiciones también se pueden usar para comparar dos valores. La instrucción cmp compara sus dos operandos y, a continuación, establece marcas como si restasen un operando del otro. Las condiciones siguientes se pueden usar para comprobar el resultado de cmp value1, value2.
Nombre de condición | Flags | Significado después de una operación de CMP. |
---|---|---|
E |
ZF=1 |
value1 == value2. |
NE |
ZF=0 |
value1 != value2. |
GE NL | SF=OF |
value1>= value2. Los valores se tratan como enteros con signo. |
LE NG | ZF=1 o SF!=OF |
value1<= value2. Los valores se tratan como enteros con signo. |
G NLE | ZF=0 y SF=OF |
value1>value2. Los valores se tratan como enteros con signo. |
L NGE | SF!=OF |
value1<value2. Los valores se tratan como enteros con signo. |
AE NB | CF=0 |
value1>= value2. Los valores se tratan como enteros sin signo. |
BE NA | CF=1 o ZF=1 |
value1<= value2. Los valores se tratan como enteros sin signo. |
Una NBE | CF=0 y ZF=0 |
value1>value2. Los valores se tratan como enteros sin signo. |
B NAE | CF=1 |
value1<value2. Los valores se tratan como enteros sin signo. |
Normalmente, las condiciones se usan para actuar sobre el resultado de una instrucción cmp o test . Por ejemplo,
cmp eax, 5
jz equal
compara el registro eax con el número 5 calculando la expresión (eax - 5) y estableciendo marcas según el resultado. Si el resultado de la resta es cero, se establecerá la marca zr y la condición jz será true para que se tome el salto.
Tipos de datos
byte: 8 bits
word: 16 bits
dword: 32 bits
qword: 64 bits (incluye doubles de punto flotante)
tword: 80 bits (incluye doubles extendidos de punto flotante)
oword: 128 bits
Notación
En la tabla siguiente se indica la notación utilizada para describir las instrucciones del lenguaje de ensamblado.
Notación | Significado |
---|---|
r, r1, r2... |
Registros |
m |
Dirección de memoria (consulte la sección Modos de direccionamiento correctos para obtener más información). |
#n |
Constante inmediata |
r/m |
Registro o memoria |
r/#n |
Registro o constante inmediata |
r/m/#n |
Registro, memoria o constante inmediata |
Cc |
Código de condición enumerado en la sección Condiciones anteriores. |
T |
"B", "W" o "D" (byte, word o dword) |
accT |
Acumulador T de tamaño: al if T = "B", ax if T = "W" o eax if T = "D" |
Modos de direccionamiento
Hay varios modos de direccionamiento diferentes, pero todos toman la forma T ptr [expr], donde T es un tipo de datos (consulte la sección Tipos de datos anteriores) y expr es una expresión que implica constantes y registros.
La notación para la mayoría de los modos se puede deducir sin mucha dificultad. Por ejemplo, BYTE PTR [esi+edx*8+3] significa "tomar el valor del registro esi , agregarlo ocho veces el valor del registro edx , agregar tres y, a continuación, acceder al byte en la dirección resultante".
Pipelining
Pentium es de doble problema, lo que significa que puede realizar hasta dos acciones en un tic de reloj. Sin embargo, las reglas de cuando es capaz de realizar dos acciones a la vez (conocidas como emparejamiento) son muy complicadas.
Dado que x86 es un procesador CISC, no tiene que preocuparse por las ranuras de retraso de salto.
Acceso a memoria sincronizada
Las instrucciones de carga, modificación y almacenamiento pueden recibir un prefijo de bloqueo , que modifica la instrucción de la siguiente manera:
Antes de emitir la instrucción, la CPU vaciará todas las operaciones de memoria pendientes para garantizar la coherencia. Todas las capturas previas de datos se abandonan.
Al emitir la instrucción, la CPU tendrá acceso exclusivo al autobús. Esto garantiza la atomicidad de la operación load/modify/store.
La instrucción xchg obedece automáticamente las reglas anteriores cada vez que intercambia un valor con memoria.
Todas las demás instrucciones son predeterminadas para no interbloquear.
Predicción de saltos
Se predicen saltos incondicionales.
Se predicen saltos condicionales que se van a tomar o no, en función de si se tomaron la última vez que se ejecutaron. La memoria caché del historial de saltos de grabación tiene un tamaño limitado.
Si la CPU no tiene un registro de si se tomó o no el salto condicional la última vez que se ejecutó, predice los saltos condicionales hacia atrás según se toman y reenvía los saltos condicionales como no se toman.
Alineación
El procesador x86 corregirá automáticamente el acceso a la memoria no asignada, con una penalización de rendimiento. No se genera ninguna excepción.
Un acceso a memoria se considera alineado si la dirección es un entero múltiplo del tamaño del objeto. Por ejemplo, todos los accesos BYTE están alineados (todo es un entero múltiplo de 1), los accesos de WORD a direcciones uniformes están alineados y las direcciones DWORD deben ser un múltiplo de 4 para alinearse.
El prefijo de bloqueo no debe usarse para los accesos a memoria no asignados.
Comentarios
https://aka.ms/ContentUserFeedback.
Próximamente: A lo largo de 2024 iremos eliminando gradualmente GitHub Issues como mecanismo de comentarios sobre el contenido y lo sustituiremos por un nuevo sistema de comentarios. Para más información, vea:Enviar y ver comentarios de