这个真实模式代码有什么问题

时间:2013-07-15 08:51:29

标签: assembly x86 real-mode

我有一段代码在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版本的问题。

有谁能告诉我这里可能出现什么问题?

2 个答案:

答案 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),这样就可以避免再使用一条指令。