从软盘问题中读取数据
这是代码的工作版本,但我对此有问题和疑问
- BIOS 返回软盘驱动器 = 231 而不是 0,因为我读到软盘应该是 = 0,因此在替换
dl 在
read:
中使用 0,无法读取磁盘,但是当它替换reset:
中的dl
时,它会成功重置,以便重置哪个驱动器而软盘驱动器= 0 - 当我在运行程序后将
pusha
放在 print_string 中的其余代码之前,将popa
放在 print_done 中的ret
之前时,它只打印bootmsg
- 当用 0x1000 替换 0x0F00 并用 0x10000 替换 0xF000 时,它不会打印 Hello World,但会打印
S
我不知道为什么 - 当用 0x1000 替换 0x0F00 并用 es:bx 替换 0xF000 时(虽然它必须等于 0x10000),它既不
Hello World
也不S
编辑:我正在使用盖姆
program_intialization:
org 0x7C00 ;load program at 0x7C00
push dx ;save drive number to stack appeared to be 231 not 0
jmp program_start ;go to program_start
print_string:
cld ;clear direction flag to increase si after copying the value of the address pointed by it
lodsb ;copy [si] into al then increase si
or al,al ;check if al is null
jz print_done ;if null then go to print_done
mov ah,0x0E ;else copy 0x0E to ah which is the video output code
int 0x10 ;then interrupt the program with 0x10 the video routine code which will print the character in al
jmp print_string ;and print the next character until null is found
print_done:
mov al,0x0A ;copy the code of line feed into al
mov ah,0x0E ;copy 0x0E to ah which is the video output code
int 0x10 ;interrupt the program with 0x10 the video routine code which will print the character in al (the line feed)
mov al,0x0D ;copy the code of carriage return into al
mov ah,0x0E ;copy 0x0E to ah which is the video output code
int 0x10 ;interrupt the program with 0x10 the video routine code which will print the character in al (the carriage return)
ret ;return to the place the function is called from
program_start:
xor ax,ax ;intialize ax to 0
mov ds,ax ;intialize ds to 0
mov es,ax ;intialize es to 0
mov si,bootmsg ;copy bootmsg address to si
call print_string ;print bootmsg
reset:
mov si,rstmsg ;copy reset adress to si
call print_string ;print reset
mov ah,0 ;drive reset code
pop dx ;get drive number into dl
push dx ;save drive number again
int 0x13 ;reset drive
jc reset ;if failed try again
mov ax,0x0F00 ;copy 0x0F00 to ax
mov es,ax ;copy 0x0F00 to es
xor bx,bx ;make bx = 0x0000
mov si,scs ;if success
call print_string ;print scs
read:
mov si,rdmsg ;copy reset adress to si
call print_string ;print reset
pop dx ;get the drive number into dl
mov ah,0x02 ;copy disk read code to ah
mov al,1 ;read 1 sector
mov ch,0 ;on track 0
mov cl,2 ;read sector number 2
mov dh,0 ;head number 0
int 0x13 ;read from disk to memory address es:bx (0xF000)
jc read ;if failed try again
mov si,scs ;if success
call print_string ;print scs
end:
mov si,0xF000 ;which is es:bx
call print_string0 ;print Hello World read from memory 0xF000
cli ;clear all interupts
hlt ;halt the system
bootmsg db "Bootloader v0.1",0
rstmsg db "Trying to reset Floppy Disk",0
rdmsg db "Trying to read Floppy Disk",0
scs db "Operation Successful",0
times 510 - ($-$$) db 0 ;fill the rest of bootsector with 00
dw 0xAA55 ;boot magic number
msg db "Hello World",0 ;add hello world to the next sector (512bytes) which will be read
This is the working version of the code, but I have problems and questions about it
- BIOS returns the floppy drive = 231 not 0 as I read floppy should be = 0 so when replacing
dl
with 0 inread:
it fails to read the disk but when it replacingdl
inreset:
it resets successfully so which drive is reset while the floppy drive = 0 - When I put
pusha
in print_string before the rest of the code andpopa
in print_done beforeret
after running the program it only printsbootmsg
- When replacing 0x0F00 with 0x1000 and 0xF000 with 0x10000 it doesn't print Hello World but it prints
S
I don't know why - When replacing 0x0F00 with 0x1000 and 0xF000 with es:bx (while it must be equivalent to 0x10000) it doesn't
Hello World
norS
Edit: I'm using qemu
program_intialization:
org 0x7C00 ;load program at 0x7C00
push dx ;save drive number to stack appeared to be 231 not 0
jmp program_start ;go to program_start
print_string:
cld ;clear direction flag to increase si after copying the value of the address pointed by it
lodsb ;copy [si] into al then increase si
or al,al ;check if al is null
jz print_done ;if null then go to print_done
mov ah,0x0E ;else copy 0x0E to ah which is the video output code
int 0x10 ;then interrupt the program with 0x10 the video routine code which will print the character in al
jmp print_string ;and print the next character until null is found
print_done:
mov al,0x0A ;copy the code of line feed into al
mov ah,0x0E ;copy 0x0E to ah which is the video output code
int 0x10 ;interrupt the program with 0x10 the video routine code which will print the character in al (the line feed)
mov al,0x0D ;copy the code of carriage return into al
mov ah,0x0E ;copy 0x0E to ah which is the video output code
int 0x10 ;interrupt the program with 0x10 the video routine code which will print the character in al (the carriage return)
ret ;return to the place the function is called from
program_start:
xor ax,ax ;intialize ax to 0
mov ds,ax ;intialize ds to 0
mov es,ax ;intialize es to 0
mov si,bootmsg ;copy bootmsg address to si
call print_string ;print bootmsg
reset:
mov si,rstmsg ;copy reset adress to si
call print_string ;print reset
mov ah,0 ;drive reset code
pop dx ;get drive number into dl
push dx ;save drive number again
int 0x13 ;reset drive
jc reset ;if failed try again
mov ax,0x0F00 ;copy 0x0F00 to ax
mov es,ax ;copy 0x0F00 to es
xor bx,bx ;make bx = 0x0000
mov si,scs ;if success
call print_string ;print scs
read:
mov si,rdmsg ;copy reset adress to si
call print_string ;print reset
pop dx ;get the drive number into dl
mov ah,0x02 ;copy disk read code to ah
mov al,1 ;read 1 sector
mov ch,0 ;on track 0
mov cl,2 ;read sector number 2
mov dh,0 ;head number 0
int 0x13 ;read from disk to memory address es:bx (0xF000)
jc read ;if failed try again
mov si,scs ;if success
call print_string ;print scs
end:
mov si,0xF000 ;which is es:bx
call print_string0 ;print Hello World read from memory 0xF000
cli ;clear all interupts
hlt ;halt the system
bootmsg db "Bootloader v0.1",0
rstmsg db "Trying to reset Floppy Disk",0
rdmsg db "Trying to read Floppy Disk",0
scs db "Operation Successful",0
times 510 - ($-$) db 0 ;fill the rest of bootsector with 00
dw 0xAA55 ;boot magic number
msg db "Hello World",0 ;add hello world to the next sector (512bytes) which will be read
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您在使用堆栈时不知道它在内存中的位置,也不知道它有多少空间可供您使用,这一点很重要,这与您的
pusha
/popa
问题有关。在重置中,您将DriveCode保留在堆栈上。但是,在读取中,您不会将 DriveCode 放回。当失败时,读取尝试重复该操作,DriveCode 无法再从堆栈中弹出,并且一些随机值将取代它!
这是您可能编写的代码:
发生的情况是,每次打印一个字符时,代码都会跳回到 的开头print_string 其中另一组寄存器被推入堆栈(因为
pusha
指令被重复)。对于包含 15 个字符的 bootmsg 文本,这种情况会发生 16 次。当最终找到终止零时,popa
指令将仅执行一次,从而在堆栈上留下大量不需要的字节。ret
指令没有可返回的有意义的地址,因此程序崩溃。在代码中,您从:
到:
您的设置是正确的
ES =0x1000
对应于线性地址0x10000(65536)。然而,像mov si, 0x10000
这样的指令不会加载SI
寄存器中的特定地址,因为它太大,无法放入字大小的寄存器中(允许的值范围为0 到 65535)。大多数汇编器不会抱怨这一点,只是将截断的值存储在寄存器中,例如 0。您所说的打印的“S”来自内存中的第一个字节。如果你替换了
mov si ,0xF000
与push es
push bx
pop si
pop ds
,它会工作得很好,因为 print_string 例程是从DS:SI
运行的,并且您必须以这种方式使用它。鉴于上述错误和误解,我最好的猜测可能是您没有收到驱动器代码 231 根本没有,但可能找错了地方。
我肯定会保留 BIOS 提供的值,而不是强制使用诸如 DL=0 之类的值。
这是代码的改进版本:
ps:不要忘记删除
中的拼写错误调用 print_string0
。You are using the stack without knowing where it is in memory and how much room it has for you to use which is important is relation to your
pusha
/popa
issue.In reset you keep the DriveCode on the stack. However in read you don't put the DriveCode back. When, on failure, read tries to repeat the operation, the DriveCode can no longer get popped off the stack and some random value will replace it!
This is the code that you would have written:
What happens is that each time a character is printed, the code jumps back to the start at print_string where another set of registers is pushed to the stack (because the
pusha
instruction gets repeated). With your bootmsg text that has 15 characters, this will happen 16 times. When finally the terminating zero is found, thepopa
instruction will execute just once, leaving lots of unwanted bytes on the stack. Theret
instruction has no meaningful address to return to and the program crashes.In code you went from:
to:
You are correct that setting
ES=0x1000
corresponds to linear address 0x10000 (65536). However an instruction likemov si, 0x10000
will not load that particular address in theSI
register since it is too big to fit in a word-sized register (allowed values range from 0 to 65535). Most assemblers will not complain about this and just store a truncated value in the register, in casu 0. The "S" that you say it prints comes from the very first byte in memory.If you replaced
mov si,0xF000
withpush es
push bx
pop si
pop ds
, it would have worked fine since the print_string routine operates fromDS:SI
and you must use it that way.Given the above errors and misconceptions, my best guess could be that you're not receiving drivecode 231 at all, but are perhaps looking in the wrong place.
I would definitely stay with the value that BIOS provided and not force something like
DL=0
.This is an improved version of your code:
ps: Don't forget to remove the typo in
call print_string0
.