8086 ASM:Turbodebugger打开文本文件,正常执行没有

时间:2012-09-07 04:24:31

标签: assembly x86 dos x86-16 tasm

我正在处理我正在进行的ASM任务这个小问题。当我使用TD时,它就像一个魅力...... 因为我对大会很新,我真的找不到问题所在。

我需要在屏幕上打印.txt文件中每个ASCII代码有多少个字符(多少个,多少个b,等等)。我首先使用int 21h / 3dh打开文件来创建一个句柄,然后缓冲一些字节,处理它们,并缓冲下一部分直到文件结束。 正如我所说,当我使用TurboDebugger运行它时,它运行得很好。但是,当我执行它只是形成命令行时,它甚至不创建文件句柄。它在3dh中断后设置CF,这意味着错误。

我真的认为我没有做我需要做的事情,我很感激这方面的帮助。谢谢! 顺便说一句,我正在使用TASM进行编译。我不认为发布我的代码会有所帮助,但如果您不这么认为我会很乐意修改帖子。

这是整个代码,对于西班牙语的评论感到抱歉         

NLCR       macro
           mov dl, 0dh      ;Caracter a imprimir a dl
           mov ah, 02h      ;Preparo la impresion de un caracter
           int 21h          ;Ejecuto
           mov dl, 0ah      ;Caracter a imprimir a dl
           mov ah, 02h      ;Preparo la impresion de un caracter
           int 21h          ;Ejecuto
           endm

SData Segment para 'Data' msgerrorab db "Error al abrir el archivo.$" msgerrorca db "Error al cargar el archivo.$" msgnombre db "Ingrese el nombre del archivo a abrir: $" msgnoexiste db "Error: el archivo no existe.$" msgimprimir db "========= Caracter ========== Cantidad =======",10,13,"$" msglinea1 db "=== $" caracter db 0 msglinea2 db " ========== $" cuantos dw 0 msglinea3 db "==========",10,13,"$" msgtecla db "Presione una tecla para mostrar mas...$" noarchivo db "$$" nombre db 20 Dup(?) buffer db 4096 Dup(4) handle dw 0 caracteres dw 255 Dup(0) cantidad dw 0 eof db 0 bytesinv db 10 dup("$") bytes db 10 dup("$") contador db 0

SData EndS

pila segment stack 'stack' dw 256 dup (?) pila ends

CSeg Segment para public 'Code' Begin: Assume CS:CSeg, DS:SData,SS:pila

LeeChar Proc ;Procedure para leer un caracter y guardarlo. Lo salva en AL xor ax,ax ;Limpia el ax para guardar el resultado mov ah, 08h ;Prepara el servicio para leer un caracter int 21h ;Lo ejecuta ret ;Retorna LeeChar endP

ImpChar Proc ;Similar, pero imprime un caracter xor ax,ax ;Limpia el ax para guardar el resultado mov ah,02h ;Prepara el servicio para imprimir un caracter int 21h ;Lo ejecuta ret ;Retorna ImpChar endP

ImpStr Proc ;Similar, pero imprime un caracter xor ax,ax ;Limpia el ax para guardar el resultado mov ah,09h ;Prepara el servicio para imprimir un caracter int 21h ;Lo ejecuta ret ;Retorna ImpStr endP

ImpNum Proc ;el numero en ax, el bx en 000A, dx en 0, y el di en 0. hexadec: ;Con esto se pasa "a decimal", es decir convierte los caracteres a numeros para ser impresos. div bx ;Divido por 10 y consigo en DL el numero de mas a la derecha add dx, 30h ;Sumo 48 para pasarlo a caracter. EL MODULO QUEDA EN DX mov bytesinv[di], dl ;Lo guardo en el vector xor dx,dx ;Limpio para volverlo a hacer inc di ;Aumento el indice del vector cmp ax,0 ;Si ya no queda nada je resfinal ;Brinco al resultado final jmp hexadec ;Si todavia queda, hago el proceso de division de nuevo

resfinal: ;Inversion de los caracteres xor si,si mov al, bytesinv[di-1] ;Estas dos lineas vuelcan el vector en otro, pero en el orden que corresponde mov bytes[si],al ;Pasa al nuevo vector los caracteres dec di ;Decrementa para mover el indice inc si ;Aumento el indice del vector cmp di,0 ;Si ya no queda nada jne resfinal lea dx, bytes xor ax,ax mov ah,09h int 21h ret ImpNum endP ;;;;;;;;;;;;;;;;;;;;;;;
;Comienzo del programa; ;;;;;;;;;;;;;;;;;;;;;;;

inicio: mov ax,SData ;Con estas dos lineas, pasamos la direccion del segmento SData y lo pasamos al ds mov ds,ax mov ax,pila mov ss,ax

