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 [2013/05/16 22:58] cnigri Se incorpora la version borrador de las directivas |
— (actual) | ||
---|---|---|---|
Línea 1: | Línea 1: | ||
- | ====== Guía de supervivencia de ensamblador ====== | ||
- | {{ 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 basto 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 ===== | ||
- | ===== 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 ; | ||
- | </ | ||
- | ===== 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 sunció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. Parte del código realizar alguna operación sobre una variable, observemos que ocurre con y sin la utilización de **//ORG//** | ||
- | * **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> | ||
- | | ||
- | | ||
- | | ||
- | ... | ||
- | |||
- | | ||
- | </ | ||
- | * **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 ==== | ||
- | * **EXTERN :** | ||
- | * **GLOBAL :** | ||
- | ===== 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 resw 1 ; | ||
- | Mi_var_short resb 2 ;Otra opcion de lo anterior | ||
- | Mi_var_long | ||
- | 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, | ||
- | |||
- | ===== 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 | ||
- | * Linea simple: es el caso más básico de macros, el cual permite realizar la definición en una única línea utilizando la directiva **// | ||
- | <code asm> | ||
- | | ||
- | </ | ||
- | * Lineas múltiples: 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:// | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||