Sunteți pe pagina 1din 26

Pedro A.

Castillo Valdivieso

Dpto. ATC. UGR

2008-2009

ENSAMBLADOR EN ENTORNOS LINUX / UNIX


1.1. Herramientas

Para desarrollar programas ensamblador en Linux, deberemos elegir el compilador de ensamblador que queremos utilizar. La eleccin lgica es usar GAS (as), el estndar que lleva toda distribucin Linux. GAS tiene la desventaja de utilizar la sintaxis AT&T, que difiere bastante de la sintaxis Intel (algo ms sencilla). Una alternativa es utilizar NASM, que ofrece la misma funcionalidad que GAS, pero utiliza la sintaxis de Intel. Sin embargo, puesto que gcc utiliza as como ensamblador, conviene conocer ambas sintaxis. As pues, los programas que hagamos en esta parte de las prcticas los desarrollaremos utilizando las herramientas NASM y GAS.

1.2.

Programar con sintaxis Intel. NASM

En NASM, un programa ensamblador aparece dividido en tres secciones (datos con valor de inicializacin, datos no inicializados e instrucciones de programa). Veamos el ejemplo Hola mundo programado para NASM:
section .data mensaje db hola mundo,0xA mensajeSIZE equ $ - mensaje section .text global _inicio _inicio: mov edx,longitud mov ecx,mensaje mov ebx,1 mov eax,4 int 0x80 mov ebx,0 mov eax,1 int 0x80

;definimos el punto de entrada ;EDX=long. de la cadena ;ECX=cadena a imprimir ;EBX=manejador de fichero (STDOUT) ;EAX=funcin sys_write() del kernel ;interrupc. 80 (llamada al kernel) ;EBX=cdigo de salida al SO ;EAX=funcin sys_exit() del kernel ;interrupc. 80 (llamada al kernel)

El fichero lo debemos guardar con extensin .asm (hola.asm). La compilacin se lleva a cabo mediante las siguientes rdenes de shell:
nasm f hola.asm ld s o hola hola.o

lo que nos genera el ejecutable hola que nos mostrar el mensaje definido.

Ensamblador en entornos Linux / Unix

Descripcin detallada del programa Hola mundo (NASM) En la seccin .data definiremos datos que deben recibir un valor inicial al cargar el programa. Las directivas utilizadas para definir los tipos de datos (DB, DD, etc) son las mismas y se usan del mismo modo que en el ensamblador de Intel bajo MSDOS.
section .data mensaje db hola mundo mensajeSIZE equ $ - mensaje

En este caso, la definicin de la cadena de texto pasa por indicar un nombre de variable, el tipo de datos que va a almacenar (definir bytes) y el valor (contenido de la cadena). Por otro lado, la funcin del sistema que escribe una cadena de texto, necesita la longitud exacta de la cadena a escribir (ya que no ponemos un carcter de final de cadena). En este caso, mensajeSIZE es una constante que almacena el nmero de bytes (caracteres) desde el comienzo de mensaje hasta la definicin de mensajeSIZE (el final de mensaje). En la seccin .bss podemos definir las variables del programa que no reciben un valor de inicializacin. No es obligatorio y suele contener entradas como las siguientes:
fichero: caracter: palabra: numero: num_real: precision: resb resb resw resd resq rest 256 1 1 1 1 1
;REServa ;REServa ;REServa ;REServa ;REServa ;REServa 256 Bytes 1 Byte (8 bits) 1 Word (palabra, 16 bits) 1 DoubleWord (doble palabra, 32bits) 1 float de doble precision (64 bits) 1 float de precision extendida (128 bits)

El acceso desde el programa a estas variables se realiza de la forma que ya conocemos. Por ltimo, la seccin .text es donde escribimos las instrucciones de ensamblador (las instrucciones de cdigo mquina). El comienzo del programa se indica mediante la directiva global _start al principio de la seccin .text . Es la forma que tenemos de indicarle al kernel cul es la primera instruccin a ejecutar en nuestro programa. En otros lenguajes, el punto de entrada forma parte de la sintaxis del lenguaje (en C/C++ es el inicio de la funcin main). En otros ensambladores, como el de la familia 80x86 bajo MSDOS/Windows se indica al final del texto del programa, con la directiva END:
codigo segment 'code' main PROC

....
main ENDP codigo ends END main

En el caso del ensamblador en Linux lo indicamos justo despus del inicio de la seccin. Ese punto puede ser cualquiera, y lo indicamos con una etiqueta:
section .text global _start _start: ;definimos el punto de entrada

En el ejemplo anterior, el programa simplemente hace uso de dos llamadas al sistema para mostrar una cadena por pantalla y para terminar el programa (ver el cdigo para ms detalle).

Ensamblador en entornos Linux / Unix

Interaccin con el sistema operativo. Llamadas al sistema En el ejemplo hemos hecho uso de la interrupcin 80h (su funcionalidad se podra equiparar a la 21h del MSDOS) para mostrar la cadena de texto y para terminar el programa y salir al SO. En ocasiones, nuestros programas necesitan hacer uso de funciones complejas del sistema operativo para, por ejemplo, mostrar una cadena de texto por pantalla, leer un dato desde el teclado, etc. Este tipo de funciones, que slo los puede proveer el sistema operativo se llaman interrupciones software. La forma de pedirle al sistema que ejecute cierta funcin para servir a nuestro programa es utilizando la instruccin de ensamblador INT (seguido del nmero de interrupcin, que identifica a quin le pedimos que ejecute esa funcin). Las interrupciones software aaden una serie de funcionalidades al lenguaje para hacer tareas que o bien no sabemos cmo hacerlas (mostrar por pantalla, leer de teclado, acceso a ficheros, etc) o bien nos costara mucho hacerlas por nuestra cuenta. De hecho, la interaccin con el sistema operativo se lleva a cabo a travs de las llamadas al sistema (al kernel, realmente) a travs de la interrupcin 80h. En MSDOS/Windows existe otra interrupcin software similar (la 21h). Para pedirle al kernel del SO que haga una tarea para nuestro programa, debemos indicar en EAX la funcin del sistema que queremos usar. Si esa funcin necesita argumentos, estos deben indicarse en los registros EBX, ECX, EDX, ESI, EDI y EBP (en este orden). As, para terminar un programa, haremos uso de la funcin sys_exit() que tiene asignado el nmero 1 (lo damos en EAX), e indicaremos el cdigo de retorno en EBX:
mov eax,1 mov ebx,0 int 0x80

