L'ASM efficace pour lutins pressés

PART III

Dans cet ultime volet nous nous attaquerons à la conception d'un serveur socket. Oulaaaa.. chôôôoo.. OUI ! MAIS ! C'est l'assurance d'un poil brillant pour toute l'année! Alors, partant?.. Coquin(e) va :)

I - Le code mystérieux et magique

Le code si dessous s'acquitte d'une tache simple: accepter une connexion, lire les données qu'on lui envoie et renvoyer un anagramme dès que l'utilisateur appuie sur la touche entrée. Si l'utilisateur ne saisis rien et appuie sur la touche entrée, l'application se termine.

     1	section .bss
     2		buffer:				resb 256
     3	
     4	section .text
     5		global main
     6		extern strfry
     7		extern strlen
     8		extern fprintf
     9		extern puts
    10		extern socket
    11		extern bind
    12		extern dup2
    13		extern accept
    14		extern listen
    15		extern read
    16		extern write
    17		extern close
    18		extern perror
    19	
    20	section .rodata
    21		KERN:				equ 0x80
    22		STDIN:				equ 0
    23		STDOUT:				equ 1
    24		STDERR:				equ 2
    25		AF_INET:			equ 2
    26		SOCK_STREAM:		equ 1
    27		IPPROTO_TCP:		equ 6
    28		INADDR_ANY: 		equ 0
    29		SOCKADDRIN_SIZE:	equ 16
    30		PORT:				equ 47269
    31	
    32	section .data
    33		str_perror: db "Perror "
    34		
    35		align 4
    36		sockaddr_in:
    37			sin_family:		dw	0
    38			sin_port: 		dw	0
    39			sin_addr: 		dd	0
    40			sin_zero: 		db	0,0,0,0,0,0,0,0
    41	
    42		sock_listen:		dd	0
    43		sock_accept:		dd	0
    44		socklen:			dd	0
    45		length: 			dd 	0
    46	
    47	
    48	main:
    49		push dword 0
    50		push dword SOCK_STREAM
    51		push dword AF_INET
    52		call socket
    53		add esp, 12
    54	
    55		cmp dword eax, 0
    56		jnz asm_perror
    57	
    58		mov [sock_listen], eax
    59	
    60		mov word [sin_family], AF_INET
    61		mov dword [sin_addr], INADDR_ANY
    62		mov word [sin_port], PORT
    63	
    64		push dword SOCKADDRIN_SIZE
    65		push sockaddr_in
    66		push dword [sock_listen]
    67		call bind
    68		add esp, 12
    69	
    70		cmp dword eax, 0
    71		jnz asm_perror
    72	
    73		push dword 1
    74		push dword [sock_listen]
    75		call listen
    76		add esp, 8
    77	
    78		cmp dword eax, 0
    79		jnz asm_perror
    80	
    81		mov dword [socklen], SOCKADDRIN_SIZE
    82		push socklen
    83		push sockaddr_in
    84		push dword [sock_listen]
    85		call accept
    86		add esp, 12
    87	
    88		cmp dword eax, 0
    89		jnz asm_perror
    90	
    91		mov [sock_accept], eax
    92	
    93	read_lbl:
    94		push dword 256
    95		push buffer 
    96		push dword [sock_accept]
    97		call read
    98		add esp, 12
    99	
   100		cmp dword eax, 3
   101		jnz asm_perror
   102	
   103		mov [length], eax
   104	
   105		; removing \r\n
   106		mov dword ebx, [length]
   107		mov byte [buffer+ebx-2],0x00
   108		mov byte [buffer+ebx-1],0x00
   109		
   110		push buffer
   111		call strfry
   112		add esp, 4
   113	
   114		; adding \n
   115		mov byte [buffer+ebx-1],0x0a
   116	
   117		push dword [length]
   118		push buffer
   119		push dword [sock_accept]
   120		call write
   121		add esp, 12
   122	
   123		cmp dword eax, 0
   124		jnz asm_perror
   125	
   126		jmp read_lbl
   127	
   128	close_sock_accept:
   129		push dword [sock_accept]
   130		call close
   131		add esp,4
   132	
   133	close_sock_listen:
   134		push dword [sock_listen]
   135		call close
   136		add esp, 4
   137	
   138	exit:
   139		xor eax, eax
   140		inc eax
   141		xor ebx, ebx
   142		int 80h
   143	
   144	asm_perror:
   145		push str_perror
   146		call perror
   147		add esp, 4
   148		cmp dword [sock_accept],0
   149		jnz close_sock_accept
   150		cmp dword [sock_listen],0
   151		jnz close_sock_listen
   152		jmp exit

152 lignes, ça reste correct, sachant qu'il y a une gestion minimale des erreurs avec perror. Oui, car on aurait pu se la jouer crado hein..

II - Explications

Si vous lisez ces lignes, je suppose que vous avez lu les deux premières parties, et vais donc me contenter d'expliquer les parties pas ou peu étudiées dans les parties précédentes.

Vous êtes aussi censés savoir comment fonctionne un serveur socket.

Ligne 1: Section .bss, là où on alloue de la mémoire.

Ligne 2: Ici on réservere 256 octets (bytes), et comme nous savons tous, un char = 1 octet sur nos architextures x86, et comme vous vous en doutez cette lignes équivaut à un “buffer[256];” en C.

