【问题标题】:TASM program to take 3-digit input, subtract a number from the input, and output the resultTASM 程序接受 3 位输入,从输入中减去一个数字,然后输出结果
【发布时间】:2014-02-18 13:59:14
【问题描述】:

这是我使用 TASM 编写的程序:

dosseg
.model small
.stack 100h
.data
h1 db 0
t1 db 0
o1 db 0
n db 0
hc db 0
tc db 0
prompt db 'Input 3 digit number: $'
prompt2 db 'Result: $'
lf db 0Dh,0Ah,24h

.code
mov ax,@data
mov ds,ax

lea dx,prompt
mov ah,09h
int 21h

mov ah,01h
int 21h
sub al,30h
mov h1,al

int 21h
sub al,30h
mov t1,al

int 21h
sub al,30h
mov o1,al

cmp h1,00h
jg hn
add n,00h

o:
mov bl,o1
add n,bl
jmp t

hn:
add n,64h
dec h1,01h
cmp h1,00h
jne hn

t:
cmp t1,00h
jg tn
add n,00h
jmp d

tn:
add n,0Ah
dec t1,01h
cmp t1,00h
jg tn
jmp o

d:
sub n,14h
cmp n,64h
jge d2
mov hc,00h

da:
cmp n,0Ah
jge d3
mov tc,00h
jmp dsp

d2:
sub n,64h
add hc,01h
cmp n,64h
jge d2
jmp da

d3:
sub n,0Ah
add tc,01h
cmp n,0Ah
jge d3

dsp:
add hc,30h
add tc,30h
add n,30h

lea dx,lf
mov ah,09h
int 21h

lea dx,prompt2
mov ah,09h
int 21h




mov dl,hc
mov ah,02h
int 21h







mov dl,tc
mov ah,02h
int 21h


mov dl,n
mov ah,02h
int 21h

mov ah,4Ch
int 21h
end

程序显示 3 位输入和 20 之间的差异。 我输入小于 148 没有问题。当我输入 148 或更高时,它不显示 128。我该怎么办?

【问题讨论】:

  • 您做错的第一件事是在汇编源文件中放入零个 cmets,并为大多数变量和标签使用 1 或 2 个字母。虽然逆向工程大约是 1990 年的 DOS 代码可能很有趣,但也有点耗时。对您的来源进行去混淆处理,也许会有更多人看到它。
  • 请记住,因为您使用的是字节变量,所以 signed 字节的范围是 -128..+127,并且 jgjge表示有符号大于(/或等于)。

标签: assembly tasm


【解决方案1】:

将结果转换回数字时,您正在使用带符号的比较。如果结果大于 128,将被视为负数,您的转换将失败。

如果您将两个有缺陷的jge 更改为jae,那么这是一个去混淆和稍微清理过的代码版本。

dosseg
.model small
.stack 100h
.data

; input digits
in_1        db 0
in_10       db 0
in_100      db 0

; output digits
out_1       db 0
out_10      db 0
out_100     db 0

; display
d_prompt    db 'Input 3 digit number: $'
d_result    db 'Result: $'
d_crlf      db 0Dh,10,'$'

.code

    mov ax,@data    ; setup data segment
    mov ds,ax

    lea dx,d_prompt ; display prompt
    mov ah,09h
    int 21h

    mov ah,01h      ; read 3 decimal digits and turn them to numbers
    int 21h
    sub al,30h
    mov in_1,al

    int 21h
    sub al,30h
    mov in_10,al

    int 21h
    sub al,30h
    mov in_100,al

    cmp in_1,00h    ; convert them to a byte
    jg add_hundreds

add_units:
    mov bl,in_100
    add out_1,bl
    jmp check_tens

add_hundreds:
    add out_1, 100
    dec in_1
    cmp in_1,00h
    jne add_hundreds

check_tens:
    cmp in_10,00h
    jg add_tens
    jmp compute

add_tens:
    add out_1,10
    dec in_10
    cmp in_10,00h
    jg add_tens
    jmp add_units

compute:
    sub out_1, 20       ; substract 20 to result

    cmp out_1, 100
    jge above_99        ; ***bug*** should use unsigned comparison (jae)

convert_tens:
    cmp out_1,10
    jge between_10_and_99
    jmp display_result

above_99:
    sub out_1,100       ; convert hundreds
    inc out_100 
    cmp out_1,100
    jge above_99        ; ***bug*** should use unsigned comparison (jae)
    jmp convert_tens

between_10_and_99:
    sub out_1,10        ; convert tens
    inc out_10
    cmp out_1,10
    jge between_10_and_99

display_result:
    add out_100,30h     ; convert digits to characters
    add out_10,30h
    add out_1,30h

    lea dx,d_crlf       ; display line break
    mov ah,09h
    int 21h

    lea dx,d_result     ; display result message
    mov ah,09h
    int 21h

    mov dl,out_100      ; display output
    mov ah,02h
    int 21h

    mov dl,out_10
    mov ah,02h
    int 21h

    mov dl,out_1
    mov ah,02h
    int 21h

    mov ah,4Ch      ; terminate program
    int 21h
end

我自己解决问题,能够处理数字 > 255
此版本将处理高达 65535 的任何内容,然后翻转到 0。
负面结果(即输入

.model small
.stack 100h
.data

; value to substract
SUB_VALUE   equ 20

; number of digits
NUM_DIGITS  equ 5

; conversion steps
convert label word
num = 1
rept NUM_DIGITS-1
num = num * 10
endm
rept NUM_DIGITS
    dw  num
num = num / 10
endm

; display
d_prompt    db 'Enter a ',NUM_DIGITS+'0',' digits number: $'
d_result    db 0Dh, 0Ah, 'Result: $'

.code

main:
    mov ax,@data    ; setup data segment
    mov ds, ax

    lea dx,d_prompt ; display prompt
    mov ah, 09h
    int 21h

    mov ah,01h      ; read decimal number
    mov cx, NUM_DIGITS
    lea si, convert
    cld
read:
    mov ah,01h  ; read a digit
    int 21h
    sub al, '0' ; convert to number
    mov dl, al
    xor dh, dh
    lodsw       ; multiply by power of 10
    mul dx
    add bx, ax  ; cumulate result
    loop    read

    sub bx, SUB_VALUE   ; do the substraction

    lea dx,d_result     ; display result message
    mov ah,09h
    int 21h

    mov cx, NUM_DIGITS
    lea si, convert
write:
    lodsw       ; power of 10 divider
    xchg    ax,bx   
    xor dx, dx
    div bx  ; divide result by power of 10
    mov bx, dx  ; store remainder
    mov dl, '0' ; print current digit
    add dl, al
    mov ah,02h
    int 21h
    loop    write

    mov ah,4Ch      ; terminate program
    int 21h
end main

我花了一些时间来运行一个运行 TASM 的 DosBox,但这让我想起了我作为 DOS 黑客的日子 :)

【讨论】:

  • 如果高于或等于则跳转。它将最后一次比较的结果解释为无符号,而 jge(如果大于或等于则跳转)将其解释为有符号。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-09
  • 1970-01-01
  • 1970-01-01
  • 2021-12-20
  • 2021-01-29
  • 1970-01-01
  • 2015-10-28
相关资源
最近更新 更多