在开始之前讲个有意思的笑话。某日,一程序猿退休在家,闲来无事想学习书法。开始时候左思右想,不知如何下笔,突然灵光一闪提笔写下了几个大字,定睛一看“hello world”。
所以这里,国际惯例我这里也是按照hello world开始。OK。
编译连接完成了以后,这个代码必须是在MBR上大小为512个字节并且必须要以0xAA55结束,这里不要问我为啥子。我也不晓得,估计这个需要问IBM的PC开发的工程师为啥要这样定。开机自检完成以后PC会将MBR上的前512个字节的程序,读取到内存0x0000:0x07c0处,然后跳转到这个地址执行,这里执行的就是我们的程序。这个Hello world 程序相当简单,调用0x10号中断,完成清屏和显示“terrycheng”。这个程序我是在ubuntu下面实际能够编译完成,在bochsrc能够运行的。嘎嘎。
详细代码:boot.asm
.section .text
.global _start
.code16
#这个也很重要,因为这里实际PC还是在实模式下,也就说为16位的机器,所以这里的数据都是要16位的。
.extern main
_start:
movw %cx, %ax
movw %ax, %ds
movw %ax, %es
#上面3行的作用是设置数据段寄存器,这个时候PC跳转到了0x0000:0x07c0处,所以CX寄存器地址为0x0000,然而其他的数据段确不是这个地址。
#所以需要设置和代码段一样否则后面的terrycheng这个数据,是找不到的。
call ClearScreen
#调用后面的ClearScreen函数,完成清屏。
movw $msgstr, %bp
movw $10, %cx
call Display
#调用0x10号中断,显示terrycheng
1:
jmp 1b
#不解释,死循环。
ClearScreen:
movw $0x0700, %ax
movw $0x0000, %cx
movw $0xFFFF, %dx
int $0x10
ret
Display:
movw $0x1300, %ax
movw $0, %dx
movw $0x000C, %bx
int $0x10
ret
msgstr:
.asciz "terrycheng"
#terrycheng的数据位置。
len:
.int . - msgstr
#计算terrycheng的长度
.org 0x1fe, 0x00
#进行填充,之前我说过的MBR大小必须为512个字节,所以这里就把后面的数据填充为0
.word 0xaa55
#魔数 0xaa55。
下面是makefile:
TARGET=boot.img
OBJECTS=
CSRC=$(wildcard *.c)
COBJ=$(patsubst %.c,%.o,$(CSRC))
ASRC=$(wildcard *.asm)
AOBJ=$(patsubst %.asm,%.o,$(ASRC))
ALLSRC=$(ASRC) $(CSRC)
ALLOBJECTS=$(AOBJ) $(COBJ)
%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
%.o : %.asm
$(AS) -o $@ $<
$(patsubst %.img,%.bin,$(TARGET)):$(ALLOBJECTS)
ld -Ttext 0x7c00 -e _start $(ALLOBJECTS) -o $@
$(TARGET):$(patsubst %.img,%.bin,$(TARGET))
objcopy -R .note -R .comment -S -O binary $< $@
Debug:$(TARGET)
objdump -D -b binary -mi8086 $(TARGET)
cleanDebug:
rm -fr $(ALLOBJECTS) $(TARGET) $(patsubst %.img,%.bin,$(TARGET))
惯例,上图上真相:
网友评论