2012-01-29 122 views
0

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

这里是给定的情景:

[... 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(除空字节外)加载任何数据。

我在考虑数据段可能有问题的事实。

因此,我添加了下面一行启动程序的开始:

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 

解决了这个问题!

最佳 塞巴斯蒂安

+0

它是否仍然会直接转到'.PrintDone',并且设置为'ds',还是只是不打印任何内容? (我想你想在中断之前使用'ah',而不是'ax'。) – ughoavgfhw 2012-01-29 04:32:53

+0

嘿,斧头上的经典错字 - 再次固定到啊。现在该程序正在打印一些东西,但只是一个奇怪的字符。当检查寄存器当执行达到系统停止它们具有以下条目:ES = 07e0 00007e00 0000FFFF 00009300 CS = 07e0 00007e00 0000FFFF 00009b00 SS = 9000 00090000 0000FFFF 00009300 DS = 07e0 00007e00 0000FFFF 00009300 – 2012-01-29 04:48:51

+0

我不认为中断会移动光标,这意味着如果打印多个字符,则只能看到最后一个。另外,请检查以确保'si'指向最后的正确位置。如果我计算正确,那么在“数据字段”评论中必须有24个字节的数据才是正确的。代码看起来很好。 – ughoavgfhw 2012-01-29 05:43:54

回答

2

有几个问题。

首先,您没有正确设置功能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

+0

感谢帖子!但是,它不应该是'org 0'吗?由于程序被加载到偏移量为0001的基地址0x7e0,那么1会进一步减少一个字节的权利?该程序可能会打印出'ello World!' – 2012-01-29 06:31:07

+0

'org n'将第一条指令或数据项的偏移量设置为'n'。如果'org 0',加载到0,但是跳到0x7e0:1,则跳到'jmp Start'的中间,而不是开始。如果你'org 0',加载到0,并跳转到0x7e0:0,一切正常。同样,如果您使用'org 1',则加载为1,然后跳转到0x7e0:1。 – 2012-01-29 06:37:17

+0

全部清除 - 谢谢:) – 2012-01-29 06:39:44