Compartir a través de


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:

  1. 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.

  2. 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.