【问题标题】:TASM infinite loopTASM 无限循环
【发布时间】:2013-12-16 10:09:19
【问题描述】:

我的程序中的问题是,当我尝试从包含一串字符的缓冲区中获取一个字符时,将一个字符分配给AL 寄存器并调用一个过程,该过程将AL 中的字符转换为十六进制,我得到一个无限循环。这是我的代码:

.model small
.stack 100H

.data

about           db 'example.exe [/?] [sourceFile2]]',13,10,13,10,9,'/? - help',13,10,'$'
err_s           db 'Unable to open source file',13,10,'$'
str_term        db '$'
sourceF         db 12 dup (0)
sourceFHandle   dw ?
buffer          db 500 dup (?)

.code

START:
    mov ax, @data
    mov es, ax                  ; es so we can use stosb function: Store AL at address ES:(E)DI

    mov si, 81h

    call    skip_spaces

    mov al, byte ptr ds:[si]    ; read first symbol of program parameter
    cmp al, 13                  ; if there's no parameters
    jne _1
    jmp help                    ; then jump to help
_1:

    ;; do we need to print out help
    mov ax, word ptr ds:[si]
    cmp ax, 3F2Fh               ; if input is "/?" - 3F = '?'; 2F = '/'
    jne _2
    jmp help                    ; if "/?" is found, print out help

_2:

    ;; source file name
    lea di, sourceF
    call    read_filename       ; move from parameter to line

    push    ds
    push    si

    mov ax, @data
    mov ds, ax

    jmp startConverting

readSourceFile:
    pop si
    pop ds

    ;; source file name
    lea di, sourceF
    call    read_filename           ; move from parameter to line

    push    ds
    push    si

    mov ax, @data
    mov ds, ax

    cmp byte ptr ds:[sourceF], '$'  ; if there was nothing to read
    jne startConverting
    jmp closeF

startConverting:
    ;; open
    cmp byte ptr ds:[sourceF], '$'  ; if there was nothing to read
    jne source_from_file

    mov sourceFHandle, 0
    jmp read

source_from_file:
    mov dx, offset sourceF          ; file name
    mov ah, 3dh                     ; open file command
    mov al, 0                       ; 0 - reading, 1-writing
    int 21h                         ; INT 21h / AH= 3Dh - open existing file
    jc  err_source                  ; CF set on error AX = error code.
    mov sourceFHandle, ax           ; save filehandle

read:
    mov bx, sourceFHandle
    mov dx, offset buffer           ; address of buffer in dx
    mov cx, 500                     ; how many bytes to read
    mov ah, 3fh                     ; function 3Fh - read from file
    int 21h

    mov cx, ax                      ; bytes actually read
    cmp ax, 0                       ; if there was nothing to read
    jne _6                          ; not the end of file

    mov bx, sourceFHandle           ; end of the file being read
    mov ah, 3eh                     ; close the file
    int 21h
    jmp readSourceFile              ; open another file to read if it was specified in the parameters
_6:
    mov si, offset buffer           ; read from buffer

    cmp sourceFHandle, 0
    jne _7
    cmp byte ptr ds:[si], 13
    je  closeF
_7:
    push    cx                      ; save big loop CX

sort_out:
    lodsb                           ; Load byte at address DS:(E)SI into AL
    push    cx                      ; place cx
    mov ah, 40h                     ; INT 21h / AH= 40h - write to file
    int 21h
    pop cx
    loop    sort_out

    pop cx

    loop    read

help:
    mov ax, @data
    mov ds, ax

    mov dx, offset about         
    mov ah, 09h
    int 21h

    jmp _end

closeF:
    ;; close the destination file
    mov ah, 3eh                     ; close
    int 21h

result:
    MOV si, offset buffer           ; source index = buffer coordinates
    INC si                          ; add 1 to si
    MOV bh, [si]                    ; let bh know how many symbols in total
    INC si                          ; go to the symbol itself

    mov bl, 0                       ; initialize bl counter to 0

    jmp char

    ; print out the text in buffer
    mov dx, offset buffer
    mov ah, 09h
    int 21h

