[Dernière fois] Remplacement de "Hello, World! In assembly language" dans 1 par le langage C. L'exemple de programme est ici.
L'environnement de développement est le même que Dernière fois.
Lorsque vous allumez votre PC, un logiciel appelé BIOS démarre. Lorsque l'initialisation du périphérique est terminée, ce BIOS charge le MBR (Master Boot Record) du périphérique de démarrage (FDD, HDD, etc.) dans la mémoire et transfère le contrôle au programme dans la zone MBR. Le programme de cette zone MBR s'appelle le chargeur d'amorçage.
code16gcc.h
indique à GCC que le programme est en mode 16BIT.
code16gcc.h
#ifndef _CODE16GCC_H_
#define _CODE16GCC_H_
__asm__(".code16gcc\n");
#endif
À l'aide de l'assembleur en ligne, créez un programme qui affiche "Hello, World!" De la même manière que Dernière fois.
hello.c
#include"code16gcc.h"
__asm__("jmp main");
#define TEXT_COLOR_WHITE 0x07
void print(const char *s)
{
while(*s) {
//Appelez la fonction BIOS et affichez un caractère à l'écran
__asm__ __volatile__ ("int 0x10" : : "a"(0x0E00 | *s), "b"(TEXT_COLOR_WHITE));
s++;
}
}
void main(void) {
print("Hello, World!");
while(1) {
//Arrêter le fonctionnement du processeur
__asm__ __volatile__("hlt");
}
}
Le BIOS charge le MBR à l'adresse 0x7C00 en mémoire. Par conséquent, la position de départ du programme est 0x7C00. La signature de démarrage (0xAA55) est comme une signature que le MBR est valide, sans la signature de démarrage, le MBR est traité comme non valide. La signature de démarrage se trouve dans MBR 510-511 octets. L'adresse mémoire de la signature de démarrage est l'adresse 0x7DFE (0x7C00 + 510 octets = 0x7DFE).
linker.ld
ENTRY(main);
SECTIONS
{
/*Position de départ du programme*/
. = 0x7C00;
.data : { hello.o; }
/*Signature de démarrage*/
. = 0x7DFE;
.sig : { SHORT(0xaa55); }
}
Créez un fichier objet (hello.o) avec les informations de lien de bibliothèque standard (telles que les informations de débogage) supprimées.
#compiler
gcc -m32 -ffreestanding -fno-common -fno-builtin -fomit-frame-pointer -O2 -c -o hello.o hello.c
Créez un fichier binaire (hello.bin) à partir d'un fichier objet (hello.o) à l'aide d'un éditeur de liens.
#Créer un fichier binaire
ld -m elf_i386 -s -static -Tlinker.ld -nostdlib -nmagic --oformat binary -o hello.bin hello.o
Écrivez le fichier binaire sur l'image de la disquette de la même manière que Dernière fois. Si vous exécutez QEMU et que la sortie "Hello, World!" Est sortie, elle réussit.
#Lancez et connectez-vous à Vagrant
host$ vagrant up
host$ vagrant ssh
#Exécuter un exemple de programme
vagrant$ cd /vagrant/hello-c
vagrant$ rake
Rakefile
OBJECT_FILE = 'hello.o'
BINARY_FILE = 'hello.bin'
IMAGE_FILE = 'floppy.img'
LINKER_FILE = 'linker.ld'
task :default => :run
task :run => [ BINARY_FILE, IMAGE_FILE ] do
sh "dd status=noxfer conv=notrunc if=#{BINARY_FILE} of=#{IMAGE_FILE}"
sh "qemu -boot a -fda #{IMAGE_FILE} -curses -monitor stdio"
end
file BINARY_FILE => [ LINKER_FILE, OBJECT_FILE ] do
sh "ld -m elf_i386 -s -static -T#{LINKER_FILE} -nostdlib -nmagic --oformat binary -o #{BINARY_FILE} #{OBJECT_FILE}"
end
file IMAGE_FILE do
sh "qemu-img create -f raw #{IMAGE_FILE} 1440K"
end
rule '.o' => '.c' do |t|
sh "gcc -masm=intel -m32 -ffreestanding -fno-common -fno-builtin -fomit-frame-pointer -O2 -c -o #{t.name} #{t.source}"
end
rule '.s' => '.c' do |t|
sh "gcc -S -masm=intel -m32 -ffreestanding -fno-common -fno-builtin -fomit-frame-pointer -O2 -c -o #{t.name} #{t.source}"
end
require 'rake/clean'
CLEAN.include([ '*.bin', '*.img', '*.o' ])
Convertissons le langage C en langage assembleur et comparons-le avec le programme de Dernière fois. La commande suivante crée «hello.s» à partir de «hello.c».
cd /vagrant/hello-c-optimization
rake hello.s
Le programme suivant supprime les directives inutiles (.xxxx) pour plus de lisibilité. La syntaxe est légèrement différente entre les langages d'assemblage produits par NASM et GCC.
/vagrant/hello-c-optimization/hello.s
.file "hello.c"
.intel_syntax noprefix
.code16gcc
jmp main
print:
push ebx
mov edx, eax //Définissez l'adresse de début de la chaîne dans le registre EDX
movzx eax, BYTE PTR [eax] //Obtenez un caractère de la chaîne et définissez-le dans le registre EAX
test al, al
je .L1
mov ebx, 7 //Couleur du texte (blanc)(0x07)
.L4:
movsx eax, al
or ah, 14 //Dites au BIOS un affichage à un seul caractère(0x0E)
int 0x10 //Appelez une fonction dans le BIOS. Appel vidéo interruption.
add edx, 1 //Incrémenter le registre EDX
movzx eax, BYTE PTR [edx] //Obtenez un caractère de la chaîne et définissez-le dans le registre EAX
test al, al
jne .L4
.L1:
pop ebx
ret
.LC0:
.string "Hello, World!"
main:
mov eax, OFFSET FLAT:.LC0 //Définissez l'adresse de début de la chaîne dans le registre EAX
call print
.L8:
hlt
jmp .L8
Recommended Posts