es muy similar a haber hecho return 0; en el main de un programa en C. En cuanto a la funcin utilizada para mostrar una cadena, hay que tener en cuenta que todo en Linux / Unix es tratado como un fichero, por lo que para mostrar informacin por pantalla debemos hacer uso del descriptor STDOUT (definido con el valor 1 en /usr/include/unistd.h). El resto de parmetros que necesita esta funcin son la direccin de comienzo de la cadena a mostrar (ECX) y la longitud de dicha cadena (EDX). La seccin 5 de este guin presenta una descripcin detallada de todas las funciones del sistema, nmeros asignados, y los argumentos que necesitan para su ejecucin. De todas formas, podemos obtener ms informacin sobre las llamadas en el archivo que las define ( /usr/include/sys/syscall.h ) y en las pginas de manual del sistema (o con la orden info):
man man man man ... 2 2 2 2 exit read write open info info info info ... exit read write open

Ensamblador en entornos Linux / Unix

Acceso a la pila en un programa ensamblador en Linux La estructura de la pila al iniciar un programa en Linux es bastante sencilla. En el caso de Linux la pila es inicializada con los argumentos pasados a travs de la lnea de comandos (de forma similar a como le llegan al programa C/C++ el nmero de argumentos en argc y las cadenas en *argv). Al igual que cuando programamos en C, en Linux el kernel establece el valor de ciertas variables de entorno que necesitar el programa, y tambin inicializa el vector de argumentos de lnea de comandos y el contador. Todos esos datos quedan cargados en la pila del programa, de acuerdo a la siguiente estructura:
argc argv[0] argv[1] argv[2] argv[3] ...... argv[argc-1] NULL env[1] env[2] env[3] ...... env[n] NULL contador del nmero de argumentos. Entero de 32bits nombre del programa. Puntero a la cadena de texto (32bits) argumentos pasados por la lnea de comandos. Punteros a las cadenas de texto (32bits cada uno) fin de los argumentos (32bits) variables de entorno para el programa. Punteros a las cadenas de texto (32bits cada uno)

Fin de las variables de entorno (32bits)

Cuando el kernel carga nuestro programa, establece esa estructura en la pila del programa. As, si nuestro programa fue llamado de la siguiente forma:
$ miprograma 37 hola

la pila contendr la siguiente informacin: 3 argc miprograma argv[0] 37 argv[1] hola argv[2] NULL fin de los argumentos ...variables de entorno... NULL fin de las variables Para acceder a cada uno de los argumentos y variables de entorno, vamos recorriendo la pila, extrayendo (pop) los valores, teniendo siempre en cuenta que argc y argv[0] siempre estn presentes. La extraccin de los argumentos y variables de entorno se debe hacer al principio del programa (para evitar la prdida de algunos por la manipulacin a lo largo del programa):
. . . . . . _start:

Ensamblador en entornos Linux / Unix

pop eax ;extraer el contador de argumentos pop ebx ;extraer nombre del programa (el puntero) argumentos: pop ecx ;vamos extrayendo los argumentos test ecx,ecx ;comprobamos si llegamos al NULL jnz argumentos entorno: pop edx ;vamos extrayendo las variables test edx,edx ;comprobamos si llegamos al NULL jnz entorno . . . . . .

Acceso a ficheros desde un programa ensamblador en Linux Veamos un ejemplo ms complejo, en el que hagamos uso de la pila y los argumentos de comando de lnea, y usemos llamadas al sistema para acceder a ficheros:
... ... pop ebx pop ebx pop mov mov int ebx eax,5 ecx,0 0x80 ;extraer argc ;extraer argv[0] ;extraer el primer argumento (puntero a una cadena) ;funcin para sys_open() ;O_RDONLY (definido en fcntl.h) ;interrupc. 80 (llamada al kernel)

test eax,eax ; devuelve error (en EAX) o el descriptor? jns leer_del_fichero hubo_error: mov ebx,eax mov eax,1 int 0x80 leer_del_fichero: mov ebx,eax mov eax,3 mov ecx,buffer mov edx,tamano int 0x80 js hubo_error

;salir al SO devolviendo el cdigo de error

;no hubo error=>devuelve el descriptor de fich ;funcin para sys_read() ;variable donde guardaremos lo leido del fich ;tamao de lectura

mostrar_por_pantalla: mov edx,eax ;longitud de la cadena a escribir mov eax,4 ;funcin sys_write() mov ebx,1 ;descriptor de STDOUT int 0x80 ... ...

El cdigo anterior lee el nombre de un fichero de la lnea de rdenes, y utiliza llamadas al sistema para abrirlo, leer la informacin que contiene, y mostrarla por pantalla. Bsicamente, funciona como el programa cat, aunque habra que mejorarlo para leer toda la informacin del fichero (el ejemplo completo se mostrar en la seccin 1.7).

Ensamblador en entornos Linux / Unix

1.3.

Sintaxis AT&T. Ensamblador de GNU

GAS (Gnu ASsembler) utiliza la sintaxis de AT&T, que tiene pequeas diferencias con respecto a la sintaxis estndar de Intel (usada en NASM, TASM, MASM, etc). Las principales diferencias se detallan a continuacin: En AT&T, a los nombres de los registros se les aade el prefijo % AT&T: %eax INTEL: eax

En AT&T, el destino se coloca a la derecha y el fuente a la izquierda (en Intel es al revs). Las siguientes instrucciones cargan en ebx el valor de eax AT&T: movl %eax, %ebx INTEL: mov ebx, eax En AT&T, a los valores inmediatos se les aade el prefijo $ en el siguiente ejemplo, la primera instruccin carga la direccin de la variable en eax; la segunda carga el valor 0F02h en ebx AT&T: movl $var, %eax
movl $0xf02, %ebx

INTEL:

mov eax, offset var mov ebx, 0f02h

En AT&T, el tamao del resultado se especifica con sufijos (b, w o l) en las instrucciones (en Intel cuando hay ambigedad se utiliza byte ptr, word ptr o dword ptr). Si lo omitimos, GAS intentar adivinar el tamao, y es algo que no queremos que haga... AT&T: movb var, %ah INTEL: AT&T:
movw %bx, %ax mov ah, byte ptr var mov ax, bx movb movw movl movl %bl,%al %bx, %ax %ebx,%eax (%ebx),%eax

Ensamblador en entornos Linux / Unix

INTEL:

mov mov mov mov

al,bl ax, bx eax,ebx eax, dword ptr [ebx]

Direccionamiento a memoria: Es uno de los aspectos que ms cambian. Veamos la sintaxis de Intel para hacer un direccionamiento a base, con ndice y desplazamiento:
[ base + indice*escala + desplazamiento ]

en la sintaxis AT&T esto queda como sigue:


