1

我有一段代码在实模式下运行并在屏幕上打印一条消息,我使用 Dosbox 0.7 作为我的执行环境。下面是代码

 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 版本的问题。

谁能让我知道这里可能是什么问题?

4

2 回答 2

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
于 2013-07-15T09:17:20.087 回答
1

代码的问题在于字符串常量的位置。它必须放在永远不会“执行”的地方,因为它不是代码。

另一个问题是代码如何结束。引导记录应该加载一些其他代码(操作系统内核或更大的引导程序)并跳转到它。或者至少(如果你只想测试一些东西)简单地进行无限循环。在您的情况下,程序落入 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 以开始执行代码。

只要(可能)初始代码是在偏移量 $0000 处编译的,第一次跳转只是将段更改为 7c0h 并将偏移量更改为 0000h,以提供程序的正确执行。

但是我们可以将程序的原点设置为 7c00h (org 7c00h),这样就可以避免使用多条指令。

于 2013-07-15T10:11:09.373 回答