Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
codaz:asm:l_assembleur_pour_lutins_presses [2007/09/08 14:51]
heroine
codaz:asm:l_assembleur_pour_lutins_presses [2010/01/12 13:29] (current)
Line 1: Line 1:
 +====== L'ASM efficace pour lutins pressés ======
 +
 +===== PART I =====
 +
 +Ce petit tutoriel a pour but de vous apprendre a programmer rapidement
 +en assembleur. Il s'​adresse à des personnes ayant plus que des notions
 +en C ou tout autre langage plus haut niveau que l'ASM, hors langages ​
 +de balisage tels que le HTML qui ne vous seront d'​aucune utilité ici.
 +
 +Le ton sera imprécis et circoncis, je ne m'​attarderais pas sur les points
 +que je juge trop théoriques. Si par moments vous vous dites : "Mais
 +pourquoi il a mis ça là? Et pis ça veut dire quoi d'​abord?",​ alors je
 +vous invite à vous référer aux liens cités en fin de tutoriel.
 +
 +==== I - Débroussaillage.. TtZzzRzzRrrRRzz Prrrt PrrRrtt.. ====
 +
 +Comme vous le savez tous, nos chers ordinateurs sont composés de
 +composants, dont le CPU fait partie. Ce fameux CPU pour faire pleins de
 +calculs contient des variables nommées Registres. Sur l'​architecture ​
 +X86 il en existe tout un tas et je ne vais pas m'​attarder là dessus.
 +
 +Nous nous contenteront pour commencer de citer les plus connus et ceux
 +qui nous seront utiles : ''​EAX'',​ ''​EBX'',​ ''​ECX'',​ ''​EDX'',​ ''​ESP'',​ ''​EFLAGS''​.
 +
 +''​EAX'',​ ''​EBX'',​ ''​ECX''​ et ''​EDX'',​ sont des registres généraux qui vont nous permettre
 +de stocker des nombres, des strings, des adresses mais aussi des fringues
 +des voitures et plein d'​autres trucs cools (éléphants,​ mouettes, loutres,
 +jambons de bayonne, etc...)
 +
 +''​ESP''​ est un registre qui contiendra toujours l'​adresse de l'​élément le
 +plus haut sur la pile (ou stack en anglais).
 +
 +''​EFLAGS''​ est un registre qui contient plein de drapeaux (ou flags en anglais)
 +qui vont nous permettre de connaitre le résultat de divers tests.
 +
 +La stack késséssai ? C'est une pile de données. Une pile késséssai ? Bah c'est
 +une pile. Genre t'as plein de livres et tu les empiles, ça te donne une pile.
 +Pour se déplacer dans la pile et accéder aux valeurs on utilisera toujours
 +''​ESP''​. Pour se déplacer dans la pile on va toujours de 4 en 4.
 +Genre le premier élément se trouve avec ''​ESP'',​ et le second avec ''​ESP+4'',​ et le
 +troisième avec ''​ESP+8'',​ ainsi de suite.
 +
 +
 +==== II - Compréhensage.. GnnnnnnGnnn iiiGniiiaaaaiiii.. aaaaRgr.. ====
 +
 +Pour utiliser ces variables, les registres, nous allons utiliser des
 +instructions. Il en existe tout un tas et on ne vas se servir que des
 +plus simples, mais quand mêmes puissantes.
 +
 +''​MOV REGISTRE, DONNEE''​\\
 +Cette instruction permet de mettre une donnée dans un registre ou une
 +variable. Ex: ''​mov eax, 4''​ Va mettre 4 dans le registre eax.
 +
 +''​ADD REGISTRE, VALEUR''​\\
 +Cettre instruction va ajouter VALEUR à la valeur que contient déjà
 +le registre. Ex: si ebx vaut 8 alors après un "add ebx, 4" ebx vaudra
 +12. Jusque là ça va ?
 +
 +''​SUB REGISTRE, VALEUR''​\\
 +La même chose que l'​instruction mais au lieu d'​additionner elle permet
 +de soustraire une valeur.
 + 
 +''​INC REGISTRE''​\\
 +Permet d'​incrémenter (ajouter 1) à un registre ou une variable.
 +Equivaut à un "add REGISTRE, 1".
 +
 +''​DEC REGISTRE''​\\
 +Permet de décrémenter (enlever 1) à un registre ou une variable.
 +Equivaut à un "sub REGISTRE, 1".
 +
 +''​JMP LABEL''​\\
 +Cette instruction effectue un saut jusqu'​au ''​LABEL''​ puis exécute les
 +instructions qui suivent le label. Nous verrons plus tard comment
 +on déclare un label.
 +
 +''​CMP REGISTRE, VALEUR''​\\
 +Cette instruction permet de comparer deux valeurs. Elle permet, avec
 +des instructions conditionelles de saut, de reproduire l'​équivalent
 +d'un branchement if/else.
 +Cette instruction modifie certains bits du registre ''​EFLAGS''​.
 +En effet elle va soustraire VALEUR au REGISTRE et modifiers certains
 +flags en fonction du résultat.
 +
 +''​JNZ LABEL''​\\
 +Jump if Not equal Zero.
 +Après une instruction ''​CMP''​ certains bits de ''​EFLAGS''​ vont changer d'​état.
 +C'est à dire passer de 1 à 0 ou l'​inverse. Les instructions de saut 
 +conditionelles telles que ''​JNZ'',​ vont vérifier l'​état d'un Flag dans le
 +registre ''​EFLAGS''​ et sauter au label indiqué si la condition est vraie.
 +Dans ''​EFLAGS''​ il y a un drapeau nommé zeroflag (ZF), qui change d'​état si 
 +un résultat est nul (il se met à 1).
 +
 +Si donc la soustraction ''​CMP REGISTRE, VALEUR''​ vaut 0, ZF sera à 1.
 +JNZ signifie qu'il faut sauter si ZF n'est pas à 0.
 +
 +''​CALL FUNCTION''​\\
 +Similaire à jmp, sauf que la partie de code vers laquelle on jmp devra
 +se terminer par l'​instruction ''​RET''​. De toute façon pour le moment on 
 +s'en fout alors ne paniquez pas.
 +
 +Il existe plein d'​autres commandes mais vous les apprendrez sur le tas.
 +
 +==== III - Passage à l'​acte... Sarah Connor ? Non c'est à côté... ====
 +
 +NON, vous n'y échapperez pas. "Hello world!"​...
 +
 +En C:
 +
 +<​code>​
 +  #include <​stdio.h>​
 +
 +  int main(int argc, char **argv) {
 +      write(1, "Hello World!\n",​ 13);
 +      exit(0);
 +  }
 +</​code>​
 +
 +On compile avec: <​code>​gcc hello.c -o hello</​code>​
 +
 +En ASM:
 +
 +<​code>​
 +  section .data
 +      strhello: db "Hello World!\n"​
 +      lenhello: equ $-strhello
 +
 +  section .text
 +      global _start
 +
 +  _start:
 +      mov eax, 4
 +      mov ebx, 1
 +      mov ecx, strhello
 +      mov edx, lenhello
 +
 +      int 80h
 +
 +      mov eax, 1
 +      mov ebx, 0
 +
 +      int 80h
 +</​code>​
 +
 +On assemble avec: <​code>​nasm -f elf hello.asm</​code>​ et on link avec 
 +<​code>​ld hello.o -o hello</​code>​
 +
 +==== IV - Décortiquationage... (bruitages en grève) ====
 +
 +Bon, déjà c'est quoi ces trucs là "​section machin"​...
 +En assembleur, et je ne vous dirais pas pourquoi c'est comme ça,
 +mais il y a des sections qui doivent se trouver en début de code.
 +Ces sections diffèrent en fonction du format de fichier de votre
 +OS (elf, olf, ...)
 +
 +''​.data''​\\
 +Dans cette section on déclare des variables en leur affectant une 
 +valeur.
 +
 +''​.rodata''​\\
 +Dans cette section on déclare des constantes. Ou si vous préférez des
 +variables dont on ne pourra pas modifier le contenu.
 +
 +''​.bss''​\\
 +Dans cette section on ne fait que déclarer des variables en réservant
 +simplement de l'​espace mémoire. (on y reviendra)
 +
 +''​.text''​\\
 +Dans cette section on déclarera les fonctions externes et la fonction
 +principale.
 +
 +On peut certainement faire d'​autres trucs avec les sections, et il en
 +existe sûrement d'​autres,​ mais on s'en fiche on a pas besoin d'en
 +savoir d'​avantage pour le moment.
 +
 +Bon ensuite, ça veut dire quoi tous ces chiffres qu'on met dans des
 +registres et puis int 80h, c'est quoi ?
 +
 +Les chiffres qu'on met dans les registres c'est dans un premier temps
 +le numéro de l'​appel système que l'on souhaite exécuter puis ses
 +arguments.
 +
 +Pour connaitre le numéro de chaque appel système il faut regarder le
 +fichier /​usr/​include/​asm-i386/​unistd.h
 +Dans ce fichier on a la ligne : #define __NR_write 4
 +Qui signifie que pour le noyau, 4 = write.
 +On pourra remarque également que exit = 1.
 +
 +Si on fait un "man 2 write" et qu'on regarde la déclaration de cet
 +appel système on apprend qu'il prend en premier argument le 
 +descripteur de fichier sur leque écrire, en second argument la 
 +string qu'il doit écrire et en dernier argument la longeur de cette
 +chaine de caractères.
 +
 +Vous êtes censés savoir que stdin = 0, stdout = 1, et stderr = 2.
 +
 +D'où le code suivant :
 +
 +<​code>​
 +   mov eax, 4          ; 4 signifie ici "​write"​
 +   mov ebx, 1          ; 1 pour stdout
 +   mov ecx, strhello ​  ; La string que write requiert
 +   mov edx, lenhello ​  ; Et la lenght de cette dernière
 +</​code>​
 +
 +Comme vous le devinez sans doute, int 80h, dit au kernel "​exécute
 +les instructions placées dans les registres."​
 +Le kernel va donc regarder la valeur d'eax et comprendre (il est futé)
 +qu'il faut appeller write, puis il va aller chercher son premier argument
 +dans ebx, le second dans ecx et le troisième dans edx, et si tout vas bien
 +vous devririez voir un joli "Hello World!"​ dans votre shell.
 +
 +Bien évidemment c'est une explication simpliste, mais c'est pour que vous
 +compreniez, si vous voulez approfondir sur les interruptions,​ il y plein
 +de doc chouettes qui existent. (oui car int signifie interrupt ou en
 +français interruption).
 +
 +Quant au equ $-lenhello, c'est une bidouille nasmique qui permet de
 +récupérer la longeur de la chaine strhello, cf manuel de nasm.
 +Par contre l'​instruction EQU permet de déclarer une constante, comme
 +nous le verrons plus tard.
 +
 +En guise de conclusion, je vous laisse deviner ce que font les trois
 +dernières lignes de notre programme.. :)
 +
 +Dans le prochain tuto nous aborderons le passage d'​arguments à un 
 +programme ainsi que les sauts et les fonctions.
 +
 + --- //​[[jf.guchens@gmail.com|jfg]] 2007/09/21 00:41//
 +
 +===== Linux/BSD Compatibility =====
 +
 +Le monde étant ce qu'il est, les abeilles ne pollenisant plus les fleurs à cause d'un virus et le soleil se réveillant en septembre, il s'​avère que BSD et Linux ont décidé de faire les choses différemments.
 +
 +Si sous Linux, le passage des arguments se fait par les registres ebx, ecx, edx et autres, sous BSD, il en va tout autrement: Les syscall prennent leur paramètres comme toute fonction normale, c'est à dire par la pile.
 +
 +Plutot qu'on long exemple, je vous indiquerais plutot ce lien qui explique comment rendre son code assembleur portable de bsd vers linux grace à une macro : \\ 
 +[[http://​www.freebsd.org/​doc/​en_US.ISO8859-1/​books/​developers-handbook/​x86-portable-code.html|FreeBSD Developers Handbook]]
 +
 +( CF Part II & III du tuto :)
  
codaz/asm/l_assembleur_pour_lutins_presses.txt · Last modified: 2010/01/12 13:29 (external edit)