desplazamiento ( base , indice , escala )

Veamos dos ejemplos: AT&T: movl array (, %eax, 4), %edx INTEL: mov edx, array[eax*4] AT&T: INTEL: Salto lejano AT&T:
lcall $seccin, $offset ljmp $seccin, $offset lret $V call far seccin:offset jmp far seccin:offset ret far V movl (%ebx) , %eax movl 3(%ebx) , %eax mov eax , [ebx] mov eax,[ebx+3]

INTEL:

Nemotcnico. Varan los nemotcnicos de algunas instrucciones AT&T: movswl %ax, %ecx
movzbw %ah, %cx cbtw cwtl cwtd cltd

INTEL:

movsx ecx, ax movzx cx, ah cbw cwde cwd cdq

Directivas del compilador. Como vimos, los programas ensamblador, adems de las instrucciones que componen el programa, contienen rdenes al compilador que le servirn para definir las secciones del programa, definir los tipos de datos, macros, etc. (directivas del compilador).

Ensamblador en entornos Linux / Unix

Como comentamos ms arriba, hay diferencias en cuanto a algunas directivas al programar con el ensamblador GAS o NASM. o En ambos ensambladores hay que definir las secciones de datos y cdigo utilizando los mismos nombres (.data .bss .text). Sin embargo, la directiva utilizada para definir las secciones difiere de un ensamblador a otro: NASM
section .data section .bss section .text

GAS
[.section] .data [.section] .bss [.section] .text

o En ambos ensambladores, la etiqueta de entrada al programa ensamblador suele ser _start. Sin embargo, la directiva utilizada difiere de un ensamblador a otro: NASM
section .text global _start _start: .text .globl _start _start:

GAS

o La definicin de datos constantes se lleva a cabo utilizando de la misma forma, pero utilizando palabras reservadas diferentes: NASM
section .data cadena db un texto longitud equ $ cadena cero dw 0 letra db A .data cadena: .ascii un texto longitud = . cadena cero: .hword 0 letra: .byte A

GAS

En la pgina web del DJGPP podemos encontrar una gua detallada sobre la sintaxis AT&T, y ejemplos de ensamblador en lnea: http://www.delorie.com/djgpp/doc/brennan/brennan_att_inline_djgpp.html El programa Hola mundo con GAS Veamos el ejemplo que explicamos para NASM, esta vez en el formato AT&T (slo hay que tener en cuenta las diferencias comentadas anteriormente):
.section .data mensaje: .ascii hola mundo \n longitud = . - mensaje .section .text .globl _start _start: movl $longitud,%edx

#definimos el punto de entrada #EDX=long. de la cadena

Ensamblador en entornos Linux / Unix

movl $mensaje,%ecx movl $1,%ebx movl $4,%eax int $0x80 movl $0,%ebx movl $1,%eax int $0x80

#ECX=cadena a imprimir #EBX=manejador de fichero (STDOUT) #EAX=funcin sys_write() del kernel #interrupc. 80 (llamada al kernel) #EBX=cdigo de salida al SO #EAX=funcin sys_exit() del kernel #interrupc. 80 (llamada al kernel)

El fichero lo debemos guardar con extensin .s (hola.s). La compilacin se lleva a cabo mediante las siguientes rdenes de shell:
as o hola.o hola.s ld o hola hola.o

lo que nos genera el ejecutable hola que nos mostrar el mensaje definido. Vemos varias diferencias, tanto en cuanto a la sintaxis como en las directivas al compilador (palabras reservadas). Descripcin del programa Hola mundo (GAS) El ejemplo es prcticamente igual al que vimos en la sintaxis Intel (NASM), de hecho se utilizan las mismas instrucciones. Slo hay que tener en cuenta las diferencias de sintaxis comentadas ms arriba.

1.4.

Formato binario de un ejecutable ELF

Durante el proceso de carga de un programa ELF (ejecutable bajo Linux) se inicializan diversas zonas de memoria (zona de variables y la pila) y los registros del procesador. Veamos cmo actan dichos procesos y el estado en que queda la memoria y los registros (ya hemos visto la pila), aunque la informacin que demos aqu slo ser aplicable a programas ensamblador planos (programados para gas / nasm y compilados con estos); la inicializacin de la pila y registros no ser la misma si compilamos y linkamos con gcc (ste inserta su propio cdigo de inicio antes de pasar el control a la funcin main). La fuente de informacin sobre el formato ELF ms completa y detallada es el fichero fuente del kernel /usr/source/fs/binfmt_elf.c Los procesos de carga e inicializacin quedan descritos en el fichero fuente del kernel /usr/include/linux/sched.h Ejecucin de un programa de usuario Todo programa de usuario es ejecutado mediante la funcin del sistema sys_execve() , normalmente al escribir el nombre en el prompt del shell. A continuacin diversos procesos del kernel se ponen en marcha para cargar el programa en memoria y comenzar su ejecucin:

10

Ensamblador en entornos Linux / Unix

Funcin del sistema shell execve() sys_execve() sys_execve() do_execve() search_binary_handler() load_elf_binary() start_thread()

Fichero del kernel

arch/i386/kernel/process.c fs/exec.c fs/exec.c fs/binfmt_elf.c include/asm-i386/processor.h

Comentarios escribimos el nombre del programa y pulsamos ENTER el shell llama a la funcin correspondiente de libc libc pasa la llamada al kernel la llamada llega al espacio del kernel abre el fichero obtiene el tipo de ejecutable carga el binario ELF y las libreras necesarias. Inicializa la memoria pasa el control al cdigo del programa de usuario

El programa ELF en memoria Una vez cargado el binario ELF, la estructura de la memoria asignada al programa de usuario es la siguiente:
direccin 0x08048000 cdigo datos bss ... ... ... pila argumentos vars.entorno nombre del ejecutable NULL direccin 0xBFFFFFFF seccin .text (cdigo mquina del programa) seccin .data (datos constantes del programa) seccin .bss (variables del programa) espacio libre de memoria pila del programa, inicializada con los argumentos de la lnea de comandos y las variables de entorno duplicado en la pila (argv[0]) 32 bits inicializados al valor 0

