APÈNDIX: ENSAMBLADOR LINUX

Documentos relacionados
movl $var, %eax movl $0xf02, %ebx movb var, %ah movw %bx, %ax mov ebx, eax movl %ebx, %eax movl 3(%ebx), %eax

Conceptos de Arquitectura de Computadoras Curso 2015

El Diseño de un Lenguaje Máquina

Construyendo Programas más Complejos

Aprendiendo Sistemas Operativos: Programación de Procesadores de Arquitectura IA-32

Resumen de las instrucciones del 8086/8088

Tema 5.1: Presentación de datos en pantalla

Objetivo. Introducción. Tema: GENERACION DE CODIGO. Compiladores, Guía 11 1

Práctica 1. Introducción a la programación en ensamblador

ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA

ESCUELA POLITÉCNICA SUPERIOR PRÁCTICA 2: EXPRESIONES, PRINTF Y SCANF

Instrucción De Salto Incondicional

8.4. El software en los μprocesadores

Intel Arquitectura. Programación en Ensamblador Ing. Marcelo Tosini

Arquitectura (Procesador familia 80 x 86 )

Apellidos Nombre DNI

DOCUMENTACIÓN PARA EL TRABAJO CON LA PLATAFORMA GUADALBOT

Introducción a la Computación. Capítulo 10 Repertorio de instrucciones: Características y Funciones

Todo programa en 'C' consta de una o más funciones, una de las cuales se llama main.

Fundamentos de Arquitectura y Código Máquina

Explicación didáctica sobre comandos de Linux: Comandos de Inicio

Fundamentos de Computadores

Examen de Arquitectura de Computadores 2 22 de febrero del 2011

Sobre cómo dividir un programa ensamblador x86 (modo Real) en módulos compilables por separado.

Fig. 1: Tipos de datos que puede manejar el procesador

Principios de Computadoras II

Arquitectura intel Preámbulo de OSO para alumnos formados en el procesador MIPS. Asignatura Sistemas Operativos Murcia abril de 2005

Tema 3 SUBRUTINAS. Estructura de Computadores OCW_2015 Nekane Azkona Estefanía

LENGUAJE. Tema 2 Elementos de un programa

UNIVERSIDAD TECNOLÓGICA NACIONAL FACULTAD REGIONAL SAN NICOLÁS INGENIERIA EN ELECTRÓNICA

Desde los programas más simples escritos en un lenguaje de programación suelen realizar tres tareas en forma secuencial.

$0 Representa al parámetro cero o nombre del programa $1 Representa al parámetro uno $2 Representa al parámetro dos

ISA (Instruction Set Architecture) Arquitectura del conjunto de instrucciones

Arquitectura de Computadores II Clase #3

Tema 5: La pila, las macros y los procedimientos

Tema 5. Presentación de datos por pantalla

TEMA 2. EL LENGUAJE C. ELEMENTOS BÁSICOS

Instrucciones de Control de Flujo y Usos de la Pila

Lección 2 Introducción al lenguaje C

Práctica 3: El teclado del PC

Intel 8086 modelo básico (primera parte) Registros:

Manual de turbo pascal

El nivel ISA (II)! Conjunto de Instrucciones

Práctica 4. Organización del Computador 1 12 de septiembre de Algunas consideraciones preliminares:

PROCESADORES DE LENGUAJE EXAMEN FINAL 8-JUNIO-07

Organización n del Computador. CPU (ISA) Conjunto de Instrucciones de la Arquitectura

UNIVERSIDAD NACIONAL DE INGENIERIA. Programación en Lenguaje Ensamblador

"Programación en Ensamblador del microprocesador Pentium (I)"

Ensamblador. Introducción. Dpto. Física y Arquitectura de Computadores. Universidad Miguel Hernandez

PHP: Lenguaje de programación

Operadores y Expresiones

LENGUAJE ENSAMBLADOR PRÁCTICA 11 PRÁCTICA 11 CUATRO OPERACIONES FUNDAMENTALES EN NÚMEROS DE 8 BYTES

Paso de parámetros y gestión del marco de pila

PRONTUARIO I. INFORMACIÓN GENERAL

Procesadores de 64 bits

