Intel x86 Assembly Language & Microarchitecture
Flujo de control
Buscar..
Saltos incondicionales
jmp a_label ;Jump to a_label
jmp bx ;Jump to address in BX
jmp WORD [aPointer] ;Jump to address in aPointer
jmp 7c0h:0000h ;Jump to segment 7c0h and offset 0000h
jmp FAR WORD [aFarPointer] ;Jump to segment:offset in aFarPointer
Relativo a saltos cercanos.
jmp a_label es:
- cerca
Solo especifica la parte de desplazamiento de la dirección lógica de destino. Se supone que el segmento esCS. - relativo
La instrucción semántica es jump rel bytes adelante 1 de la siguiente dirección de instrucción oIP = IP + rel.
La instrucción se codifica como EB <rel8> o EB <rel16/32> , y el ensamblador toma la forma más adecuada, por lo general prefiere una más corta.
La anulación por ensamblador es posible, por ejemplo con NASM jmp SHORT a_label , jmp WORD a_label y jmp DWORD a_label generan las tres formas posibles.
Absolutos saltos indirectos cercanos.
jmp bx y jmp WORD [aPointer] son:
- cerca
Solo especifican la parte de desplazamiento de la dirección lógica de destino. Se supone que el segmento esCS. - absoluto indirecto
La semántica de las instrucciones es saltar a la dirección en reg o mem oIP = reg,IP = mem.
La instrucción se codifica como FF /4 , para la memoria indirecta, el tamaño del operando se determina como para cualquier otro acceso a la memoria.
Saltos lejanos absolutos
jmp 7c0h:0000h es:
lejos
Especifica ambas partes de la dirección lógica : el segmento y el desplazamiento.absoluto La semántica de la instrucción es saltar al segmento de dirección : desplazamiento o
CS = segment, IP = offset.
La instrucción se codifica como EA <imm32/48> según el tamaño del código.
Es posible elegir entre las dos formas en algún ensamblador, por ejemplo con NASM jmp 7c0h: WORD 0000h y jmp 7c0h: DWORD 0000h genera la primera y la segunda forma.
Saltos lejanos indirectos absolutos
jmp FAR WORD [aFarPointer] es:
Lejos Especifica ambas partes de la dirección lógica : el segmento y el desplazamiento.
Absoluto indirecto La semántica de la instrucción es saltar al segmento: desplazamiento almacenado en mem 2 o
CS = mem[23:16/32], IP = [15/31:0].
La instrucción se codifica como FF /5 , el tamaño del operando puede ser controlador con los especificadores de tamaño.
En NASM, un poco no intuitivo, son jmp FAR WORD [aFarPointer] para un operando 16:16 y jmp FAR DWORD [aFarPointer] para un operando 16:32 .
Saltos faltantes
casi absoluto
Puede ser emulado con un salto casi indirecto.mov bx, target ;BX = absolute address of target jmp bxpariente lejano
No tiene sentido o es demasiado estrecho de uso de todos modos.
1 Dos complementos se utilizan para especificar un desplazamiento firmado y, por lo tanto, saltar hacia atrás.
2, que puede ser un seg16: off16 o seg16: off32 , de tamaños 16:16 y 16:32 .
Condiciones de prueba
Para utilizar un salto condicional se debe probar una condición. La prueba de una condición aquí se refiere solo al acto de verificar las banderas, el salto real se describe en Saltos condicionales .
x86 prueba las condiciones basándose en el registro EFLAGS, que contiene un conjunto de indicadores que cada instrucción puede establecer potencialmente.
Las instrucciones aritméticas, como sub o add , y las instrucciones lógicas, como xor y and , obviamente, "establecen las banderas". Esto significa que las banderas CF , OF , SF , ZF , AF , PF son modificadas por esas instrucciones. Sin embargo, cualquier instrucción puede modificar los indicadores, por ejemplo, cmpxchg modifica la ZF .
Siempre revise la referencia de la instrucción para saber qué indicadores son modificados por una instrucción específica.
x86 tiene un conjunto de saltos condicionales , referidos anteriormente, que saltan si y solo si algunos indicadores están establecidos o algunos son claros o ambos.
Banderas
Las operaciones aritméticas y lógicas son muy útiles para establecer las banderas. Por ejemplo, después de un sub eax, ebx , que ahora tiene valores sin firmar , tenemos:
| Bandera | Cuando se establece | Cuando claro |
|---|---|---|
| ZF | Cuando el resultado es cero. EAX - EBX = 0 ⇒ EAX = EBX | Cuando el resultado no es cero. EAX - EBX ≠ 0 ⇒ EAX ≠ EBX |
| CF | Cuando el resultado fue necesario llevar para el MSb. EAX - EBX <0 ⇒ EAX <EBX | Cuando el resultado no fue necesario llevar para el MSb. EAX - EBX ≮ 0 ⇒ EAX ≮ EBX |
| SF | Cuando se establece el resultado MSb. | Cuando el resultado MSb no se establece. |
| DE | Cuando se produjo un desbordamiento firmado. | Cuando no se produjo un desbordamiento firmado. |
| PF | Cuando el número de bits establecido en el byte menos significativo del resultado es par. | Cuando el número de bits establecido en el byte menos significativo del resultado es impar. |
| AF | Cuando el dígito BCD inferior genera un carry. Es bit 4 carry. | Cuando el dígito BCD inferior no generó un acarreo. Es bit 4 carry. |
Ensayos no destructivos.
El sub y and instrucciones que modifican su operando destino y requerirían dos copias adicionales (guardar y restaurar) para mantener el destino sin modificar.
Para realizar una prueba no destructiva hay las instrucciones cmp y test . Son idénticos a sus homólogos destructivos, excepto que el resultado de la operación se descarta y solo se guardan las banderas .
| Destructivo | No destructivo |
|---|---|
sub | cmp |
and | test |
test eax, eax ;and eax, eax
;ZF = 1 iff EAX is zero
test eax, 03h ;and eax, 03h
;ZF = 1 if both bit[1:0] are clear
;ZF = 0 if at least one of bit[1:0] is set
cmp eax, 241d ;sub eax, 241d
;ZF = 1 iff EAX is 241
;CF = 1 iff EAX < 241
Pruebas firmadas y no firmadas.
La CPU no da un significado especial para registrar los valores 1 , signo es una construcción de programador. No hay diferencia cuando se prueban valores firmados y no firmados. El procesador calcula suficientes indicadores para probar las relaciones aritméticas habituales (igual, menor que, mayor que, etc.) tanto si los operandos se consideraran firmados como no firmados.
1 Aunque tiene algunas instrucciones que solo tienen sentido con formatos específicos, como el complemento de dos. Esto es para hacer que el código sea más eficiente, ya que la implementación del algoritmo en el software requeriría una gran cantidad de código.
Saltos condicionales
Según el estado de las banderas, la CPU puede ejecutar o ignorar un salto. Una instrucción que realiza un salto basado en las banderas cae bajo el nombre genérico de Jcc - Salta en el Código de condición 1 .
Sinónimos y terminología
Para mejorar la legibilidad del código de ensamblaje, Intel definió varios sinónimos para el mismo código de condición. Por ejemplo, jae , jnb y jnc tienen el mismo código de condición CF = 0 .
Si bien el nombre de la instrucción puede dar una idea muy clara de cuándo usarlo o no, el único enfoque significativo es reconocer los indicadores que deben probarse y luego elegir las instrucciones de manera adecuada.
Sin embargo, Intel dio los nombres de las instrucciones que tienen perfecto sentido cuando se usan después de una instrucción cmp . Para los propósitos de esta discusión, se asumirá que cmp ha establecido las banderas antes de un salto condicional.
Igualdad
El operando es igual si ZF se ha establecido, de lo contrario difieren. Para probar la igualdad necesitamos ZF = 1 .
je a_label ;Jump if operands are equal
jz a_label ;Jump if zero (Synonym)
jne a_label ;Jump if operands are NOT equal
jnz a_label ;Jump if not zero (Synonym)
| Instrucción | Banderas |
|---|---|
je , jz | ZF = 1 |
jne jnz | ZF = 0 |
Mas grande que
Para los operandos sin firmar , el destino es mayor que el origen si no se necesita carry, es decir, si CF = 0 . Cuando CF = 0 es posible que los operandos fueran iguales, la prueba de ZF se desambiguará.
jae a_label ;Jump if above or equal (>=)
jnc a_label ;Jump if not carry (Synonym)
jnb a_label ;Jump if not below (Synonym)
ja a_label ;Jump if above (>)
jnbe a_label ;Jump if not below and not equal (Synonym)
| Instrucción | Banderas |
|---|---|
jae , jnc , jnb | CF = 0 |
ja , jnbe | CF = 0, ZF = 0 |
Para los operandos firmados debemos verificar que SF = 0 , a menos que haya un desbordamiento firmado, en cuyo caso el SF resultante se invierte. Dado que OF = 0 si no se produjo un desbordamiento firmado y 1 de lo contrario, debemos verificar que SF = OF .
ZF se puede utilizar para implementar una prueba estricta / no estricta.
jge a_label ;Jump if greater or equal (>=)
jnl a_label ;Jump if not less (Synonym)
jg a_label ;Jump if greater (>)
jnle a_label ;Jump if not less and not equal (Synonym)
| Instrucción | Banderas |
|---|---|
jge , jnl | SF = OF |
jg , jnle | SF = OF, ZF = 0 |
Menos que
Estos utilizan las condiciones invertidas de arriba.
jbe a_label ;Jump if below or equal (<=)
jna a_label ;Jump if not above (Synonym)
jb a_label ;Jump if below (<)
jc a_label ;Jump if carry (Synonym)
jnae a_label ;Jump if not above and not equal (Synonym)
;SIGNED
jle a_label ;Jump if less or equal (<=)
jng a_label ;Jump if not greater (Synonym)
jl a_label ;Jump if less (<)
jnge a_label ;Jump if not greater and not equal (Synonym)
| Instrucción | Banderas |
|---|---|
jbe jna | CF = 1 o ZF = 1 |
jb jc jnae | CF = 1 |
jle , jng | SF! = OF o ZF = 1 |
jl , jnge | SF! = OF |
Banderas especificas
Cada bandera se puede probar individualmente con j<flag_name> donde nombre de bandera no contiene la F posterior (por ejemplo, CF → C , PF → P ).
Los códigos restantes no cubiertos antes son:
| Instrucción | Bandera |
|---|---|
js | SF = 1 |
jns | SF = 0 |
jo | OF = 1 |
jno | OF = 0 |
jp , jpe (e = par) | PF = 1 |
jnp , jpo (o = impar) | PF = 0 |
Un salto más condicional (extra)
Un salto condicional especial x86 no prueba la bandera. En su lugar, prueba el valor del registro cx o ecx (basado en que el modo de dirección de la CPU actual es de 16 o 32 bits), y el salto se ejecuta cuando el registro contiene cero.
Esta instrucción fue diseñada para la validación del registro de contador ( cx/ecx ) antes de las instrucciones similares a las rep , o antes de loop bucles de loop .
jcxz a_label ; jump if cx (16b mode) or ecx (32b mode) is zero
jecxz a_label ; synonym of jcxz (recommended in source code for 32b target)
| Instrucción | Registro (no bandera) |
|---|---|
jcxz , jecxz | cx = 0 (modo 16b) |
jcxz , jecxz | ecx = 0 (modo 32b) |
1 O algo así.
Probar relaciones aritméticas
Enteros sin firmar
Mas grande que
cmp eax, ebx
ja a_label
Mayor que o igual
cmp eax, ebx
jae a_label
Menos que
cmp eax, ebx
jb a_label
Menor o igual
cmp eax, ebx
jbe a_label
Igual
cmp eax, ebx
je a_label
No es igual
cmp eax, ebx
jne a_label
Enteros firmados
Mas grande que
cmp eax, ebx
jg a_label
Mayor que o igual
cmp eax, ebx
jge a_label
Menos que
cmp eax, ebx
jl a_label
Menor o igual
cmp eax, ebx
jle a_label
Igual
cmp eax, ebx
je a_label
No es igual
cmp eax, ebx
jne a_label
a_label
En los ejemplos anteriores, a_label es el destino de destino para la CPU cuando la condición probada es "verdadera". Cuando la condición probada es "falsa", la CPU continuará en la siguiente instrucción después del salto condicional.
Sinónimos
Hay sinónimos de instrucciones que pueden usarse para mejorar la legibilidad del código.
Por ejemplo, ja y jnbe (Saltar no por debajo ni igual) son la misma instrucción.
Códigos de acompañante firmados y sin firmar.
| Operación | No firmado | Firmado |
|---|---|---|
| > | ja | jg |
| > = | jae | jge |
| < | jb | jl |
| <= | jbe | jle |
| = | je | je |
| ≠,! =, <> | jne | jne |