Está en la página 1de 7

Lenguaje ensamblador x86

El lenguaje ensamblador x86 es la familia de los


lenguajes ensambladores para los procesadores de la familia x86, que incluye desde los procesadores Intel 8086
y 8088, pasando por los Pentium de Intel y los Athlon
de AMD y llegando hasta los ltimos procesadores x86
de estas compaas. Como el resto de lenguajes ensambladores, usa una serie de mnemotcnicos para representar las operaciones fundamentales que el procesador puede realizar. Los compiladores a menudo producen cdigo
ensamblador como un paso intermedio cuando traducen
un programa de alto nivel a cdigo mquina. Considerado como un lenguaje de programacin de bajo nivel y
especco para cada mquina. Aunque algunas veces es
usado para software de aplicacin de sistemas de ventanas, los lenguajes ensambladores son utilizados principalmente en aplicaciones crticas como sistemas de arranque, Sistemas Operativos, ncleos y en controladoras de
dispositivos, as como en sistemas en tiempo real o pequeos sistemas embebidos.

procesadores x86, aunque existen algunas excepciones.


Esta compatibilidad se logra gracias al uso de 2 conjuntos de instrucciones de arquitecturas, lo cual es comnmente criticado. La compatibilidad de los programas en
lenguaje ensamblador con procesadores ms antiguos slo es posible cuando el programa no incluye instrucciones
solo disponibles en los procesadores nuevos.

2 Mnemotcnicos y cdigos de operacin

Generalmente, cada nuevo procesador de la serie tiene


unas cuantas instrucciones adicionales y ms capacidades y mejor desempeo que los anteriores. El 286 agreg unas cuantas instrucciones. el modo protegido y capacidad multitarea, el 386 extendi la plataforma de 16 a
32 bits, aadi algunas instrucciones e hizo al conjunto
de instrucciones ms ortogonal, hacindolo la base de los
procesadores siguientes hasta que aparecieron los de 64
bits. Con el 486 se incorpor el coprocesador numrico
en el propio chip, otros procesadores posteriores agregaron instrucciones para acelerar el procesamiento multimedia, multithreading, 2 ms ncleos, 64 bits, etc.

Historia

Los procesadores Intel 8086 y 8088 fueron los primeros