La pila crece hacia direcciones de memoria menores (hacia arriba), hasta encontrarse con la seccin .bss . Esta seccin de variables del programa es totalmente inicializada con el valor 0 en el inicio, de forma que cualquier variable definida no contendr un valor aleatorio al principio. Podemos evitarnos el trabajo de inicializar una variable a 0 en nuestro programa, simplemente definindola en esta seccin. El espacio libre de memoria despus del .bss queda para asignacin dinmica de memoria ( malloc() ). Inicializacin de los registros Al pasar el control a la primera instruccin de nuestro programa, el kernel (segn su versin) habr puesto los valores de los registros generales (EAX, EBX, ECX, EDX, ESI, EDI, EBP) a cero, o bien habr dejado los valores que tenan justo antes de que el programa llamador hiciese la llamada: En el kernel de versin 2.0 EAX y EDX quedan inicializados a 0, mientras que el resto contienen los valores que tenan justo antes de la llamada a sys_execve() En el kernel de versin 2.2 todos los registros generales quedan inicializados a 0

11

Ensamblador en entornos Linux / Unix

1.5.

Lista de algunas de las llamadas al sistema

La siguiente tabla muestra la lista de llamadas al sistema. Como ya hemos comentado, estas llamadas son como un API entre el espacio del kernel y del programa de usuario. A la izquierda quedan los nmeros de las funciones (valores a poner en EAX para hacer la llamada). A la derecha aparecen los tipos de valores que espera en cada registro de carcter general (parmetros de la funcin) antes de llamar a la interrupcin 80h. Tras cada llamada, se devuelve un nmero entero en EAX (cdigo de retorno).
%eax 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Funcin Fuentes del kernel %ebx char * const char * int unsigned int * int const char * int %ecx %edx %esx %edi

sys_exit sys_fork sys_read sys_write sys_open sys_close sys_waitpid sys_creat sys_link sys_unlink sys_execve sys_chdir sys_time sys_mknod sys_chmod sys_lchown sys_stat sys_lseek sys_getpid sys_mount
sys_oldumount

int kernel/exit.c arch/i386/kernel/p struct rocess.c pt_regs unsigned int fs/read_write.c unsigned int fs/read_write.c const char * fs/open.c unsigned int fs/open.c pid_t kernel/exit.c const char * fs/open.c const char * fs/namei.c const char * fs/namei.c arch/i386/kernel/p struct rocess.c pt_regs const char * fs/open.c int * kernel/time.c const char * fs/namei.c const char * fs/open.c const char * fs/open.c

size_t size_t
int int -

dev_t

18

fs/stat.c

char *

19 20 21 22 23 24 25 26 27

sys_setuid sys_getuid sys_stime sys_ptrace sys_alarm sys_fstat sys_pause

unsigned int fs/read_write.c kernel/sched.c char * fs/super.c char * fs/super.c kernel/sys.c uid_t kernel/sched.c int * kernel/time.c arch/i386/kernel/p long trace.c unsigned int kernel/sched.c

mode_t uid_t gid_t struct __old_kernel_st at * unsigned int off_t char * long char * long -

long -

28

fs/stat.c arch/i386/kernel/s ys_i386.c

unsigned int

struct __old_kernel_st at *
-

29

12

Ensamblador en entornos Linux / Unix

30 33 34 36 37 38 39 40 41 42 43 45 46 47 48 49 50 51 52 54 55 57

sys_utime sys_access sys_nice sys_sync sys_kill sys_rename sys_mkdir sys_rmdir sys_dup sys_pipe sys_times sys_brk sys_setgid sys_getgid sys_signal sys_geteuid sys_getegid sys_acct sys_umount sys_ioctl sys_fcntl sys_setpgid sys_olduname sys_umask sys_chroot sys_ustat sys_dup2 sys_getppid sys_getpgrp sys_setsid sys_sigaction sys_sgetmask sys_ssetmask sys_setreuid sys_setregid

char * fs/open.c struct utimbuf * const char * int fs/open.c int kernel/sched.c fs/buffer.c int int kernel/signal.c const char * const char * fs/namei.c const char * int fs/namei.c const char * fs/namei.c unsigned int fs/fcntl.c arch/i386/kernel/s unsigned long * ys_i386.c kernel/sys.c struct tms * unsigned long mm/mmap.c kernel/sys.c gid_t kernel/sched.c int kernel/signal.c __sighandler_t kernel/sched.c kernel/sched.c const char * kernel/acct.c char * int fs/super.c unsigned int unsigned int fs/ioctl.c

unsigned long unsigned long -

fs/fcntl.c kernel/sys.c

unsigned int

unsigned int

59

60 61 62 63 64 65 66

pid_t pid_t struct arch/i386/kernel/s oldold_utsn ys_i386.c ame * int kernel/sys.c const char * fs/open.c fs/super.c dev_t struct ustat * unsigned int unsigned int fs/fcntl.c kernel/sched.c kernel/sys.c kernel/sys.c arch/i386/kernel/s ignal.c
int const struct

67

struct old_siga old_sigaction * ction *


-

68 69 70 71 72

73 74

kernel/signal.c int kernel/signal.c kernel/sys.c uid_t uid_t kernel/sys.c gid_t gid_t arch/i386/kernel/s int int sys_sigsuspend ignal.c old_sigset_t sys_sigpending kernel/signal.c * char * int sys_sethostnam kernel/sys.c

old_sigs et_t
-

13

Ensamblador en entornos Linux / Unix

75 76 77 78

79 80 81

e sys_setrlimit kernel/sys.c sys_getrlimit kernel/sys.c sys_getrusage kernel/sys.c sys_gettimeofda kernel/time.c y sys_settimeofda kernel/time.c y sys_getgroups kernel/sys.c sys_setgroups kernel/sys.c
old_select

unsigned int unsigned int int

struct timeval * struct timeval *


int int

struct rlimit * struct rlimit * struct rusage * struct timezone * struct timezone * gid_t * gid_t *
-

82

83

sys_symlink sys_lstat sys_readlink sys_uselib sys_swapon sys_reboot


old_readdir

struct arch/i386/kernel/s sel_arg_stru ys_i386.c ct * const char * fs/namei.c fs/stat.c fs/stat.c fs/exec.c mm/swapfile.c kernel/sys.c fs/readdir.c
char *

const char *

84

struct __old_kernel_st at *
char * int int void *

85 86 87 88 89

const char * const char * const char * int unsigned int

int int

void *

unsigned int -

90

old_mmap

91 92 93 94 95 96 97 99 100 101 102 103

struct arch/i386/kernel/s mmap_arg_ ys_i386.c struct * unsigned long sys_munmap mm/mmap.c const char * sys_truncate fs/open.c unsigned int sys_ftruncate fs/open.c unsigned int sys_fchmod fs/open.c unsigned int sys_fchown fs/open.c int sys_getpriority kernel/sys.c int sys_setpriority kernel/sys.c const char * sys_statfs fs/open.c unsigned int sys_fstatfs fs/open.c arch/i386/kernel/i unsigned long sys_ioperm oport.c int sys_socketcall net/socket.c int sys_syslog kernel/printk.c sys_setitimer sys_getitimer kernel/itimer.c kernel/itimer.c fs/stat.c fs/stat.c fs/stat.c
int

