CPU上电后会自动跳转到地址 0xFFFF0(BIOS ROM)处执行,BIOS完成一系列自检后将软盘(假设从软驱引导)第一个扇区(Cylinder/Head/Sector=0/0/1)复制到内存地址0x7C00处,并跳转到该地址执行引导代码;
第一扇区最后两个字节必须是"0x55,0xAA"才能被当作引导扇区加载。
引导扇区格式
Address | Description | Size in bytes | |
---|---|---|---|
Hex | Dec | ||
000 | 0 | Code | 440 |
1b8 | 440 | Optional disk signature | 4 |
1bc | 444 | 0x0000 | 2 |
1be | 446 | Four 16-byte entries for primary partitions | 64 |
1fe | 510 | 0xaa55 | 2 |
代码示例
GNU as | NASM |
---|---|
|
|
|
|
GNU as(gas)
汇编大致有AT&T和Inter两种语法,只是采用不同的书写格式而已;汇编器GNU as采用AT&T语法; NASM采用Inter语法;
--oformat binary: 用来去除ELF头,将boot.o链接成纯二进制代码;
-Ttext和-Tdata用于修改代码段和数据段的起始地址,因为CS和DS初始为0,所以重定位只是改变代码中的相对地址而已(可使用objdump -d -mi8086 boot.o观察链接前的"b8 00 00"三个字节,链接重定位后使用hexdump -C boot查看则变成了"b8 20 7c")
gas默认会将数据段会定位到0x1010以后,这样会超出引导扇区512字节的限制;观察发现0x20后面就没有代码了,可以将数据段定位至此,压缩空间;
默认链接:
00000000 8c c8 8e d8 8e c0 b8 1c 8c 89 c5 b9 0c 00 b8 01 |................|
00000010 13 bb 0c 00 b2 00 cd 10 eb fe 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00001010 00 00 00 00 00 00 00 00 00 00 00 00 48 65 6c 6c |............Hell|
00001020 6f 20 57 6f 72 6c 64 21 |o World!|
数据段重定位:
00000000 8c c8 8e d8 8e c0 b8 20 7c 89 c5 b9 0c 00 b8 01 |....... |.......|
00000010 13 bb 0c 00 b2 00 cd 10 eb fe 00 00 00 00 00 00 |................|
00000020 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 |Hello World!|
软驱映像(Image)
在linux下可使用dd命令生成Floppy Image,大小为1.44M(1M=1000KB,1KB=1024B),即2880个扇区(1扇区=512B);
因为gas没法像NASM那样方便的在代码中填充若干0后再填充引导魔数(magic number),因此只好手动使用dd寻址后修改;
生成image文件后,将其插入虚拟机的虚拟软驱引导即可验证。(Linux环境常用虚拟机有VirturalBox、VMWare、Boches、Virt-Manager等)
BIOS中断
本样例代码使用BIOS中断0x10显示字符串:
AH=0x13 #写字符串
AL=1 #写模式
BH=0 #页号
BL=0x0C #字符颜色属性
CX=12 #字符数
DH,DL=0,0 #起始行,列
ES:BP=0:$msg #写入地址
BIOS Color Attribute
Attribute(HL) | |||||||
Background Color | Character color | ||||||
I | R | G | B | I | R | G | B |
I代表Blink Enable(闪烁效果)
Hex | Binary | Color | |
---|---|---|---|
0 | 0000 | Black | |
1 | 0001 | Blue | |
2 | 0010 | Green | |
3 | 0011 | Cyan | |
4 | 0100 | Red | |
5 | 0101 | Magenta | |
6 | 0110 | Brown | |
7 | 0111 | Light Gray | |
8 | 1000 | Dark Gray | |
9 | 1001 | Light Blue | |
A | 1010 | Light Green | |
B | 1011 | Light Cyan | |
C | 1100 | Light Red | |
D | 1101 | Light Magenta | |
E | 1110 | Yellow | |
F | 1111 | White |
参考:
http://en.wikipedia.org/wiki/BIOS_interrupt_call
http://susam.in/articles/boot-sector-code/
http://gas.linuxsir.org/docs/as.html/index.html
http://www.ibm.com/developerworks/linux/library/l-gas-nasm/index.html
http://objectmix.com/asm-x86-asm-370/69342-tralnslate-sintax-nasm-gas.html
http://linuxgazette.net/issue77/krishnakumar.html
http://www.pcguide.com/ref/hdd/file/structMBR-c.html
《自己动手写操作系统》于渊
《Linux内核完全剖析》赵炯