使用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
; 结束标志