___________________________________________________________________________ | | | bhats curso 2006/2007 - Bajo Nivel - Notas 0x002 http://www.bhats.org | |___________________________________________________________________________| Justificado a 77 columnas MAX. ÍNDICE ====== ___________________________________________________________________________ | Título | NÚM | |-----------------------------------------------------------------|---------| | Introducción. | 0x000 | | Windows. | 0x001 | | Linux. | 0x002 | | Bibliografía. | 0x003 | |_________________________________________________________________|_________| 0x000 - INTRUDUCCIÓN ==================== En este documento se expondran varios ejemplos del típico "Hellow world" en ensamblador para x86 en los sistemas operativos: Windows y Linux. Se han usado los ensambladores: MASM32, NASM & GAS. 0x001 - WINDOWS =============== En windows para mostrar un mensaje se puede hacer mediante consola o una caja de diálogo (dialog box). En el documento solo se usarán mensajes por ventana usando funciones de la API de win32. MASM32 ====== Macro ensamblador de Microsoft. Función para mostrar un mensaje, MessageBox: int MessageBox( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType ); Tipos de datos de Windows: HWND: Manejador de ventana. LPCTSTR: Puntero a constante de cualquier tipo. UINT: Entero sin signo. Argumentos que recibe la función: hWnd: Manejador del creador de la ventana, si se indica NULL la ventana no tiene creador. lpText: Mensaje de la ventana que consiste en un puntero a cadena de caracteres estilo C (acabada en byte 0x00). lpCaption: Título de la ventana, consiste en un puntero a cadena de caracteres estilo C, si se indica NULL se muestra como título: Error. uType: Especifica el contenido y el comportamiento de la caja de diálogo, por defecto se asume MB_OK (botón típico de aceptar). Ejemplo de hola mundo en MASM32 para WIN32: .386 ; Este código estará destinado para plataformas 386 y compatibles. .model flat, stdcall ; Modelo de memoria plana (flat) y paso de parámetros ; STDCALL (izq-dch, llamada ajusta la pila). option casemap:none ; No hace distinción entre letras mayúsculas y ; minúsculas. include \masm32\include\user32.inc ; Declaraciones de estructuras, ; funciones ... de user32.dll includelib \masm32\lib\user32.lib ; Biblioteca de user32.dll .data ; Sección de datos iniciados a un valor determinado. titulo db "Saludo a un bhat", 00h ; Título de la ventana. mensaje db "Hola bhat!", 00h ; Mensaje de la ventana. .code ; Sección de código ejecutable. start: ; Etiqueta donde empieza a ejecutar el programa. PUSH 00h ; NULL: La ventana no tiene creador. PUSH offset titulo ; Dirección de memoria donde se ; encuentra el título. PUSH offset mensaje ; Dirección de memoria donde se ; encuentra el mensaje. PUSH 00h ; NULL: La ventana solo tendrá un botón de ; aceptar (MB_OK). CALL MessageBox ; Llamamos a la función MessageBox. RET ; Fin del programa, informamos al SO. end start ; Fin de la etiqueta. Comandos necesarios para obtener un fichero ejecutable: C:\bh4ts> ml.exe /c /coff /Cp holamundomasm.asm C:\bh4ts> link.exe /SUBSYSTEM:WINDOWS holamundomasm.obj C:\bh4ts> holamundomasm.exe Esto suponiendo que el código en ensamblador puesto arriba esté situado en un fichero llamado holamundomasm.asm Vamos a explicar paso por paso que hemos hecho: 1) ml.exe /c /coff /Cp holamundomasm.asm: Ensamblamos sin enlazar (/c), creamos un fichero con formato COFF (/coff), no hacemos distinción entre letras mayúsculas y minúsculas (/Cp) 2) link.exe /SUBSYSTEM:WINDOWS holamundomasm.obj: Enlazamos el fichero objeto para WINDOWS. NASM ===== En el MASM32 llamabamos a MessageBox pero vemos en user32.inc a donde realmente llamamos: user32.inc - MASM32: MessageBoxA PROTO :DWORD,:DWORD,:DWORD,:DWORD MessageBox equ Esto quiere decir que llamamos realmente a MessageBoxA (que es la implementación ANSI de la función MessageBox). Nota: Se menciona esto por que a continuación se llamará a MessageBoxA directamente. Ejemplo de hola mundo para NASM en WIN32: ; Funciones de la API de WIN32 que vamos a usar. [extern MessageBoxA] ; Usaremos la función MessageBoxA. [segment .data] ; Sección de datos iniciados a un valor determinado. titulo: db 'Saludo a un bhat', 0 ; Titulo de la ventana. mensaje: db 'hola bhat', 0 ; Mensaje de la ventana. [segment .text] ; Nombre de la sección de código ejecutable. [global main] ; Indicamos donde se empezará a ejecutar el programa. main: ; Punto de entrada. PUSH DWORD 0x00 ; NULL: La ventana no tiene creador. PUSH DWORD titulo ; Dirección de memoria donde se encuentra el ; título. PUSH DWORD mensaje ; Dirección de memoria donde se encuentra el ; mensaje. PUSH DWORD 0x00 ; NULL: La ventana solo tendrá un botón de aceptar (MB_OK). CALL MessageBoxA ; Llamamos a la función MessageBox. RET ; Fin del programa, informamos al SO. ; Fin del programa. Comandos necesarios para obtener un fichero ejecutable: C:\bh4ts> nasmw.exe -f win32 holamundonasmw.asm C:\bh4ts> alink.exe -oPE win32.lib holamundonasmw.obj C:\bh4ts> holamundonasmw.exe Esto suponiendo que el código en ensamblador puesto arriba esté situado en unfichero llamado holamundonasmw.asm Vamos a explicar paso por paso que hemos hecho: 1) nasmw.exe -f win32 holamundonasmw.asm: Ensamblamos holamundonasmw.asm, creando un fichero objeto para win32. 2) alink.exe -oPE win32.lib holamundonasmw.obj: Enlazamos el fichero objeto dandole como salida un formato PE32 (son los ejecutables de win32), win32.lib se especifica para que se pueda encontrar MessageBoxA. GAS (mingw32) ============= Ejemplo de hola mundo para WIN32 con GAS: .data ; Sección de datos iniciados a un valor determinado. titulo: .string "Saludo a un bhat.\0" ; Titulo de la ventana. mensaje: .string "Hola bhat!\0" ; Mensaje de la ventana. .text ; Sección de código ejecutable. .globl _WinMain@16 ; Indicamos donde se empezará a ejecutar el ; programa. _WinMain@16: ; Punto de entrada. PUSH $00 ; NULL: La ventana no tiene creador. PUSH $titulo ; Dirección de memoria donde se encuentra el tít PUSH $mensaje ; Dirección de memoria donde se encuentra el mensaje. PUSH $00 ; NULL: La ventana solo tendrá un botón de aceptar (MB_OK). CALL _MessageBoxA@16 ; Llamamos a la función MessageBox. RET ; Fin del programa, informamos al SO. ; Fin del programa. Comandos necesarios para obtener un fichero ejecutable: 1) C:\bh4ts> gcc -c holamundogas.s 2) C:\bh4ts> gcc holamundogas.o -o holamundogas.exe -mwindows 3) C:\bh4ts> holamundogas.exe Vamos a explicar paso por paso que hemos hecho: 1) gcc -c holamundogas.s: Creamos un fichero objeto a partir de holamundogas.s 2) gcc holamundogas.o -o holamundogas.exe -mwindows: Convertimos el fichero objeto en un fichero ejecutable y le añadimos -mwindows para que no salga la consola (solo la ventana). Esto suponiendo que el código en ensamblador puesto arriba esté situado en un fichero llamado holamundogas.asm 0x002 - LINUX ============= Cuando en Linux queremos por ejemplo escribir o leer (y otras muchas cosas) se llama a una syscall (llamada del sistema) que realiza una función determinada. Ejecucion de una Llamada al sistema (syscall) desde el punto de vista de un proceso: 1) Un proceso deposita los parámetros necesarios en los registros. 2) Se pone en %EAX el numero de la syscall. 3) Se ejecuta la interrupción 0x80. 4) Se retorna un valor en %EAX. NOTA: El paso 1 y 2 no tienen por que ir en ese orden (pero el paso 3 y 4 siempre en el orden expuesto). Llamada al sistema (syscall) sys_write: ___________________________________________________ | %EAX | %EBX | %ECX | %EDX | |----------|---------------|--------------|---------| | 4 | unsigned int | const char * | size_t | |__________|_______________|______________|_________| Esto quiere decir que para escribir necesitaremos: 1) Depositar en %EAX: el valor 4 (número de la syscall). 2) Depositar en %EBX: el medio donde se quiere escribir. 3) Depositar en %ECX: la dirección de memoria donde se encuentra el mensaje. 4) Depositar en %EDX: el tamaño en bytes de lo que desea escribir. Y los tipos de datos se muestran en la tabla. GAS ==== Ejemplo de programa que muestra una cadena de caracteres por pantalla para GAS: # Sección con datos iniciados a un valor determinado. .data # Nombre de la sección. mensaje: .string "hola bhat.\n" # Cadena de caracteres. # Sección con código ejecutable. .text # Nombre de la sección. .globl main # Definimos donde se empezará a # ejecutar el programa. .type main, @function # Indicamos que main es una función main: # Punto de entrada MOVL $11, %EDX # Ponemos en EDX el tamaño de la cadena de # caracteres mensaje. MOVL $mensaje, %ECX # Dirección en memoria en la que estará el # mensaje. MOVL $1, %EBX # Indicamos que mostraremos el mensaje por # pantalla (1 == STDOUT) MOVL $4, %EAX # Numero de la llamada al sistema (syscall) # que corresponde a Write. INT $0x80 # Llamamos a la interrupción 0x08. RET # El programa a finalizado. Se llama a RET # para que lo sepa el SO. # fin del código. Comandos necesarios para obtener un fichero ejecutable: David Reguera García@localhost ~/bhats $ gcc -c holabhat.s David Reguera García@localhost ~/bhats $ gcc holabhat.o -o holabhat David Reguera García@localhost ~/bhats $ ./holabhat Esto suponiendo que el código en ensamblador puesto arriba esté situado en un fichero llamado holabhat.s Vamos a explicar paso por paso que hemos hecho: 1) gcc -c holabhat.s: Convertimos el código en ensamblador a código objeto. 2) gcc holabhat.o -o holabhat: Enlazamos el código objeto creando un ejecutable. 3) ./holabhat: Ejecutamos el programa. Nota: Se podría hacer de otras maneras, pero así es más simple. NASM ==== Ejemplo de hola mundo para Linux con NASM: ; Sección con datos iniciados a un valor determinado. SECTION .data ; Nombre de la sección. mensaje: db "hola bhat!", 0x0A ; Cadena de caracteres que ; mostraremos por pantalla. ; 0x0A = '\n' (retorno de ; carro y nueva linea). ; Sección con código ejecutable. SECTION .text ; Nombre de la sección. global main ; Indicamos donde se empezará a ejecutar el ; programa. main: ; Punto de entrada. MOV EDX, 11 ; Ponemos en EDX el tamaño de la cadena de ; caracteres mensaje. MOV ECX, mensaje ; Dirección en memoria en la que estará el ; mensaje. MOV EBX, 1 ; Indicamos que mostraremos el mensaje por pantalla ; (1 == STDOUT) MOV EAX, 4 ; Numero de la llamada al sistema (syscall) que ; corresponde a Write. INT 0x80 ; Llamamos a la interrupción 0x08. RET ; El programa a finalizado. Se llama a RET para que lo sepa el ; SO. ; Fin del código. Comandos necesarios para obtener un fichero ejecutable: David Reguera García@localhost ~/bhats $ nasm -f elf holabhatnasm.s David Reguera García@localhost ~/bhats $ gcc holabhatnasm.o -o holabhatnasm David Reguera García@localhost ~/bhats $ ./holabhatnasm Esto suponiendo que el código en ensamblador puesto arriba esté situado en un fichero llamado holabhatnasm.s Vamos a explicar paso por paso que hemos hecho: 1) nasm -f elf holabhatnasm.s: Convertimos el código en ensamblador a código objeto ELF. 2) gcc holabhatnasm.o -o holabhatnasm: Enlazamos el código objeto creando un ejecutable. 3) ./holabhatnasm: Ejecutamos el programa. Nota: Se podría hacer de otras maneras, pero así es más simple. 0x003 - BIBLIOGRAFÍA ==================== http://docs.cs.up.ac.za/programming/asm/derick_tut/syscalls.html http://www.linuxassembly.org/ http://win32assembly.online.fr/ http://msdn.microsoft.com/library/ Cualquier duda se planteará por IRC, FORO o Lista de correo. ( ver la dirección de las mismas en http://www.bhats.org ). By David Reguera García, http://www.bhats.org 2006-2007, David Reguera García@bhats.org \===========================================================================/ EOF /===========================================================================\