62/8&,21(6$/(;$0(1'( /$%25$725,2'((6758&785$6'(/26&20387$'25(6 &8562)(%5(52

Módulo 08 Lenguaje Ensamblador

REPERTORIO DE INSTRUCCIONES DEL MICROPROCESADOR 8086

Sesión 8- Práctica de Medida de Rendimiento

Comparaciones en lenguaje ensamblador

Elementos de un programa en C

Entorno de Ejecución del Procesador Intel Pentium

Programas de ordenador (software)

Estructura de Microprocesadores. Profesor Ing. Johan Carvajal Godínez

Arquitectura de Computadores II 8086 Parte II

Programación en C. Algoritmo y Estructura de Datos. Ing. M. Laura López. Programación en C

TIPOS DE DATOS EN ABAP

Fundamentos de Programación 2017-I

Ensamblador x86: lazos y procedimientos

Trabajo Práctico Nro 3: Assembler

Métodos que devuelven valor Dado el siguiente triángulo rectángulo:

El lenguaje C. 1. Identificadores, constantes y variables

Organización del Computador I 1er. Parcial 17-Mayo Turno:

Estatutos de Control C# Estatutos de Decisión (Selección)

CICLOS DEL PROCESADOR

LECCIÓN 14: DISEÑO DE COMPUTADORES MEDIANTE MICROPROGRAMACION

Relación de Problemas I

Clasificación del procesador según el número de referencias a memoria.

Práctica 4. Introducción a la programación en lenguaje ensamblador

Todos los comandos de DEBUG se invocan usando una sola letra y son los siguientes:

Plataformas de soporte computacional: arquitecturas avanzadas,

Unidad II Fundamentos de C++ M.C. Juan Carlos Olivares Rojas

Objetivos de la sesión. Aplicación de consola 7/30/11. Código con que se inicia un programa en Visual C# (aplicación de consola)

MODOS DE DIRECCIONAMIENTO DEL µc51

GENERALIDADES DEL LENGUAJE C

SISTEMAS BASADOS EN MICROPROCESADORES

DIRECTIVAS DEL ASM86

Definición de Memoria

Java Avanzado. Guía 1. Java Avanzado Facultad de Ingeniería. Escuela de computación.

JUGANDO CON C, ASM Y SYSCALLS Alejandro Hernández

Generación de código para funciones. Generación de código para funciones. Generación de código para funciones. Generación de código para funciones

Práctica 4 - Arquitectura CPU

EJEMPLOS EN ENSAMBLADOR

INDICE Programa Entrada Unidad de control Unidad aritmética y lógica (ALU)

La Pila en los Procesadores IA-32 e Intel c 64

M. en E. Noemí López García

Tema 2: Lenguaje máquina. La interfaz entre el hardware y el software

P1.- Para facilitar la tarea, suponemos definido en el segmento de datos lo siguiente:

Introducción a C++ y Code::Blocks

Transcripción:

1. Ensamblador Linux APÈNDIX: ENSAMBLADOR LINUX Aquest tutorial està extret directament de l adreça web: http://www.publispain.com/supertutoriales/programacion/ensamblador/cursos/1/linas m.htm 1.1. Sintaxis del Ensamblador.AT&T x86 DJGPP usa la sintaxis propia de AT&T, que es un poco diferente de la que estamos acostumbrados a ver. Las diferencias principales son las siguientes: En la sintaxis de AT&T el destino de una operación se pone en el segundo parámetro y el origen se pone en el primer parámetro. (Al revés que en los Intel). El nombre de los registros es precedido por el carácter porcentaje ("%"). Los valores inmediatos han de ser precedidos por el carácter "$". El tamaño de los operandos se especifica mediante un último carácter de la instrucción:"b" (8-bits) "w" (16-bits) "l" (32-bits). Veamos algunos ejemplos. (Entre paréntesis figura el equivalente en Intel) movw %bx, %ax (mov ax, bx) xorl %eax, %eax (xor eax, eax) movw $1, %ax (mov ax,1) movb X, %ah (mov ah, byte ptr X) movw X, %ax (mov ax, word ptr X) movl X, %eax (mov eax, X) La mayoría de los opcodes son idénticos entre el formato AT&T y el formato Intel excepto para estos: movssd (movsx) movzsd (movzx) Donde S representa el tamaño del origen y D el del destino ("b","w" o "l"). Por ejemplo: "movswl %ax, %ecx (movsx ecx, ax)". cbtw (cbw) cwtl (cwde) cwtd (cwd) cltd (cdq) lcall $S,$O (call far S:O) ljmp $S,$O (jump far S:O) lret $V (ret far V) Los prefijos de instrucción no deberían (mas bien no deben) escribirse en la misma línea de la instrucción sobre la que actúan. Por ejemplo, "rep" y "stosd" deberían escribirse en dos líneas separadas. Los direccionamientos a memoria se expresan de distinta manera. La sintaxis típica Intel para direccionar la RAM sigue el siguiente modelo: SECTION:[BASE + INDEX*SCALE + DISP] se escribe en AT&T como sigue SECTION:DISP(BASE, INDEX, SCALE). He aquí algunos ejemplos: (con sus equivalentes en Intel) - 1 -

movl 4(%ebp), %eax (mov eax, [ebp+4]) addl (%eax,%eax,4), %ecx (add ecx, [eax + eax*4]) movb $4, %fs:(%eax) (mov fs:eax, 4) movl _array(,%eax,4), %eax (mov eax, [4*eax + array]) movw _array(%ebx,%eax,4), %cx (mov cx, [ebx + 4*eax + array]) Las instrucciones de salto nunca se ven precedidas como en Intel de las palabras reservadas "near", "short" o "far" pues el ensamblador elige la instrucción a ensamblar en cada caso tendiendo a optimizar el código eligiendo las instrucciones que desplazan menos el puntero de instrucciones. Dado que las instrucciones de salto condicionales en la arquitectura del PC solo pueden ser de tipo "short" todas las instrucciones siguientes tienen un único byte para el desplazamiento. Ejemplo de algunas instrucciones: "jcxz", "jecxz", "loop", "loopz", "loope", "loopnz" and "loopne". Remediamos este problema como lo hacíamos en el formato de ensamblador de los Intel, utilizando etiquetas intermediarias para los saltos como se ve en el siguiente código para realizar la lógica "jcxz foo". jcxz cx_zero jmp cx_nonzero cx_zero: jmp foo cx_nonzero: Hay que tener cuidado cuando utilicemos las instrucciones de multiplicación como "mul" o "imul". En este tipo de instrucciones, si expresamos dos operandos, solo tendrá en cuenta el ensamblador el PRIMER operando. Así, la instrucción "imul $ebx, $ebx" no pondrá el resultado en "edx:eax". Para esto, debemos utilizar la misma instrucción pero con un solo operando, es decir, la instrucción "imul %ebx". 1.2. Ensamblador en linea - (dentro de C o C++) Vamos a empezar por la macro "asm" pues su funcionamiento es frecuentemente preguntado. Su sintaxis basica es la que se describe a continuación: Los cuatro campos son: asm (sentencias en ensamblador : salidas : entradas : registros modificados sentencias en ensamblador en formato AT&T separados por un retorno de carro Salidas - indicador seguido del nombre entre paréntesis separado por una coma Entradas- indicador seguido del nombre entre paréntesis separado por una coma Registros modificados - nombres separados por una coma El ejemplo más sencillo: asm (" pushl %eax\n movl $1, %eax\n popl %eax" Los 3 últimos campos no son indispensables pues si no se utilizan variables o punteros de entrada o de salida y no quieres informar al compilador de los registros que modificas por si se te olvida alguno no pasa nada. Veamos un ejemplo más complejo con variables de entrada. - 2 -

int i = 0; asm (" movl %0, %%eax\n addl $1, %%eax\n : : "g" (i) /* i++; */ No os desesperéis todavía! Tratare de explicarlo. Nuestra variable de entrada "i" queremos incrementarla en 1. No tenemos variables de salida ni registros modificados (pues se restaura eax). Por esta razón el segundo y cuarto parámetro están vacíos. Si se especifica el campo de entrada es necesario especificar el campo de salida hallan o no hallan variables de salida. Simplemente se deja sin especificar (el campo vacío). Para el ultimo campo esta operación no es necesaria. Se debe poner un espacio o un retorno de carro para separar un campo de otro. Analicemos el campo de la entrada. El indicador del campo no es ni más ni menos que una directiva que indica al compilador como debe gestionar las variables. Toda directiva debe ponerse entre dobles comillas. En este caso la directiva "g" indica al compilador que decida donde desea almacenar el parámetro (pila, registro, memoria) y se utiliza mucho pues generalmente los compiladores optimizan bien el código. Otra directiva útil es la directiva "r" que le permite cargar la variable en cualquier registro que este libre de uso. De igual manera: "a" (ax/eax), "b" (bx/ebx), "c" (cx/ecx), "d" (dx/edx), "D" (di/edi), "S" (si/esi), etc. El primer parámetro de entrada se simboliza como "%0" dentro de las sentencias de ensamblador. Y así en el mismo orden de especificación en el campo de entrada. Es decir, que para N entradas y ninguna salida "%0" hasta %N-1 simbolizaran las variables de entrada en el orden en el que se listen en el campo 3. Algo muy importante! Si se utiliza el campo de entrada, salida o de modificación de registros los nombres de los registros deben ser precedidos de 2 % ("%%eax") en vez de uno como solíamos hacerlo. Veamos ahora el significado de la directiva volatile después de asm en un ejemplo con dos entradas. int i=0, j=1; movl %0, %%eax\n addl %1, %%eax\n : : "g" (i), "g" (j) /* i = i + j; */ Queda claro que "%0" simboliza "i" y que "%1" simboliza "j", verdad? Pero entonces para qué sirve la directiva volatile? Simplemente previene al compilador para que modifique nuestras sentencias de ensamblador si le es posible para optimizar el código (reordenación, eliminación de código inútil, recombinación). Es una opción muy recomendada. - 3 -

Pasemos ahora a como se especifican los parámetros de salida. Veamos un ejemplo: int i=0; movl $1, %%eax\n : "=g" (i) /* i++; */ Todos los indicadores o directivas especificados en el campo de variables de salida deben ser precedidos de "=" y van a ser ordenados y simbolizados como en el caso de las variables de entrada. Cómo entonces se distingue uno de entrada con uno de salida? Veamos un ejemplo. int i=0, j=1, k=0; movl %1, %%eax\n addl %2, %%eax\n : "=g" (k) : "g" (i), "g" (j) /* k = i + j; */ Si se ha entendido todo lo anterior solo puede no entenderse como distinguir un parámetro de entrada con uno de salida pues he aquí la explicación. Cuando utilizamos parámetros de entrada y salida %0 %K representan las salidas %K+1 %N son las entradas Así en el ejemplo anterior "%0" se refiere a "k", "%1" a "i" y "%2" a "j". No era tan complicado verdad? Más adelante puede sernos útil utilizar el tercer campo pues nos evita de utilizar la pila para conservar y restaurar los registros modificados. Veamos el ejemplo anterior con este campo en vez de las instrucciones "push" y "pop". int i=0, j=1, k=0; movl %1, %%eax\n addl %2, %%eax\n movl %%eax, %0" : "=g" (k) : "g" (i), "g" (j) : "ax", "memory" /* k = i + j; */ Como puede deducirse el registro de 32 bits "eax" se ve modificado por nuestra rutina en ensamblador y sin embargo especificamos como registro de 16 bits "ax" como modificado, por qué? Se debe simplemente a que los registros de 16 bits indicados en el tercer campo recogen todos los tamaños posibles de los mismos (32,16,8) - 4 -

Si modificamos la memoria (escribimos en variables) es recomendable especificar la directiva "memory". En todos los ejemplos anteriores deberíamos haber utilizado esta directiva pero por razones de simplicidad no se ha utilizado. Las etiquetas locales dentro del ensamblador en línea debe terminar por una b o una f según si esta después o antes la etiqueta relacionada con la instrucción de salto. Creo que queda lo suficientemente claro en el siguiente ejemplo. 0:\n jmp 0b\n jmp 1f\n 1:\n 1.3. Ensamblador Externo El mejor modo de aprender a utilizar el ensamblador interno es analizar los ficheros en ensamblador generados por el C mediante "gcc -S file.c". Su esquema básico es:.file "myasm.s".data somedata:.word 0.text.globl myasmfunc myasmfunc: ret Y las macros! Simplemente es necesario incluir el fichero de librería para definirlas en ensamblador. Simplemente incluimos ese fichero en nuestro fuente en ensamblador y las usamos de la manera adecuada. Veamos un ejemplo, myasm.s: #include <libc/asmdefs.h>.file "myasm.s".data.align 2 somedata:.word 0.text.align 4 FUNC( MyExternalAsmFunc) ENTER movl ARG1, %eax jmp mylabel mylabel: LEAVE Este puede ser un buen esqueleto de fuente para utilizar el ensamblador externo. - 5 -

- 6 -