我正在尝试以实模式学习汇编。我想读取硬盘的启动扇区,所以下面是代码
org 100h
start:
xor ax, ax
mov es, ax ; ES <- 0
mov cx, 1 ; cylinder 0, sector 1
mov dx, 0080h ; DH = 0 (head), drive = 80h (0th hard disk)
mov bx, buff ; segment offset of the buffer
mov ax, 0201h ; AH = 02 (disk read), AL = 01 (number of sectors to read)
int 13h
jnc .read
.read:
mov ax, cs ; set up segments
mov ds, ax
mov es, ax
mov al, 03h
mov ah, 0
int 10h
mov si, buff
call print_string
.done:
jmp .done
print_string:
lodsb ; grab a byte from SI
test al, al ; logical or AL by itself
jz .done ; if the result is zero, get out
mov ah, 0x0E
int 0x10 ; otherwise, print out the character!
jmp print_string
.done:
ret
buff dw 512
我的执行环境是DosBox0.70,exe文件是.COM。 我希望在屏幕上看到512个字节,但是当我运行我的.COM文件时,它只是空白屏幕。我可以在后面看到几个原因
1)给出的代码没有正确地从Bios中断返回(int 13h)。 2)字符串应该以null结束,这不会发生在这里。
但不确定导致它发生的上述原因,如果是,我该如何解决这些问题?
答案 0 :(得分:3)
磁盘的引导扇区不包含ASCII数据,而是包含代码。概率很高,第一个字节之一将为NULL,并且可能不是可打印代码(例如CR,LF等)。
尝试打印INT 10h打印缓冲区,打印ascii代码,结束0将导致可能根本没有显示任何内容。
您应该将缓冲区的每个字节转换为十六进制字符串,然后将这些字符串打印到显示器。这样,您将获得引导扇区的简单十六进制转储。
答案 1 :(得分:1)
Dos将.com文件加载到它自己选择的某个段中,并将ds
和es
设置为该段。您的buff
位于该细分受众群中,而不是第0段!你正在读第一个扇区到0,这可能会破坏你的IVT。单独留下es
。
读取一个扇区后,检查进位标志(表示错误),但是进入.read
是否已设置。如果错误,您可能需要重置驱动器并再次尝试读取。你可能想要一个“重试计数器”,所以你不要进入无限循环。
你的buff
不会保留512个字节,而是保留两个字节,值为512.因为它位于文件的末尾,这可能不会造成任何伤害,但它不是“正确的”
成功读取扇区后,您可以将其打印为ascii字符,但是要打印所有512个字节,而不是在遇到的前0处停止。十六进制转储可能更具可读性。
如果您的MBR的第一个字节为零,我们处于深水中!有效的bootsector的第一个字节应该是短jmp
,后跟nop
或近jmp
。关于以这种方式启动bootsector我们有点随意,而且大多数BIOS都没有检查,但那就是“应该”在那里。如果将CPU视为第一个字节,CPU会执行什么操作? (提示:这是add
)
我认为你的两个主要问题是将es
设置为零,并在遇到零时停止打印。再试一遍。 FFS,在读取工作可靠之前,不要尝试向驱动器写入任何内容!