On peut écrire un programme assembleur qui pourra être compilé en exécutable. Il faut pour cela qu'il dispose d'une méthode main comme pour les programmes C/C++ :
Pour compiler :
> nasm -f elf hello_world_nasm.asm
> gcc -o hello_world_nasm.exe hello_world_nasm.o -m32
> ./hello_world_nasm.exe
Hello World !
Note : lorsqu'on travaille en mode 64 bits on utilisera :
L'option -m64 de gcc peut être omise si l'on est sur un système 64 bits, le compilateur utilisant ce mode par défaut
Il est parfois plus simple d'écrire un programme C/C++ et de ne coder en assembleur que la partie que l'on désire optimiser. Dans ce cas il faut déclarer en externe les méthodes assembleur. Prenons en exemple concret, on désire appeller la fonction array_sum écrite en assembleur dans le fichier array_sum_nasm.asm depuis le fichier C++ array_sum.cpp
Pour compiler et exécuter, on utilise les commandes suivantes :
> nasm -f elf array_sum_nasm.asm
> g++ -c array_sum.cpp -m32
> g++ -o array_sum.exe array_sum.o array_sum_nasm.o -m32
> ./array_sum.exe
sum=55
La troisième ligne réalise l'édition de lien en prenant le fichier objet C++ et la fichier objet Nasm.
On peut éventuellement installer le paquet Electric-Fence qui permet de traquer les erreurs d'accès à la mémoire :
sudo apt-get install electric-fence
On peut vérifier que les librairies sont installées :
> ls /usr/lib/libef*
/usr/lib/libefence.a /usr/lib/libefence.so.0
/usr/lib/libefence.so /usr/lib/libefence.so.0.0
Si vous êtes sur une architecture 64 bits et que vous voulez disposer des sources 32 bits par exemple.
Pour compiler votre programme, attention vous devriez obtenir des warnings :
gcc -o a_nasm.exe a_nasm.o -ggdb -m32 libefence32.a -lpthread
libefence32.a(page.o): In function `stringErrorReport':
/home/richer/install/electric-fence-master/page.c:49: warning: `sys_errlist' is deprecated; use `strerror' or `strerror_r' instead
/home/richer/install/electric-fence-master/page.c:48: warning: `sys_nerr' is deprecated; use `strerror' or `strerror_r' instead
Installer le débugueur en mode graphique ddd, celui-ci représente une interface au débugueur en ligne de commande gdb :
sudo apt-get install ddd
On utilise le programme suivant pour exemple de travail a_nasm.asm :
On utilise lors de la compilation, les arguments pour chaque programme qui permettent d'inclure des informations qui seront utiles au débogueur :
nasm -f elf -g -F dwarf a_nasm.asm
gcc -o a_nasm.exe a_nasm.o -ggdb -lefence
ou cf ci-dessus si vous êtes sur un système 64 bits et que vous avez installé electric-fence en compilant le code source en 32 bits :
gcc -o a_nasm.exe a_nasm.o -ggdb libefence32.a -lpthread
gdb, le GNU débugueur, est un débugueur en mode console :
> gdb a_nasm.exe
GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2) 7.4-2012.04
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
...
Reading symbols from /home/richer/dev/asm/a_nasm.exe...done.
(gdb)
On donne un argument au programme et on l'exécute :
(gdb) set args 10
(gdb) run
Starting program: /home/richer/dev/asm/a_nasm.exe 10
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
Electric Fence 2.1 Copyright (C) 1987-1998 Bruce Perens.
Program received signal SIGSEGV, Segmentation fault.
main.for1 () at a_nasm.asm:45
45 mov [ebx + ecx*4], eax
(gdb)
Remarque : on aurait pu utiliser plus simplement run 10
L'erreur d'accès mémoire s'est produite en ligne 45 et provient forcément de l'adresse : [ebx + ecx*4] qui n'est pas valide; on examine alors les registres :
(gdb) info registers
eax 0x4 4
ecx 0x3 3
edx 0x1 1
ebx 0xb7cf8ff4 -1211133964
esp 0xbffff248 0xbffff248
ebp 0xbffff268 0xbffff268
esi 0x0 0
edi 0x0 0
eip 0x8048518 0x8048518
eflags 0x210297 [ CF PF AF SF IF RF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
soit ebx n'est pas une adresse valide, soit c'est l'indice ecx, en relisant le programme on s'apercevra qu'on a alloué que 10 octets (et non pas 10 entiers), et donc lorsqu'on tente d'accèder au 3*4 = 12 ième octet, une erreur est donc levée.
ddd a_nasm.exe
Dans le menu principal cliquer sur Program, puis Run.
Saisir le pamamètre : 10, dans le champ "Run with Arguments"
Dans le menu principal cliquer sur Status, puis Registers :
Dans le menu Status, le sous menu Backtrace permet d'avoir accès à la pile des appels de sous-programmes.
(gdb) set \$eax=1
(gdb) set \$st0=3.14
(gdb) set \$xmm0.v4_int32={1,2,3,4}
(gdb) set \$xmm0.v4_float={1.1,2.13,3.14926,4e-5}
On peut afficher les registres dans leur totalité, par catégorie ou en détaillant le type du registre :
On peut également choisir d'afficher un registre en particulier :
(gdb) print \$eax
\$2 = 1448448008
(gdb) set \$xmm0.v4_int32={1,2,3,4}
(gdb) print \$xmm0
\$5 = {v4_float = {1.40129846e-45, 2.80259693e-45, 4.20389539e-45, 5.60519386e-45}, v2_double = {4.2439915824246103e-314, 8.4879831653432862e-314}, v16_int8 = {1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0}, v8_int16 = {1, 0, 2, 0, 3, 0, 4, 0}, v4_int32 = {1, 2, 3, 4}, v2_int64 = {8589934593, 17179869187}, uint128 = 316912650112397582603894390785}
(gdb) print \$xmm0.v4_int32
\$6 = {1, 2, 3, 4}
(gdb)
Considérons la section de données suivante que l'on désire afficher :
section .data
v: dd 1, 2, 3, 4
x: db 1, 2, 3, 4, 5, 6, 7, 8
db 255, 6, 5, 4, 3, 2, 1, 128
L'adresse de v est 0x56559008. On peut l'obtenir par commande :
(gdb) print &v
\$7 = (<data variable, no debug info> *) 0x56559008 <v>
On utilise la commande x/ suivie :
Par exemple, pour afficher 32 octets affichés sous forme d'entiers (signés) :
(gdb) x/32db 0x56559008
0x56559008 <v>: 1 0 0 0 2 0 0 0
0x56559010: 3 0 0 0 4 0 0 0
0x56559018 <x>: 1 2 3 4 5 6 7 8
0x56559020: -1 6 5 4 3 2 1 -128
Pour afficher 32 octets affichés sous forme d'entiers non signés :
(gdb) x/32ub 0x56559008
0x56559008 <v>: 1 0 0 0 2 0 0 0
0x56559010: 3 0 0 0 4 0 0 0
0x56559018 <x>: 1 2 3 4 5 6 7 8
0x56559020: 255 6 5 4 3 2 1 128
Pour afficher 10 double mots en hexadécimal, on utilisera :
(gdb) x/10xw 0x56559008
0x56559008 <v>: 0x00000001 0x00000002 0x00000003 0x00000004
0x56559018 <x>: 0x04030201 0x08070605 0x040506ff 0x80010203
0x56559028 <completed>: 0x00000000 0x00000000