Ensamblador en Linux
Ensamblador en Linux
Ensamblador en Linux
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
jcxz cx_zero
jmp cx_nonzero
cx_zero:
jmp foo
cx_nonzero:
Hay que tener cuidado cuando utilicemos las instrucciones de multiplicacion como
"mul" o "imul". En este tipo de instrucciones, si expresamos dos operandos, solo
tendra en cuenta el ensamblador el PRIMER operando. Asi,la instruccion "imul $ebx,
$ebx" no pondra el resultado en "edx:eax". Para esto, debemos utilizar la misma
instruccion pero con un solo operando, es decir , la instruccion "imul %ebx".
--------------------------------------------------------------------------------
int i = 0;
__asm__("
pushl %%eax\n
movl %0, %%eax\n
addl $1, %%eax\n
movl %%eax, %0\n
popl %%eax"
:
: "g" (i)
);
/* i++; */
No os desespereis todavia ! 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 razon el
segundo y cuarto parametro estan vacios.
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 vacio). Para el ultimo campo esta operacion no es necesaria. Se debe poner un
espacio o un retorno de carro para separar un campo de otro.
int i=0;
__asm__ __volatile__("
pushl %%eax\n
movl $1, %%eax\n
movl %%eax, %0\n
popl %%eax"
: "=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. Como Entonces se distingue uno de entrada con uno de
salida ? Veamos un ejemplo.
int i=0, j=1, k=0;
__asm__ __volatile__("
pushl %%eax\n
movl %1, %%eax\n
addl %2, %%eax\n
movl %%eax, %0\n
popl %%eax"
: "=g" (k)
: "g" (i), "g" (j)
);
/* k = i + j; */
Si se ha ententido todo lo anterior solo puede no entenderse como distinguir un
parametro de entrada con uno de salida pues he aqui la explicacion.
Cuando utilizamos parametros de entrada y salida
Asi en el ejemplo anterior "%0" se refiere a "k", "%1" a "i" y "%2" a "j". No era
tan complicado verdad ?
Mas adelante puede sernos util 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".
Las etiquetas locales dentro del ensamblador en linea debe terminar por una b o una
f segun si esta despues o antes la etiqueta relacionada con la instruccion de
salto. Creo que queda lo suficientemente claro en el siguiente ejemplo.
__asm__ __volatile__("
0:\n
...
jmp 0b\n
...
jmp 1f\n
...
1:\n
...
);
--------------------------------------------------------------------------------
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
basico es:
.file "myasm.S"
.data
somedata: .word 0
...
.text
.globl __myasmfunc
__myasmfunc:
...
ret
Y las macros ! Simplemente es necesario incluir el fichero de libreriapara
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 .
--------------------------------------------------------------------------------
Get MASM and compile your sources to COFF format (object file format used by DJGPP)