de 16 bits en tener un conjunto de instrucciones conocido actualmente como x86. Fueron un paso evolutivo en
comparacin con la generacin anterior de CPUs de 8
bits, como el 8080 y heredaron muchas caractersticas e
instrucciones, las cuales fueron extendidas para trabajar
con 16 bits. Ambos CPUs contenan un bus de direcciones de 20 bits y un grupo de registros internos de 16 bits.
El 8086 tena un bus de datos externo de 16 bits y el 8088
uno de 8 bits. El 8088 estaba previsto como una versin
de bajo coste del 8086. El lenguaje ensamblador del x86
tambin cubre las diferentes versiones de CPU que siguieron, como el 80188 y 80186, 80286, 80386, 80486,
Pentium, etc, de Intel, tambin como los CPU de AMD y
Cyrix como los procesadores 5x86 y K6, y el NEC V20
de NEC. El trmino x86 aplica a cualquier CPU pueda
correr el lenguaje ensamblador original (usualmente tambin correr por lo menos algunas de las extensiones.

Cada instruccin del x86 est representada por un


mnemotcnico, que traduce directamente a una serie de
bytes la representacin de la instruccin, llamada cdigo
de operacin. Por ejemplo, la instruccin NOP se codica como 0x90 y la instruccin HLT como 0xF4. Algunos
cdigos de operacin no tienen nombres mnemotcnicos
y no estn documentados. Diferentes procesadores en la
familia del x86 pueden interpretar cdigos de operacin
indocumentados de forma distinta, haciendo que un mismo programa se comporte de forma distinta en diferentes
procesadores.

2.1 Sintaxis
El lenguaje ensamblador x86 tiene 2 vertientes diferentes en cuanto a su sintaxis de programacin: sintaxis
Intel, usada en sus inicios para la documentacin de la
plataforma x86, y sintaxis AT&T .[1] La sintaxis Intel es
la dominante en la plataforma Windows, mientras que en
Unix/Linux ambas son utilizadas aunque GCC solo soportaba la sintaxis AT&T en sus primeras versiones.

El moderno conjunto de instrucciones x86 es un superconjunto de las instrucciones del 8086 y el 8088 y una
serie de extensiones a este conjunto de instrucciones que
comenzaron con el microprocesador Intel 8008. Existe
casi una completa compatibilidad binaria desde los chips
Intel 8088 y 8086 con los modernos procesadores Intel
Pentium 4, Intel Core Duo, Intel Core i7, AMD Athlon La mayora de los ensambladores x86 utilizan la sinta64, AMD Opteron, hasta la generacin actual de micro- xis de Intel, como MASM, TASM, NASM, FASM and
1

MODOS DE EJECUCIN

YASM. GAS ha soportado ambas sintaxis desde la ver- Se utilizan dos registros para el direccionamiento: uno
sin 2.10 a travs de la directiva .intel_sintax.[1][2][3]
para indicar el segmento, y el otro para indicar el desplazamiento.

Registros

Para obtener la direccin de memoria (direccin efectiva): se toma el valor de registro de segmento, se desplaza
4 bits a la izquierda (multiplicacin por 16), y se le suma
el valor del desplazamiento.

Los procesadores x86 tienen una serie de registros disponibles para almacenar informacin. Este conjunto de Ejemplo: Si DS contiene 0x000A y DX contiene
registros son conocidos como registros de propsito ge- 0x5F0A, apuntaran a la direccin de memoria: 0x000A
* 0x10 + 0x5F0A = 0x5FAA
neral o GPR (del ingls General Purpose Register).
Adems de los GPR, existen adicionalmente:
registros de segmento (CS, DS, ES, FS, GS, SS)
otros registros (IP, Registro de estado)
registros extra (MMX, 3DNow!, SSE, etc).
El registro IP apunta a la posicin del programa en la que
el procesador est ejecutando el cdigo. EL registro no
puede ser accedido por el programador directamente.
Los registros del x86 pueden ser usados mediante la instruccin MOV. Por ejemplo:
mov ax, 1234h mov bx, ax
copia el valor 1234h en el registro ax y en la siguiente
lnea copia el valor de ax en el registro bx.

Direccionamiento segmentado

La arquitectura x86 utiliza el mtodo de segmentacin


para direccionar memoria, en lugar del mtodo lineal usado en otras arquitecturas. La segmentacin implica descomponer una direccin lineal en dos partes un segmento y un desplazamiento. El segmento apunta al inicio de un bloque de 64K direcciones y el desplazamiento
indica la diferencia entre el lugar apuntado y el inicio del
segmento.

Para referirse a una direccin con un segmento y


un desplazamiento, se utiliza la notacin segmento:
desplazamiento . En el ejemplo anterior, la direccin lineal 0x5FAA se nombrara como 0x000A:0x5F0A, o si
las dos partes se encuentran almacenadas en los registros
mencionados, se podra utilizar el par DS:DX. Hay una
serie de combinaciones especiales entre registros de segmentos y registros generales que apuntan a direcciones
importantes:
CS:IP apunta a la siguiente direccin de cdigo en
la que se posicionar el procesador.
SS:SP apunta al ltimo elemento apilado en la pila.
DS:SI se suele usar para apuntar informacin que va
a ser copiada a ES:DI.

5 Modos de ejecucin
El procesador soporta numerosos modos de operacin
para cdigo x86, en los cules no todas las instrucciones
estn disponibles. Un sub-repertorio de instrucciones de
16-bit est disponible en modo real (disponible en todos los procesadores x86), modo protegido 16-bit (disponible desde el Intel 80286), o en el modo v86 (disponible desde el Intel 80386). Por su parte, las instrucciones de 32-bits estn disponibles para el modo protegido
32-bit y para el modo heredado (disponible con las extensiones de 64 bits). El repertorio de instrucciones parte
de ideas similares en cada modo, pero da lugar a distintas formas de acceso a memoria y de este modo emplea
estrategias de programacin diferentes.

Este modo de direccionamiento se utiliza para aprovechar las caractersticas del procesador. El problema estaba en que los registros internos del procesador eran de 16
bits, mientras que el bus de direcciones era de 20. Faltaban por tanto 4 bits para poder aprovechar al mximo Los modos en los que el cdigo x86 puede ser ejecutado
las capacidades de direccionamiento del procesador. Pa- son:
ra resolver esto, cada direccin de memoria ser especicada como un segmento y un desplazamiento dentro de
Modo real (16-bit)
ese segmento. Esta solucin divide la memoria en segmentos de 64 K, lo cul limit bastante los diseos de los
Modo protegido (16-bit y 32-bit)
procesadores posteriores de la familia (Intel 80286, Intel
80386, etc.); aunque posteriormente se idearon mtodos
Modo 8086 virtual (16-bit)
para resolver este problema, como la memoria extendida
(no compatible con el x86/x88). Con esto se consigue que
System Management Mode (16-bit)
el procesador sea capaz de direccionar 1,048,576 direc Modo largo (64-bit)
ciones de 1 byte, o lo que es lo mismo, 1Mbyte.

6.2

Instrucciones de la ALU con enteros

Tipos de instrucciones

la funcin se retome el programa donde se dej. Esta direccin puede almacenarse en un sitio jo (como hacen
En general, las caractersticas del repertorio de instruc- algunos microcontroladores), pero eso tiene el inconveniente de que si esa funcin a su vez llama a otra funcin
ciones x86 son:
(o a s misma!) podemos sobreescribir la direccin de
retorno anterior, y al regresar de la segunda llamada, no
Una codicacin compacta
podramos volver desde la primera. Adems, es deseable
que la funcin guarde los valores de todos los registros
Longitud variable y alineacin independiente
que vaya a usar en algn sitio, para que el que la llame
(codicacin en formato little endian)
no tenga que preocuparse de ello (pues si sabe que los
Instrucciones de una y dos direcciones, en las registros van a ser modicados, pero no sabe cules, los
que el primer operando es tambin el destino. guardar todos por si acaso). Todas estas cosas, y algunas
Operandos de memoria como origen y des- ms, se hacen con la pila.
tino compatibles (normalmente utilizados pa- El segmento de pila est indicado por SS, y el desplazara leer/escribir elementos de la pila usando pe- miento dentro del segmento, por SP.
queos desplazamientos inmediatos)
Cuando arranca el programa, SP apunta al nal del seg Uso de los registros generales e implcitos; a mento de pila. Para almacenar informacin en la pila se
pesar de que los siete registros generales (con- decrementa SP para que apunte un poco ms arriba y se
tando 'ebp') pueden ser utilizados como acu- copia a esa posicin de memoria, SS:SP. Para sacarlo,
muladores o para direccionar, la mayora de copiamos lo que haya en SS:SP a nuestro destino, e inellos son tambin usados implcitamente por crementamos el puntero.
algunas instrucciones especiales; los registros
afectados deben conservar temporalmente la Como con todo lo que se hace con frecuencia, hay disinformacin, si estn siendo utilizados duran- puestas instrucciones propias para el manejo de la pila.
te el uso de estas instrucciones (normalmente Las dos bsicas son PUSH origen (empujar) y POP destino (sacar). La primera decrementa el puntero de pila y
mediante el uso de la pila).
copia a la direccin apuntada por l (SS:SP) el operando
Produce ags condicionales implcitamente me- origen (de tamao mltiplo de 16 bits), mientras que la
diante el uso de la mayora de instrucciones de la segunda almacena el contenido de la pila (elemento apuntado por SS:SP) en destino y altera el puntero en conseALU
cuencia. Si el operando es de 16 bits se modica en 2 uni Soporta varios modos de direccionamiento
dades, de 32 en 4, etc. Lo que se incrementa/decrementa
es siempre SP, claro, porque SS nos indica dnde est
Incluye punto otante en una pila de registros
ubicado el segmento de pila.
Contiene soporte especial para instrucciones atmi- La instruccin ret size se utiliza para recuperar de la pila
cas (XCHG, CMPXCHG(8B), XADD e instruccio- los valores de IP o de CS e IP dependiendo del caso. Al
salir de un procedimiento es necesario dejar la pila como
nes enteras combinadas con el prejo LOCK)
estaba; para ello podemos utilizar la instruccin pop, o
Instrucciones SIMD (instrucciones que aplican una bien ejecutar la instruccin ret size donde size es el nmisma operacin sobre un conjunto ms o menos mero de posiciones que deben descartarse de la pila.
grande de datos)

6.1

Instrucciones de pila

La pila es un segmento que es de suma utilidad en estos


microprocesadores. En l se almacenan valores temporales como las variables locales de las funciones, o las direcciones de retorno de stas. Una funcin no es ms que
una subrutina, o un fragmento de cdigo al que se le llama
generalmente varias veces desde el programa principal, o
desde una funcin jerrquicamente superior. Cuando se
llama a una funcin se hace un mero salto al punto donde empieza ese cdigo. Sin embargo esa subrutina puede
ser llamada desde distintos puntos del programa principal, por lo que hay que almacenar en algn sitio la direccin desde donde se hace la llamada, cada vez que esa
llamada tiene lugar, para que al nalizar la ejecucin de

6.2 Instrucciones de la ALU con enteros


El ensamblador x86 tiene las operaciones matemticas
estndar, como add, sub, mul, y idiv; los operadores lgicos and, or, xor, neg; desplazamientos, sal/sar, shl/shr;
rotacin con/sin acarreo, rcl/rcr, rol/ror, un complemento
de instrucciones aritmticas BCD, aaa, aad, daa y otras.

6.3 Instrucciones en coma otante


El ensamblador x86 incluye instrucciones para pila basada en unidades en coma otante. Entre ellas se encuentran la suma, resta, negacin, multiplicacin, divisin, resto, races cuadradas, truncamiento entero y truncamiento fraccionado. Las operaciones tambin incluyen

instrucciones de conversin con las que se puede cargar o


almacenar un valor desde memoria a cualquiera de los siguientes formatos: BCD, entero de 32 bits, entero de 64
bits, punto otante de 32 bits, punto otante de 64 bits
u 80 bits. El x86 tambin incluye funciones como seno,
coseno, tangente, arco tangente, exponente con base 2 y
logaritmos de base 2, 10 o e.

FLUJO DEL PROGRAMA

ajustada al tamao del cualquier registro sobre el que est


operando.
Los repertorios de instrucciones x86 incluyen instrucciones de carga, almacenamiento y movimiento de cadenas (LODS, STOS and MOVS) que representan cada
operacin con un tamao especicado (B para bytes, W
para palabras de 16-bits, D para dobles palabras de 32
bits) e incrementan/decrementan el registro de direccin
implcito (SI para LODS, DI para STOS y ambos para
MOVS). Para la carga y almacenamiento, el registro destino/fuente implcito es el AL, AX o EAX, dependiendo
del tamao. El segmento usado implcitamente es DS para LODS, ES para STOS y ambos para MOVS.

La conversin de instrucciones al formato del registro de


pila es normalmente F (OP) st, st(*) o F (OP) st(*), st,
donde st es equivalente a st(0), y st(*) es uno de los 8 registros de pila (st(0), st(1), ..., st(7)). Como con los enteros, el primer operando acta como primera fuente y como operando destino. La suma, resta, multiplicacin, divisin, almacenamiento y comparacin de instrucciones La pila est implementada con un puntero que disminuincluye modos de instruccin que se encargan de desapi- ye (push) y aumenta (pop) implcitamente. En el molar una vez completada la operacin.
do de 16 bits, este puntero se corresponde a la direcEn el caso de que no exista ningn operando, supone des- cin SS:[SP], en 32- bits sera SS:[ESP] y en 64-bits
tino = ST(1), fuente = ST y se hace adems pop sobre la [RSP]. El puntero de pila se encarga de apuntar al lpila, de modo que el resultado se sita en lo alto de la pila. timo valor almacenado, asumiendo que su tamao coinPor ejemplo, FADD calcula ST(1)=ST(1)+ST y hace pop cide con el modo del procesador (12, 32 o 64 bits) para
sobre la pila (incrementando en uno el puntero de pila), que coincida con el ancho por defecto de las instrucciones
con lo que el nuevo elemento en lo alto de la pila contiene PUSH/POP/CALL/RET. Otras instrucciones para maniel resultado.
pular la pila son PUSHF y POPF, que se utilizan para almacenar y recuperar el registro de FLAGS, almacenndolo o retirndolo de la parte alta de la pila.

6.4

Instrucciones SIMD

Los procesadores x86 modernos tienen instrucciones


SIMD, que permiten realizar la misma operacin en paralelo sobre diversos valores codicados en un registro
SIMD. Varias tecnologas de instrucciones soportan diferentes operaciones sobre distintos repertorios de registros, pero todos (desde MMX hasta SSE4,2) incluyen
clculo general sobre aritmtica entera o en coma otante
(suma, resta, multiplicacin, desplazamiento, minimizacin, maximizacin, comparacin, divisin o raz cuadrada). Por ejemplo, PADDW MM0, MM1 aplica 4 sumas
paralelas de enteros de 16 bits (debido a la W que indica
que son palabras) de los valores de mm0 hasta mm1, y
los almacena en mm0. SSE tambin incluye el modo en
coma otante en el que el primer valor de los registros
est modicado (expandido en el SSE2).

6.5

Instrucciones de manipulacin de datos

El procesador x86 tambin incluye modos de direccionamiento complejo para direccionar memoria con un desplazamiento inmediato, un registro, un registro con desplazamiento, un registro escalado con o sin desplazamiento y un registro con desplazamiento opcional y otro registro escalado. Entonces por ejemplo, uno puede codicar
mov eax, [Table + ebx + esi*4] como una instruccin simple que carga 32 bits de datos desde la direccin localizada en el desplazamiento (Table + ebx + esi * 4) desde el
segmento DS, y almacenarla en el registro eax. En general, los procesadores x86 pueden cargar y usar memoria

7 Flujo del programa


El ensamblador x86 tiene una operacin de salto incondicional, jmp, que admite una direccin inmediata, un registro o una direccin indirecta mediante registro como
parmetro.
Tambin se permiten los saltos condicionales, como je
(saltar cuando hay igualdad), jne (saltar en desigualdad),
jg (saltar si 'mayor que', con signo), jl (saltar si 'menor
que', con signo), ja (saltar si 'superior/mayor que', sin
signo), jb (saltar si 'inferior/menor que', sin signo). Estas
operaciones condicionales se basan en el estado especco de los bits del registro de FLAGS. La mayora de las
operaciones aritmticas se encargan de actualizar estos
ags segn su resultado. Las instrucciones de comparacin cmp y test modican el estado del registro de ags
sin modicar los operandos. Las comparaciones en coma
otante se realizan mediante las instrucciones FCOM o
FICOM.
Cada operacin de salto tiene tres formas diferentes, dependiendo del tamao del operando. Un salto sort usa un
operando con signo de 8bits, que se corresponde con el
desplazamiento relativo a la instruccin actual. El salto
near es similar al corto pero usa un operando de 16 o
32 bits con signo. Un salto far utiliza el segmento entero
base:desplazamiento como una direccin total. Tambin
hay forma indirecta e indexada para cada uno de ellos.
Adems de las operaciones de salto, existen las instrucciones call y ret para llamar y regresar de una subrutina.

8.1

Ensambladores

Antes de transferir el control a la subrutina, call apila el


desplazamiento de la instruccin siguiente a la llamada
en la pila; ret desapila este valor de la pila, y transere
el control a la direccin que indicaba el valor desapilado.
En el caso de que se trate de una llamada a una funcin
lejana, far call, la base tambin se apila siguiendo al desplazamiento.

5
Lenguaje de mquina
Conjunto de instrucciones
Diseo CPU
DOS

Existen algunas instrucciones similares, como la interrupcin int. sta activa el procedimiento de interrupcin especicado por el operando y guarda el valor del registro 8.1 Ensambladores
de ags en la pila . La activacin de la interrupcin se realiza mediante una llamada a un procedimiento lejano (far
Comparacin de ensambladores
call), pero en lugar de una direccin, utiliza ese vector
de interrupcin. La direccin de este vector se calcula
High Level Assembly
multiplicando por 4 el operando, que es un valor entre
0 y 255. Normalmente, el manejador de interrupciones
Netwide Assembler
guarda todos los registros que el procesador est usando, a menos que estn siendo usados para almacenar el
Flat assembler
resultado de una operacin. Por otro lado, para volver al
programa desde una interrupcin se utiliza iret, que se
GNU Assembler
encarga de restablecer el valor de los ags. Las interrupciones ligeras descritas anteriormente son usadas por al Microsoft Macro Assembler
gunos sistemas operativos para las llamadas del sistema,
y pueden tambin ser usadas para depurar los manejado RosASM
res de interrupciones fuertes. stas son provocadas por
eventos hardware externos, y deben mantener los valores
GoASM
de todos los registros ya que el estado del programa en
ejecucin se desconoce. En el Modo Protegido, las inte A86 y A386 assemblers
rrupciones pueden ser activadas por el Sistema Operativo
para realizar un cambio de tarea, almacenando automti Turbo Assembler
camente todos los registros de la tarea en ejecucin.
GNU toolchain

Vase tambin
Arquitectura x86
Anexo:Listados de instrucciones x86

8.2 Desensambladores
Interactive Disassembler

Lenguaje ensamblador
Ensamblador
Macro ensamblador
Ensamblador de alto nivel
Lenguaje ensamblador tipeado

8.3 Depuradores
SoftICE
GNU Debugger

Desensamblador

OllyDbg

Compilador

Valgrind

Decompilador
Intrprete (informtica)
Depurador

RosASM
A86 y A386 assemblers

Lenguaje de alto nivel

Data Display Debugger

Lenguaje de bajo nivel

debug (comando)

11 ENLACES EXTERNOS

8.4

Microprocesadores

Antecesores (las races de la arquitectura x86):


1971 Datapoint 2200. Terminal de computadora
programable. Su conjunto de instrucciones es la base de los procesadores Intel desde el 8008 al 8085,
los cuales a su vez son los antecesores de la arquitectura x86
1972 Intel 8008
1974 Intel 8080
1977 Intel 8085
Algunos microprocesadores de la Arquitectura x86:
1978 y 1979 Intel 8086 y 8088. Primeros
microprocesadores de la arquitectura x86

AMD64 Architecture Programmers Manual Volume 2: System Programming (PDF)


AMD64 Architecture Programmers Manual Volume 3: General-Purpose and System Instructions
(PDF)
AMD64 Architecture Programmers Manual Volume 4: 128-Bit Media Instructions (PDF)
AMD64 Architecture Programmers Manual Volume 5: 64-Bit Media and x87 Floating-Point Instructions (PDF)

11 Enlaces externos
An Introduction to Writing 32-bit Applications
Using the x86 Assembly Language
Robys Assembly Programming Tutorial

1980 Intel 8087. Primer coprocesador numrico de


la arquitectura x86, inicio de la serie x87

Novice and Advanced Assembly resources for x86


Platform

1982 Intel 80186 y 80188. Mejoras del 8086 y 8088

x86 Instruction set

1982 Intel 80286. Aparece el modo protegido, tiene


capacidad para multitarea

80x86 instruction set

1985 Intel 80386. Primer microprocesador x86 de


32 bits
1989 Intel 80486. Incorpora el coprocesador numrico en el propio chip
1993 Intel Pentium. Mejor desempeo, arquitectura
superescalar
2003 AMD Opteron. Primer microprocesador x86
de 64 bits, con el conjunto de instrucciones AMD64)

