本文讨论的是AT&T汇编语言。
1.工具准备
Linux发行版
QEMU虚拟机
2.使用AT&T汇编语言编写BootSector
.code16 #十六位汇编
.global _start #程序开始
.text
.equ BOOTSEG, 0x07c0 #equ定义常量;被BIOS识别为启动扇区,装载到内存0x07co处
#此时处于实汇编,内存寻址为 (段地址 << 4 +量) 可寻址的线性空间为 20位
ljmp $BOOTSEG,$_start #修改cs寄存器为BOOTSEG,并跳转到_start处执行代码
_start:
mov $BOOTSEG,%ax #ax = BOOTSEG
mov %ax,%es #设置ES寄存器,为输出字符串作准备
mov $0x03,%ah #在输出信息前读取光标位置储存在DX里,DH为行,DL为列
xor %bh,%bh
int $0x10
mov $20,%cx #设定输出长度 cx = 20
mov $0x0007,%bx #page 0, attribute 7 (normal) 设置必要的属性
#lea msg1,%bp
mov $msg1,%bp
mov $0x1301,%ax #写字符,移动光标 ax = 0x1301
int $0x10 #使用这个中断0x10时,输出所得的,因而要设置好 ES 和 BP
loop_forever: #一直循环
jmp loop_forever
sectors:
.word 0
msg1:
.byte 13,10
.ascii "Hello world!"
.byte 13,10,13,10
.=0x1fe #对齐语法,等价于.org,表示在该处补0,即第一扇区的最后两字节
#在此填充魔术值,BIOS会识别硬盘中第一扇区,以0xaa55结尾的为启动扇区,于是BIOS会装载
boot_flag:
.word 0xAA55
3.在QEMU中启动这个引导
假设这个BootSector汇编代码的文件名是Lesson1.s。
汇编
这是关于as命令比较详细的文档:as -32 -o Lesson1.o Lesson1.s
https://www.ibm.com/support/knowledgecenter/zh/ssw_aix_71/com.ibm.aix.cmds1/as.htm
as支持-32和-64,参数中写-32。
汇编出的目标文件Lesson1.o符合要求的标志是,执行这段语句
file Lesson1.o
得到的是
Lesson1.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
链接
ld -m elf_i386 -Ttext 0 -o Lesson1.bin Lesson1.o
elf-i386 和-Ttext 0两个参数是必须的。-T设置输出文件的文本部分的开始地址到T后紧跟的数字,_text用于指定程序的第一个位置。
ld默认会给代码内所有的偏移加上0x08048000,使用-Ttext 0会让ld给代码内所有的偏移加上0,这样相当于保留了符号引用的原值。
这是关于ld命令比较详细的文档:
https://www.ibm.com/support/knowledgecenter/zh/ssw_aix_71/com.ibm.aix.cmds3/ld.htm
链接得到Lesson1.bin。
修改目标文件
这段是本文最重要的地方。修改目标文件是十分必要的。我们需要了解ELF格式和BIN格式的区别:
BIN格式即 raw binary,这种文件只包含机器码;
ELF格式除了机器码外,还包含其他信息,诸如段的加载地址,运行地址,重定位表,符号表等。
ELF格式的体积比对应的BIN格式要大。
前述的汇编出的.o文件是ELF格式的文件,而此处我们需要让QEMU使用BIN格式的镜像。
关于QEMU和镜像格式:http://www.10tiao.com/html/625/201410/201566704/1.html
objcopy -O binary Lesson1.bin
这句话可将ELF 32-bit的Lesson1.bin转化为BIN格式。
Lesson1.bin符合要求的标志是,执行这段语句
file Lesson1.bin
得到的是:
Lesson1.bin: DOS/MBR boot sector
在QEMU中启动
然后,恭喜你打开了OS世界的大门,Hello world!qemu-system-i386 Lesson1.bin