leernombre: xor di,di xor ax,ax ;Limpio AX xor dx,dx ;Limpio DX lea dx, msgnombre ;Cargo el offset del mensaje que pide el nombre mov ah,09h ;Preparo el servicio de impresion int 21h ;Ejecuto xor ax,ax ;Limpio AX xor dx,dx ;Limpio DX lea dx, noarchivo ;Carga el offset de donde voy a guardar el nombre del archivo mov ah,0ah ;Preparo el servicio de entrada buffereada int 21h ;Ejecuto nlcr ;New line carriage return xor ah,ah ;Limpio AH mov al, noarchivo[1] ;En narchivo[1] esta la cantidad de caracteres que mide el nombre de archivo mov di,ax ;Lo paso al DI para usarlo como indice mov noarchivo[di+2],0 ;La posicion di+2 del nombre contiene el Enter, o 0ah. Lo convierto en 0. mov ah,3dh ;Preparo el servicio de creacion de handle para abrir el archivo mov al,0 ;En modo de solo lectura lea dx, nombre ;Cargo el offset del nombre en DX, sin los bytes que sobran antes int 21h ;Ejecuto. El handle queda en AX jc errorabrir mov handle,ax ;Lo paso a su variable correspondiente jmp cargarbuffer errorabrir: lea dx, msgerrorab ;Cargo el offset del mensaje que pide el nombre mov ah,09h ;Preparo el servicio de impresion int 21h
jmp final errorcarga: lea dx, msgerrorca ;Cargo el offset del mensaje que pide el nombre mov ah,09h ;Preparo el servicio de impresion int 21h
jmp final cargarbuffer: xor ax,ax ;Limpio AX xor bx,bx lea dx, buffer ;Cargo el offset del buffer de texto mov ah,3fh ;Preparo el servicio para mover el contenido del archivo mov bx,handle ;Uso el handle que me genero la int 21/3dh mov cx,10 ;Voy a guardar 4096 caracteres a la vez int 21h jc errorcarga

      mov cantidad,ax       ;Cargo la cantidad de caracteres leidos
      cmp cantidad,4096     ;Si es menor a lo que le dije que cargara, llego al end of file
      jl  endoffile         ;
      xor si,si
      xor ax,ax
      mov bx,handle
      mov ah,3eh
      int 21h
      jmp procesarbuffer

endoffile: mov eof,1 jmp procesarbuffer

procesarbuffer: xor bx,bx xor ax,ax xor di,di xor dx,dx mov bl,2 mov al,buffer[si] mul bl mov di,ax inc caracteres[di] inc si cmp si,cantidad jne procesarbuffer cmp eof,1 je imprimir jmp cargarbuffer imprimir: xor di,di xor dx,dx xor ax,ax xor bx,bx

mov di,0 mov si,0 lea dx, msgimprimir mov ah,09h int 21h linea: cmp caracteres[di],0 je noimprime inc contador mov ax,si mov caracter,al lea dx, msglinea1 mov ah,09h int 21h mov dl,caracter xor ax,ax mov ah,02h int 21h lea dx, msglinea2 xor ax,ax mov ah,09h int 21h push di push si mov ax, caracteres[di] mov bx,10 xor dx,dx xor di,di call ImpNum pop si pop di inc di inc di inc si nlcr cmp si,254 je final cmp contador,20 je pidetecla jmp linea noimprime: inc di inc di inc si cmp si,254 je final jmp linea pidetecla: lea dx, msgtecla xor ax,ax mov ah,09h int 21h xor ax,ax mov ah,08h int 21h nlcr jmp linea final: xor ax,ax ;Limpia el al y prepara el ah para la salida. mov ax,4c00h ;Servicio AH=4c int 21h para salir del programa. int 21h ;Llamada al DOS. Termine el programa. CSeg EndS ;Fin del segmento de código. End inicio ;Fin del programa la etiqueta al final dice en que punto debe comenzar el programa.

修改
似乎中断返回的错误代码是5,这意味着Access被拒绝...可能是因为路径文件??该文件位于我正在编译它的同一文件夹中,它是F:\ dos \ tasm \ a.txt。顺便说一下,我正在使用DosBox。

1 个答案:

答案 0 :(得分:3)

我发现了一些错误并修复了它们。请参阅包含;;;;的行以了解更改和注释。我不确定问题究竟在哪里。它现在在这里工作。你能试试吗?

NLCR macro
        mov dl, 0dh             ;Caracter a imprimir a dl
        mov ah, 02h             ;Preparo la impresion de un caracter
        int 21h                 ;Ejecuto
        mov dl, 0ah             ;Caracter a imprimir a dl
        mov ah, 02h             ;Preparo la impresion de un caracter
        int 21h                 ;Ejecuto
endm

SData Segment para 'Data'

