今天再次研究了boot.asm。
首先解决昨天的问题:
1。我编译好的exe有1009B,用exe2com转换后com文件才497字节,并不是原来的512B。按说这样的0xAA55h不在正确的位置,但是写入后居然可以启动。
关于这个我想我找到了解决办法。首先是不再使用exe2bin,直接用UltraEdit打开将近32k的exe,把7e00h前的二进制删除,保存,此时文件正好512b。将后缀改为bin,然后写入img文件,加载启动,成功。不过代码稍有改动,第二点将详细说明。
2.org 07c0h不能使用,否则编译后程序有31k之巨,也不能写入磁盘。那么这个org究竟是什么用?怎么会使编译后的程序变大?按说它只在运行时影响内存才对。
原先有31K,我想跟org 这句有不小的关系。那个宏定义总是让人不舒服,现在采用这句:
db 510-($-[start]) dup(0)
我不得不承认我原先没有过多的编写汇编程序,连书后习题也没怎么做过。今天也是突然想起来这句,比于源在nasm里使用的方便许多,事实证明这句确实有用。
3.rept 510-($-seg start) 始终对这句话不放心,这句话能可靠地把AA55放到511和512吗?结果看来是这样的,但是boot.bin只有497B,很不放心。
如上解决,确信是org的问题。恐怕masm十分省事地在07c00h前填0了事,这样就不用在每个寻址处计算地址了。这就是为什么编译后有32K的原因吧。
4.说前三个问题时我没有注释掉这三行 ; rept 510-($-seg start) ;填满至510B 现在注释掉了,编译并且转换后程序才48B,但是正常启动了。这回的AA55h肯定不在应该在的地方了,可是还是正常启动, 跟已知是不符的。 只能说可能是现在的BIOS更智能了?发现1st boot device有启动代码就会尝试启动吧。不过既然有标准,就应该按照标准去做,现在使用新的方法已经非常接近nasm做出的结果了,除了生成的地址不一致,以及编译后的代码比原先少了一B(就是说比nasm的多填一个0,所以总大小仍为512B) 现在看看我今天发现的东西吧: 1.org 07c0h 究竟有没有用?答案是绝对有用。PC开机确实是把boot sector加载到这个地址,所以如果没有加上这句,程序中所有的地址都没有07c0h的偏移,访问数据就会出错,也就是ds指向错误。但是可不可以不用它呢?答案是可以的。既然ds错误,那么让它正确不就可以了?所以mov ax,07c0h mov ds,ax这两句过后就正确了,而且link后程序仅1k。注意,mov的是07c0h,因为寻址的地址ds要左移四位,就是07c00h了。当然,还是需要将200h前的二进制删除,删除后仍然512B。不过这种办法比org的版本二进制代码又多了1B。 2.我使用的masm是615版本,很遗憾,这个版本似乎为与想象中的汇编差距大了许多。比如上边说了,需要手动删除一些才能使用。删除的都是0吗?不是,这里有8B的二进制代码。这应该是msam的link多此一举了,肯定是为系统建立某些传送信息的堆栈。当然,不删除的话写到img里是会出错的。 3.两种方法的优劣:先说一下org版。这个版本编译后不必修改就可以直接看它在dos窗口中打出红色的字符串来,甚至不必像作者用org 0100h来调试,实在是方便。这是因为那个org使得数据在win下的加载位置已经偏移了(所以才32k啊,都是masm搞的鬼)。而mov的办法十分狂野,在win下也不会打出字来,因为数据加载位置没有变化,但是ds已经指向数据理应加载的位置。不过有一点要注意:删除了那些0后在win下就不能正确寻址了,所以不要用512B的bin去调试了。 最后附上我的代码,一个是org版,一个mov版: bootmov.asm: code segment bootorg.asm code segment
; db 0
; endm
start:
mov ax,07c0h ;init
mov ds,ax
mov es,ax
call dispstr
jmp $ ;循环
dispstr:
mov ax,msg ;以下几行参见原书注释
mov bp,ax
mov cx,15
mov ax,01301h
mov bx,000ch
mov dl,0
int 10h
ret
msg:
db "Hello,OS world!" ;所要打印字符串
db 510-($-[start]) dup(0)
dw 0AA55h
code ends ;编译结束
end start
org 07c00h
start:
mov ax,cs ;init
mov ds,ax
mov es,ax
call dispstr
jmp $ ;循环
dispstr:
mov ax,msg ;以下几行参见原书注释
mov bp,ax
mov cx,15
mov ax,01301h
mov bx,000ch
mov dl,0
int 10h
ret
msg:
db "Hello,OS world!" ;所要打印字符串
db 510-($-[start]) dup(0)
dw 0AA55h
code ends ;编译结束
end start