Referencias

[1] Ram Narayam (17 de octubre de 2007). Linux assemblers: A comparison of GAS and NASM. Consultado el
2 de julio de 2008.
[2] Randall Hyde. Which Assembler is the Best?. Consultado el 18 de mayo de 2008.
[3] GNU Assembler News, v2.1 supports Intel syntax. 4 de
abril de 2008. Consultado el 2 de julio de 2008.

10

Seguir leyendo

Intel 64 and IA-32 Software Developer Manuals


AMD64 Architecture Programmers Manual Volume 1: Application Programming (PDF)

Which Assembler is the Best? - A comparison of


x86 assemblers
El universo digital del IBM PC, AT y PS/2, Ciriaco
Garca de Celis

12
12.1

Texto e imgenes de origen, colaboradores y licencias


Texto

Lenguaje ensamblador x86 Fuente: https://es.wikipedia.org/wiki/Lenguaje_ensamblador_x86?oldid=82471241 Colaboradores: El Moska, AlfonsoERomero, Museo8bits, GermanX, Adama~eswiki, CEM-bot, TXiKiBoT, Technopat, Shooke, Muro Bot, Bigsus-bot, LucienBOT, MarcoAurelio, Luckas-bot, Sas16, FrescoBot, TiriBOT, KLBot2, Rotlink, BenjaBot y Annimos: 7

12.2

Imgenes

12.3

Licencia de contenido

Creative Commons Attribution-Share Alike 3.0