User Tools

Site Tools


archi:x86

Differences

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

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
archi:x86 [2016/03/09 22:26] – [Quelques notes sur x86 IA32 avec GAS] orelarchi:x86 [2024/03/18 15:06] (current) – external edit 127.0.0.1
Line 6: Line 6:
 ====Quelques notes sur x86 IA32 avec GAS==== ====Quelques notes sur x86 IA32 avec GAS====
  
-Il existe plusieurs langages de programmation assembleur (GAS, NASM, ...) pour générer du code machine x86 32-bit. Nous utilisons ici le langage GAS ou //GNU Assembler//, qui n'utilise pas la syntaxe Intel contrairement à NASM. Un programme GAS est un fichier texte d'extension '.s' (ou '.S'). La compilation s'effectue avec //as// et l'édition de lien avec le linker //ld// (format ELF). On peut aussi utiliser directement le compilateur //gcc//. L'utilisation du suffixe '.S' indique au compilateur d'effectuer une passe de //preprocessing// avant la compilation. +Il existe plusieurs langages de programmation assembleur ([[http://www.gnu.org/software/binutils/|GAS]][[http://www.nasm.us/|NASM]], ...) pour générer du code machine x86 32-bit. Nous utilisons ici le langage GAS ou //GNU Assembler//, qui n'utilise pas la syntaxe Intel contrairement à NASM. Un programme GAS est un fichier texte d'extension '.s' (ou '.S'). La compilation s'effectue avec //as// et l'édition de lien avec le linker //ld// (format ELF). On peut aussi utiliser directement le compilateur //gcc//. L'utilisation du suffixe '.S' indique au compilateur d'effectuer une passe de //preprocessing// avant la compilation. 
  
   * Les registres généralistes sur 32 bits (%eax, %ebx, %ecx, %edx) ont des variantes 16 bits (%ax, %bx, %cx, %dx) et 8 bits (%ah, %al, %bh, %bl, %ch, %cl, %dh, %dl). En pratique, %al est la partie basse de %ax. Respectivement, %ah est la partie haute de %ax.    * Les registres généralistes sur 32 bits (%eax, %ebx, %ecx, %edx) ont des variantes 16 bits (%ax, %bx, %cx, %dx) et 8 bits (%ah, %al, %bh, %bl, %ch, %cl, %dh, %dl). En pratique, %al est la partie basse de %ax. Respectivement, %ah est la partie haute de %ax. 
   * On dispose d'opérations classiques : //mov, add, sub, and, ...// qui se déclinent en trois versions selon que l'on manipule des registres 8, 16 ou 32 bits. On ajoute respectivement le suffixe 'b', 'w' ou 'l' à l'instruction. Par exemple, //addw %ax,%dx// ajoute %ax au registre %dx (en 16 bits).   * On dispose d'opérations classiques : //mov, add, sub, and, ...// qui se déclinent en trois versions selon que l'on manipule des registres 8, 16 ou 32 bits. On ajoute respectivement le suffixe 'b', 'w' ou 'l' à l'instruction. Par exemple, //addw %ax,%dx// ajoute %ax au registre %dx (en 16 bits).
-  * Pour faire des comparaisons, on dispose de l'instruction //cmp//. Par exemple, //cmpw %ax,%dx// met à jour le flag de condition Z à 1 si %ax est égal à %dx (%dx-%ax=0), de telle sorte que le saut conditionnel //je// soit vrai.+  * Pour faire des comparaisons, on dispose de l'instruction //cmp//. Par exemple, //cmpw %ax,%dx// met à jour le flag de condition Z à 1 si %ax est égal à %dx (%dx-%ax=0), de telle sorte que le saut conditionnel //je// soit vrai. On dispose d'autres sauts conditionnels comme //je, jne, jl, jg, ...//, ainsi que du saut //jmp//.
   * Les constantes sont précécés du symbole %%$%%, comme par exemple %%$1%% ou %%$0x0b8000%% ou encore %%$'A'%%.   * Les constantes sont précécés du symbole %%$%%, comme par exemple %%$1%% ou %%$0x0b8000%% ou encore %%$'A'%%.
   * GAS supporte plusieurs types de commentaires %%# ...%% ou %%// ...%% ou encore %%/* ... */%%.    * GAS supporte plusieurs types de commentaires %%# ...%% ou %%// ...%% ou encore %%/* ... */%%. 
