本实验在Linux环境上用gnu as汇编格式完成
.code16
.org 0x7c00
movw %cs, %ax
movw %ax, %ds
movw %ax, %es
movw $hello, %ax
movw %ax, %bp
movw $13, %cx
movw $0x1301, %ax
movw $0x000c, %bx
xorb %dl, %dl
int $0x10
jmp .
hello:
.asciz "hello, world\n"
.org 0x7c00+510
.byte 0x55, 0xaa
汇编:
$ as boot.s -o boot.o
这时候生成的boot.o是elf格式,而我们需要的是纯二进制格式
我们可以用objcopy命令把elf格式拷贝成二进制格式,命令如下:
$ objcopy -O binary boot.o boot.bin
然后我们用xxd命令观察一下boot.bin的内容
$ xxd -a boot.bin
00000000: 0000 0000 0000 0000 0000 0000 0000 0000 ................
*
00007c00: 8cc8 8ed8 8ec0 b81a 7c89 c5b9 0d00 b801 ........|.......
00007c10: 13bb 0c00 30d2 cd10 ebfe 6865 6c6c 6f2c ....0.....hello,
00007c20: 2077 6f72 6c64 0a00 0000 0000 0000 0000 world..........
00007c30: 0000 0000 0000 0000 0000 0000 0000 0000 ................
*
00007df0: 0000 0000 0000 0000 0000 0000 0000 55aa ..............U.
发现在0x7c00之前全是0,我们要把它截断,使用命令如下:
$ xxd -p -s 0x7c00 boot.bin > boot.hex
$ xxd -p -r boot.hex > boot.bin
第一条命令是从偏移0x7c00处把boot.bin dump到boot.hex文件中
第二条命令是逆向操作,把boot.hex还原为二进制格式
上述转换也可以使用dd命令,如下:
dd if=boot.bin of=boot.out ibs=1 skip=31744 count=512
mv boot.out boot.bin
ibs表示input block size,这里设置为1个字节
skip表示跳过多少个ibs,这里是跳过31744即0x7c00个字节
count表示拷贝多少个ibs,这是是512个字节
我们再用xxd命令看一下boot.bin的内容
$ xxd -a boot.bin
00000000: 8cc8 8ed8 8ec0 b81a 7c89 c5b9 0d00 b801 ........|.......
00000010: 13bb 0c00 30d2 cd10 ebfe 6865 6c6c 6f2c ....0.....hello,
00000020: 2077 6f72 6c64 0a00 0000 0000 0000 0000 world..........
00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
*
000001f0: 0000 0000 0000 0000 0000 0000 0000 55aa ..............U.
ok,这下没问题了。
剩下的操作可以参照《Orange’S》上的步骤完成
bochsrc配置文件可以从bochs源代码目录下拷贝一份出来修改,源代码根目录下有一个.bochsrc文件,用ls -A命令才能显示出来。
其中有几处需要注释掉的,我是根据bochs报错信息,搜索关键字,然后注释掉。
效果如下图:
本来想在macOS上做实验的,结果发现macOS上的汇编器as
输出代码的时候 movw $hello, %ax
这条指令生成的机器码为 b8 00 00
其中hello的地址为0,macOS的汇编器把符号重定位的工作留给了ld。
在linux上的as生成的机器码为 b8 1a 7c
,hello的地址为0x7c1a,这是对的。
当然在macOS上我们也可以通过编辑二进制文件来打个补丁。
如果借助连接器ld,就不用上面那么麻烦。
使用ld的话,汇编代码要略作修改,boot.s代码如下
.code16
.text
.globl _start
_start:
movw %cs, %ax
movw %ax, %ds
movw %ax, %es
movw $hello, %ax
movw %ax, %bp
movw $13, %cx
movw $0x1301, %ax
movw $0x000c, %bx
xorb %dl, %dl
int $0x10
jmp .
hello:
.ascii "hello, world\n"
.org _start + 510
.byte 0x55, 0xaa
链接脚本如下boot.lds(链接脚本参考gnu ld的官方文档https://sourceware.org/binutils/docs-2.28/ld/index.html)
OUTPUT_FORMAT(binary)
ENTRY(_start)
SECTIONS {
. = 0x7c00;
.text : {
*(.text)
}
}
写个简单的Makefile来自动化构建过程
boot.bin: boot.o boot.lds
ld -Tboot.lds boot.o -o boot.bin
boot.o: boot.s
as boot.s -o boot.o
这下输入简单的make就可以生成boot.bin了
$ make
as boot.s -o boot.o
ld -Tboot.lds boot.o -o boot.bin
$ xxd -a boot.bin
00000000: 8cc8 8ed8 8ec0 b81a 7c89 c5b9 0d00 b801 ........|.......
00000010: 13bb 0c00 30d2 cd10 ebfe 6865 6c6c 6f2c ....0.....hello,
00000020: 2077 6f72 6c64 0a00 0000 0000 0000 0000 world..........
00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
*
000001f0: 0000 0000 0000 0000 0000 0000 0000 55aa ..............U.
ok,跟之前的一模一样。