ASSEMBLER MALIZIOSO Quanti di voi si sono mai chiesti cos'è una sistem call in realtà? Facciamo un esempio pratico per andarlo a capire a fondo: bakunin: ~/C$ cat "int main(void) {fork();}" > a.c bakunin: ~/C$ cc a.c bakunin: ~/C$ cc a.c -ggdb bakunin: ~/C$ gdb a.out GNU gdb 5.2 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 "i686-pc-linux-gnu"... (gdb) disassemble main Dump of assembler code for function main: 0x8048400
: push %ebp 0x8048401 : mov %esp,%ebp 0x8048403 : sub $0x8,%esp 0x8048406 : call 0x80482e0 0x804840b : mov %ebp,%esp 0x804840d : pop %ebp 0x804840e : ret End of assembler dump. (gdb) disassemble fork Dump of assembler code for function fork: 0x80482e0 : jmp *0x80495a4 0x80482e6 : push $0x8 0x80482eb : jmp 0x80482c0 <_init+40> End of assembler dump. (gdb) Il magico lavoro del linker. Non possiamo arrivare a quell'indirizzo in maniera troppo semplice. Il modo migliore per risolvere il problema è compilare in maniera statica il programma di prima. Spiego meglio: quando si compila un programma, tutte le funzioni come printf, fork, qualsiasi in somma che noi non creiamo, sono prese dalle glibc. Queste glibc possiedono tutto quel codice che permette la esecuzione della fork e della printf. In particolare questo codice non viene messo all'interno del nostro programma per economia di spazio, ma viene richiamato quando serve attraverso a jmp (salti) in librerie condifise. Questo obbrobrio di spiegazione serve a spiegare questo comando: bakunin: ~/C$ cc a.c -ggdb -static Con l'opzione static imponiamo che tutto il codice venga messo all'interno del nostro software. Le dimensioni ovviamente aumentano. bakunin: ~/C$ gdb a.out GNU gdb 5.2 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 "i686-pc-linux-gnu". (gdb) disassemble main Dump of assembler code for function main: 0x80481d0
: push %ebp 0x80481d1 : mov %esp,%ebp 0x80481d3 : sub $0x8,%esp 0x80481d6 : call 0x804bfc0 0x80481db : mov %ebp,%esp 0x80481dd : pop %ebp 0x80481de : ret End of assembler dump. (gdb) Uguale a prima. Ora la fork: (gdb) disassemble fork Dump of assembler code for function fork: 0x804bfc0 : mov $0x2,%eax 0x804bfc5 : int $0x80 0x804bfc7 : cmp $0xfffff001,%eax 0x804bfcc : jae 0x80519d0 <__syscall_error> 0x804bfd2 : ret 0x804bfd3 : lea 0x0(%esi),%esi 0x804bfd9 : lea 0x0(%edi,1),%edi End of assembler dump. (gdb) Molto più interessante. Abbiamo trovato come funziona la fork: mov $0x2,%eax int $0x80 Siamo sicuri? int main(void) { asm(" mov $0x2,%eax int $0x80 "); sleep(2000); } bakunin: ~/C$ ./a.out & ps aux | grep a.out [1] 1162 bakunin 1162 0.0 0.2 1316 296 tty2 S 22:03 0:00 ./a.out bakunin 1165 0.0 0.2 1316 296 tty2 S 22:03 0:00 ./a.out bakunin: ~/C$ Esatto. L'interrupt 0x80, gestisce le syscall del kernel di unix. Mettendo valori dentro al registro %eax possiamo lanciare le chiamate di sistema come noi vogliamo. Implementiamo un for: int main(void) { asm(" mov $0x2,%eax int $0x80 jmp .-7 "); } Ed ecco un esempio di Assembler dentro il C. Il jmp di -7 byte ritorna esattamente al mov. Si poteva saltare anche solo a -2. Come si fa a sapere i salti? bakunin: ~/C$ cc a.c -ggdb bakunin: ~/C$ gdb a.out GNU gdb 5.2 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 "i686-pc-linux-gnu"... (gdb) (gdb) disassemble main Dump of assembler code for function main: 0x80483d0
: push %ebp 0x80483d1 : mov %esp,%ebp 0x80483d3 : mov $0x2,%eax 0x80483d8 : int $0x80 0x80483da : jmp 0x80483d8 0x80483dc : mov %ebp,%esp 0x80483de : pop %ebp 0x80483df : ret End of assembler dump. (gdb)