我有一段代码在realmode中运行并在屏幕上打印一条消息,我使用Dosbox 0.7作为我的执行环境.Below是代码
jmp 0x7c0:start
start:
mov ax, cs ; set up segments
mov ds, ax
mov es, ax
mov al,03h
mov ah,0
int 10h
welcome db "This is insane now"
mov si, welcome
call print_string
print_string:
lodsb ; grab a byte from SI
or 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
我可以很好地组装这段代码,但是当我运行它时,它只是挂在那里,我可以在linux终端中看到一条消息
Illegal read from b0671921, CS:IP 7c0: 4468
这就是我组装它的方式
nasm PRINT.ASM -o out.com
我尝试在google中搜索此邮件,发现它可能是DOSBox版本的问题。
有谁能告诉我这里可能出现什么问题?
答案 0 :(得分:1)
让我们一步一步:
jmp 0x7c0:start ;jump to start
start:
mov ax, cs ; set up segments
mov ds, ax
mov es, ax
mov al,03h ; Set up screen to 80 by 25
mov ah,0
int 10h
字符串不是可执行代码,因此将其放在start
标签之前和jmp之后。
字符串必须以零字符结束!
welcome db "This is insane now"#0
mov si, welcome ;Print string
call print_string
缺少最终代码以正确退出程序,因此print_string
将再次执行
print_string:
cld ;Clear direction flag instruction is missing
lodsb
or al, al ; test if zero char
jz .done ; exit if zero char
mov ah, 0x0E ; Write Char in Teletype Mode
mov bh, 0 ; Define 0 page if we have multiple pages
int 0x10 ; print character!
jmp print_string
.done:
ret
答案 1 :(得分:1)
代码的问题是字符串常量的位置。它必须放在永远不会被“执行”的地方,因为它不是代码。
另一个问题是代码如何结束。引导记录应该加载一些其他代码(OS内核或更大的引导程序)并跳转到它。或者至少(如果你只想测试一些东西)只需做无限循环。在您的情况下,程序将落入print_string子例程,然后尝试“返回”无处。
这是固定版本:
org 7c00h
start:
mov ax, cs ; set up segments
mov ds, ax
mov es, ax
mov al, 03h
mov ah, 0
int 10h
mov si, welcome
call print_string
.sleep:
jmp .sleep
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
welcome db "This is insane now", 0
为什么要删除跳转?从磁盘加载引导扇区后,BIOS将其置于地址0000h:7c00h。它分别跳转到$ 0000:$ 7c00以开始执行代码。
只要(可能)inial代码是在偏移$ 0000编译的,第一次跳转只是将段更改为7c0h并偏移到0000h,以便正确执行程序。
但我们可以将程序的原点设置为7c00h(org 7c00h),这样就可以避免再使用一条指令。