【问题标题】:Data segment issue with x86 Assembler (nasm) for print function用于打印功能的 x86 汇编程序 (nasm) 的数据段问题
【发布时间】:2012-01-29 04:07:34
【问题描述】:

我目前正在使用 x86 汇编程序,因为我想刷新我的低级编程技能:-)。出于测试目的,我尝试编写一个仅打印给定字符串的函数。打印功能本身工作正常。在进一步的步骤中,我想从磁盘加载第二个汇编程序跳转到它并打印出一个文本。在跳转到地址时从磁盘加载工作正常。

这是给定的场景:

[... loading from disk etc ... program is loaded to 0x7e0:0001]

jmp 0x7e0:0001

[... context of other asm ...]

jmp Start
;data fields
msg db "Hello World!",0

Start:
     xor si, si     ; clear SI register
     mov si, msg    ; load message to SI register

     call Print

     cli
     hlt            ; halt the system

Print:
     .PrintLoop:
         lodsb                ; load byte from SI register
         or al, al            ; check if 0 byte
         jz short .PrintDone  ; if so - stop
         mov ah, 0Ah          ; function - print text to cursor
         int 0x10             ; BIOS interrupt

         jmp .PrintLoop       ; continue with next char
     .PrintDone:
         ret

所有这个程序都运行良好。我面临的唯一问题是,没有打印文本。在调试过程中,我看到打印函数立即跳转到 .PrintDone 标签,因为 SI 中似乎没有数据,因此 lodsb 不向 al 加载任何内容(除了空字节)。

我在想一个事实,数据段可能有问题。

因此,我在 Start-Routine 的开头添加了以下行:

xor ax, ax    ; clear ax register
mov ax, cs    
mov ds, ax    ; set data segment pointer

但这并没有改变程序行为。没有打印任何内容。

当执行到停止指令时检查 CPU 寄存器,给出以下结果:

EAX=00000a00 EBX=00000000 ECX=00000002 EDX=00000000
ESI=00000026 EDI=00000000 EBP=00000000 ESP=0000ffff
EIP=00000036 EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=1
ES =07e0 00007e00 0000ffff 00009300
CS =07e0 00007e00 0000ffff 00009b00
SS =9000 00090000 0000ffff 00009300
DS =07e0 00007e00 0000ffff 00009300

你知道这里发生了什么吗?

[编辑 - 问题已解决]

替换:

mov ah, 0Ah -> mov ah, 0xE

解决问题!

最好的 塞巴斯蒂安

【问题讨论】:

  • 它仍然直接进入.PrintDone 并添加到设置ds,还是它只是不打印任何东西? (我想你想要在中断之前ah,而不是ax。)
  • 嘿,斧头上的经典错字 - 再次固定为 ah。现在程序正在打印一些东西,但只有一个奇怪的字符。当执行到达系统停止时检查寄存器时,它们具有以下条目: ES =07e0 00007e00 0000ffff 00009300 CS =07e0 00007e00 0000ffff 00009b00 SS =9000 00090000 0000ffff 00009300 DS =07e0 000070
  • 我认为中断不会移动光标,这意味着如果打印多个字符,您只会看到最后一个。另外,检查以确保si 指向最后的正确位置。如果我数对了,“数据字段”注释中必须有 24 个字节的数据才能正确。代码看起来不错。
  • 您好,问题已通过将中断向量函数从 0Ah 替换为 0xE 得到解决……现在一切正常!感谢您的帮助!

标签: assembly io x86 nasm bios


【解决方案1】:

有一些问题。

首先,您没有正确设置函数 0Ah 的寄存器。您必须将 bh 设置为页码 (0),并将 cx 设置为重复计数 (1)。

其次,此 BIOS 功能不会提前光标位置,所有字符都会打印到屏幕上的同一位置,相互覆盖,这应该只会导致“!”可见,因为它是最后一个字符。

我建议改用函数 0Eh。

第三,你没有初始化lodsb所依赖的方向标志(flags.df)。您应该使用cld 重置df

第四,我没有看到所有代码,但您应该使用正确的org 指令来为指令和数据生成正确的偏移量。

另外,NMIsSMIs 将导致 hlt 完成,随后的代码将执行(接下来是你的 Print)。你想循环执行hlt

通过这些修复,我们得出:

bits 16
org 1

jmp Start
;data fields
msg db "Hello World!",0

Start:
     mov ax, cs    
     mov ds, ax    ; set data segment pointer
     cld

     mov si, msg    ; load message to SI register

     call Print

     cli
.halt:
     hlt            ; halt the system
     jmp .halt

Print:
     .PrintLoop:
         lodsb                ; load byte from SI register
         or al, al            ; check if 0 byte
         jz short .PrintDone  ; if so - stop
;         mov ah, 0Ah          ; function - print text to cursor
;         xor bh, bh
;         mov cx, 1
         mov ah, 0Eh          ; function - print text tty

         int 0x10             ; BIOS interrupt

         jmp .PrintLoop       ; continue with next char
     .PrintDone:
         ret

您通过使用nasm blah.asm -f bin -o blah.bin 编译上面得到的二进制文件然后应该加载到0x7e0:0001 并使用jmp 0x7e0:0001 跳转到。

【讨论】:

  • 感谢您的帖子!但它不应该是'org 0'吗?由于程序加载到偏移量为 0001 的基地址 0x7e0 org 1 会进一步削减一个字节,对吗?该程序可能会打印出“hello World!”
  • org n 将第一条指令或数据项的偏移量设置为n。如果你org 0,在 0 处加载,但跳转到 0x7e0:1,你会跳转到 jmp Start 的中间而不是开头。如果你org 0,在 0 处加载,然后跳转到 0x7e0:0,一切正常。同样,如果您org 1,一切正常,在 1 处加载,然后跳转到 0x7e0:1。
猜你喜欢
  • 2011-02-19
  • 2011-10-17
  • 2017-12-26
  • 2018-05-14
  • 1970-01-01
  • 2015-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多