Author Topic: Byte2Str:byte to string from"asm Language step-by-step" by Jeff Duntemann  (Read 7049 times)

Offline Shikatsu

  • Jr. Member
  • *
  • Posts: 10
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":

Code: [Select]
;---------------------------------------------------------------
;  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:

Code: [Select]
;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.
« Last Edit: March 23, 2012, 09:50:53 PM by Shikatsu »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2379
  • Country: us
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:

Code: [Select]
; 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...

Code: [Select]
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


Offline codeFoil

  • Jr. Member
  • *
  • Posts: 13
This was originally an exercise in hand assembling machine code (4 hours).
Code: [Select]
;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
   

Offline Shikatsu

  • Jr. Member
  • *
  • Posts: 10
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.

Offline Shikatsu

  • Jr. Member
  • *
  • Posts: 10
Word2Str routine
« Reply #4 on: March 28, 2012, 02:11:22 PM »
Greetings EveryOne ;D

Here is an implementation of Word2Str routine from "Assembly Language Step-by-step: Programming with DOS and Linux" by Jeff Duntemann.

Code: [Select]
;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
« Last Edit: March 28, 2012, 02:13:24 PM by Shikatsu »