_end:
    ; add a string terminator to avoid static output
    db '$'
    mov ax, @data

    mov ax, 4c00h
    int 21h  

char:
    LODSB                               ; take a character from es:si and add it to al

    ; increment bl
    INC bl

    MOV dl, al                          ; add a symbol from al to dl
    mov ah,2
    int 21h

    ; try to convert the current symbol in al to HEX and print it out

    ; =======INFINITE LOOP PROBLEM HERE========
    call char_to_hex

    DEC bh                              ; subtract 1 from total amount of symbols
    JZ _end                             ; if bh = 0, end program
    JMP char                            ; if not, jump to other symbol

err_source:
    mov ax, @data
    mov ds, ax

    mov dx, offset err_s        
    mov ah, 09h
    int 21h

    mov dx, offset sourceF
    int 21h

    mov ax, 4c01h
    int 21h 

;; procedures

skip_spaces PROC near

skip_spaces_loop:
    cmp byte ptr ds:[si], ' '
    jne skip_spaces_end
    inc si
    jmp skip_spaces_loop
skip_spaces_end:
    ret

skip_spaces ENDP

read_filename PROC near

    push    ax
    call    skip_spaces
read_filename_start:
    cmp byte ptr ds:[si], 13        ; if there is no parameters
    je  read_filename_end           ; if yes, its the end of the filename
    cmp byte ptr ds:[si], ' '       ; if space
    jne read_filename_next          ; then skip it and jump to the next parameter
read_filename_end:
    mov al, '$'                     ; add '$' to the end
    stosb                           ; Store AL at address ES:(E)DI, di = di + 1
    pop ax
    ret

read_filename_next:
    lodsb                           ; loads other symbol
    stosb                           ; Store AL at address ES:(E)DI, di = di + 1
    jmp read_filename_start

read_filename ENDP

; Char to Hex converting
char_to_hex PROC                   ; Accept a character, print it's ascii value in hex.

        MOV DX, OFFSET AskChar      ; Display prompt
        MOV AH, 09H
        INT 21H

        MOV AH, 07H                 ; Get keyboard input w/ no echo (AL)
        INT 21H

        MOV CL, AL                  ; Copy user input (AL) to CL
        MOV AX, 0                   ; Clear AX (get rid of HO bits)
        MOV AL, CL                  ; Copy user input back into AL

        MOV BX, 16                  ; Set up the divisor (base 16)
        MOV CX, 0                   ; Initialize the counter
        MOV DX, 0                   ; Clear DX

        Div2:                         
                                    ; Dividend (what's being divided) in DX/AX pair, Quotient in AX, Remainder in DX.
            DIV BX                  ; Divide (will be word sized).
            PUSH DX                 ; Save DX (the remainder) to stack.

            ADD CX, 1               ; Add one to counter
            MOV DX, 0               ; Clear Remainder (DX)
            CMP AX, 0               ; Compare Quotient (AX) to zero
            JNE Div2              ; If AX not 0, go to "Div2:"

        getHex2:
            MOV DX, 0               ; Clear DX.
            POP DX                  ; Put top of stack into DX.
            ADD DL, 30h             ; Conv to character.

            CMP DL, 39h
            JG MoreHex2

        HexRet2:        

            MOV AH, 02h             ; 02h to display AH (DL)
            INT 21H                 ; Send to DOS

            LOOP getHex2            ; If more to do, getHex2 again
                                    ; LOOP subtracts 1 from CX. If non-zero, loop.
            JMP Skip2
        MoreHex2:
            ADD DL, 7h
            JMP HexRet2             ; Return to where it left off before adding 7h.
        Skip2:
            RET
    char_to_hex ENDP

end START

我的任务是得到这样的输出:

00000000 4d 61 6e 6f 20 62 61 74 61 69 20 62 75 76 6f 20 ¦Mano batai buvo ¦
00000010 64 75 2c 0a 56 69 65 6e 61 73 20 64 69 6e 67 6f ¦du,.Vienas dingo ¦
00000020 20 2d 20 6e 65 72 61 6e 64 75 2e 0a 41 f0 20 73 ¦ - nerandu..Aš s ¦
00000030 75 20 76 69 65 6e 75 20 62 61 74 75 6b 75 0a 4e ¦u vienu batuku.N¦
00000040 69 65 6b 75 72 20 65 69 74 69 20 6e 65 67 61 6c ¦iekur eiti negal ¦
00000050 69 75 2e 0a ¦iu..¦
00000054

尽管我的程序需要做更多工作才能得到这样的结果,但我至少希望正确地将字符转换为十六进制部分。

【问题讨论】:

  • 你到底是从哪里得到无限循环的?
  • 人们仍在编写 16 位代码,尤其是使用 TASM 时,还在做什么? :P 十年或更长时间都没有意义。
  • @cHao:它似乎在一些学校被用于教育目的(不要问我为什么)。哎呀,我曾经参加过一门课程,我们有一些 M68000 组装实验室任务,这不是很多年前的事了。
  • @Michael,M68K 至少很酷。 :)
  • 查看您的代码后,我建议您重写将 AL 中的值转换为 HEX 字符串的方式。创建十六进制输出不需要使用div,这使得 IMO 变得更加复杂。在这种情况下使用移位运算符会更合适,并且使代码更具可读性。