Ligne 4: La section .text où on déclare la fonction principale et les fonctions externes. Genre ici on déclare toutes les fonctions de la libC que l'on va utiliser dans notre programme. On pourrait très bien utiliser des fonctions d'autres librairies, mais pour ce faire il faudra l'indiquer à gcc avec un truc genre -lqqc..

Ligne 20: La section .rodata où l'on déclare toutes nos constantes, l'équivalent d'un “#define BLAH 654”..

Ligne 32: La section data où l'on déclare nos variables. Vous remarquerez ici la déclaration de la fameuse “struct sockaddr_in”. En fait ici on ne fait que déclarer une variable nommée sockaddr_in, qui va pointer sur sin_family. Ouais c'est la même zone mémoire, c'est ce qu'il faut voir. Pour connaitre le nombre d'octets à réserver pour chaque membre de la structure, référez vous aux headers de la libc.

Ligne 49 à 53: Ce qu'il faut retenir ici c'est que pour passer des argument à une fonction suffit de les empiler sur la stack dans l'ordre inverse de la déclaration. Genre ici pour socket(..) on va push en premier le dernier argument, puis le second, puis le premier.
Ensuite on call socket qu'on a déclaré dans la section .text, puis on enlève les arguments de la stack (comme 4*3=12 on enlève 12 octets).

Ligne 55-56: Ici on ne fait que vérifier le retour de socket. Si le résultat n'est pas supérieur à 0 alors on appelle perror.

Dans les lignes qui suivent on remplit notre pseudo structure, puis on appelle bind.

Je pense que la suite du code se passe de commentaires, si vous avez compris les principes de base, ce n'est qu'une répétition de push/call/add/cmp hein…

Ligne 93: Boucle principale du programme où on attend que l'utilisateur envoie du texte sur la socket.

On vérifie que la chaine fasse plus de 3 caractères, sinon ça voudrait dire que l'utilisateur veut quitter le programme. CF explications du début.

Comme on suppose que l'utilisateur utilise telnet, on enlève \r\n de la fin de la chaine pour pas qu'strfry les prenne en compte.

Ensuite la fin de programme est on ne peut plus claire, enfin je l'espère.

Pour compiler tout ça :

   nasm -felf sockstrfry.asm
   gcc sockstrfry.o -o sockstrfry

Il y a quelques oublis volontaires, qui ne vous empêcherons pas de faire tourner le programme. J'espère que vous saurez les apercevoir.

III - Conclusionnage

A présent vous êtes censés pouvoir voler de vos propres ailes et faire des programmes utiles en assembleur.

Pour terminer voici tous les liens utiles que j'ai sur l'ASM. Si ces turotiels vous ont plus, un petit mail me ferait plaisir, et dans le cas contraire un mail expliquant ce qui vous a déplu m'aidera pour mes prochaines rédactions.

Certains sont mieux que d'autres, mais tous m'ont été utiles à un moment donné ou à un autre. J'espère qu'ils vous permettront d'approfondir vos connaissance.

J'espère enfin vous avoir donné envie d'aller plus loin.

   http://www.monkey.org/openbsd/archive/misc/0105/msg01202.html
   http://inferno.cs.univ-paris8.fr/~am/tutorial/os/nasmC.html
   http://asm.sourceforge.net/resources.html#tutorials
   http://docs.cs.up.ac.za/programming/asm/derick_tut/
   http://www.alrj.org/docs/asm/linux-asm.html
   http://docs.cs.up.ac.za/programming/asm/derick_tut/syscalls.html
   http://www.iprezo.org/index.php?page=asm
   http://rs1.szif.hu/~tomcat/win32/apj3.txt
   http://jeanfrancoisdelnero.free.fr/hard.htm
   http://www.leto.net/writing/nasm.txt
   http://milw0rm.org/papers/46
   http://download.savannah.gnu.org/releases/pgubook/
   http://sourceware.org/binutils/docs-2.17/as/index.html
   http://database.sarang.net/study/linux/asm/linux-asm.txt
   http://www.coder-studio.com/index.php?page=tutoriaux_aff&code=asm_4
   http://mdbui2.ift.ulaval.ca/17583_E2007/Labs/Instructions_Chaines_caracteres.htm
   http://www.developpez.net/forums/showthread.php?t=378804
   http://cui.unige.ch/DI/cours/1840/cours/
   http://www.dil.univ-mrs.fr/~jfp/tp_lex_yacc2005/yacc/docAs/Assembleur/index.html
   http://www.ai.univ-paris8.fr/~n/gpi/GPIas32bits/GPIas32bits.html
   http://pluton.up.univ-mrs.fr/eremy/Ens/Info1.Archi/asm.html
   http://www.games-creators.org/wiki/Tutorial_7_:_Les_instructions_asm_les_plus_courantes_et_le_corps_d'un_programme_FASM_pour_les_librairies
   http://www.technocage.com/~ray/notespage.jsp?pageName=nasmexamples
   http://www.kernelthread.com/programming/miscellaneous/asm/
   http://www.csee.umbc.edu/~plusquel/310/nasm/
   http://pdos.csail.mit.edu/6.828/2004/readings/i386/toc.htm
   http://asm.sourceforge.net/articles/
   http://www.alrj.org/docs/asm/linux-asm.html
   http://www.pouet.free.fr/docs/boso/tutorial07.html
   http://flyers.next-touch.com/data/homework/article/Nasm_fr.htm

jfg 2007/09/21 00:37

codaz/asm/l_assembleur_pour_lutins_presses_3.txt · Last modified: 2010/01/12 13:29 (external edit)