size_t
unsigned long unsigned long

mode_t uid_t
int int

gid_t
int int int

struct statfs * struct statfs *


unsigned long unsigned long * char *

104

105 106 107 108

int char * char * unsigned int

sys_newstat sys_newlstat sys_newfstat

struct struct itimerval itimerval * * struct itimerval * struct stat * struct stat * struct stat *

14

Ensamblador en entornos Linux / Unix

109

sys_uname sys_iopl sys_vhangup sys_idle sys_vm86old

110 111 112

113

struct arch/i386/kernel/s old_utsname ys_i386.c * arch/i386/kernel/i unsigned long oport.c fs/open.c arch/i386/kernel/p rocess.c struct arch/i386/kernel/v unsigned long vm86plus_struc m86.c t* kernel/exit.c mm/swapfile.c kernel/info.c pid_t
const char * unsigned long *

114

sys_wait4 sys_swapoff sys_sysinfo


sys_ipc(*Note)

int options

struct rusage *
-

115 116

struct sysinfo *

117 118 119

sys_fsync sys_sigreturn sys_clone

120

arch/i386/kernel/s uint ys_i386.c unsigned int fs/buffer.c arch/i386/kernel/s unsigned long ignal.c arch/i386/kernel/p struct rocess.c pt_regs
char *

int -

int -

int -

void * -

121

sys_setdomainn kernel/sys.c ame


sys_newuname

int

122

kernel/sys.c arch/i386/kernel/l dt.c kernel/time.c

struct new_utsnam e*
int void *

123

sys_modify_ldt sys_adjtimex

unsigned long unsigned long

124 125 126

struct timex *
unsigned long int

127 128 129

sys_mprotect mm/mprotect.c sys_sigprocmas kernel/signal.c k sys_create_mod kernel/module.c ule sys_init_module kernel/module.c sys_delete_mod kernel/module.c ule sys_get_kernel_ kernel/module.c syms sys_quotactl sys_getpgid fs/dquot.c kernel/sys.c

size_t old_sigset_t * size_t struct module *


-

old_sigs et_t *
-

const char * const char * const char *

130

struct kernel_sym *
int

131 132

const char * -

int -

caddr _t
-

pid_t

15

Ensamblador en entornos Linux / Unix

133 134 135 136 138 139 140 141

sys_fchdir sys_bdflush sys_sysfs

unsigned int fs/open.c int fs/buffer.c int fs/super.c kernel/exec_doma unsigned long sys_personality in.c sys_setfsuid kernel/sys.c uid_t sys_setfsgid kernel/sys.c gid_t

long unsigned long unsigned long void *

unsigned long unsigned long

unsigned int -

sys_llseek sys_getdents sys_select sys_flock sys_msync sys_readv sys_writev sys_getsid sys_fdatasync sys_sysctl

fs/read_write.c fs/readdir.c fs/select.c fs/locks.c mm/filemap.c fs/read_write.c fs/read_write.c kernel/sys.c fs/buffer.c kernel/sysctl.c

unsigned int unsigned int

loff_t *

unsigned int -

142

int

fd_set *
unsigned int

fd_set *
int unsigned long unsigned long -

struct fd_set timev * al *


-

143 144 145

unsigned int unsigned long unsigned long

146 147 148

unsigned long

size_t const struct iovec * const struct iovec *


-

pid_t
unsigned int

149

150 151 152 153 154

155

sys_mlock mm/mlock.c sys_munlock mm/mlock.c sys_mlockall mm/mlock.c sys_munlockall mm/mlock.c sys_sched_setpa kernel/sched.c ram sys_sched_getp kernel/sched.c aram sys_sched_setsc kernel/sched.c heduler sys_sched_getsc kernel/sched.c heduler sys_sched_yield kernel/sched.c sys_sched_get_ kernel/sched.c priority_max sys_sched_get_ kernel/sched.c priority_min sys_sched_rr_g kernel/sched.c et_interval sys_nanosleep kernel/sched.c sys_mremap mm/mremap.c

struct __sysctl_arg s* unsigned long size_t unsigned long size_t


int -

pid_t pid_t pid_t pid_t


int

struct sched_param * struct sched_param *


int

156

struct sched_p aram *


-

157 158 159

160

int

161

162 163

struct timespec * struct struct timespec timespec * * pid_t


unsigned long unsigned long

unsigned

unsigned -

16

Ensamblador en entornos Linux / Unix

long 164 165

long -

sys_setresuid sys_getresuid sys_vm86

kernel/sys.c kernel/sys.c

166

uid_t uid_t uid_t * uid_t * struct arch/i386/kernel/v vm86_struct m86.c *


const char * int

uid_t uid_t *
-

167

sys_query_mod kernel/module.c ule sys_poll sys_nfsservctl sys_setresgid sys_getresgid sys_prctl


sys_rt_sigreturn

char *

size_t
-

size_t *
-

168 169 170 171 172 173

fs/select.c

struct pollfd *

unsigned int void *

long void *

fs/filesystems.c int kernel/sys.c gid_t kernel/sys.c gid_t * int kernel/sys.c arch/i386/kernel/s unsigned long ignal.c kernel/signal.c kernel/signal.c kernel/signal.c kernel/signal.c
int

gid_t gid_t *
unsigned long -

gid_t gid_t *
unsigned long -

unsigned unsigned long long -

174

sys_rt_sigaction

const struct sigaction * sigset_t * size_t siginfo_t *

175 176

sys_rt_sigprocmask sys_rt_sigpending

int

struct sigaction size_t * sigset_t size_t *


-

sigset_t * const sigset_t *


int

177

sys_rt_sigtimedwait

178

sys_rt_sigqueueinfo

kernel/signal.c

int

const struct size_t timespec * siginfo_t *


-

179 180 181 182 183 184

185

186 187 190

arch/i386/kernel/s sigset_t * size_t ignal.c unsigned int char * sys_pread fs/read_write.c size_t unsigned int const char * sys_pwrite fs/read_write.c size_t const char * sys_chown fs/open.c uid_t gid_t sys_getcwd char * unsigned long fs/dcache.c cap_user_he sys_capget kernel/capability.c cap_user_data_t ader_t cap_user_he const sys_capset kernel/capability.c ader_t cap_user_data_t arch/i386/kernel/s const sys_sigaltstack stack_t * ignal.c stack_t * int int sys_sendfile mm/filemap.c off_t * arch/i386/kernel/p struct sys_vfork rocess.c pt_regs
sys_rt_sigsuspend