-  * Plus de détails sur la [[https://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax|GAS]] et sur [[https://en.wikibooks.org/wiki/X86_Assembly|x86]]+ 
 +Plus de détails 
 +  * [[https://sourceware.org/binutils/docs/as/ | Doc GAS]] 
 +  * [[https://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax|Syntaxe GAS]]  
 +  * [[https://en.wikibooks.org/wiki/X86_Assembly|Assembleur x86]] 
 +  * Compiler Explorer: https://gcc.godbolt.org
  
 ====Exemple Hello World en GAS ==== ====Exemple Hello World en GAS ====
Line 58: Line 63:
 </code>   </code>  
  
-==== Bootloader ====+==== Bootloader au format multiboot ====
  
-Considérons le code assembleur x86 suivant d'un //bootloader// minimaliste en 32 bits. Le code se compose du //bootloader// à proprement parler (fichier //boot.s//), qui appelle la fonction //main// du //kernel// (fichier //kernel.s//).+Considérons le code assembleur x86 suivant d'un //bootloader// minimaliste en 32 bits au format //multiboot//. Le code se compose du //bootloader// à proprement parler (fichier //boot.s//), qui appelle la fonction //main// du //kernel// (fichier //kernel.s//).
  
 <code c boot.s> <code c boot.s>
Line 97: Line 102:
  
 Pour aller plus loin :  Pour aller plus loin : 
 +  * https://www.gnu.org/software/grub/manual/multiboot/multiboot.html (multiboot format)
 +  * https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#OS-image-format (multiboot header: 0x1BADB002)
   * https://en.wikibooks.org/wiki/X86_Assembly/Bootloaders   * https://en.wikibooks.org/wiki/X86_Assembly/Bootloaders
   * http://wiki.osdev.org/Bare_bones   * http://wiki.osdev.org/Bare_bones
Line 122: Line 129:
 </code> </code>
  
-Lors de l'édition de lien, il est important de préciser que le point d'entrée est le symbole '_start' et de placer la séquence magique de 12 octets du //bootloader// à une adresse supérieure à 0x100000. En effet, les adresses < 1MiB sont réservées pour le BIOS, la RAM Video, etc. +Lors de l'édition de lien, il est important de préciser que le point d'entrée est le symbole '_start' et de placer la séquence magique de 12 octets du //bootloader// à une adresse supérieure à 0x100000, suivi du code (segment .text). En effet, les adresses < 1MiB sont réservées pour le BIOS, la RAM Video, etc. 
  
 On peut aussi utiliser un //external linker script// pour compiler notre //kernel// :  On peut aussi utiliser un //external linker script// pour compiler notre //kernel// : 
Line 169: Line 176:
  
   qemu-system-i386 -enable-kvm -kernel kernel   qemu-system-i386 -enable-kvm -kernel kernel
 +  
 +L'option //-kernel// permet de "booter" directement sur un noyau linux au format //bzimage// ou sur un code au format //multiboot// comme celui décrit dans cette section. Notons que c'est le format standard supporté par GRUB.
      
 ==== Kernel en C ==== ==== Kernel en C ====
Line 287: Line 296:
   qemu-system-i386 -cdrom mykernel.iso   qemu-system-i386 -cdrom mykernel.iso
  
-Chercher comment se passer de GRUB ? Un peu de lecture...+==== Booter son Kernel depuis un disque (sans GRUB) ====
  
-  * http://wiki.osdev.org/Bare_bones +Pour booter son Kernel depuis un disque (//floppy//, //hard disk// ou //usb disk//), il faut tout d'abord modifier la séquence de boot du BIOS pour qu'il puisse amorcer le système depuis ce périphérique au démarrage de l'ordinateurCes 3 types de disque utilisent la même organisation en secteur de 512 octets. Pour rendre un disque bootable, il faut ajouter la signature de boot (i.e. //0x55aa//) à la fin du secteur 0. 
-  * http://wiki.osdev.org/El-Torito + 
-  * https://wiki.archlinux.org/index.php/GRUB +<code hello.s> 
-  * http://www.syslinux.org/wiki/index.php?title=ISOLINUX +.code16                  # generate 16-bit code 
-  * http://wiki.osdev.org/Mkisofs +.text                    # executable code location 
-  * http://wiki.osdev.org/Bootable_CD +     .globl _start; 
-  * http://stackoverflow.com/questions/34268518/creating-a-bootable-iso-image-with-custom-bootloader+ 
 +_start                 # code entry point 
 + 
 +     #print letter 'H' onto the screen 
 +     movb $'H' , %al 
 +     movb $0x0e, %ah 
 +     int  $0x10 
 + 
 +     #print letter 'e' onto the screen 
 +     movb $'e' , %al 
 +     movb $0x0e, %ah 
 +     int  $0x10 
 + 
 +     #print letter 'l' onto the screen 
 +     movb $'l' , %al 
 +     movb $0x0e, %ah 
 +     int  $0x10 
 + 
 +     #print letter 'l' onto the screen 
 +     movb $'l' , %al 
 +     movb $0x0e, %ah 
 +     int  $0x10 
 + 
 +     #print letter 'o' onto the screen 
 +     movb $'o' , %al 
 +     movb $0x0e, %ah 
 +     int  $0x10 
 + 
 +     hlt # halt 
 + 
 +     . = _start + 510      #mov to 510th byte from 0 pos 
 +     .byte 0x55            #append boot signature 
 +     .byte 0xaa            #append boot signature  
 + 
 +</code> 
 + 
 +Attention, dans ce cas précis, le BIOS recopie en mémoire physique le secteur 0 (512 octets) et passe la main au CPU pour qu'il commence à exécuter en //mode real// (16 bits) les instructions au début du secteur 0... Notons que dans ce cas, il est possible de faire appel aux interruptions du BIOS pour écrire en mémoire VGA (//int 0x10//).  
 + 
 +Il faut ensuite compiler ce programme //en flat binary// (et non en ELF) puis le copier sur sa disquette : 
 + 
 +  as hello.s -o hello.o 
 +  ld --oformat=binary hello.o -o hello.bin 
 +  dd if=/dev/zero of=floppy.img bs=512 count=2880  # standard floppy disk (1.44MB) 
 +  dd if=hello.bin of=floppy.img 
 + 
 +On peut facilement tester ce programme depuis son disque avec QEMU : 
 + 
 +  qemu-system-i386 -fda floppy.img -boot a   # boot on floppy disk 
 +  qemu-system-i386 -hda floppy.img           # boot on hard disk   
 +   
 +On peut également mettre son bootloader sur le premier secteur d'une clef USB : /dev/sdc sur ma machine (fdisk -l)Mais, attention de ne pas se tromper au risque de perdre toutes vos données !    
 + 
 +  cat hello.bin > /dev/sdc 
 +   
 +Puis on reboote la "vraie" machine avec la clef USB et voici le résultatNotons que nous n'avons pas préparé de table des partitions, d'où le message affiché par le BIOS : //Invalid Partition Table// avant notre fameux //Hello World// :-) 
 + 
 +{{ :archi:helloboot-laptop.jpg?direct&300 |}} 
 + 
 +Pour aller plus loin :  
 +  * http://www.codeproject.com/Articles/664165/Writing-a-boot-loader-in-Assembly-and-C-Part 
 +  * http://www.codeproject.com/Articles/668422/Writing-a-boot-loader-in-Assembly-and-C-Part 
 +  * http://www.codeproject.com/Articles/737545/Writing-a-bit-dummy-kernel-in-C-Cplusplus
  
  
Line 304: Line 374:
   * External Linker Script : http://www.emprog.com/support/documentation/thunderbench-Linker-Script-guide.pdf   * External Linker Script : http://www.emprog.com/support/documentation/thunderbench-Linker-Script-guide.pdf
  
 +
 +
 +==== Pour aller encore plus loin ====
 +
 +  * http://viralpatel.net/taj/operating-system-tutorial.php
 +  * http://wiki.osdev.org/Main_Page
 +  * http://wiki.osdev.org/Bare_bones
 +  * http://wiki.osdev.org/El-Torito
 +  * https://wiki.archlinux.org/index.php/GRUB
 +  * http://www.syslinux.org/wiki/index.php?title=ISOLINUX
 +  * http://wiki.osdev.org/Mkisofs
 +  * http://wiki.osdev.org/Bootable_CD
 +  * http://stackoverflow.com/questions/34268518/creating-a-bootable-iso-image-with-custom-bootloader
  
  
archi/x86.1457562396.txt.gz · Last modified: 2024/03/18 15:05 (external edit)