【问题标题】:Whats is wrong with this real mode code这个实模式代码有什么问题
【发布时间】:2013-07-15 08:51:28
【问题描述】:

我有一段代码在实模式下运行并在屏幕上打印一条消息,我使用 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 版本的问题。

谁能告诉我这里可能是什么问题?

【问题讨论】:

  • 您是否正在尝试编写引导加载程序? COM 文件在地址 0x100 加载,因此您不能以这种方式运行引导加载程序。您必须创建一个虚拟软盘驱动器或硬盘驱动器,并将引导加载程序二进制文件放在第一个扇区中。此外,您的欢迎字符串缺少 NUL 终止符,不应该放在代码中间,因为 CPU 不知道代码和数据之间的区别。
  • 如果您真的想创建一个 .COM 文件(而不是引导加载程序),您应该使用 [org 0x100] 并删除开头的 jmp(同时解决上述问题字符串变量)。
  • 谢谢 Micheal,会试一试。

标签: assembly x86 real-mode


【解决方案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),这样就可以避免使用多条指令。

【讨论】:

  • 感谢@johnfound 的回答,想问您几个疑问 1) 为什么 jmp 0x7c0:start 已从代码中删除,虽然 Micheal 上面对此进行了解释,但也想听听您的意见2)。或者至少(如果您只想测试某些东西)简单地进行无限循环,请您更详细地解释它,或者如果在您的答案中添加它的详细信息会很棒。
  • @AmitSinghTomar 现在答案是固定的。未测试,但应该没问题。
  • 再次感谢 Johnfound,将对其进行测试并告诉您结果。
  • 字符串应该有一个 NUL 终止符,因为 print_string 函数依赖于它。
  • @AmitSinghTomar 你是如何测试这个程序的?它必须写入某些媒体的 MBR 中,然后从它启动。如果您想在 DOS 中测试它,只需将 7c00h 替换为 100h 并将无限循环替换为“ret”。但在这种形式下,它不能用作引导扇区。
【解决方案2】:

让我们一步一步来:

    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

【讨论】:

  • 谢谢 GJ。为响应。只是想知道我是否以正确的方式组装此代码??
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-18
  • 2012-08-07
  • 2014-08-29
  • 2013-06-05
  • 2014-06-04
  • 2011-07-07
相关资源
最近更新 更多