-2

I am trying to write an assembly code to do a file hexdump, just like in Linux when you do "hexdump -C sample.txt" from the command line. I got as far as opening the file and reading the contents into a buffer, but I can't get beyond, trying to convert those bytes to hexadecimal.

Any help would be greatly appreciated.

   _WRITE   = 4                !System call number for WRITE        
   _READ    = 3                !System call number for READ    
   _OPEN    = 5                !System call number for OPEN
   _EXIT    = 1                !System call number for EXIT
   _GETCHAR = 117                !System call number for GETCHAR
   _PUTCHAR = 122                !System call number for PUTCHAR
   _PRINTF  = 127                !System call number for PRINTF
   _SPRINTF = 121                !System call number for SPRINTF
   _SSCANF  = 125                !System call number for SSCANF
   _OPEN    = 5                !System call number for OPEN

   bufsiz  = 512                !bufsiz = 512

   .SECT .TEXT                !Start label
    start:     
    MOV BP, SP            !System trap instruction
    MOV CX, de-greet
    PUSH CX
    PUSH greet
    PUSH _PRINTF
    SYS
    ADD SP, 8

    CALL GetFileInput

    Byte2Hexadecimal:

    !Conversion needs to take place here



    Word2Hexadecimal:


      !From Word to Hexadecimal needs to take place here 




    GetFileInput:
    PUSH BP
    MOV BP,SP
    MOV DI, buf
    PUSH _GETCHAR

    next_char:SYS
    CMPB AL, '\n'
    STOSB
    JNE next_char
    JL 9f
    JE 1f
        MOVB (DI),0
        POP AX
        POP BP 
        RET

    PUSH 0
    PUSH buf
    PUSH _OPEN
    SYS
    CMP AX,0
    JL 9f
    MOV (fildes),AX
    MOV SI,linh+2
    MOV BX,0

     1: CALL fillbuf
    CMP CX, 0
    JLE 3f
     2: MOV        

      9: MOV SP,BP
     PUSH buf
     PUSH errmess
     PUSH _PRINTF
     SYS
     PUSH _EXIT
     PUSH _EXIT
     SYS     

    OpenFile:


    fillbuf:
    PUSH bufsiz
    PUSH buf
    PUSH (fildes)
    PUSH _READ
    SYS
    ADD SP,8
    MOV CX,AX
    ADD BX,CX
    MOV DI,buf
    RET


   .EXIT: 
    PUSH 0                !Return code
    PUSH _EXIT            !Return to OS
    SYS                !System trap instruction

    .SECT .DATA
    errmess:     .ASCIZ "Open %s failed\n"
    numfmt:         .ASCIZ "%d"
    greet:         .ASCIZ "Welcome to our program, please enter the file name: \n"
    de:         .BYTE 0

   .SECT .BSS
    linh: .SPACE 8192        !
    fildes: .SPACE 2        !Memory location for the fildes 
     byte1:    .SPACE 8        !Memory location for the Byte 
    addr:    .SPACE 8        !Memory location for the address
    word:   .BYTE  2          !Memory location for the byte 
    buf:     .SPACE 80        !Memory location for the BUFF
    buffer: .SPACE bufsiz+2        
nrz
  • 10,435
  • 4
  • 39
  • 71