loff_t loff_t
-

size_t
-

17

Ensamblador en entornos Linux / Unix

1.6.

Herramientas

Por lo general, toda distribucin de Linux ya lleva instalado el compilador GCC que incluye las herramientas necesarias para desarrollar programas en ensamblador con sintaxis AT&T (gas). De cualquier forma, las rdenes para instalar el compilador en una distribucin basada en Debian son:
apt-get install gcc g++ make configure autoconf

las correspondientes a una distribucin basada en Red Hat o Fedora son:


yum install -y g++ make configure autoconf

Si necesitamos instalar el NASM, podemos hacerlo (ponemos las instrucciones para Debian y Red Hat):
apt-get install nasm yum install -y nasm

De todas formas, en el archivo comprimido, en la carpeta de los ejemplos de la sintaxis NASM disponemos de un ejecutable compilado estticamente que se puede usar en cualquier distribucin de Linux. Para obtener ms informacin sobre los compiladores NASM y GAS, su forma de uso, la sintaxis que aceptan, etc., se recomienda que se visiten los enlaces que se ofrecen al final de este guin.

1.7.

Ejemplos

Uso de macros en ensamblador (GAS) Podemos hacer uso de macros para facilitar la programacin. Para ello, debemos utilizar la directiva .macro de la siguiente forma:
.macro nombreMacro instrucciones .endm

En el ejemplo definiremos una macro para terminar el programa, otra para mostrar una cadena por salida estndar, y otra para leer cadenas de texto desde entrada estndar. La forma de llamar a una macro es parecida a como se llama a una funcin de C/C++ (por la forma en que le pasaremos los valores):
#COMPILAR: # as -o m.o m.s # ls -o m m.o .macro terminar movl $1,%eax movl $0,%ebx int $0x80 .endm

18

Ensamblador en entornos Linux / Unix

#espera ECX=cadena ; EDX=longitud .macro escribir_cadena cadena longitud movl $4,%eax movl $1,%ebx #stdout movl \cadena,%ecx movl \longitud,%edx int $0x80 .endm #espera ECX=cadena ; EDX=longitud .macro leer_cadena cadena longitud movl $3,%eax movl $0,%ebx #stdin movl \cadena,%ecx movl \longitud,%edx int $0x80 .endm

.data retorno: .byte 0x0A mensaje1: .ascii "\n Introduce una cadena: " longitud1 = . - mensaje1 buffer: .ascii " " .text .globl _start _start: escribir_cadena $mensaje1 $longitud1 leer_cadena $buffer $10 escribir_cadena $retorno $1 escribir_cadena $buffer $10 escribir_cadena $retorno $1 terminar

Uso de funciones en ensamblador (GAS) Podemos hacer uso de funciones para facilitar la programacin. Dentro de la seccin .text (y antes del punto de entrada al programa) podemos definir las diferentes funciones (subrutinas), utilizando una etiqueta que indiquen el inicio de la funcin y cuidando siempre terminar la ejecucin de sta con la instruccin ret. Una funcin tendr el siguiente aspecto:
nombreFuncion: instrucciones ret

Veamos el ejemplo anterior (el de las macros) utilizando tres subrutinas. Como se ver en el programa principal, el paso de parmetros a la funcin hay que hacerlo a travs de la pila o en los registros o variables globales del programa (segn como se haya programado la subrutina):
#COMPILAR: # as -o f.o f.s # ls -o f f.o

19

Ensamblador en entornos Linux / Unix

.data retorno: .byte 0x0A mensaje1: .ascii "\n Introduce una cadena: " longitud1 = . - mensaje1 buffer: .ascii " " .text .globl _start funcion_terminar: movl $1,%eax movl $0,%ebx int $0x80 ret #parmetros ECX=cadena ; EDX=longitud funcion_escribir_cadena: movl $4,%eax movl $1,%ebx #stdout int $0x80 ret #parmetros ECX=cadena ; EDX=longitud funcion_leer_cadena: movl $3,%eax movl $0,%ebx #stdin int $0x80 ret _start: #los movl movl call

parmetros se pasan en los registros $mensaje1,%ecx $longitud1,%edx funcion_escribir_cadena

movl $buffer,%ecx movl $10,%edx call funcion_leer_cadena movl $retorno,%ecx movl $1,%edx call funcion_escribir_cadena movl $buffer,%ecx movl $10,%edx call funcion_escribir_cadena movl $retorno,%ecx movl $1,%edx call funcion_escribir_cadena #esta ltima no necesita ningn parmetro call funcion_terminar

Lectura de parmetros de la lnea de comandos (GAS) Veamos un ejemplo de lectura de los argumentos de lnea de comando, programado para el ensamblador GAS. En este ejemplo se hace uso de todo lo descrito en Acceso a la pila en un programa ensamblador en Linux:

20

Ensamblador en entornos Linux / Unix

#COMPILAR: # as -o parametros.o parametros.s # ls -o parametros parametros.o .data retorno: .byte 0x0A .text .globl _start _start: pop %eax #extraer de la pila el ARGC repetir: #bucle para recorrer todos los argumentos pop %eax #extraer el ARGV[i] testl %eax,%eax #comprobar si es NULL jz terminar call funcion_pintar_cadena #llamada a la funcion jmp repetir terminar: movl $1, %eax movl $0, %ebx int $0x80

#funcion del sistema para terminar

funcion_pintar_cadena: #definicion de una funcion movl %eax,%ecx #el parametro ha sido pasado en EAX xorl %edx,%edx contar: #debemos calcular la longitud del param. movb (%ecx,%edx,$1),%al testb %al,%al #comprobar el caracter de la cadena jz fin_contar incl %edx #vamos incrementando el calculo en EDX jmp contar fin_contar: movl $4,%eax #una vez calculada la longitud,se muestra movl $1,%ebx int $0x80 movl $4,%eax movl $retorno,%ecx movl $1,%edx int $0x80 ret #mostramos el RETORNO_CARRO #es un solo caracter

Para cada parmetro llamamos a una funcin que lo muestre por salida estndar. Para ello debe calcular la longitud de la cadena (argumento actual), contando uno por uno cada carcter que la forma. Tras cada argumento impreso, se hace un retorno de carro (es una cadena de caracteres de longitud 1). El programa muestra tambin el nombre del ejecutable como primer argumento (sera casi inmediato hacer que slo muestre los argumentos reales). Lectura del contenido de un fichero (NASM) El siguiente ejemplo lee los 1024 primeros bytes de un fichero que le pasemos como primer argumento por la lnea de comandos y los muestra por salida estndar. En este ejemplo, la sintaxis utilizada ha sido la de Intel (NASM).

