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:25] – [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), 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'ordinateur. Ces 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ésultat. Notons 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.1457562343.txt.gz · Last modified: 2024/03/18 15:05 (external edit)