MOV AH,02
MOV AX,'0' ; sets ah=0. this is your bug (there may be others).
以下循环打印所有数字,但不留空格。我会把它留给你。 (编辑:哎呀,这会打印从 0..9 开始的数字,因为这就是您的代码在系统调用之后对 inc 所做的事情,并且以“0”开头。显然,请改用 '1' 开头。)
MOV AH, 2
mov dl, '0'
.l1:
INT 21H
INC dl
cmp dl, '9'
jle .l1
假设 int 21 / ah=2 打印 dl 中的字符。 int 21 不会破坏任何寄存器 (except the return value in al),因此您不需要在循环内使用 mov dx, ax。 (编辑:是的,因为如果您一次打印一个字节,则需要交替空格和数字)。
使用 AH=09h 编写整个字符串意味着您可以有效地构造它,然后打印整个字符串。例如
;; Not debugged or tested (I don't keep DOS around...)
;; So I may have gotten some 2-character constants in the wrong order
sub sp, 22 ; reserve space (slightly more than necessary because I didn't debug or even test this)
mov di, sp
mov ax, '0 '
.l1:
stosw ; store digit and trailing space into [edi+=2]
inc al
cmp al, '9'
jle .l1
; note that NASM doesn't process \ escapes, but MASM does
mov word [di], '\n$' ; newline and DOS end-of-string marker
mov dx, sp ; dx=input param = start of our buffer
; this only works if DS=SS, I guess. Yay segments.
mov ah, 09h ; DOS write string syscall
int 21h
...
add sp, 22 ; release the stack buffer
...
请注意,与大多数 asm 示例不同,此代码不使用静态缓冲区(bss 或数据部分)。这可能是因为细分。不要花太多时间学习段,它们对于现代操作系统下的现代程序没有用。请参阅x86 wiki。
还要注意它不使用loop,因为that's slow。
我本可以使用push 在堆栈上创建字符串,但这可能更令人困惑,而且您永远不会看到编译器会这样做。使用推送,它会是这样的
push '\n$'
mov ax, '9 '
.l1:
push ax ; like stosw in reverse, but with SP instead of DI
dec al
cmp al, '0'
jge .l1
... make the system call with dx=sp
不过,这会在 9 之后留下一个尾随空格。