Запуск своего кода во время загрузки позволяет полностью контролировать работу компьютера, давая полную свободу действий. Рассмотрим процесс создания и запуска "голого" кода.

При создании загрузочного кода необходимо учитывать следующие особенности:
-  16 битный «реальный режим»
-  mbr-код только 446 байт
-  нет системных вызовов и функций ОС, нет библиотек (только статические)
-  есть(эмулируются) прерывания bios

   


1. Hello world

В интернете существует множество примеров кода для вывода строки. Так как в дальнейшем этот код станет основной системного загрузчика и других программ, то будем сразу использовать язык программирования си.

helloboot.c:

Код:
void putch(char ch){                      // функция вывода символа на экран в текстовом режиме
    asm(                                  // ассемблерная вставка, для вызова прерываний bios
"	mov	$0x0e, %ah	""\n"
"	mov	%[ch], %%al	""\n"
"	int	$0x10    ""\n"
:
: [ch]"g"(ch)
	);
}

void __attribute__((noreturn)) main() {  // главная функция, которая не завершается
    char *hello="hello world";
    char *p = hello;
    while(*p!=0) putch(*p++);            // вывод по символам

    while (1);                           // бесконечное ожидание
}

   


2. Сборка

Скомпилируем объектный модуль:

Код:
> gcc -m16 -ffreestanding -fno-builtin -Os -c -o helloboot.o helloboot.c

-m16 -- для создания 16 битного кода
-ffreestanding -- код произвольной структуры
-fno-builtin -- не использовать встроенные функции
-Os -- оптимизировать размер

Скомпонуем бинарный образ без заголовков и секции:

Код:
> ld --oformat binary -Ttext 0x7c00 -e main -o helloboot.bin helloboot.o

--oformat binary -- создать образ состоящий только из кода и данных, размещенных последовательно
-Ttext 0x7c00 -- виртуальный адрес начала размещения кода, куда загрузчик передает управление
-e main -- точка входа в программу

   


3. Проверка кода

Используя утилиты binutills, можно убедиться в правильности создания образа.

Код:
>objdump -b binary -m i8086 -x -D -s helloboot.bin
helloboot.bin:     file format binary
helloboot.bin
architecture: UNKNOWN!, flags 0x00000000:

start address 0x00000000

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .data         00000079  00000000  00000000  00000000  2**0
                  CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
no symbols


Contents of section .data:
 0000 66556689 e56683ec 0467668b 45086788  fUf..f...gf.E.g.
 0010 45fcb40e 678a45fc cd109066 c966c366  E...g.E....f.f.f
 0020 556689e5 6683ec10 6766c745 f86d7c00  Uf..f...gf.E.m|.
 0030 0067668b 45f86766 8945fceb 2267668b  .gf.E.gf.E.."gf.
 0040 45fc6766 8d500167 668955fc 678a0066  E.gf.P.gf.U.g..f
 0050 0fbec066 5066e8a5 ffffff66 83c40467  ...fPf.....f...g
 0060 668b45fc 678a0084 c075d2eb fe68656c  f.E.g....u...hel
 0070 6c6f2077 6f726c64 00                 lo world.       

Disassembly of section .data:

00000000 <.data>:
   0:	66 55                	push   %ebp
   2:	66 89 e5             	mov    %esp,%ebp
   5:	66 83 ec 04          	sub    $0x4,%esp
   9:	67 66 8b 45 08       	mov    0x8(%ebp),%eax
   e:	67 88 45 fc          	mov    %al,-0x4(%ebp)
  12:	b4 0e                	mov    $0xe,%ah
  14:	67 8a 45 fc          	mov    -0x4(%ebp),%al
  18:	cd 10                	int    $0x10
  1a:	90                   	nop
  1b:	66 c9                	leavel 
  1d:	66 c3                	retl   
  1f:	66 55                	push   %ebp
  21:	66 89 e5             	mov    %esp,%ebp
  24:	66 83 ec 10          	sub    $0x10,%esp
  28:	67 66 c7 45 f8 6d 7c 	movl   $0x7c6d,-0x8(%ebp)
  2f:	00 00 
  31:	67 66 8b 45 f8       	mov    -0x8(%ebp),%eax
  36:	67 66 89 45 fc       	mov    %eax,-0x4(%ebp)
  3b:	eb 22                	jmp    0x5f
  3d:	67 66 8b 45 fc       	mov    -0x4(%ebp),%eax
  42:	67 66 8d 50 01       	lea    0x1(%eax),%edx
  47:	67 66 89 55 fc       	mov    %edx,-0x4(%ebp)
  4c:	67 8a 00             	mov    (%eax),%al
  4f:	66 0f be c0          	movsbl %al,%eax
  53:	66 50                	push   %eax
  55:	66 e8 a5 ff ff ff    	calll  0x0
  5b:	66 83 c4 04          	add    $0x4,%esp
  5f:	67 66 8b 45 fc       	mov    -0x4(%ebp),%eax
  64:	67 8a 00             	mov    (%eax),%al
  67:	84 c0                	test   %al,%al
  69:	75 d2                	jne    0x3d
  6b:	eb fe                	jmp    0x6b
  6d:	68 65 6c             	push   $0x6c65
  70:	6c                   	insb   (%dx),%es:(%di)
  71:	6f                   	outsw  %ds:(%si),(%dx)
  72:	20 77 6f             	and    %dh,0x6f(%bx)
  75:	72 6c                	jb     0xe3
  77:	64                   	fs
	...

Так же перед использованием загрузочного образа, необходимо убедиться, что его размер не превышает 446 байт:

Код:
>size --target binary helloboot.bin
   text	   data	    bss	    dec	    hex	filename
      0	     65	      0	     65	     41	helloboot.bin

   


4. Запуск кода

Тестирование и отладку загружаемого кода, удобнее делать используя виртуальную машину.
Если разработка уже идет из виртуальной машины, то необходимо подключить новый виртуальный диск на несколько мегабайт, и создать разметку mbr с помощью fdisk или parted.

!!!Иначе, лучше тогда создать новый виртуальный фиксированного размера в формате vhd, с файлом которого можно работать как с содержимым обычного диска.

запишем загрузочный образ на новый диск.

Код:
>dd if=helloboot.bin of=/dev/sdb

Перезагрузимся и выберем новый диск для загрузки:
http://s2.uploads.ru/t/3RbIV.jpg
http://s2.uploads.ru/t/Fu1pA.jpg
Видно, что код выполнился и вывел на экран строку.

!!! При использовании виртуальной машины qemu, существует возможность отлаживать выполняемый код через gdb.