使用nasm的 $ 和$$要注意了,这两个符号是和段有关。
例如,下面的代码使用nasm编译成bin格式的文件后,不能在末尾加上启动扇区标识0xaa55,原因就在于“
[section .data]”,这个section,导致了
$ 和$$不能按照我的预期工作,仔细查看nasm的手册才明白了,所以记下来。
%define DEBUG_POINT xchg bx, bx
org 07c00h
; Boot 状态, Bios 将把 Boot Sector 加载到 0:7C00 处并开始执行
jmp
LABEL_BEGIN
;one_byte
db 0
; FAT 引导扇区的格式
BS_OEMName
db
'aiht\0\0\0\0'
;OEM string,必须8个字节
BPB_BytesPerSec
dw
512
;每个扇区的字节数
BPB_SecPerClus
db
1
;每个簇含有的扇区数
BPB_RsvdSecCnt
dw
1
;boot占用的扇区数
BPB_NumFATs
db
2
;FAT表的个数
BPB_RootEntCnt
dw
0xE0
;根目录文件最大值
BPB_TotalSec16
dw
0xB40
;扇区总数
BPB_Media
db
0xF0
;介质描述符
BPB_NumPerFAT
dw
9
;每个FAT的扇区数
BPB_SecPerTrk
dw
0x12
;每磁道扇区数
BPB_NumHeads
dw
0x2
;磁头数
BPB_HideSec
dd
0
;隐藏扇区数
BPB_TotalSec32
dd
0
;如果BPB_TotalSec16的值为0,则由此字段记录总扇区数
BS_DrvNum
db
0
;中断13的驱动器号
BS_Reserved1
db
0
;未使用
BS_BootSig
db
0x29
;扩展引导标记
BS_VolID
dd
0
;卷序列号
BS_VolLab
db
'OrangeS\0\0\0\0';卷标
BS_FileSysType
db
'FAT12\n\n\n'
;文件系统类型
[section .data]
;end of [section .data]
;define macro for const via
BegSecNumRootDir
equ
0;根目录起始扇区号
EntSizeRootDir
equ
0x16;根目录条目大小
;1.44M软盘参数
TrkNumPerHeader
equ
80;每个盘面的柱面(磁道)数
;
;end define
LABEL_BEGIN:
;初始化各段寄存器
mov
ax, cs
mov
ds, ax
mov
ss, ax
mov
es, ax
mov
sp, 0x7C00
DEBUG_POINT
;复位软驱
xor
ah, ah
mov
dl, [BS_DrvNum]
int
13
;初始化根目录扇区号
mov
ax, [BPB_NumPerFAT]
mov
bl, [BPB_NumFATs]
mul
bl
test
dx, dx
;dx是乘积的高16位
jnz
LABEL_END
inc
ax
;查找根目录下的有无loader.bin
;1.求出柱面编号
mov
eax, [BegSecNumRootDir]
mov
bl, [BPB_SecPerTrk]
div
bl
;
push
ax
;保存商
;2、两个盘面,柱面是跨盘面的,因此需要除以盘面数(2),用shr优化,不用div
shr
al, 1
;商除2
mov
ch, al
;柱面号存入ch
inc
ah
mov
cl, ah
;起始扇区号存入cl
mov
bl, [BPB_NumHeads]
pop
ax
xor
ah, ah
div
bl
mov
dh, ah
;磁头号存入dh
mov
dl, [BS_DrvNum] ;驱动器号存入dl
mov
ah, 0x2
;读操作
mov
al, 1
;读取的扇区数
sub
sp, 512
;堆栈上分配512byte作为缓冲区
mov
bx, sp
;es:bx指向缓冲区
int
13
;
LABEL_END:
jmp
$;
;读取loader.bin
;控制权移交给loader
;----------------------------------------------------------------------------------------------
times
510-($-$$)
db
0
; 填充剩下的空间,使生成的二进制代码恰好为512字节
dw
0xaa55
; 结束标志