Programando en Assembly [ Entrega 1 ]

En esta liga podemos ver teoria sobre el lenguaje Assembly.

Que necesitamos?
 - un ensamblador para pasar nuestro codigo Assembly a un formato objeto.
 - un enlazador que combine nuestros archivos objeto con las librerias necesarias.

En este caso utilizaremos assembly con sintaxis de Intel, ya que a mi parecer es un codigo muy limpio. Nuestro ensamblador sera NASM ya que es propio del uso de la sintaxis de Intel para 16 y 32 bits.
Nuestro enlazador por fortuna viene agregado como herramienta de GNU en sistemas con nucleo linux, su nombre es ld.

Como instalar NASM?
NASM esta en los repositorios de muchas distribuciones, solo se tiene que usar el comando del gestor de paquetes como ejemplo para debian/ubuntu:

              sudo apt-get install nasm

y como mencionamos el enlazador viene por default.

Ahora veamos un Hola escrito para lenguaje assembly utilizando sintaxis Intel




;; Asi se hacen los comentarios.
SECTION .data ;Definimos la seccion de datos estaticos, equivalentes de constantes.
msg: db "Hola clase (:",10,13 ;etiqueta: db (DefineByte) "cadena",bytes sin formato, 10 = fin de linea, 13 = salto de linea
lon: equ $-$$ ;etiqueta: equ (EQUAL) cantidad. Es el equivalente de #define en lenguaje C
;$ es para la posicion actual del puntero en la ejecuccion desde que se inicio la seccion.
;$$ es para ver la posicion inicial desde la seccion. (donde estoy - donde estaba)
SECTION .text
;seccion text, aqui es donde va el codigo
global _start ;etiqueta para el enlazador
_start: ;punto de entrada para el enlazador ( funcion main )
mov edx,lon ;Registro D, aqui guardaremos la longuitud de la cadena a imprimir
mov ecx,msg ;Registro C, aqui pondremos el puntero a los caracteres.
mov ebx,1 ;Registro B, aqui le ponemos el descriptor del archivo ( recordando que en unix todo es un archivo ) 1 =STDOUT
mov eax,4 ;Registro A, numero de comando 4=sys_write
int 0x80 ;interrupcion 80, llama al kernel y ejecuta la llamada que este en el acumulador
mov ebx,0 ;salida del codigo al sistema operativo
mov eax,1 ;numero de comando 1 = sys_exit
int 0x80 ;interrumpcion 80 hex, llama al kernel
view raw assembly hosted with ❤ by GitHub
El codigo esta lleno de comentarios utiles para la comprension del programa.

Ahora lo ensamblaremos y lo enlazaremos con sus librerias para que nos quede un ejecutable.


 Lo pasamos a un archivo de tipo ELF ( Archivo Ejecutable y enlazable ) para depues  enlazarlo usando ld.


Ahora nos queda un ejecutable y solo tenemos que mandarlo llamar.

Asi se hace una impresion utilizando Assembly con sintaxis intel sobre linux.

Dejando en claro cada linea de este programa.

SECTION .data es una seccion del programa que especifica la memoria del segmento de datos. Solo los datos iniciados se deber definir en este segmento.
En este segmento utilizamos db para reservar bytes, usamos la etiqueta msg para  despues guardar caracteres " H "," o "," l "... y ademas le agregamos dos caracteres de escape ( 10 y 13 ) para estetica. Ademas utilizamos otra etiqueta llamada lon para guardarle un numero que comprende de la resta de la posicion actual del puntero menos la posicion inicial del puntero, si no fallo seria un 15.


SECTION .text en esta seccion se define la parte del codigo.
     MOV nos permite mover valores hacia los registros.
     INT hace la llamada a una interrupcion y en este caso usamos la 0x80 que nos permite decirle al kernel que ejecute una llamada al sistema dependiendo de acumulador.


Ahora veremos otro programa que apartir de un argumento crea un nuevo archivo, le escribe una linea de caracteres predefinida.
Despues reabre el archivo, toma lectura de una linea y la imprime en pantalla.


section .data
line db "hola esto es una linea de prueba",10
len equ $ - $$
section .bss ;Block Started by Symbol
buffer: resb len
file: resb 4
num: resb 4
section .text
global _start
_start:
pop ebx ;saca el ultimo dato de la pila, en este caso el # de argumentos
cmp ebx,3 ;juzga ebx para ver cuantos argumentos se pasaron
jne error ;salta si no es igual o es cero
pop ebx ;saca el siguiente, es el nombre del ejecutable
pop ebx ;saca el siguiente, es el argumento[1].
cmp ebx,0 ;compara si no esta vacio
jbe error ;salta si no es 1.
mov [file], ebx ;lo que esta en ebx, muevelo a file, uso de corchetes para contenidos, no punteros.
mov eax,8 ;llamada creat
mov ecx,511 ;permisos para lectura y de ejecuccion
int 0x80
mov eax,5 ;llamada sys_open
mov ebx,[file] ;nombre del archivo
mov ecx,1 ;1 = Escritura, 0 = Lectura
int 0x80
mov ebx,eax ;guarda el file descriptor en EBX, ya que el sistema nos lo regresa en EAX
mov eax, 4 ;sys_write
mov edx, len ;mensaje
mov ecx, line ;size
int 0x80
mov eax, 6 ;sys_close
int 0x80
mov eax, 5 ;sys_open file with filedescriptor in ebx
mov ebx, [file] ;archivo que se abrira
mov ecx, 0 ;O_RDONLY zero es para solo lectura
int 0x80
cmp eax, 0 ;checa que el filedescriptor en EAX sea mayor a 0
jbe error ;no se abrio el archivo
mov ebx, eax ;guarda el file descrip
;; leer desde el archivo al .bss buffer para desplegarlo en pantalla
mov eax, 3 ;sys_read
mov ecx, buffer ;puntero a la variable buffer
mov edx, len ;size de los datos a leer.
int 0x80
js error ;Error de lectura
cmp eax, len ;checa si no tubo una lectura menor a la requerida por len
jb close
mov eax, 4 ;sys_write
push ebx ;save file descriptor en pila for sys_close
mov ebx, 2 ;file descriptor de stderr que es ilimitada
mov ecx, buffer ;puntero al buffer con data
mov edx, len ;size de los datos
int 0x80
pop ebx ;recupera filedescriptor en ebx de la pila
close:
mov eax, 6 ;sys_close file con
int 0x80
mov eax, 1 ;sys_exit
mov ebx, 0 ;ok
int 0x80
error:
mov ebx, eax ;exit code = sys call result
mov eax, 1 ;sys_exit
int 0x80
view raw assembly hosted with ❤ by GitHub
Aqui estan las hojas de referencia para assembly
Manual para uso de NASM
Aqui les dejo la tabla de las llamadas al sistema

Leave a Reply

Ever Medina. Con la tecnología de Blogger.