NASM - The Netwide Assembler
NASM Forum => Example Code => Topic started by: Manasi on October 05, 2013, 01:11:50 PM
-
The following code displays the contents of file in their equivalent hex value. Can anyone help me to display the ASCII equivalent of the contents?
SECTION .data
file_name db 'abc.txt'
SECTION .bss
fd_in resd 1
temp resb 250
filecontent resb 250
fbuff_len equ $-filecontent
SECTION .text
global _start
_start:
mov eax,5 ;open a file
mov ebx,file_name
mov ecx,0
mov edx,777
int 80h
mov dword[fd_in],eax
mov eax,3 ;read from file
mov ebx,[fd_in]
mov ecx,filecontent
mov edx,fbuff_len
int 80h
mov edi,temp
mov esi,filecontent
mov dh,25
nextnum: mov dl,2
mov al,byte[esi]
dispnum: rol al,4
mov bl,al
and al,0fh
add al,30h
mov byte[edi],al
inc edi
mov al,bl
dec dl
jnz dispnum
inc esi
dec dh
jnz nextnum
mov eax,4
mov ebx,1
mov ecx,temp
mov edx,250
int 80h
mov eax,6
mov ebx,[fd_in]
int 80h
mov eax,1
mov ebx,0
int 80h
Thanks in advance
Regards,
Manasi
-
Hi Manasi,
I put "code tags" around your code (just the word "code" in square brackets and "/code" at the end of it). Arguably makes it easier to read, and definitely makes it easier to download. Then I downloaded it. :)
Can't say that it really worked very well. In the first place, there was no "abc.txt" (until I created it). No matter, even though the sys_open failed, your program continued. This is not ideal! Really should "issue a diagnostic" and "exit gracefully" (or retry) aka "scream and die". I added a "quick and dirty" check and just exited if the sys_open failed.
Then... you don't really display hex. Worked okay for '0' through '9', but 'A' through 'F' came out garbled. I fixed that, too. And I limited output to the actual length that we read. There are other things that could be improved... You're going to need two hex digits for each byte/character read, so the "temp" buffer should be twice as long. Well... it's a start...
SECTION .data
file_name db 'abc.txt'
SECTION .bss
fd_in resd 1
temp resb 250
filecontent resb 250
fbuff_len equ $-filecontent
length_read resd 1
SECTION .text
global _start
_start:
mov eax,5 ;open a file
mov ebx,file_name
mov ecx,0
mov edx,777
int 80h
; did open succeed?
test eax, eax
js exit
mov dword[fd_in],eax
mov eax,3 ;read from file
mov ebx,[fd_in]
mov ecx,filecontent
mov edx,fbuff_len
int 80h
; eax has length actually read
mov [length_read], eax
mov edi,temp
mov esi,filecontent
mov dh,25
nextnum: mov dl,2
mov al,byte[esi]
dispnum: rol al,4
mov bl,al
and al,0fh
add al,30h
cmp al, '9'
jbe dec_digit
add al, 7
dec_digit:
mov byte[edi],al
inc edi
mov al,bl
dec dl
jnz dispnum
inc esi
dec dh
jnz nextnum
mov eax,4
mov ebx,1
mov ecx,temp
mov edx,[length_read]
shl edx, 1 ; two bytes of hex for each character read
int 80h
mov eax,6
mov ebx,[fd_in]
int 80h
exit:
mov eax,1
mov ebx,0
int 80h
To display "ASCII equivalent", just sys_write the file... or perhaps I don't understand the question...
Best,
Frank
-
Frank,
Thank you for the help
hex equivalent means it shows that if file abc.txt has 'a' then it displays 61
b=62
A=41
B=42
and so on
what i wanted to know is how do i display the ASCII equivalent i.e.
A=65
B=66
and so on for all the content in the file.
I would really appreciate if you could help me out with this.
Thanks again,
Regards,
Manasi
-
Maybe something like this?
; display characters and hex ascii codes from a file
;
; nasm -f elf32 myfile.asm
; ld -o myfile myfile.o -melf_i386
SECTION .data
file_name db 'abc.txt'
SECTION .bss
fd_in resd 1
filecontent resb 250
fbuff_len equ $-filecontent
length_read resd 1
SECTION .text
global _start
_start:
mov eax,5 ;open a file
mov ebx,file_name
mov ecx,0
mov edx,777
int 80h
; did open succeed?
test eax, eax
js exit
mov dword[fd_in],eax
mov eax,3 ;read from file
mov ebx,[fd_in]
mov ecx,filecontent
mov edx,fbuff_len
int 80h
; eax has length actually read
mov [length_read], eax
mov esi,filecontent
; point edi to end of file
mov edi, esi
add edi, [length_read]
nextnum:
mov dl,2 ; count for hex digits
mov al,byte[esi]
call putc
push eax
mov al, '='
call putc
pop eax
dispnum:
rol al,4
mov bl,al
and al,0fh
add al,30h
cmp al, '9'
jbe dec_digit
add al, 7
dec_digit:
call putc
mov al,bl
dec dl
jnz dispnum
mov al, 'h'
call putc
mov al, 10 ; linefeed
call putc
inc esi
cmp esi, edi
jnz nextnum
mov eax,6 ; __NR_close
mov ebx,[fd_in]
int 80h
; pretend no error
xor eax, eax
exit:
mov ebx, eax ; possible error number in ebx
neg ebx ; negate it for easier reading with "echo $?"
mov eax,1
int 80h
;---------------------------
; print character in al
putc:
push edx
push ecx
push ebx
push eax ;this serves as our buffer
mov ecx, esp ; buffer
mov edx, 1 ; just 1
mov ebx, 1 ; stdout
mov eax, 4 ; __NR_write
int 80h
pop eax
pop ebx
pop ecx
pop edx
ret
;------------------------------
Really would have been better to put all this stuff in a buffer and print it all in one system call rather than call system for every single character. This was easy.
Best,
Frank
-
Frank,
The program works successfully but i still havent got how do i display the ASCII values. let me give an example
my file 'abc.txt' has the following contents:
ABCD
so my output should be
65666768
but what it is showing are the hex values
i.e 41424344 and so on
So basically i need to Display ASCII so that i get the desired output
But i am unable to do that.
Please help me.
Thanks again
Regards,
Manasi
-
Do I understand that you want to represent the ascii codes as decimal? (why? hex is much more civilized!) Well, okay... this is crude, but I think it does what you want...
; display characters and decimal ascii codes from a file
;
; nasm -f elf32 myfile.asm
; ld -o myfile myfile.o -melf_i386
SECTION .data
file_name db 'abc.txt'
SECTION .bss
fd_in resd 1
filecontent resb 250
fbuff_len equ $-filecontent
length_read resd 1
SECTION .text
global _start
_start:
mov eax,5 ;open a file
mov ebx,file_name
mov ecx,0
mov edx,777
int 80h
; did open succeed?
test eax, eax
js exit
mov dword[fd_in],eax
mov eax,3 ;read from file
mov ebx,[fd_in]
mov ecx,filecontent
mov edx,fbuff_len
int 80h
; eax has length actually read
mov [length_read], eax
mov esi,filecontent
; point edi to end of file
mov edi, esi
add edi, [length_read]
xor eax, eax ; just to make sure upper bytes are clear
nextnum:
mov al,byte[esi]
call putc
push eax
mov al, '='
call putc
pop eax
dispnum:
call showeaxd
mov al, 10 ; linefeed
call putc
inc esi
cmp esi, edi
jnz nextnum
mov eax,6 ; __NR_close
mov ebx,[fd_in]
int 80h
; pretend no error
xor eax, eax
exit:
mov ebx, eax ; possible error number in ebx
neg ebx ; negate it for easier reading with "echo $?"
mov eax,1
int 80h
;---------------------------
; print character in al
putc:
push edx
push ecx
push ebx
push eax ;this serves as our buffer
mov ecx, esp ; buffer
mov edx, 1 ; just 1
mov ebx, 1 ; stdout
mov eax, 4 ; __NR_write
int 80h
pop eax
pop ebx
pop ecx
pop edx
ret
;------------------------------
;---------------------------------
; showeaxd - print a decimal representation of eax to stdout
; for "debug purposes only"... mostly
; expects: number in eax
; returns; nothing useful
showeaxd:
push eax
push ebx
push ecx
push edx
push esi
sub esp, 10h
lea ecx, [esp + 12]
mov ebx, 10
xor esi, esi
.top:
dec ecx
xor edx, edx
div ebx
add dl, '0'
mov [ecx], dl
inc esi
or eax, eax
jnz .top
mov edx, esi
mov ebx, 1
mov eax, 4
int 80h
add esp, 10h
pop esi
pop edx
pop ecx
pop ebx
pop eax
ret
;---------------------------------
Best,
Frank
-
Frank,
Thanks a ton for the help.
This is what I exactly wanted.
Thanks again!!!! :) :D
Regards,
Manasi
-
Frank,
In the last code could you please explain the logic for the function showeaxd.
I mean how does the program show the decimal representation.
Thanks,
Regards,
Manasi
-
;---------------------------------
; showeaxd - print a decimal representation of eax to stdout
; for "debug purposes only"... mostly
; expects: number in eax
; returns; nothing useful
showeaxd:
; save all registers used
; this is "overkill" - a "C-style" function would expect ecx and edx
; to be trashed and the "result" returned in eax
; since I don't return anything, and might be using ecx/edx
; I saved everything, "for convenience"
push eax
push ebx
push ecx
push edx
push esi
; make a buffer on the stack
; a 32-bit number could be up to 10 digits
; we might want a terminating 0 - or perhaps a linefeed
; we might want space for a minus sign
; 16 bytes is just a "nice round number" - rather arbitrary
sub esp, 10h
; since "div" is going to give us our remainders - our digits - in the "wrong" order
; we want to start at the "end" (higher memory) of the buffer and work backwards
; towards the beginning of the buffer (lower memory)
;
; since sys_write is going to expect the buffer address in ecx
; I use ecx as the buffer pointer throughout
; the 12 is, again, rather arbitrary
lea ecx, [esp + 12]
; we're going to want to divide by 10
mov ebx, 10
; since sys_write expects the count in edx, I'd use edx...
; but "div" is using edx (!) so I need another digit counter
xor esi, esi
; at this point, I sometimes modify this function to add a linefeed "after" the number
; if you wanted a zero-terminated string you could do it here
; this explains why I move to next position first thing in my loop...
.top:
; move to next position "backwards" in buffer
dec ecx
; "div" divides edx:eax by what you say (32-bit parameter)
; and puts the quotient in eax and the remainder in edx
; if the quotient won't fit in eax, it throws an exception, crashing our program
; the CPU doesn't ignore edx, so we can't either (common newbie error!)
; we want it zero!
xor edx, edx
div ebx
; quotient in eax, remainder in edx
; we know the remainder is between 0 and 9 so it'll all fit in dl
; we want to "convert" the number to the ascii character representing that number
; adding 30h or 48 decimal or the character '0' will do it
add dl, '0'
; and stuff it in the buffer
mov [ecx], dl
; and count it
inc esi
; quotient is still in eax - is it zero?
; usually I use "test" here, I don''t know why I used "or"
; the idea is to set the flags without altering eax
; you could just "cmp eax, 0"
or eax, eax
; if quotient isn't zero, do it again
jnz .top
; now we just print the buffer using sys_write - ecx is all set
; move our count into edx
mov edx, esi
mov ebx, 1 ; stdout
mov eax, 4 ; __NR_write
int 80h ; ask the kernel to make it so
; we're done with our buffer, make it go away
add esp, 10h
; restore callers regs
pop esi
pop edx
pop ecx
pop ebx
pop eax
; click your heels together and say "there's no place like home"
ret
;---------------------------------
I don't know if that answers your question. We can break it down further if need be.
Best,
Frank
-
Frank,
Thank you for explaining the logic of the function. It did explain what i had not understood.
Thanks,
Regards,
Manasi