21

Ensamblador en entornos Linux / Unix

;COMPILAR: ; nasm -f elf acceso_a_fich.asm ; ld -s -o acceso_a_fich acceso_a_fich.o section .data mensaje longitud mensaje2 longitud2 tamano section .bss buffer:

db 0xA,"---vamos a probar esto---",0xA equ $ - mensaje db 0xA,"---hemos terminado---",0xA equ $ - mensaje2 equ 1024

resb

1024

section .text global _start _start: mov edx,longitud mov ecx,mensaje mov ebx,1 mov eax,4 int 0x80 pop ebx pop ebx pop mov mov int ebx eax,5 ecx,0 0x80

;definimos el punto de entrada ;EDX=long. de la cadena ;ECX=cadena a imprimir ;EBX=manejador de fichero (STDOUT) ;EAX=funcin sys_write() del kernel ;interrupc. 80 (llamada al kernel)

;extraer "argc" ;extraer argv[0] (nombre del ejecutable) ;extraer el primer arg real (puntero a cadena) ;funcin para sys_open() ;O_RDONLY (definido en fcntl.h) ;interrupc. 80 (llamada al kernel)

test eax,eax ;comprobar si dev. error o el descriptor jns leer_del_fichero hubo_error: mov ebx,eax mov eax,1 int 0x80

;terminar, devolviendo el cdigo de error

leer_del_fichero: mov ebx,eax push ebx mov eax,3 mov ecx,buffer mov edx,tamano int 0x80 js hubo_error mostrar_por_pantalla: mov edx,eax mov eax,4 mov ebx,1 int 0x80 cerrar_fichero: pop ebx mov eax,6 int 0x80

;no hay error=>devuelve descriptor ;funcin para sys_read() ;variable donde guardamos lo leido ;tamao de lectura

;longitud de la cadena a escribir ;funcin sys_write() ;descriptor de STDOUT

;funcin para cerrar un fichero

22

Ensamblador en entornos Linux / Unix

mov mov mov mov int

edx,longitud2 ;EDX=long. de la cadena ecx,mensaje2 ;ECX=cadena a imprimir ebx,1 ;EBX=manejador de fichero (STDOUT) eax,4 ;EAX=funcin sys_write() del kernel 0x80 ;interrupc. 80 (llamada al kernel)

mov ebx,0 mov eax,1 int 0x80

;EBX=cdigo de salida al SO ;EAX=funcin sys_exit() del kernel ;interrupc. 80 (llamada al kernel)

Hemos hecho uso de datos inicializados (seccin .data) y no inicializados (seccin .bss) donde guardamos los datos ledos del fichero. El acceso al fichero para abrirlo, leerlo y cerrarlo se hace mediante las funciones del sistema (int 80h) de forma muy sencilla. Llamar a funciones externas definidas en un mdulo de C/C++ desde ensamblador Vamos a suponer que tenemos un mdulo escrito en C/C++ que define varias funciones muy tiles que luego querremos llamar desde nuestro programa ensamblador. El mdulo en C/C++ de este ejemplo tendr dos funciones, una que recibe dos parmetros, y otra que no recibe ninguno. Ambas, para este ejemplo, slo van a mostrar por salida estndar un mensaje y los parmetros recibidos. El cdigo fuente podra ser el siguiente:
#include <stdio.h> #include <stdlib.h> void func_con_parametros(int x, int y); void func_sin_parametros(); void func_con_parametros(int x, int y) { printf("Llamada con dos parametros x=%d y=%d \n", x , y ); } void func_sin_parametros() { printf("Llamada SIN parametros \n"); }

En este caso, nos vemos obligados a definir como punto de entrada del programa ensamblador, en lugar de _start, la etiqueta main (como en C/C++). Ya dentro del programa, antes de llamar a ninguna funcin, nuestro programa ensamblador (sintaxis GAS) debe inicializar la pila. Luego, para pasar los parmetros (si son necesarios), debe insertarlos en la pila en el orden inverso (primero el ltimo, etc.), hacer la llamada a la funcin, y por ltimo, deshacer las inserciones hechas antes de la llamada (ajustar el valor del registro puntero de pila, SP):
.data mensaje: .ascii " --mensaje desde ASM directamente--\n" mensaje_SIZE = . - mensaje .text .globl main main: # inicializar la pila

23

Ensamblador en entornos Linux / Unix

pushl %ebp movl %esp, %ebp # llamar a la funcin que recibe 2 argumentos de tipo entero pushl $25 pushl $76 call func_con_parametros addl $8, %esp # # # # # segundo parametro (4 bytes) primer parametro (4 bytes) func_con_parametros(76,25) quitar de la pila 8 bytes (dos num. enteros)

# mostrar texto directamente con la INT 80h movl $4, %eax movl $1, %ebx movl $mensaje, %ecx movl $mensaje_SIZE, %edx int $0x80 # llamar a la funcin que NO recibe argumentos call func_sin_parametros # restaurar el valor del EBP # (dejar la pila como esta al principio del programa) popl %ebp # terminar y salir al sistema operativo movl $1, %eax movl $0, %ebx int $0x80

Para compilarlo, puesto que tenemos mdulos escritos en C/C++ y en ensamblador, vamos a usar el compilador GCC:
gcc -Wall -O2 -o progr funciones.c progr.s

1.8.

Depuracin de cdigo usando gdb

En Linux podemos hacer uso del gdb para depurar el cdigo que hemos escrito (trazar paso a paso, comprobar el valor de ciertos registros en cada momento, etc). Para ello, debemos ensamblar nuestros programas con una opcin especial del as :
as a -gstabs o prog.o prog.s

la opcin a nos mostrar un listado de memoria durante el proceso de ensamblaje, donde podremos ver la localizacin de las variables y cdigo respecto al principio de los segmentos de cdigo y datos. La opcin gstabs introduce informacin de depuracin en el fichero binario, que luego usar gdb.
host:~/asm$ as -a --gstabs -o h.o hola.s GAS LISTING hola.s page 1 1 ## hola.s 2 3 ## COMPILAR: 4 ## as -o hola.o hola.s

24

Ensamblador en entornos Linux / Unix