user2268636
  • 11
  • 1
  • 5
  • 2
    show some code. we're not here to do your job for you. but if you have some actual code, we'll try to help fix that. – Marc B Apr 11 '13 at 03:22
  • I have included assembly code up above. That is how far I've got. Within those subroutines, needs for conversion. The whole point is that I can't generate code on my own. I just need help with the subroutine, code would help – user2268636 Apr 11 '13 at 03:35
  • possible duplicate of [Printing Hexadecimal Digits with Assembly](http://stackoverflow.com/questions/3853730/printing-hexadecimal-digits-with-assembly) – Bo Persson Apr 11 '13 at 09:31

4 Answers4

1

There is no such thing as "converting the bytes into hexadecimal". The actual data is invariant and consists from binary ones and zeros. Your interpretation to these bits can be different, according to your needs. E.g., it can be interpreted as text character or decimal or hexadecimal or whatever value.

E.g.:

Binary 01010101 = decimal 85 = hexadecimal 55 = octal 125 = 'U' ASCII character.

SomeWittyUsername
  • 18,025
  • 3
  • 42
  • 85
  • You are required to write your own subroutines to convert each byte to the corresponding hexadecimal digits in ASCII. Make a subroutine called Byte2Hexadecimal that takes two parameters: the byte to convert and the address of a buffer where the two-digit hexadecimal string will be written. These parameters should be passed in reverse order via the stack. – user2268636 Apr 11 '13 at 03:44
1

A crude and simple implementation is to split the byte into two nibbles and then use each nibble as an index into a hex character "table".

; cdecl calling convention (google if you're not familiar with)

HEX_CHARSET        db '0123456789ABCDEF'


; void byteToHex(byte val, char* buffer)
proc byteToHex
    push bp
    mov bp,sp
    push di

    mov dx,[word ptr ss:bp + 4] ; the address of val
    mov di,[word ptr ss:bp + 6] ; the address of buffer

    ; high nibble first
    mov ax,dx
    mov cl,4
    shr al,cl
    push ax
    call nibbleToHex
    add sp,4
    stosb

    ; low nibble second
    mov ax,dx
    push ax
    call nibbleToHex
    add esp,4
    stosb

    pop di
    mov sp,bp
    pop bp
    ret
endp byteToHex


; char nibbleToHex(byte nibble)
proc nibbleToHex
    push bp
    mov bp,sp
    push si

    mov ax,[word ptr ss:bp + 4]
    and ax,0Fh    ; Sanitizing input param
    lea si,[ds:HEX_CHARSET]
    add si,ax
    lodsb

    pop si
    mov sp,bp
    pop bp
    ret
endp nibbleToHex
Powerslave
  • 1,408
  • 15
  • 16
0

A hexadecimal digit has 4 bits in it. A byte has 8 bits in it or 2 hex digits.

To display a byte in hex, you need to separate each of those two 4-bit halves and then convert the resultant value of each (which, unsurprisingly, will be from 0 to 24-1, IOW, from 0 to 15 or from 0 to 0FH) to the corresponding ASCII code:

0 -> 48 (or 30H or '0')
1 -> 49 (or 31H or '1')
...
9 -> 57 (or 39H or '9')

10 (or 0AH) -> 65 (or 41H or 'A')
11 (or 0BH) -> 66 (or 42H or 'B')
...
15 (or 0FH) -> 70 (or 46H or 'F')

Once you've converted a byte into two ASCII characters you can call the appropriate API (system call) of your OS to display those characters either one by one or as a string (you'll probably need to append a zero byte after those two characters to make a string).

That's all.

Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
  • "*you can call the appropriate Linux API*" - why Linux assumed? – SomeWittyUsername Apr 11 '13 at 08:25
  • @icepack Something made me think it's Linux. You're right, it's whatever OS it is. Updated. – Alexey Frunze Apr 11 '13 at 08:30
  • What assembler is this? (as86?) What OS? I don't think I'm familiar with any system where we push a system call number equated to `_PRINTF` and do `SYS`. I'm quite confused! Same algorithm, anyway. I'm fond of `rol` to get my 4 bits in position (if really 8086, may have only `1` and `cl` for shift/rotate counts). You'll want to make a copy, 'cause you'll have to mask off the 4 bits. Then add '0' and if it's bigger than '9', add another 7. OTOH, if you've got `%d` then `%X` may solve your problem. The real "hexdump" prints ascii on the right - don't try to print anything less than 20h! – Frank Kotler Apr 11 '13 at 08:36
  • @FrankKotler What OS and what assembler — you should probably ask the OP about it. Anyhow, `SYS` could be a macro expanding into `INT SomeNumber` or `CALL SomeFunction` or something similar. – Alexey Frunze Apr 11 '13 at 08:40
  • Hi Alexey. I was asking the OP - wrote my comment before I'd read yours. Can you think of any system where either `int somenumber` or `call somefunction` would do that? I think it may be homemade! – Frank Kotler Apr 11 '13 at 09:20
  • @FrankKotler I like lemonade and homemade. :) I mean, why not? Just because you haven't seen something before doesn't mean it doesn't exist, however odd that something may appear. – Alexey Frunze Apr 11 '13 at 09:25
  • Right. Apparently it exists. What is it? – Frank Kotler Apr 11 '13 at 10:57
  • We're doing this for an assignment due tomorrow for school, code would certainly help, there aren't many resources online, so we've been really struggling and desperate for help. – user2268636 Apr 12 '13 at 01:51
0

The instructions explicitly say you're supposed to write this yourself!

; push ax  ; byte in al
; push outbuf
; call Byte2Hexadecimal
; add sp, 4

Byte2Hexadecimal:
    push bp
    mov bp, sp
    push di
    mov di, [bp + 4]  ; buffer to put it
    mov ax, [bp + 6]  ; we're only interested in al
    mov ah, al  ; make a copy
    mov cl, 4  ; ASSume literal 8086
    shr al, cl   ; isolate high nibble first
    add al, '0'  ; '0'..'9'
    cmp al, '9'  ; or...
    jbe skip
    add al, 7  ; 'A'..'F'
skip:
    stosb
    mov al, ah  ; restore our al from copy
    and al, 0Fh  ; isolate low nibble
    add al, '0'  ; etc...
    cmp al, '9'
    jbe skip2
    add al, 7
skip2:
    stosb
    pop di
    mov sp, bp
    pop bp
    ret

Untested(!)... something like that... (probably want to zero-terminate (or '$' terminate?) your buffer).

Insanely short way to convert nibble to hex ascii

cmp al, 0Ah
sbb al, 69h
das

You probably don't want to figure that one out... and das is dog slow anyway...

Now: What assembler? What OS?

Frank Kotler
  • 3,079
  • 2
  • 14
  • 9