NASM - The Netwide Assembler
NASM Forum => Example Code => Topic started by: Shikatsu on March 23, 2012, 01:59:17 PM
-
Greetings EveryOne ;D
Currently I am reading this book: "Assembly Language Step-by-step: Programming with DOS and Linux" by Jeff Duntemann. I found it very informative and I recommend it to everyone. in the book you can find an important section that explains about "The Three Major Assembly Programming Models" which are: "Real Mode Flat Model", "Real Mode Segmented Model", and "Protected Mode Flat Model".
I would like to share with you his routine that converts hexadecimal numbers to hexadecimal digits "Byte2Str":
;---------------------------------------------------------------
; Byte2Str -- Converts a byte passed in AL to a string at
; DS:SI
; Last update 9/18/99
;
; 1 entry point:
;
; Byte2Str:
; Caller must pass:
; AL : Byte to be converted
; DS : Segment of destination string
; SI : Offset of destination string
;
; This routine converts 8-bit values to 2-digit hexadecimal
; string representations at DS:SI. ?; string representations at DS:SI. The "H" specifier is
; *not* included. Four separate output examples:
; 02 B7 FF 6C
;---------------------------------------------------------------
?Byte2Str:
mov DI,AX ; Duplicate byte in DI
and DI,000FH ; Mask out high 12 bits of DI
mov BX,Digits ; Load offset of Digits into DI
mov AH,BYTE [BX+DI] ; Load digit from table into AH
mov [SI+1],AH ; and store digit into string
xor AH,AH ; Zero out AH
mov DI,AX ; And move byte into DI
; WARNING: The following instruction requires 286 or better!
shr DI,4 ; Shift high nybble of byte to low
mov AH,BYTE [BX+DI] ; Load digit from table into AH
mov [SI],AH ; and store digit into string
ret ; We're done-go home!
At first I had a little hard time grasping the procedure but as they say Assembly means never give up, with the help of "debug" I got it at the end.
This is an implementation of the "Byte2Str" procedure, note that I had added my own comments to the procedure hopefully it will make it easier for a newbie like me:
;link: http://forum.nasm.us/index.php?topic=1335.0
;Book: "Assembly Language Step-by-step: Programming with DOS and Linux" by Jeff Duntemann.
;Page: 228
;nasm Byte2Str.asm -fbin -o Byte2Str.com
bits 16
org 100h
section .txt
start:
mov AL, 0abh
mov SI, str ;Load the address of our
;reserved string to SI;
call Byte2Str
mov DX, SI
call Write
mov AX, 4C00h
int 21h
;procedure
;-------------------------------------------
;Byte2Str: Caller must pass:
;AL: The byte we want to converte;
;DS: Segment of destination string
; must be already set;
;SI: Offset of destination string
; must be already set;
;
;return:
;The returned string is set to SI offset
;-------------------------------------------
Byte2Str:
mov BX, Digits ;Load offset of our
;string table that been
;saved at offset named
;Digits to BX register;
mov DI, AX ;We cant pass 8-bit reg to
;16-bit reg (AL to DI is
;not valid) so we pass
;AX to DI;
and DI, 000Fh ;Mask out the unwanted
;high 12 bits by setting
;them to 0 leaving the
;low 8 bits conserved as
;been copied from AX,
;lets say we copied 0ABh
;to AL this instruction
;will make DI look like
;this: DI=000B;
mov AH, byte [BX+DI] ;Load the ASCII of
;the Hex digit that
;been loaded to DI,
;in our example the
;Hex digit is 0Bh;
mov [SI+1], AH ;Load the ASCII to our
;string leaving the first
;byte alone;
xor AH, AH ;Clear AH to 00
mov DI, AX ;Remeber that AL is
;unmutated and still holds
;the byte we want to
;converte, AH is cleared
;as you can see in the
;line above so we are
;copying our target byte
;again to DI;
shr DI, 4 ;Warning: this requires 286
;or better!
;We shift DI to the right by
;4-bits, so for our example
;DI look like this: DI=000A
mov AH, byte [BX+DI] ;Load the ASCII of
;the Hex digit that
;been loaded to DI,
;in our example the
;Hex digit is 0Ah;
mov [SI], AH ;Load the ASCII to first
;byte of our string;
mov byte [SI+2], '$' ;Append '$' to the
;end of our string;
ret
;-------------------------------------------
Write:
mov AH, 09h
int 21h
ret
;-------------------------------------------
section .data
Digits DB '0123456789ABCDEF'
;-------------------------------------------
section .bss
str: RESB 3
;-------------------------------------------
Shikatsu.
-
Hi Shikatsu,
You must have Jeff Duntemann's Second Edition of "Assembly Language Step by Step". There's a Third Edition out, for Linux only:
http://www.duntemann.com/assembly.html
The First Edition was Masm syntax, and the last I knew (a while ago) there were some errors (in the downloadable code, not the book) in "translating" some of the Masm syntax to Nasm. If you should encounter any "odd looking" displays, I'll see if I can dig up my proposed "corrections".
There are different ways to approach the "byte2hex" routine. Here are a couple:
; nasm -f bin -o showal.com showal.asm
org 100h
mov al, 255
call showal3
call showal
call showal2
ret
;----------------------------
showal:
push ax
aam 16
hex:
xchg ah,al
cmp al,0Ah
sbb al,69h
das
int 29h
mov al,89h
jc short hex
pop ax
ret
;------------------------
;----------------------------
showal2:
push ax
shr al, 4
call .tail
pop ax
.tail
and al, 0Fh
cmp al,0Ah
sbb al,69h
das
int 29h
ret
;------------------------
showal3:
push ax
push cx
push dx
mov cx, 2
mov ah, 2
.top
rol al, 4
push ax
mov dl, al
and dl, 0Fh
add dl, '0'
cmp dl, 3Ah
jc .num
add dl, 7
.num
int 21h
pop ax
loop .top
pop dx
pop cx
pop ax
ret
As you can see, all these methods call the OS for each character, which is kinda slow - better to put it all in a string and just call the OS once to display it. The "look up table" method you (and Jeff) show is probably better. Good opportunity to try out the "xlat" instruction, although it probably isn't very fast. ("das" is horribly slow, although it's the shortest way I know). Something like...
mov bx, digits
...
; isolate a digit in al by a method of your choice
and al, 0Fh
xlat
; now al holds the character
stosb ; ?
...
I can try to work up an actual working, tested example using "xlat", but what you show is probably as good or better. Despite your excellent tutorial, I still haven't gotten DosBox installed on my system, so it might be in Linux... :)
Best,
Frank
-
This was originally an exercise in hand assembling machine code (4 hours).
;DumpHex.asm
;Translates bytes from STDIN to space
;separated two digit hexadecimal notion
;Ryan Kelly (codeFoil) 2012
;Nasm -f bin -o DumpHex.com DumpHex.asm
;Usage:
; commandx | DumpHex
;Or
; DumpHex < somefile.xxx
;Or
; DumpHex (use CTRL-C to terminate)
Org 0x100
ReadIn: MOV AH, 0x3F ; Read from handle
XOR BX, BX ; - STDIN = 0
MOV CX, 0x10 ; - 16 bytes
MOV DX, inBuff ; - Destination
INT 0x21
JS Exit ; Exit on error
OR AX, AX ; If no bytes read
JNZ Translate
Exit: MOV AH, 0x4C ; Terminate proccess
INT 0x21
Translate: MOV CX, AX ; Set loop counter to bytes in buffer
MOV [bytesRead], AX ; Save byte count
MOV DI, outBuff ; Initialize for string instruction
MOV SI, inBuff
Begin: MOV AL, 0x20 ; ASCII space
STOSb ; Store in output buffer
LODSb ; Load byte from input buffer
MOV AH, AL ; Duplicate
SHR AL, 0x04 ; High nibble to low sibble
AND AX, 0x0F0F ; Mask out high nibbles
; High nibble is now in low 4 of AL
; Low niblle is in low 4 of AH
OR AX, 0x3030 ; Shift code bank
CMP AL, 0x39 ; If high nibble > '9'
JBE Skip1
ADD AL, 0x07 ; adjust to alphabetic
Skip1: CMP AH, 0x39 ; If low nibble > '9'
JBE Skip2 ;
ADD AH, 0x07 ; adjust to alphabetic
Skip2: STOSw ; Save word in output buffer
LOOP Begin ; Repeat while bytes remain.
MOV AX, 0x0A0D ; carriage return, linefeed
STOSw ; terminate line
MOV AX, [bytesRead] ; Output buffer length is now
MOV CX, 0x0003 ; 3 * bytesRead + 2
MUL CX
ADD AX, 0x02
MOV CX, AX ; - byte count
MOV AH, 0x40 ; Write to handle
MOV BX, 0x0001 ; - STDOUT = 1
MOV DX, outBuff ; - source
INT 0x21
JMP ReadIn
Data Equ $
bytesRead: Equ Data
inBuff: Equ bytesRead + 0x02
outBuff: Equ inBuff + 0x10
-
Thank You Sir Frank Kotler for your reply.
Hi Shikatsu,
You must have Jeff Duntemann's Second Edition of "Assembly Language Step by Step". There's a Third Edition out, for Linux only:
http://www.duntemann.com/assembly.html
Yeah i do have the third edition, as i wanted to work my way up on assembly starting with 16 bits asm i liked to study the second edition first, and i can say that the second edition is as interesting as the third one.
The First Edition was Masm syntax, and the last I knew (a while ago) there were some errors (in the downloadable code, not the book) in "translating" some of the Masm syntax to Nasm. If you should encounter any "odd looking" displays, I'll see if I can dig up my proposed "corrections".
I think after studying the second and third i will consider the first edition to learn about Masm and I'll try to convert the examples to nasm that would be an interesting way to go, Thank You So Much For Offering Your Help ;)
And Thanks For your example.
Thank You codeFoil for sharing your code, i didn't had time to go though it yet but i will.
Shikatsu.
-
Greetings EveryOne ;D
Here is an implementation of Word2Str routine from "Assembly Language Step-by-step: Programming with DOS and Linux" by Jeff Duntemann.
;nasm Word2Str.asm -fbin -o Word2Str.com
bits 16
org 100h
section .text
start:
mov AX, 0bcadh
mov SI, str ;Load the address of our
;reserved string to SI;
call Word2Str
mov DX, str
call Write
mov AX, 4C00h
int 21h
;------------------------|
; Procedures |
;------------------------|
;-------------------------------------------
;Word2Str: Caller must pass:
;AX: Word to be converted;
;DS: Segment of destination string
; must be already set;
;SI: Offset of destination string
; must be already set;
;
;return:
;The returned string is set to SI offset
;-------------------------------------------
Word2Str:
mov CX, AX ;Save copy of convrtee in CX;
xchg AH, AL ;Swap high and low AX bytes to do
;high first;
call Byte2Str ;Convert AL to string at DS:SI;
add SI, 2 ;Bump SI to point to second 2 chars;
mov AX, CX ;Relod convertee into AX;
call Byte2Str ;Convert AL to string at DS:SI;
mov byte [SI+2], '$' ;Append '$' to the
;end of our string;
ret ;And we are done;
;-------------------------------------------
;Byte2Str: Caller must pass:
;AL: The byte we want to converte;
;DS: Segment of destination string
; must be already set;
;SI: Offset of destination string
; must be already set;
;
;return:
;The returned string is set to SI offset
;-------------------------------------------
Byte2Str:
mov BX, Digits ;Load offset of our
;string table that been
;saved at offset named
;Digits to BX register;
mov DI, AX ;We cant pass 8-bit reg to
;16-bit reg (AL to DI is
;not valid) so we pass
;AX to DI;
and DI, 000Fh ;Mask out the unwanted
;high 12 bits by setting
;them to 0 leaving the
;low 8 bits conserved as
;been copied from AX,
;lets say we copied 0ABh
;to AL this instruction
;will make DI look like
;this: DI=000B;
mov AH, byte [BX+DI] ;Load the ASCII of
;the Hex digit that
;been loaded to DI,
;in our example the
;Hex digit is 0Bh;
mov [SI+1], AH ;Load the ASCII to our
;string leaving the first
;byte alone;
xor AH, AH ;Clear AH to 00
mov DI, AX ;Remeber that AL is
;unmutated and still holds
;the byte we want to
;converte, AH is cleared
;as you can see in the
;line above so we are
;copying our target byte
;again to DI;
shr DI, 4 ;Warning: this requires 286
;or better!
;We shift DI to the right by
;4-bits, so for our example
;DI look like this: DI=000A
mov AH, byte [BX+DI] ;Load the ASCII of
;the Hex digit that
;been loaded to DI,
;in our example the
;Hex digit is 0Ah;
mov [SI], AH ;Load the ASCII to first
;byte of our string;
;mov byte [SI+2], '$' ;Append '$' to the
;end of our string;
;This line been moved to
;Word2Str routine;
ret
;-------------------------------------------
Write:
mov AH, 09h
int 21h
ret
;-------------------------------------------
section .data
Digits DB '0123456789ABCDEF'
;-------------------------------------------
section .bss
str: RESB 5
;-------------------------------------------
Enjoy, Shikatsu ;D