5 ## ld -o hola hola.o 6 7 ## muestra una cadena de 8 9 ######################################################################## 10 .section .data 11 hola: 12 0000 486F6C61 .ascii "Hola!\n" 12 210A 13 hola_len: 14 0006 06000000 .long . - hola 15 ######################################################################## 16 .section .text 17 .globl _start 18 19 _start: 20 0000 31DB xorl %ebx, %ebx # %ebx = 0 21 0002 B8040000 movl $4, %eax # llamada a write() 21 00 22 0007 31DB xorl %ebx, %ebx # %ebx = 0 23 0009 43 incl %ebx # %ebx = 1, fd = stdout 24 000a 8D0D0000 leal hola, %ecx # %ecx ---> hola 24 0000 25 0010 8B150600 movl hola_len, %edx # %edx = longitud 25 0000 26 0016 CD80 int $0x80 # ejecuta write() 27 28 ## termina con la llamada a la funcion _exit() 29 0018 31C0 xorl %eax, %eax # %eax = 0 30 001a 40 incl %eax # %eax = 1 _exit () 31 001b 31DB xorl %ebx, %ebx # %ebx = 0 cod. retorno 32 001d CD80 int $0x80 # ejecuta _exit () GAS LISTING hola.s page 2 DEFINED SYMBOLS hola.s:11 hola.s:13 hola.s:19 NO UNDEFINED SYMBOLS

.data:00000000 hola .data:00000006 hola_len .text:00000000 _start

El proceso de linkado se lleva a cabo con la instruccin que conocemos:


ld o prog prog.o

Primer paso de la depuracin: llamar a gdb indicndole el ejecutable a depurar


gdb ./prog
host:~/asm$ gdb ./h GNU gdb Red Hat Linux (5.2.1-4) Copyright 2002 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux"... (gdb)

La orden l muestra el texto del programa de 10 en 10 lneas:


(gdb) l 1 ## hola.s 2 3 ## COMPILAR: 4 ## as -o hola.o hola.s 5 ## ld -o hola hola.o 6 7 ## muestra una cadena de texto utilizando la llamada al sistema write() 8 9 ######################################################################## 10 .section .data

25

Ensamblador en entornos Linux / Unix

(gdb) l 11 hola: 12 .ascii "Hola!\n" 13 hola_len: 14 .long . - hola 15 ######################################################################## 16 .section .text 17 .globl _start 18 19 _start: 20 xorl %ebx, %ebx # %ebx = 0 (gdb) l 21 movl $4, %eax # llamada a write() 22 xorl %ebx, %ebx # %ebx = 0 23 incl %ebx # %ebx = 1, fd = stdout 24 leal hola, %ecx # %ecx ---> hola 25 movl hola_len, %edx # %edx = longitud 26 int $0x80 # ejecuta write() 27 28 ## termina con la llamada a la funcion _exit() 29 xorl %eax, %eax # %eax = 0 30 incl %eax # %eax = 1 _exit () (gdb)

Antes de ejecutar el programa debemos establecer dos puntos de ruptura (break): uno correspondiente a la etiqueta de comienzo del programa (_start) y otro en la lnea siguiente (en el primero no para, pero es necesario ponerlo...). Vemos que al poner el primer punto, nos indica un nmero de lnea. Nosotros debemos poner otro punto en la lnea cuyo nmero es el siguiente al que nos acaba de indicar. Una vez hecho esto, ya podemos ejecutar el programa (run):
(gdb) break _start Breakpoint 1 at 0x8048074: file hola.s, line 20. (gdb) break 21 Breakpoint 2 at 0x8048076: file hola.s, line 21. (gdb) run Starting program: /home/pedro/asm_linux/asm-tut/h Breakpoint 2, _start () at hola.s:21 21 movl $4, %eax # llamada a write() Current language: auto; currently asm

Podemos ir viendo los valores de los registros mediante info registers o bien con p/x $registro
(gdb) info registers eax 0x0 0 ecx 0x0 0 edx 0x0 0 ebx 0x0 0 esp 0xbffff990 0xbffff990 ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0x8048076 0x8048076 eflags 0x200246 2097734 cs 0x23 35 ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x0 0 fctrl 0x37f 895 fstat 0x0 0 ftag 0xffff 65535 fiseg 0x0 0 fioff 0x0 0 foseg 0x0 0 fooff 0x0 0 fop 0x0 0 xmm0 {f = {0x0, 0x0, 0x0, 0x0}}

{f = {0, 0, 0, 0}}

26

Ensamblador en entornos Linux / Unix

xmm1 xmm2 xmm3 xmm4 xmm5 xmm6 xmm7 mxcsr orig_eax (gdb) p/x $eax $1 = 0x0

{f = {0x0, {f = {0x0, {f = {0x0, {f = {0x0, {f = {0x0, {f = {0x0, {f = {0x0, 0x0 0 0xffffffff

0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,

0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -1

0x0}} 0x0}} 0x0}} 0x0}} 0x0}} 0x0}} 0x0}}

{f {f {f {f {f {f {f

= = = = = = =

{0, {0, {0, {0, {0, {0, {0,

0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0,

0}} 0}} 0}} 0}} 0}} 0}} 0}}

La traza paso a paso del programa la haremos con la orden step . A cada paso nos va mostrando la instruccin a ejecutar a continuacin; mediante las rdenes anteriores podremos ir viendo cmo cambia el contenido de los registros:
(gdb) step 22 (gdb) step 23 (gdb) step 24 (gdb) p/x $eax $2 = 0x4 (gdb) p/x $ebx $3 = 0x1 xorl %ebx, %ebx incl %ebx leal hola, %ecx # %ebx = 0 # %ebx = 1, fd = stdout # %ecx ---> hola

1.9.

Trabajo a desarrollar

A lo largo de las sesiones de prcticas se propondrn ejercicios sencillos basados en los ejemplos explicados. Esos ejercicios se debern entregar en la fecha indicada.

1.10. Enlaces interesantes


http://linuxassembly.org http://linuxassembly.org/articles/linasm.html http://www.leto.net/papers/writing-a-useful-program-with-nasm.txt http://linuxassembly.org/howto/hello.html http://linuxassembly.org/startup.html http://linuxassembly.org/articles/startup.html http://www.janw.easynet.be/eng.html http://www.gnu.org/manual/gas http://www.gnu.org/onlinedocs/gcc_toc.html http://www.gnu.org/manual/gdb-4.17/gdb.html http://leto.net/writing/nasm.php http://linuxassembly.org/howto/Assembly-HOWTO.html http://navet.ics.hawaii.edu/~casanova/courses/ics312_fall07/nasm_howto.html http://www.logix.cz/michal/doc/i386/ http://pdos.csail.mit.edu/6.828/2004/readings/i386/toc.htm http://www.cilinder.be/docs/next/NeXTStep/3.3/nd/Assembler/

S-ar putea să vă placă și