标签: file assembly x86 dos tasm


【解决方案1】:

char_to_hex clobbers bx,然后在使用bh 作为循环计数器的循环中调用它。

如果您在调试器中运行您的代码,您可以自己发现这个,这样您就可以在它运行时查看寄存器值。

【讨论】:

    【解决方案2】:

    您是否从另一个练习中取出char_to_hex 并将其粘贴到此程序中?这将解释这部分:

    ; Char to Hex converting
    char_to_hex PROC                   ; Accept a character, print it's ascii value in hex.
    
        MOV DX, OFFSET AskChar      ; Display prompt
        MOV AH, 09H
        INT 21H
    
        MOV AH, 07H                 ; Get keyboard input w/ no echo (AL)
        INT 21H
    

    我在任何地方都找不到AskChar 符号,所以谁知道正在打印什么——但最后两行(耐心地)在键盘上等待给它一个字符。会不会是“无限循环”?

    【讨论】:

    • 可以肯定地假设这个问题的 OP 早已消失。他们的user page 说“最后一次看到是 2014 年 2 月 4 日 20:11”。最好不要理会像这样的老问题,除非有什么要补充的东西对未来的读者可能真的有帮助。如果您正在浏览您喜欢的标签的未回答问题的后台档案,那么很容易回答所有问题,但是当 OP 消失时,将永远不会“接受”将问题从未回答列表中删除。跨度>
    • 这当然是我这样做的部分原因(将其从未回答的列表中删除),但它也至少为未来的读者提供了一个答案......虽然我真的不明白是 cmets 中答案的绝对数量。它们(当然)显示为“0 个答案”——我讨厌这样。
    • 是的,未回答的问题也困扰着我。有些人有发布 cmets 而不是最小但足够的答案的坏习惯。我经常开始写评论,然后意识到我可以将其发布为答案。然后我通常会花两倍的时间来扩展我要说的话......
    • ...并获得更好的最终结果。是的!
    • 是的,但我理解为什么回答问题的时间有限的人可能会将自己限制在 cmets 上。无论如何,大约一年前,当我第一次开始回答关于 SO 的很多 asm 问题时,我翻阅了未回答问题的后台档案并回答了其中一些问题,但我很快意识到,甚至没有办法赚很多在那桩上的一个凹痕。不过,我确实发现了几个值得回答的老问题,例如 this one 实际上有一种方法可以通过实验来测试它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-25
    • 1970-01-01
    • 2013-09-05
    相关资源
    最近更新 更多