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

Assembly 这个实模式代码有什么问题,assembly,x86,real-mode,Assembly,X86,Real Mode,我有一段在realmode下运行的代码,并在屏幕上打印一条消息,我使用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:

我有一段在realmode下运行的代码,并在屏幕上打印一条消息,我使用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 
我试着在谷歌上搜索这条消息,发现DOSBox版本可能有问题

有人能告诉我这里有什么问题吗?

让我们一步一步:

    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
label之前和jmp之后。 字符串必须以零字符结尾

 welcome db "This is insane now"#0

 mov si, welcome     ;Print string
 call print_string
缺少正确退出程序的最终确定代码,因此将再次执行
print\u 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

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

另一个问题是代码如何结束。引导记录应该加载一些其他代码(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以开始执行代码

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


但是我们可以将程序的源代码设置为7c00h(org 7c00h),这样就可以避免再使用一条指令。

您是否正在尝试编写引导加载程序?COM文件在地址0x100处加载,因此不能以这种方式运行引导加载程序。您必须创建一个虚拟软盘驱动器或硬盘驱动器,将引导加载程序二进制文件放在第一个扇区中。另外,您的欢迎字符串缺少一个NUL终止符,不应该放在代码中间,因为CPU不知道代码和数据之间的区别。如果您真的想要创建一个.com文件(而不是引导加载程序),则应该使用<代码> [org 0x100] < /COD>并在开始时删除<代码> JMP < /代码>。(并修复字符串变量的上述问题)。感谢Micheal,我将尝试一下。感谢GJ.的响应。我只是想知道我是否以正确的方式组装了此代码??感谢@johnfound提供的答案,我想问您几个疑问1)为什么jmp 0x7c0:start已从代码中删除,尽管Micheal在上面解释了这件事,但他也想听听你的意见。或者至少(如果你只想测试某个东西)简单地做一个无限循环,你能更详细地解释它吗?或者如果在你的答案中添加它的细节会更好。@amitsightomar现在答案已经确定了。未测试,但应该可以。再次感谢Johnfound,它将测试它并让您知道结果。字符串应该有一个NUL终止符,因为
print\u string
函数依赖于此。@amitsightomar您是如何测试此程序的?它必须写入某些媒体的MBR中,然后从中引导。如果您想在DOS中测试它,只需将7c00h替换为100h,将无限循环替换为“ret”。但在这种形式下,它不能用作引导扇区。