Hi, I'm kind of new to X86.
I was wondering if someone could help me: I need to get my head around using file input and output in X86, using function 3DH and such. I'd really appreciate some code snippets or the like, specifically reading in a text file and printing it's contents on the screen.
Thanks in advance!
Comments
http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/Chapter_13/CH13-1.html#top
http://www.emu8086.com/assembly_language_tutorial_assembler_reference/8086_bios_and_dos_interrupts.html
[code].model small
.data
Filename db 'test.txt'
FHndl dw ?
Buffer db 80h dup(?)
.stack 100h
.code
Program:
mov ah, 3dh ;Open the file
mov al, 0 ;Open for reading
lea dx, Filename ;Presume DS points at filename
int 21h ; segment.
; jc BadOpen
mov FHndl, ax ;Save file handle
LP: mov ah,3fh ;Read data from the file
lea dx, Buffer ;Address of data buffer
mov cx, 1 ;Read one byte
mov bx, FHndl ;Get file handle value
int 21h
; jc ReadError
cmp ax, cx ;EOF reached?
jne EOF
mov al, Buffer ;Get character read
call write ;Print it
jmp LP ;Read next byte
EOF: mov bx, FHndl
mov ah, 3eh ;Close file
int 21h
;jc CloseError
PROC write
push ax bx cx dx
mov ah, 2
mov dl, Buffer ;char to be printed
int 21h
pop ax bx cx dx
ret
ENDP
End Program[/code]
My issue now is actually printing the characters from the txt file to the console/cmd prompt. Am I on the right track here? I'm not sure if my write procedure is entirely accurate. Thanks again.
normal though, because asm is no easy language to learn
I hope you're not stuck to that old Tasm assembler, because it has been
obsolete for years now. I'd go with [link=http://www.flatassembler.net]Fasm[/link] instead.
Here's the code with some changes to get it to assemble with Fasm.
I can't get it to work in WinXP, but WinXP has bad DOS emulation too..
[code]
format MZ
entry codeseg:main ; program entry point
stack 100h
segment dataseg
[color=Green] ; a terminating zero is needed so that the function knows where the string ends[/color]
Filename db 'test.txt'[color=Red],0[/color]
FHndl dw ?
[color=Green]; You're reading just one byte, so the buffer only needs one byte..[/color]
Buffer db ?
segment codeseg
main:
[color=Red] mov ax, dataseg
mov ds, ax[/color]
mov ah, 3dh ;Open the file
mov al, 0 ;Open for reading
lea dx, [Filename] [color=Red];Presume DS points at filename[/color]
int 21h [color=Red]; segment.[/color]
; jc BadOpen
mov [FHndl], ax ;Save file handle
LP: mov ah,3fh ;Read data from the file
lea dx, [Buffer] ;Address of data buffer
mov cx, 1 ;Read one byte
mov bx, [FHndl] ;Get file handle value
int 21h
; jc ReadError
cmp ax, cx ;EOF reached?
jne EOF
mov al, [Buffer] ;Get character read
call write ;Print it
jmp LP ;Read next byte
EOF: mov bx, [FHndl]
mov ah, 3eh ;Close file
int 21h
;jc CloseError
[color=Green]; Don't forget to exit![/color]
[color=Red]exit:
mov ax, 4c00h
int 21h[/color]
write:
mov ah, 2
mov dl, al ;char to be printed
int 21h
ret
[/code]
I hope this helps!
One other quick thing, if it's not too much hassle to explain; I know in Java and the like you're able to format the way something is printed, with printf or whatever. Is there a simple way of doing that in assembly? For example, instead of printing the contents of that file one by one, is it possible to print it's contents (the numbers 1-6, for example), as:
123
456
I'm only able to get things to print one by one, or string by string. That's pretty much the final thing I'd like to get this piece of code to do, I suppose I'll need a procedure to do that!
go to the next line and start over. Okay, for this you need to make the buffer longer
and change cx accordingly before calling the file reading function.
Next you need a function to which you can pass the number of bytes to be printed.
There are at least two ways to do this. Either by printing out each character individually
in a loop or by turning the buffer into a string and printing it out then. I'm bored and have
no life, so I'll show you both:
[code]
; 1)
segment dataseg
Buffer db 16 dup(?)
NewLine db 13,10,"$"
...
LP: mov ah,3fh ;Read data from the file
lea dx, [Buffer] ;Address of data buffer
mov cx, [color=Red]16[/color] ;Fill the buffer
mov bx, [FHndl] ;Get file handle value
int 21h
; jc ReadError
cmp ax, 0 ;EOF reached?
jne EOF
; Number of bytes read is in ax
call write ;Print it
jmp LP ;Read next byte
...
write:
mov cx, ax ;Use cx as a counter
lea bx, [Buffer] ;Address of data buffer
nextbyte:
push cx ;Save the registers we use
push bx
mov ah, 2
mov dl, [bx] ;Get byte from buffer
int 21h
pop bx
pop cx
inc bx
dec cx
jnz nextbyte
;Print a newline
mov ah, 9
lea dx, [NewLine]
int 21h
ret[/code]
[code]; 2)
;Need one more byte for the terminating character
segment dataseg
Buffer db 16+1 dup(?)
...
write:
lea bx, [Buffer]
add bx, ax ;Point to end of data buffer
mov [bx], byte "$" ;Append terminating dollar sign
;Print the string
mov ah,9
lea dx, [Buffer]
int 21h
;Print a newline
mov ah, 9
lea dx, [NewLine]
int 21h
ret
[/code]
When it comes to formatted output, then in DOS/asm it's probably best to
make your own string handling functions. The only string functions DOS provides
are those for getting characters into video memory, nothing more. In Windows you
would also have wsprintf, plenty of console functions and other interesting functions
which are also easy to use in assembly. Of course they are not as simple to use
as those in Java & others, but they make things a lot easier. If you have the interest, then
you should definitely look into programming under Windows, that way you can actually
learn something relevant in today's world. Good luck!
If possible, avoid the hassle and start using [link=http://www.flatassembler.net]FASM[/link] or [link=http://www.nasm.us/]NASM[/link] instead.
(Sorry about my english, but I'm portuguese xD)
[code]
mov al, [Buffer] ; get byte from the buffer
xor ah, ah ; set rest of ax to zero
mov cx, 10 ; set base number for decimal
call itoa
...
; print ax as base cx
itoa:
xor bx, bx
div_loop:
xor dx, dx ; dx = 0
; Divide ax:dx by cx,
; get quotinent in ax and remainder in dx
div cx
; Convert digit to ASCII
cmp dl, 10
jb below10
add dl, 'a'-10
jmp continue
below10:
add dl, '0'
continue:
; Write ASCII character to buffer
mov [itoa_buffer+bx], dl
inc bx
; Check if there was anything left to convert
or ax, ax
jnz div_loop
; Now show the result
show_loop:
mov ah, 2
mov dl, [itoa_buffer+bx-1]
push bx
int 21h
pop bx
dec bx
jnz show_loop
itoa_ret:
ret
Buffer db ?
itoa_buffer db 9 dup(?)
[/code]