NASM - The Netwide Assembler
NASM Forum => Programming with NASM => Topic started by: acer_f on June 01, 2018, 02:47:01 AM
-
Hello everyone.. I was doing some exercise with hexdump and Im trying to convert the hexdump program from 32 bit into 64 bit, The problem is what i dont get the same output as hexdump 32 bit. Could someone please help me to find where exactly the problem is ? Thanks.
;----------------------------;
; ./hexdump1 < (input file) ;
;----------------------------;
SECTION .data ; section containing initialised data
HexStr db " 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",10
HexLen equ $-HexStr
Digits db "0123456789ABCDEF"
SECTION .bss ; section containing uninitialised data
BUFFLEN EQU 16 ; We read the file 16 bytes at a time
Buff resb BUFFLEN ; Text buffer itself
SECTION .text ; section containing code
global _start ; Linker needs this to find the entry point!
_start:
nop ; This no-op keeps gdb happy
Read:
mov eax, 3 ; specify sys_read call
mov ebx, 0 ; specify File Descriptor 0: Standard Input
mov ecx, Buff ; Pass offset of the buffer to read to
mov edx, BUFFLEN ; Pass number of bytes to read at one pass
int 80h ; Call sys_read to fill the buffer
mov ebp, eax ; Save # of bytes read from file for later
cmp eax, 0 ; If eax=0, sys_read reached EOF on stdin
je Done ; Jump if equal (to 0, from compare)
; Set up the registers for the process buffer step:
mov esi, Buff ; Place address of file buffer into esi
mov edi, HexStr ; Place address of line string into edi
xor ecx, ecx ; Clear line string pointer to 0
; Go through the buffer and convert binary values to hex digits:
Scan:
xor eax, eax ; Clear eax to 0
; Here we calculate the offset into the line string, which is ecx x 3
mov edx, ecx ; Copy the pointer into line string into edx
shl edx, 1 ; Multiply pointer by 2 using shift left
add edx, ecx ; Complete the multiplication X3
lea edx, [edx*2+edx]
; Get a character from the buffer and put it in both eax and ebx
mov al, byte [esi+ecx] ; Put a byte from the input buffer into al
mov ebx, eax ; Duplicate the byte in bl for second nybble
; Look up low nybble character and insert it into the string:
and al, 0Fh
mov al, byte [Digits+eax] ; Look up the char equivalent of nybble
mov byte [HexStr+edx+2], al ; Write the char equivalent to line string
; Look up high nybble character and insert it into the string:
shr bl, 4 ; Shift high 4 bits of char into low 4 bits
mov bl, byte [Digits+ebx] ; Look up char equivalent of nybble
mov byte [HexStr+edx+1], bl ; Write the char equivalent to line string
; Bump the buffer pointer to the next character and see if we are done:
inc ecx ; Increment line string pointer
cmp ecx, ebp ; Compare to the number of characters in the buffer
jna Scan ; Loop back if ecx is <= number of chars in buffer
; Write the line of hexadecimal values to stdout:
mov eax, 4 ; Specify sys_Write call
mov ebx, 1 ; Specify File Descriptor 1: Standard output
mov ecx, HexStr ; Pass offset of line string
mov edx, HexLen ; Pass size of the line string
int 80h ; make kernell call to display line string
jmp Read ; Loop back and load file buffer again
; All done! Let's end this party:
Done:
mov eax, 1 ; Code for Exit Syscall
mov ebx, 0 ; Return a code of zero
int 80h ; Make kernel call
;-------------------------------;
; ./hexdump1-64 < inputFile ;
;-------------------------------;
SECTION .data ; section containing initialised data
HexStr db " 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",10
HexLen equ $-HexStr
Digits db "0123456789ABCDEF"
SECTION .bss ; section containing uninitialised data
BUFFLEN EQU 16 ; We read the file 16 bytes at a time
Buff resb BUFFLEN ; Text buffer itself
SECTION .text ; section containing code
global _start ; Linker needs this to find the entry point!
_start:
nop ; This no-op keeps gdb happy
Read:
mov rax, 0 ; specify sys_read call
mov rdi, 0 ; specify File Descriptor 0: Standard Input
mov rsi, Buff ; Pass offset of the buffer to read to
mov rdx, BUFFLEN ; Pass number of bytes to read at one pass
syscall ; Call sys_read to fill the buffer
mov rbp, rax ; Save # of bytes read from file for later
cmp rax, 0 ; If eax=0, sys_read reached EOF on stdin
je Done ; Jump if equal (to 0, from compare)
; Set up the registers for the process buffer step:
mov rbx, Buff ; Place address of file buffer into esi
mov rcx, HexStr ; Place address of line string into edi
xor rsi, rsi ; Clear line string pointer to 0
; Go through the buffer and convert binary values to hex digits:
Scan:
xor rax, rax ; Clear eax to 0
; Here we calculate the offset into the line string, which is ecx x 3
mov rdx, rsi ; Copy the pointer into line string into edx
shl rdx, 1 ; Multiply pointer by 2 using shift left
add rdx, rsi ; Complete the multiplication X3
lea rdx, [rdx*2+rdx] ;
; Get a character from the buffer and put it in both eax and ebx
mov al, byte [rbx+rsi] ; Put a byte from the input buffer into al ; al
mov rdi, rax ; Duplicate the byte in bl for second nybble
; Look up low nybble character and insert it into the string:
and al, 0Fh
mov al, byte [Digits+rax] ; Look up the char equivalent of nybble
mov byte [HexStr+rdx+2], al ; Write the char equivalent to line string
; Look up high nybble character and insert it into the string:
shr dl, 4 ; Shift high 4 bits of char into low 4 bits
mov dl, byte [Digits+rdi] ; Look up char equivalent of nybble
mov byte [HexStr+rdx+1], dl ; Write the char equivalent to line string
; Bump the buffer pointer to the next character and see if we are done:
inc rsi ; Increment line string pointer
cmp rsi, rbp ; Compare to the number of characters in the buffer
jna Scan ; Loop back if ecx is <= number of chars in buffer
; Write the line of hexadecimal values to stdout:
mov rax, 1 ; Specify sys_Write call
mov rdi, 1 ; Specify File Descriptor 1: Standard output
mov rsi, HexStr ; Pass offset of line string
mov rdx, HexLen ; Pass size of the line string
syscall ; make kernell call to display line string
jmp Read ; Loop back and load file buffer again
; All done! Let's end this party:
Done:
mov rax, 60 ; Code for Exit Syscall
mov rdi, 0 ; Return a code of zero
syscall ; Make kernel call
-
; Here we calculate the offset into the line string, which is ecx x 3
mov rdx, rsi ; Copy the pointer into line string into edx
shl rdx, 1 ; Multiply pointer by 2 using shift left
add rdx, rsi ; Complete the multiplication X3
lea rdx, [rdx*2+rdx] ;
I may be in the mood to get into this later... maybe. But this oddity jumps out at me. You multiply by three... and then multiply by three again. The first comment does not match code - ecx is no longer involved. This is not the problem. You do the same thing in the 32-bit code (which does use ecx).
My memory is shot, but this "oddity" looks familiar to me. Have I seen this code before?
To help you solve this yourself... Are you sure this is really the code for the 32-bit version? What difference do you see in the output?
I'll try to get back to you on this, but I really think you only want to multiply by 3 once...
Best,
Frank
-
Hello. Thanks for your reply.
The example hexdump 32 bit is from the book Assembly Language Step By Step by Jeff Dunteman.
The first one is 32 bit, and the second one is 64 bit but the comments are not correct.
1. When I run the 32 bit version ./hexdump1 < TestHexdump1.txt
I get this output :
73 61 64 20 73 61 64 0A 73 61 64 0A 73 61 0A 20
66 64 C3 A4 0A 72 20 C3 A4 C3 B6 66 0A 77 20 45
34 35 57 34 36 50 45 46 20 36 20 32 35 66 2B 33
60 73 0A 64 73 0A 73 60 64 20 0A 73 60 0A 66 20
0A 60 73 64 0A 60 73 64 0A 73 0A 66 2E 0A 65 77
0A 0A 73 64 0A 60 73 64 0A 73 0A 66 2E 0A 65 77
2. The 64 bit version ./hexdump1-64 < TestHexdump1.txt
Output:
3 01 04 00 03 01 04 0A 03 01 04 0A 03 01 0A 00
6 04 03 04 0A 02 00 03 04 03 06 06 0A 07 00 05
4 05 07 04 06 00 05 06 00 06 00 02 05 06 0B 03
0 03 0A 0
03 0A 03 00 04 00 0A 03 00 0A 06 00
A 00 03 04 0A 00 03 04 0A 03 0A 06 0E 0A 05 07
A 0A 03 04 0A 00 03 04 0A 03 0A 06 0E 0A 05 07
-
There's more wrong with this than multiplying by 3 twice...
;-------------------------------;
; ./hexdump1-64 < inputFile ;
;-------------------------------;
SECTION .data ; section containing initialised data
HexStr db " 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",10
HexLen equ $-HexStr
Digits db "0123456789ABCDEF"
SECTION .bss ; section containing uninitialised data
BUFFLEN EQU 16 ; We read the file 16 bytes at a time
Buff resb BUFFLEN ; Text buffer itself
SECTION .text ; section containing code
global _start ; Linker needs this to find the entry point!
_start:
nop ; This no-op keeps gdb happy
Read:
mov rax, 0 ; specify sys_read call
mov rdi, 0 ; specify File Descriptor 0: Standard Input
mov rsi, Buff ; Pass offset of the buffer to read to
mov rdx, BUFFLEN ; Pass number of bytes to read at one pass
syscall ; Call sys_read to fill the buffer
mov rbp, rax ; Save # of bytes read from file for later
cmp rax, 0 ; If eax=0, sys_read reached EOF on stdin
je Done ; Jump if equal (to 0, from compare)
; Set up the registers for the process buffer step:
mov rbx, Buff ; Place address of file buffer into esi
mov rcx, HexStr ; Place address of line string into edi
;;; fortunately not used
xor rsi, rsi ; Clear line string pointer to 0
; Go through the buffer and convert binary values to hex digits:
Scan:
xor rax, rax ; Clear eax to 0
; Here we calculate the offset into the line string, which is ecx x 3
mov rdx, rsi ; Copy the pointer into line string into edx
shl rdx, 1 ; Multiply pointer by 2 using shift left
add rdx, rsi ; Complete the multiplication X3
; lea rdx, [rdx*2+rdx] ;
;;; 0nly multiply once!
; Get a character from the buffer and put it in both rax and rcx
mov al, byte [rbx+rsi] ; Put a byte from the input buffer into al ; al
;;; mov rdi, rax ; Duplicate the byte in bl for second nybble
;;; rdi is not what you want here
mov rcx, rax
; Look up low nybble character and insert it into the string:
and al, 0Fh
mov al, byte [Digits+rax] ; Look up the char equivalent of nybble
mov byte [HexStr+rdx+2], al ; Write the char equivalent to line string
; Look up high nybble character and insert it into the string:
;;; you're already using rdx
shr cl, 4 ; Shift high 4 bits of char into low 4 bits
mov cl, byte [Digits+rcx] ; Look up char equivalent of nybble
mov byte [HexStr+rdx+1], cl ; Write the char equivalent to line string
;;; I think that fixes it...
; Bump the buffer pointer to the next character and see if we are done:
inc rsi ; Increment line string pointer
cmp rsi, rbp ; Compare to the number of characters in the buffer
jna Scan ; Loop back if ecx is <= number of chars in buffer
; Write the line of hexadecimal values to stdout:
mov rax, 1 ; Specify sys_Write call
mov rdi, 1 ; Specify File Descriptor 1: Standard output
mov rsi, HexStr ; Pass offset of line string
mov rdx, HexLen ; Pass size of the line string
syscall ; make kernell call to display line string
jmp Read ; Loop back and load file buffer again
; All done! Let's end this party:
Done:
mov rax, 60 ; Code for Exit Syscall
mov rdi, 0 ; Return a code of zero
syscall ; Make kernel call
I'm not sure I've got all the comments right, but it "seems to work".
Best,
Frank
-
Heh! Well we "crossed in the mail". With all due respect, Jeff Duntemann can't multiply by 9 either! I just downloaded the code from his site. He multiplies by 3 twice, but comments out one. He comments out the shl and add and uses the lea. I commented out the lea and used the shl and add... but we are generally in agreement. In view of the fact that both methods are in the code, I wonder what it actually says in the book...
Anyway, good job on converting it to 64-bit!
Best,
Frank
-
Hello.. Now I understand why before It was not working properly. Thank your very much for your help . :) :)