Diferencias
Muestra las diferencias entre dos versiones de la página.
Ambos lados, revisión anterior Revisión previa Próxima revisión | Revisión previa | ||
td3:guiasupervivenciaasm [2018/02/17 17:48] jamontenegro |
— (actual) | ||
---|---|---|---|
Línea 1: | Línea 1: | ||
- | ====== Guía de supervivencia de ensamblador ====== | ||
- | |||
- | ** EN CONSTRUCCION ** | ||
- | |||
- | {{td3: | ||
- | |||
- | ===== Descargo ===== | ||
- | La redacción de una guía que permita aprender el lenguaje ensamblador es una tarea que no escapa al principio de incertidumbre de Heisenberg\\ | ||
- | \\ //Si el lenguaje se enseña rápidamente, | ||
- | \\ Para los menos amantes de la cuántica se puede decir que una guía de supervivencia de lenguaje ensamblador, | ||
- | \\ Por lo expresado de manera irónica en los párrafos anteriores, esta guía no pretende ser un texto que trate de forma exhaustiva los por menores del lenguaje ensamblador detallando el vasto conjunto de instrucciones de la [[http:// | ||
- | |||
- | ===== Introducción ===== | ||
- | Esta guía solo cubre la sintaxis NASM y el conjunto de instrucciones IA32 | ||
- | |||
- | ===== Registros de la familia IA ===== | ||
- | {{ td3: | ||
- | |||
- | ^ | ||
- | ^ principal | ||
- | ^ Acumulador | ||
- | ^ Puntero a datos en DS | bx ; bh ; bl | ebx ; bx ; bh ; bl | rbx ; ebx ; bx ; bl | mov ; bt ; cpuid ; in ; out ; pop ; push ; | | ||
- | ^ Contador | ||
- | ^ Puntero a I/O | dx ; dh ; dl | edx ; dx ; dh ; dl | rdx ; edx ; dx ; dl | mov ; bt ; cpuid ; pop ; push ; | | ||
- | ^ Indice origen o puntero a datos en DS | si | esi | rsi | mov ; movs ; pop ; push ; | | ||
- | ^ Indice destino o puntero a datos en ES | di | edi | rdi | mov ; movs ; pop ; push ; | | ||
- | ^ Puntero/ | ||
- | ^ Puntero a datos de pila (SS) | bp | ebp | rbp | mov ; pop ; push ; | | ||
- | ^ Uso general | ||
- | ^ Segmento/ | ||
- | ^ Segmento/ | ||
- | ^ Segmento/ | ||
- | ^ Indicador de estado | ||
- | ^ Puntero a instruccion | ||
- | ^ Registros de control | ||
- | ^ Punteros a tablas de sistema | ||
- | ^ Multimedia | ||
- | ^ Depuracion | ||
- | |||
- | ===== Instrucciones básicas ===== | ||
- | * Asignación: | ||
- | <code asm> mov ;Move </ | ||
- | * Comparación: | ||
- | <code asm> | ||
- | cmp ; | ||
- | test ;Logical Compare | ||
- | </ | ||
- | * Salto: | ||
- | * Condicionales en función del estado de un bit de bandera particular | ||
- | <code asm> | ||
- | * Absolutos | ||
- | <code asm> | ||
- | jmp ;Jump near/long | ||
- | </ | ||
- | * Binarias: operan bit a bit | ||
- | <code asm> | ||
- | and ; | ||
- | or ;Logical Inclusive OR | ||
- | xor ; | ||
- | not ; | ||
- | </ | ||
- | * Aritméticas: | ||
- | <code asm> | ||
- | add ;Add | ||
- | adc ;Add with Carry | ||
- | sub ; | ||
- | sbb ; | ||
- | inc ; | ||
- | dec ; | ||
- | clc ; | ||
- | mul ; | ||
- | div ; | ||
- | </ | ||
- | * Stack: operan con la pila, introduciendo y recuperando valores | ||
- | <code asm> | ||
- | pop ;Pop a Value from the Stack | ||
- | push ;Push Word, Doubleword or Quadword onto the Stack | ||
- | popf ;Pop Stack into FLAGS Register | ||
- | pushf ;Push FLAGS Register onto the Stack | ||
- | popad ;Pop All General-Purpose Registers | ||
- | </ | ||
- | * Desplazamiento: | ||
- | <code asm> | ||
- | shr ; | ||
- | shl ; | ||
- | ror ; | ||
- | rol ; | ||
- | </ | ||
- | |||
- | ===== Constantes, variables y tipos ===== | ||
- | ==== Constantes ==== | ||
- | La definición de un simbolo asociado a una constante se realiza mediante la pseudo instrucción **//EQU//** | ||
- | <code asm> SEL_CODE EQU 0x08 ;El simbolo SEL_CODE se reemplazara en cada uso por el valor 0x08</ | ||
- | ==== Variables ==== | ||
- | En ensamblador el concepto de variable es meramente figurativo, ya que esta no es más que un espacio identificado en memoria. Analicémoslo mediante los siguientes ejemplos: | ||
- | * Tomando la analogía con el bien conocido lenguaje C, si se quiere definir un **// | ||
- | <code asm> Mi_var_char resb 1 ; | ||
- | |||
- | Si además de definir la variable se quiere inicializar, | ||
- | <code asm> Mi_var_char db 0xA5 ;Variable inicializada </ | ||
- | |||
- | * Aplicando el mismo criterio se utilizan **//resw, resq, rest, dw, dq, dt//** | ||
- | <code asm> | ||
- | Mi_var_short | ||
- | Mi_var_short | ||
- | Mi_var_long | ||
- | Mi_var_string db ' | ||
- | Mi_var_long | ||
- | </ | ||
- | |||
- | ==== Tipos ==== | ||
- | En ciertas ocasiones es conveniente disponer de un arreglo de memoria con un formato específico, | ||
- | <code asm> | ||
- | struc | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | endstruc | ||
- | </ | ||
- | |||
- | Al igual que una variable, una estructura puede ser instanciada con o sin inialización, | ||
- | <code asm> | ||
- | Gdt_desc_nulo: | ||
- | at gdtd_t.limite, | ||
- | at gdtd_t.base00_15, | ||
- | at gdtd_t.base16_23, | ||
- | at gdtd_t.prop, | ||
- | at gdtd_t.lim_prop, | ||
- | at gdtd_t.base24_31, | ||
- | | ||
- | |||
- | Gdt_desc_extra: | ||
- | | ||
- | </ | ||
- | |||
- | Debido a que la carga de un valor en un campo de una estructura requiere cierta lógica, la misma se explica a continuación mediante un simple ejemplo, utilizando la estructura instanciada previamente. | ||
- | <code asm> mov [Gdt_desc_extra+gdtd_t.base00_15], | ||
- | |||
- | Como se explicara anteriormente, | ||
- | |||
- | ===== Directivas ===== | ||
- | Se denomina directiva a toda órden que se le da al programa ensamblador propiamente dicho y que no tiene una traducción a código de máquina. | ||
- | En este apartado se describen aquellas directivas que pueden ser catalogadas como de uso general, dejando aquellas de aplicación específica para los apartados correspondientes. | ||
- | |||
- | ==== Organización del binario ==== | ||
- | Como es bien sabido uno de los objetivos del proceso de ensamblado es generar un fichero binario que sea la copia fiel de la imagen a cargar en la memoria del μP, ya sea esta RAM o ROM, para su ejecución. Para organizar la forma en la cual el fichero binario se debe ubicar en la memoria el ensamblador dispone de las siguientes directivas | ||
- | * **ORG :** acrónimo de origen en inglés, se utiliza para especificar la dirección inicial, a partir de la cual el ensamblador asume que el binario se cargará en memoria. Esta asunción le permite al ensamblador calcular las direcciones de todas las etiquetas, no solo desplazadas respecto al inicio del código, sino tambión teniendo en cuenta la ubicación en memoria del mismo. Para ejemplificar lo comentado, tomemos el caso en el que el binario se ubica en memoria a partir de la dirección 0x7C00. Analizando el fichero //.lst// se observa, como era de esperar, que todas la direcciones se encuentran relativas respecto al inicio del código (recordar que Intel trabaja con formato //little indian//), sin embargo al visualizar el binario resultante mediante algún editor hexadecimal, | ||
- | <code asm> | ||
- | +-----------------------------------------------------------------+ | ||
- | | .lst sin ORG |.bin sin ORG | | ||
- | +--------------------------------------------------+--------------+ | ||
- | | 1 | | | ||
- | | 2 00000000 55AA | ||
- | | 3 00000002 55AA | ||
- | | 4 | | | ||
- | | 5 00000004 EB03 jmp ETIQUETA | ||
- | | 6 00000006 A3[0000] | ||
- | | 7 | ||
- | | 8 00000009 A3[0000] | ||
- | +--------------------------------------------------+--------------+ | ||
- | | .lst con ORG |.bin con ORG | | ||
- | +--------------------------------------------------+--------------+ | ||
- | | 1 ORG 0x7C00 | ||
- | | 2 00000000 55AA | ||
- | | 3 00000002 55AA | ||
- | | 4 | | | ||
- | | 5 00000004 EB03 jmp ETIQUETA | ||
- | | 6 00000006 A3[0000] | ||
- | | 7 | ||
- | | 8 00000009 A3[0000] | ||
- | +--------------------------------------------------+--------------+ | ||
- | </ | ||
- | * **SECTION :** permite especificar el tipo de memoria que debe ser utilizada, el detalle sobre que se entiende como tipos de memoria se puede encontrar en [[ td3: | ||
- | <code asm> | ||
- | | ||
- | | ||
- | | ||
- | ... | ||
- | |||
- | | ||
- | ;Aqui se deberia colocar la primer instruccion del programa | ||
- | </ | ||
- | * **BITS :** especifica el tipo de código de operación por el cual el ensamblador debe reemplazar cada instrucción. En el siguiente ejmplo se puede observar claramente como la instrucción que corresponde con el tipo nativo, no presenta ningún prefijo y como si lo hacen aquellas, cuyos operandos no corresponden con la arquitectura especificada | ||
- | <code asm> | ||
- | 1 00000000 55AA variable dw 0xAA55 | ||
- | | ||
- | | ||
- | 4 00000002 | ||
- | 5 00000005 66A3[0000] | ||
- | | ||
- | | ||
- | 8 00000009 66A3[00000000] | ||
- | 9 0000000F | ||
- | 10 | ||
- | 11 bits 64 | ||
- | 12 00000014 66890425[00000000] | ||
- | 13 0000001C | ||
- | 14 00000023 48890425[00000000] | ||
- | </ | ||
- | |||
- | ==== Enlace del binario ==== | ||
- | * **%include :** se utiliza de manera muy similar a **//# | ||
- | * **EXTERN :** permite declarar un símbolo (variable, función) que no se encuentre definido en el código a ser ensamblado. | ||
- | * **GLOBAL :** permite declarar un símbolo (variable, función), que es referenciado por otro módulo, de manera que el enlazador (// | ||
- | Para una mejor comprensión de estas directivas se recomienda leer [[td3: | ||
- | |||
- | ===== Secuencias de repetición ===== | ||
- | Las secuencias de repetición son un mecanismo provisto por la herramienta de ensamblaje, para evitar que el programador escriba en forma repetitiva líneas de código idénticas o muy similares. Es muy importante tener en cuenta que la utilización de esta metodología puede incrementar en forma considerable el tamaño del binario resultante. | ||
- | * **TIMES :** esta pseudo instrucción, | ||
- | <code asm> | ||
- | +---------------------------+------------------------------------------------------------------------------+ | ||
- | |.asm con TIMES | .lst con TIMES |.bin con TIMES | | ||
- | +---------------------------+--------------------------------------------------------------+---------------+ | ||
- | |bits 32 | 1 bits 32 | ||
- | |NULO_SEL: TIMES 8 db 1 | 2 00000000 01< | ||
- | | | 3 |01 01 01 01 01 | | ||
- | |TIMES 2 mov eax, [NULO_SEL]| 4 00000008 A1[00000000]< | ||
- | | | ||
- | +---------------------------+--------------------------------------------------------------+---------------+ | ||
- | </ | ||
- | * **Par %rep y %endrep :** a diferencia de **// | ||
- | <code asm> | ||
- | +-----------------------------+------------------------------------------------------------------------------+ | ||
- | |.asm con %rep & %endrep | ||
- | +-----------------------------+--------------------------------------------------------------+---------------+ | ||
- | | 1 bits 32 | ||
- | | 2 NULO_SEL: | ||
- | | 3 %rep 2 | ||
- | | 4 db 0xA | ||
- | | 5 dw 0x5 | ||
- | | 6 %endrep | ||
- | | | ||
- | | | ||
- | | | ||
- | | | 10 00000004 0500 < | ||
- | | | 11 | ||
- | | 7 %rep 4 | 12 %rep 4 | | | ||
- | | 8 mov eax, [NULO_SEL]| 13 mov eax, [NULO_SEL] | ||
- | |10 %endrep | ||
- | | | 15 00000006 A1[00000000] | ||
- | | | 16 0000000B A1[00000000] | ||
- | | | 17 00000010 A1[00000000] | ||
- | | | 18 00000015 A1[00000000] | ||
- | +-----------------------------+--------------------------------------------------------------+---------------+ | ||
- | </ | ||
- | |||
- | ===== Macros ===== | ||
- | En los apartados precedentes se indicó que el preprocesador utilizaba macros para realizar ciertas definiciones, | ||
- | A modo de recordatorio se define como //macro una secuencia de instrucciones que pueden ser invocadas mediante una única sentencia// | ||
- | A diferencia de las funciones la utilización de macros genera un incremento en el tamaño del código y por ende en el binario final, sin embargo tienen la ventaja de aumentar la legibilidad del código y por lo general aumentar la velocidad de ejecución respecto al mismo código implementado por función. | ||
- | Por lo general existen dos tipos de macros | ||
- | ==== Línea simple ==== | ||
- | Es el caso más básico de macros, el cual permite realizar la definición en una única línea utilizando diferentes directivas según el objetivo a realizar. | ||
- | === %define === | ||
- | Esta macro permite definir no solo valores numéricos, sino también secuencias de operaciones. En este último caso es importante que la secuencia se encuentre entre paréntesis, | ||
- | <code asm> | ||
- | | ||
- | | ||
- | </ | ||
- | === %assign === | ||
- | Es una opción algo más reducida a **// | ||
- | <code asm> | ||
- | | ||
- | | ||
- | dd i|(PAG_PRES+PAG_WRTEN+PAG_USREN); | ||
- | %assign i i+PAG_SIZE | ||
- | | ||
- | </ | ||
- | === align === | ||
- | Esta macro, como su nombre en inglés lo indica, permite alinear código o datos, a partir de la dirección múltiplo de 2< | ||
- | <code asm> | ||
- | ; | ||
- | |||
- | ; | ||
- | align 0x1000 | ||
- | | ||
- | | ||
- | .... | ||
- | | ||
- | align 65536 ;Alineacion cada 65kB para reservar el tamaño maximo de la GDT | ||
- | | ||
- | | ||
- | .... | ||
- | | ||
- | </ | ||
- | |||
- | ==== Líneas múltiples ==== | ||
- | Este tipo de macros permite realizar secuencias más complejas y emplea las directivas **// | ||
- | |||
- | Como es costumbre se explicará la utilización de macros mediante un ejemplo, el cual tiene por objetivo inicializar la instancia // | ||
- | El primer paso es definir la macro | ||
- | * **gdtdescini: | ||
- | * **Argumento 1:** Direccion de la base del segmento. Valor maximo soportado 2^32. | ||
- | * **Argumento 2:** Tamaño del segmento. Valor maximo soportado 2^20. | ||
- | * **Argumento 3:** Propiedades P; | ||
- | * **Argumento 4:** Propiedades G;D/B;L;AVL | ||
- | * **Argumento 5:** Direccion de inicio del descriptor a ser inicializado. | ||
- | |||
- | <code asm> | ||
- | %macro gdtdescini 5 ;Nombre y numero de argumentos | ||
- | push ebx ;Se almacena el valor del registro | ||
- | xor ebx, ebx | ||
- | | ||
- | mov ebx, %1 ;Se carga EL PRIMER ARGUMENTO (la direccion) en ebx | ||
- | mov [%5+gdtd_t.base00_15], | ||
- | shr ebx, 16 | ||
- | mov [%5+gdtd_t.base16_23], | ||
- | |||
- | xor ebx, ebx | ||
- | mov ebx, %2 ;Se carga EL SEGUNDO ARGUMENTO EN ebx | ||
- | mov [%5+gdtd_t.limite], | ||
- | shr ebx, 16 ;Se adapta el restante nibble y | ||
- | mov [%5+gdtd_t.lim_prop], | ||
- | |||
- | xor bl, bl | ||
- | mov bl, %3 ;Se carga el primer byte | ||
- | mov [%5+gdtd_t.prop], | ||
- | |||
- | xor bl, bl | ||
- | mov bl, %4 ;Se carga el nibble EL CUARTO ARGUMENTO | ||
- | shl bl, 4 ;Se desplaza al nibble mas significativo | ||
- | or [%5+gdtd_t.prop], | ||
- | |||
- | pop ebx | ||
- | %endmacro | ||
- | </ | ||
- | |||
- | La utilización es extremadamente sencilla, por ejemplo si se quisiera inicializar el descriptor mencionado anteriormente para direccionar la memoria de video, bastaría con el siguiente codigo | ||
- | <code asm> gdtdescini 0B8000h, 4000, 10010011b, 0b, Gdt_desc_extra </ | ||
- | |||
- | --- // | ||
- | ===== Referencias ===== | ||
- | * [[http:// | ||
- | * [[http:// | ||
- | * [[http:// | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||