【问题描述】
代码hello-DOS.asm,实现功能:打印“hello world”
; hello-DOS.asm - single-segment, 16-bit "hello world" program
;
; assemble with "nasm -f bin -o hi.com hello-DOS.asm"
[BITS 32]
org 0x100 ; .com files always start 256 bytes into the segment
; int 21h is going to want...
mov dx, msg ; the address of or message in dx
mov ah, 9 ; ah=9 - "print string" sub-function
int 0x21 ; call dos services
mov ah, 0x4c ; "terminate program" sub-function
int 0x21 ; call dos services
msg db 'Hello, World!', 0x0d, 0x0a, '$' ; $-terminated message
通过nasm -f bin -o hi.com hello-DOS.asm
编译后,执行hi.com,却什么也没打印出来。
如下:
通过debug调试,发现第一个执行的指令竟然是“66”!!!
【问题分析】
按照正常的逻辑,第一条指令mov dx, msg
应该是BA 0C 01,
查看hi.com的二进制文件,发现了BA 0C 01,但前面还多了个66
“66”指令当然无法正确执行,于是尝试修改为一条NOP指令,即先让第一条指令执行一个空指令。
于是直接更改66 为 90(NOP指令对应的二进制为90),如下:
最后,再执行,得到了正确的结果。
问题的原因找到了,就是因为nasm编译时多产生了一个“66”指令,那么怎么解决呢?
【问题解决】
多种尝试,发现更改[BITS 32]为[BITS 16]后,就不会产生“66”指令。
因此大致可以确定是由于16位和32位原因造成的该问题。
仔细分析代码,
发现mov dx,msg 使用的是dx,是不是应该使用32位的edx呢?
尝试将dx更改位edx,问题解决。
最终代码如下:(只更改了一行)
; hello-DOS.asm - single-segment, 16-bit "hello world" program
;
; assemble with "nasm -f bin -o hi.com hello-DOS.asm"
[BITS 32]
org 0x100 ; .com files always start 256 bytes into the segment
; int 21h is going to want...
mov edx, msg ; 重点再这里,32位要用edx the address of or message in dx
mov ah, 9 ; ah=9 - "print string" sub-function
int 0x21 ; call dos services
mov ah, 0x4c ; "terminate program" sub-function
int 0x21 ; call dos services
msg db 'Hello, World!', 0x0d, 0x0a, '$' ; $-terminated message
[经验教训]
对于汇编中的中断打印函数,32位下使用对应的寄存器,可能才会有对应的结果。