msgerrorab      db "Error al abrir el archivo.$"
msgerrorca      db "Error al cargar el archivo.$"
msgnombre       db "Ingrese el nombre del archivo a abrir: $"
msgnoexiste     db "Error: el archivo no existe.$"
msgimprimir     db "=========  Caracter  ==========  Cantidad  =======",10,13,"$"
msglinea1       db "===           $"
caracter        db 0
msglinea2       db "   ==========     $"
cuantos         dw 0
msglinea3       db "==========",10,13,"$"
msgtecla        db "Presione una tecla para mostrar mas...$"
noarchivo       db buffer - nombre - 1, 0 ;;;; "$$"
;;;; You must initialize the input buffer for function 2 (the max len, at least)
nombre          db 20 Dup(?)
buffer          db 4096 Dup(4)
handle          dw 0
caracteres      dw 256 Dup(0) ;;;; 255 Dup(0)
;;;; You have 256 possible chars, not 255, with 255 you can overflow into "cantidad"
cantidad        dw 0
eof             db 0
bytesinv        db 10 dup("$")
bytes           db 10 dup("$")
contador        db 0

SData EndS


pila segment stack 'stack'
  dw 256 dup (?)
pila ends


CSeg Segment para public 'Code'
Begin:
        Assume CS:CSeg, DS:SData, SS:pila

LeeChar Proc                    ;Procedure para leer un caracter y guardarlo. Lo salva en AL
        xor ax, ax              ;Limpia el ax para guardar el resultado
        mov ah, 08h             ;Prepara el servicio para leer un caracter
        int 21h                 ;Lo ejecuta
        ret                     ;Retorna
LeeChar endP

ImpChar Proc                    ;Similar, pero imprime un caracter
        xor ax, ax              ;Limpia el ax para guardar el resultado
        mov ah, 02h             ;Prepara el servicio para imprimir un caracter
        int 21h                 ;Lo ejecuta
        ret                     ;Retorna
ImpChar endP

ImpStr Proc                     ;Similar, pero imprime un caracter
        xor ax, ax              ;Limpia el ax para guardar el resultado
        mov ah, 09h             ;Prepara el servicio para imprimir un caracter
        int 21h                 ;Lo ejecuta
        ret                     ;Retorna
ImpStr endP

ImpNum Proc                     ;el numero en ax, el bx en 000A, dx en 0, y el di en 0.
hexadec:                        ;Con esto se pasa "a decimal", es decir convierte los caracteres a numeros para ser impresos.
        div bx                  ;Divido por 10 y consigo en DL el numero de mas a la derecha
        add dx, 30h             ;Sumo 48 para pasarlo a caracter. EL MODULO QUEDA EN DX
        mov bytesinv[di], dl    ;Lo guardo en el vector
        xor dx, dx              ;Limpio para volverlo a hacer
        inc di                  ;Aumento el indice del vector
        cmp ax, 0               ;Si ya no queda nada
        je resfinal             ;Brinco al resultado final
        jmp hexadec             ;Si todavia queda, hago el proceso de division de nuevo

resfinal:                       ;Inversion de los caracteres
        xor si, si
resfinal2: ;;;;
        mov al, bytesinv[di-1]  ;Estas dos lineas vuelcan el vector en otro, pero en el orden que corresponde
        mov bytes[si], al       ;Pasa al nuevo vector los caracteres
        dec di                  ;Decrementa para mover el indice
        inc si                  ;Aumento el indice del vector
        cmp di, 0               ;Si ya no queda nada
        jne resfinal2 ;;;; resfinal
;;;; You don't want to be storing all digits at 'bytes[si=0]', overwriting each other
        mov bytes[si], "$"      ;;;;
;;;; You must terminate the string with '$' for function 9, you don't want garbage
        lea dx, bytes
        xor ax, ax
        mov ah, 09h
        int 21h
        ret
ImpNum endP

;;;;;;;;;;;;;;;;;;;;;;;
;Comienzo del programa;
;;;;;;;;;;;;;;;;;;;;;;;

inicio:
        mov ax, SData           ;Con estas dos lineas, pasamos la direccion del segmento SData y lo pasamos al ds
        mov ds, ax
;;;;        mov ax, pila
;;;;        mov ss, ax
;;;; .EXEs set up SS:SP for you!

