汇编程序在返回控制之前不显示或循环
Assembly program not displaying or looping before returning control
我有这个程序应该 return 一个或多个字符的反转,例如 A -> Z,B -> Y 等。代码可以正常转换字符,但程序不显示它应该出现在屏幕上或循环播放,相反,它 return 控制在 int 21h
。
.8086
.model small
.data
; Variables
prompt_in db 0Dh, "Input: $"
prompt_out db 0Dh, 0Ah, "Output: $"
.code
main proc
; Load Variables
mov ax, @data
mov ds, ax
; Display Input Prompt
mov dx, offset prompt_in
mov ah, 09h
int 21h
mov cl, 00
mov ah, 01h
; Read input and push to BX until User presses Return (Enter)
read:
int 21h
mov bl, al
push bx
inc cx
cmp al, 0Dh
jz return
jmp read
; Display Output Prompt
return:
mov dx, offset prompt_out
mov ah, 09h
int 21h
; Calculate Inverse Letter and Display
calc:
mov ah, 00
pop bx
cmp bl, 0Dh
jz calc
mov al, bl
sub al, 41h
mov cl, 19h
mov ch, 2
mul ch
sub cl, al
add bl, cl
mov dl, bl
int 21h ; Stops Code Here without Displaying anything more
loop calc ; Doesn't Loop Here
mov ah, 4Ch
int 21H
main endp
end main
将字符写入标准输出的 DOS 服务是 int 21h
with ah = 02h
。但这不是你在做什么:
就在 calc
标签之后,您用值 00
加载 ah
,而不是 02h
。
几行之后,您有一个 mul ch
指令。请记住,x86 上的 mul
正在扩大; 8 位乘法在 ax
中产生 16 位结果,特别是会覆盖 ah
。现在在您的程序中,结果可能适合 8 位,因此 ah
再次设置为零。
当您使用 ah = 0
调用 int 21h
时,您会调用 terminate program service(int 21h / ah = 4Ch
的已弃用前身),这就是您的程序在此时终止的原因。
快速的解决方案是在 int 21h
之前插入 mov ah, 02h
,并删除前面的 mov ah, 00
,这是错误的,也是多余的。
您可以进一步改进程序,注意乘以 2 与左移 1 相同,后者速度更快且不涉及那么多寄存器。如果结果溢出 8 位(结果的高位部分丢失,而不是放在 ah
中),情况就不太一样了,但无论如何您都不希望处理这种情况。所以你的 mov ch, 2 / mul ch
可以简单地替换为 shl al, 1
。此外,这根本没有触及 ah
。
彻底解释了为什么您的程序甚至在显示任何输出之前就提前退出。我希望你现在已经纠正了这个问题。然后你会看到程序崩溃!
你把事情复杂化了。将 A-Z 转换为 Z-A 的任务很简单,既不涉及乘法也不涉及移位。
sub al, "A"
sub al, "Z"-"A"
neg al
add al, "A"
更短:
sub al, "A"
neg al
add al, "Z"
程序将永远循环并最终崩溃,因为您正在使用依赖于 CX
寄存器的 LOOP
指令并且您的代码正在使用大 non-zero 值。
mov ch, 2 <-- reloads with value 512+
...
loop calc <-- jumps forever
这会起作用:
pop dx ; First pop is the carriage return for sure!
; Why do you even push it in the first place?
calc:
pop dx
sub dl, "A"
neg dl
add dl, "Z"
mov ah, 02h ; DOS.PrintCharacter
int 21h
loop calc
请注意,在输入开始时,您应该将整个 CX
寄存器置零,而不仅仅是写入 mov cl,0
。依赖您正在使用的模拟器的特定行为(关于归零寄存器)是一个坏习惯。
我有这个程序应该 return 一个或多个字符的反转,例如 A -> Z,B -> Y 等。代码可以正常转换字符,但程序不显示它应该出现在屏幕上或循环播放,相反,它 return 控制在 int 21h
。
.8086
.model small
.data
; Variables
prompt_in db 0Dh, "Input: $"
prompt_out db 0Dh, 0Ah, "Output: $"
.code
main proc
; Load Variables
mov ax, @data
mov ds, ax
; Display Input Prompt
mov dx, offset prompt_in
mov ah, 09h
int 21h
mov cl, 00
mov ah, 01h
; Read input and push to BX until User presses Return (Enter)
read:
int 21h
mov bl, al
push bx
inc cx
cmp al, 0Dh
jz return
jmp read
; Display Output Prompt
return:
mov dx, offset prompt_out
mov ah, 09h
int 21h
; Calculate Inverse Letter and Display
calc:
mov ah, 00
pop bx
cmp bl, 0Dh
jz calc
mov al, bl
sub al, 41h
mov cl, 19h
mov ch, 2
mul ch
sub cl, al
add bl, cl
mov dl, bl
int 21h ; Stops Code Here without Displaying anything more
loop calc ; Doesn't Loop Here
mov ah, 4Ch
int 21H
main endp
end main
将字符写入标准输出的 DOS 服务是 int 21h
with ah = 02h
。但这不是你在做什么:
就在
calc
标签之后,您用值00
加载ah
,而不是02h
。几行之后,您有一个
mul ch
指令。请记住,x86 上的mul
正在扩大; 8 位乘法在ax
中产生 16 位结果,特别是会覆盖ah
。现在在您的程序中,结果可能适合 8 位,因此ah
再次设置为零。
当您使用 ah = 0
调用 int 21h
时,您会调用 terminate program service(int 21h / ah = 4Ch
的已弃用前身),这就是您的程序在此时终止的原因。
快速的解决方案是在 int 21h
之前插入 mov ah, 02h
,并删除前面的 mov ah, 00
,这是错误的,也是多余的。
您可以进一步改进程序,注意乘以 2 与左移 1 相同,后者速度更快且不涉及那么多寄存器。如果结果溢出 8 位(结果的高位部分丢失,而不是放在 ah
中),情况就不太一样了,但无论如何您都不希望处理这种情况。所以你的 mov ch, 2 / mul ch
可以简单地替换为 shl al, 1
。此外,这根本没有触及 ah
。
你把事情复杂化了。将 A-Z 转换为 Z-A 的任务很简单,既不涉及乘法也不涉及移位。
sub al, "A" sub al, "Z"-"A" neg al add al, "A"
更短:
sub al, "A" neg al add al, "Z"
程序将永远循环并最终崩溃,因为您正在使用依赖于
CX
寄存器的LOOP
指令并且您的代码正在使用大 non-zero 值。mov ch, 2 <-- reloads with value 512+ ... loop calc <-- jumps forever
这会起作用:
pop dx ; First pop is the carriage return for sure!
; Why do you even push it in the first place?
calc:
pop dx
sub dl, "A"
neg dl
add dl, "Z"
mov ah, 02h ; DOS.PrintCharacter
int 21h
loop calc
请注意,在输入开始时,您应该将整个 CX
寄存器置零,而不仅仅是写入 mov cl,0
。依赖您正在使用的模拟器的特定行为(关于归零寄存器)是一个坏习惯。