patternMinor
Hexdump utility in x86 NASM assembly
Viewed 0 times
hexdumpx86utilityassemblynasm
Problem
It's a simple hexdump that prints to stdout. I wanted to handle correctly input coming from the user typing at the terminal, this made the logic a little more complicated than just exiting after reading less than requested. It doesn't use the stack or memory variables, except for the tables and buffers, so I employed every register freely.
I'm learning, so I would like for every possible improvement to be pointed out.
``
db '{|}~...........................................................'
db '...............................................................'
db '.......'
align 4
Template: db '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 '
DivPos: db '| '
AsciiPart: db '................',NEW_LINE
TEMPLATELENGTH: equ $-Template
align 2
HexTable: db '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2'
db '02122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40'
db '4142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606'
db '162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081'
db '82838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a'
db '2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2'
db 'c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e'
db '3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'
I'm learning, so I would like for every possible improvement to be pointed out.
``
; Description : Prints stdin to stdout as hex and displays ASCII next to it.
; It handles correctly the cases in which a sys_read returns
; less than was requested but an EOF was not received, this
; allows the user to dump arbitrary text from stdin to a file
; in the following way: ./hexdump >> dump.txt
;
; Build using these commands:
; nasm -f elf hexdump.asm
; ld -o hexdump hexdump.o -m elf_i386 -s
;
; Usage:
; ./hexdump ?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz'db '{|}~...........................................................'
db '...............................................................'
db '.......'
align 4
Template: db '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 '
DivPos: db '| '
AsciiPart: db '................',NEW_LINE
TEMPLATELENGTH: equ $-Template
align 2
HexTable: db '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2'
db '02122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40'
db '4142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606'
db '162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081'
db '82838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a'
db '2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2'
db 'c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e'
db '3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'
Solution
Some random thoughts:
.
It looks right, but even if it is slightly flawed it should give you some ideas.
- Unused defines: STDIN, EXIT_SUCCESS
- I'd restructure the code above
Ok:to dojz Last; jl Errand just let jg fall thru (unless Last is further away than it looks).
- I don't believe it's safe to use esp as a general purpose register like this.
- Why do you
xor edx,edxabove .l0?
- I find your ebp/esp/edi logic confusing. I've got an alternative, but I'm not on linux, so I can't actually run this (and I HATE posting code I haven't run), but how about something like:
.
; Description : Prints stdin to stdout as hex and displays ASCII next to it.
; It handles correctly the cases in which a sys_read returns
; less than was requested but an EOF was not received, this
; allows the user to dump arbitrary text from stdin to a file
; in the following way: ./hexdump >> dump.txt
;
; Build using these commands:
; nasm -f elf hexdump.asm
; ld -o hexdump hexdump.o -m elf_i386 -s
;
; Usage:
; ./hexdump ?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz'
db '{|}~...........................................................'
db '...............................................................'
db '.......'
align 4
Template: db '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 '
DivPos: db '| '
AsciiPart: db '................',NEW_LINE
TEMPLATELENGTH: equ $-Template
align 2
HexTable: db '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2'
db '02122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40'
db '4142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606'
db '162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081'
db '82838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a'
db '2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2'
db 'c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e'
db '3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'
section .bss
BUFFERSIZE: equ 16
Buffer: resb BUFFERSIZE
section .text
global _start ; make it visible
_start:
mov ebx,STDIN
lea ecx,[Buffer]
mov edx,BUFFERSIZE
mov esi,BUFFERSIZE
Fill:
mov eax,SYS_READ
int 80h ; call
cmp eax,0 ; check return value
jl Err ; error
jz Last ; 0 = EOF
add ecx, eax ; Update where to load data
sub edx, eax ; How many more bytes needed?
jnz Fill ; Keep trying until we get 16 bytes
; At this point, we have read exactly 16 bytes.
call OutputLine ; Turn esi bytes in Buffer into
; Template and print it
jmp _start ; Get next line
; At this point, we have hit EOF. Output any leftovers
; in the buffer.
Last:
sub esi, edx ; How many did we really read?
jz End ; Did we end on exactly 16 bytes?
; Blank out the Template and AsciiPart
mov bx, 0x2020 ; ' '
mov edx,BUFFERSIZE
WriteBlanks:
dec edx
mov [Template+edx*2+edx],bx ; write blank over Template
mov [AsciiPart+edx],bl ; write blank over AsciiPart
jnz WriteBlanks
call OutputLine ; Turn esi bytes in Buffer into
; Template and print it
; Exit the program
End: mov ebx,EXIT_SUCCESS ; EXIT_SUCCESS
Exit: mov eax,SYS_EXIT
int 80h
Err: mov ebx,-1 ; EXIT_FAILURE
jmp Exit
; Input: esi: Number of chars to process from Buffer
; Clobbers: eax, ebx, edx, edx, esi
OutputLine:
xor eax, eax
NextChar: ; Process next char
dec esi
mov al,[Buffer+esi] ; read byte from buffer
mov bx,[HexTable+eax*2] ; get corresponding symbols
mov [Template+esi*2+esi],bx ; write to template
mov bl,[AsciiTable+eax] ; get ASCII symbol
mov [AsciiPart+esi],bl ; write to template
jnz NextChar ; ecx is an offset not a counter
mov eax,SYS_WRITE
mov ebx,STDOUT
mov ecx,Template
mov edx,TEMPLATELENGTH
int 80h
cmp eax,TEMPLATELENGTH
jne Err
retIt looks right, but even if it is slightly flawed it should give you some ideas.
Code Snippets
; Description : Prints stdin to stdout as hex and displays ASCII next to it.
; It handles correctly the cases in which a sys_read returns
; less than was requested but an EOF was not received, this
; allows the user to dump arbitrary text from stdin to a file
; in the following way: ./hexdump >> dump.txt
;
; Build using these commands:
; nasm -f elf hexdump.asm
; ld -o hexdump hexdump.o -m elf_i386 -s
;
; Usage:
; ./hexdump << input_file
section .data
STDIN: equ 0
STDOUT: equ 1
STDERR: equ 2
EXIT_SUCCESS: equ 0
SYS_READ: equ 3
SYS_WRITE: equ 4
SYS_EXIT: equ 1
NEW_LINE: equ 0ah
AsciiTable: db '................................ !"',"#$%&'()*+,-./0123456789:;"
db '<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz'
db '{|}~...........................................................'
db '...............................................................'
db '.......'
align 4
Template: db '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 '
DivPos: db '| '
AsciiPart: db '................',NEW_LINE
TEMPLATELENGTH: equ $-Template
align 2
HexTable: db '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2'
db '02122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40'
db '4142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606'
db '162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081'
db '82838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a'
db '2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2'
db 'c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e'
db '3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'
section .bss
BUFFERSIZE: equ 16
Buffer: resb BUFFERSIZE
section .text
global _start ; make it visible
_start:
mov ebx,STDIN
lea ecx,[Buffer]
mov edx,BUFFERSIZE
mov esi,BUFFERSIZE
Fill:
mov eax,SYS_READ
int 80h ; call
cmp eax,0 ; check return value
jl Err ; < 0 -> error
jz Last ; 0 = EOF
add ecx, eax ; Update where to load data
sub edx, eax ; How many more bytes needed?
jnz Fill ; Keep trying until we get 16 bytes
; At this point, we have read exactly 16 bytes.
call OutputLine ; Turn esi bytes in Buffer into
; Template and print it
jmp _start ; Get next line
; At this point, we have hit EOF. Output any leftovers
; in the buffer.
Last:
sub esi, edx ; How many did we really read?
jz End ; Did we end on exactly 16 byteContext
StackExchange Code Review Q#138537, answer score: 4
Revisions (0)
No revisions yet.