leernombre:
        xor di, di
        xor ax, ax              ;Limpio AX
        xor dx, dx              ;Limpio DX
        lea dx, msgnombre       ;Cargo el offset del mensaje que pide el nombre
        mov ah, 09h             ;Preparo el servicio de impresion
        int 21h                 ;Ejecuto
        xor ax, ax              ;Limpio AX
        xor dx, dx              ;Limpio DX
        lea dx, noarchivo       ;Carga el offset de donde voy a guardar el nombre del archivo
        mov ah, 0ah             ;Preparo el servicio de entrada buffereada
        int 21h                 ;Ejecuto
        nlcr                    ;New line carriage return
        xor ah, ah              ;Limpio AH
        mov al, noarchivo[1]    ;En narchivo[1] esta la cantidad de caracteres que mide el nombre de archivo
        mov di, ax              ;Lo paso al DI para usarlo como indice
        mov noarchivo[di+2],0   ;La posicion di+2 del nombre contiene el Enter, o 0ah. Lo convierto en 0.
        mov ah, 3dh             ;Preparo el servicio de creacion de handle para abrir el archivo
        mov al, 0               ;En modo de solo lectura
        lea dx, nombre          ;Cargo el offset del nombre en DX, sin los bytes que sobran antes
        int 21h                 ;Ejecuto. El handle queda en AX
        jc  errorabrir
        mov handle, ax          ;Lo paso a su variable correspondiente
        jmp cargarbuffer

errorabrir:
        lea dx, msgerrorab      ;Cargo el offset del mensaje que pide el nombre
        mov ah, 09h             ;Preparo el servicio de impresion
        int 21h
        jmp final

errorcarga:
        lea dx, msgerrorca      ;Cargo el offset del mensaje que pide el nombre
        mov ah, 09h             ;Preparo el servicio de impresion
        int 21h
        jmp final

cargarbuffer:
        xor ax, ax              ;Limpio AX
        xor bx, bx
        lea dx, buffer          ;Cargo el offset del buffer de texto
        mov ah, 3fh             ;Preparo el servicio para mover el contenido del archivo
        mov bx, handle          ;Uso el handle que me genero la int 21/3dh
        mov cx, 4096 ;;;; 10              ;Voy a guardar 4096 caracteres a la vez
;;;; You wanted 4096 and implemented logic for 4096, so use 4096.
        int 21h
        jc errorcarga

        mov cantidad, ax        ;Cargo la cantidad de caracteres leidos
        cmp cantidad, 4096      ;Si es menor a lo que le dije que cargara, llego al end of file
        jl  endoffile           ;
        xor si, si
;;;;        xor ax, ax
;;;;        mov bx, handle
;;;;        mov ah, 3eh
;;;;        int 21h
;;;; You had the condition for file closing wrong
        jmp procesarbuffer

endoffile:
        xor si, si              ;;;;
        xor ax, ax              ;;;;
        mov bx, handle          ;;;;
        mov ah, 3eh             ;;;;
        int 21h                 ;;;;
;;;; You had the condition for file closing wrong

        mov eof, 1

        cmp cantidad, 0         ;;;;
        je  imprimir            ;;;;
;;;; The original code at 'procesarbuffer' wouldn't work with 'cantidad'=0

        jmp procesarbuffer

procesarbuffer:
        xor bx, bx
        xor ax, ax
        xor di, di
        xor dx, dx
        mov bl, 2
        mov al, buffer[si]
        mul bl
        mov di, ax
        inc caracteres[di]
        inc si
        cmp si, cantidad
        jne procesarbuffer
        cmp eof, 1
        je  imprimir
        jmp cargarbuffer

imprimir:
        xor di, di
        xor dx, dx
        xor ax, ax
        xor bx, bx

        mov di, 0
        mov si, 0
        lea dx, msgimprimir
        mov ah, 09h
        int 21h

linea:        
        cmp caracteres[di], 0
        je  noimprime
        inc contador
        mov ax, si
        mov caracter, al
        lea dx, msglinea1
        mov ah, 09h
        int 21h
        mov dl, caracter
        xor ax, ax
        mov ah, 02h
        int 21h
        lea dx, msglinea2
        xor ax, ax
        mov ah, 09h
        int 21h
        push di
        push si
        mov ax, caracteres[di]
        mov bx, 10
        xor dx, dx
        xor di, di
        call ImpNum
        pop si
        pop di
        inc di
        inc di
        inc si
        nlcr
        cmp si, 254
        je final
        cmp contador, 20
        je  pidetecla
        jmp linea

noimprime:
        inc di
        inc di
        inc si
        cmp si, 254
        je final
        jmp linea

pidetecla:
        mov contador, 0 ;;;;
;;;; You want to wait for a key after each 20 lines, not just after the first 20
        lea dx, msgtecla
        xor ax, ax
        mov ah, 09h
        int 21h
        xor ax, ax
        mov ah, 08h
        int 21h
        nlcr
        jmp linea

final:
        xor ax, ax              ;Limpia el al y prepara el ah para la salida.
        mov ax, 4c00h           ;Servicio AH=4c int 21h para salir del programa.
        int 21h                 ;Llamada al DOS. Termine el programa.

CSeg EndS                       ;Fin del segmento de codigo.

End inicio                      ;Fin del programa la etiqueta al final dice en que punto debe comenzar el programa.