Estoy aprendiendo ensamblador con NASM (Netwide Assembler) bajo Linux, tengo como herramientas los compiladores gcc, g++ también el enlazador ld que es usado de manera interna por estos compiladores, también para hacer ingeniería inversa o disassembly utilizo bokken y objdump para leer las extensiones .o, .out.
Si se pudiese dar una explicación más exhaustiva de ¿Cuál es la mejor forma de usarlo?
Un ejemplo mediante la arquitectura IA-32 para hacer operaciones como de lectura y escritura se tienen dos alternativas:
- System calls de linux.
- Usar las funciones externas de C como printf, scanf.
Usando las system calls o llamadas del sistema sería:
section .data
msg: db "Coding in asm", 10, 0 ;define a string
smsg: equ msg ;length of msg
section .text
global _start:
;define a macro for print
%macro print 2
mov eax, 4 ;call to the O.S. for write
mov ebx, 1 ;file descriptor
mov ecx, %1 ;put the msg
mov edx, %2 ;put the length of msg
int 80h ; generate one interruption
mov eax, 1 ;call to the system out
mov ebx, 0 ;pass one parameter
int 80h
%endmacro
_global:
print msg, smsg
Para generar el código objeto y ejecutarlo se usa los sisguientes comandos
nasm -f elf msg.asm
ld -m elf_i386 -s -o msg msg.o
./msg
Usando las funciones externas de C
section .data
msg: db "Coding in asm", 10, 0 ;define a string
section .text
extern printf ;include the printf function in asm program
global main
main:
push ebp
mov ebp, esp ;pass the reference of reg esp to ebp
push msg
call printf ;print the current element in the stack
mov esp, ebp
pop ebp ;free the stack
ret
cuando publiques código, procura usar las etiquetas GeSHi o por lo menos code, lo hace más legible (aquí está con etiqueta ASM)
section .data
msg: db "Coding in asm", 10, 0 ;define a string
smsg: equ msg ;length of msg
section .text
global _start:
;define a macro for print
%macro print 2
mov eax, 4 ;call to the O.S. for write
mov ebx, 1 ;file descriptor
mov ecx, %1 ;put the msg
mov edx, %2 ;put the length of msg
int 80h ; generate one interruption
mov eax, 1 ;call to the system out
mov ebx, 0 ;pass one parameter
int 80h
%endmacro
_global:
print msg, smsg
section .data
msg: db "Coding in asm", 10, 0 ;define a string
section .text
extern printf ;include the printf function in asm program
global main
main:
push ebp
mov ebp, esp ;pass the reference of reg esp to ebp
push msg
call printf ;print the current element in the stack
mov esp, ebp
pop ebp ;free the stack
ret
CitarSystem calls de linux.
Usar las funciones externas de C como printf, scanf.
El resultado final es el mismo siempre.
Si usas syscalls de linux tendras que llamar a un par de syscalls extra seguramente y pasar mas de un parametro extra tambien. Los syscalls llamaran a los drivers hecho, pasa lo que tiene que pasar.
Si usas las funciones de la libreria de C standard, lo que pasará es que primero tendras que llamar menos funciones y pasar menos parametros. La libreria de C se encargará de hacer los syscalls y los syscalls llamar a los drivers.
Si cierto, tienes mas codigo que se ejecuta, pero tendrias menos lineas de codigo y seguramente un par de chequeos extra.
Yo si tengro que programar lo hago en windows si, pero al final termino usando las libreria de C standart para rutinas de i/o. Menos tedioso.
Si hay que tener que tener controlado el tema de la convencion de llamadas. C utiliza cdesl y luego syscalls de linux usan fastcall? Es decir si mal no recuerdo algunos parametros se pasan en registros.
Pudes tranquilamente depurar los rutinas llamadas por c runtime y fijarte que syscalls termina haciendo.
Saludos