NASM module to convert hex into string and print it out. Assembles but not working as expected

蹲街弑〆低调 提交于 2019-12-25 18:26:49

问题


I am trying to write a simple assembly code to spit out hex values to the screen. There are two files print_screen.asm which is working with other modules. I think the problem is in my logic when trying to convert hex to string. My code is:

[org 0x7c00]

xor dx,dx
xor ax,ax
xor bx,bx

mov dx, 0x1fb6

call print_hex

jmp endi;

print_hex:
    pusha

    mov ax,0x0001
    and ax,dx
    add ah,48
    mov byte [HEX_OUT+5],ah

    mov ax,0x0010
    and ax,dx
    add ah,48
    mov byte [HEX_OUT + 4],ah

    mov ax,0x0100
    and ax,dx
    add ah,48
    mov byte [HEX_OUT + 3],ah

    mov ax,0x1000
    and ax,dx
    add ah,48
    mov byte [HEX_OUT + 2],ah

    mov bx,HEX_OUT
    call print_string

    popa
    ret

jmp endi

%include "print_string.asm"

endi:
;data
HEX_OUT: db '0x0000',0

SAMPLE: db 'a',0
times 510 - ($-$$) db  0
dw 0xaa55

print_screen.asm (working with other modules):

 print_string:
    pusha
    cld
    mov ah,0x0e

config: mov al,[bx]
    ;Comparing the strings
    cmp byte [bx],0x00  ;Comparing for null
    jne print
    je end

print:  int 0x10
    add bx,1
    jmp config

end:    popa
    ret

回答1:


mov ax,0x0001
and ax,dx
add ah,48
mov byte [HEX_OUT+5],ah

In the above snippet you only keep a single bit where you need to keep 4 bits.
You also do an addition on AH when the result definitely is in AL.
Because of how the ASCII set is organized, you can't just merily add 48 to convert into the hexadecimal. There is a gap between the encoding for '9' (57) and the encoding for 'A' (65). Your code needs to account for this!

For the least significant hex digit:

    mov ax, dx     ;Original number
    and al, 15     ;Keep 4 bits
    add al, '0'    ;Make text
    cmp al, '9'
    jbe .LessA     ;Already fine for '0' to '9'
    add al, 7      ;Bridge the gap to reach 'A' to 'F'
.LessA:
    mov [HEX_OUT + 5], al

For the next hexdigit this would become:

    mov ax, dx     ;Original number
    shr ax, 4
    and al, 15     ;Keep 4 bits
    add al, '0'    ;Make text
    cmp al, '9'
    jbe .LessA     ;Already fine for '0' to '9'
    add al, 7      ;Bridge the gap to reach 'A' to 'F'
.LessA:
    mov [HEX_OUT + 4], al

For the next hexdigit this would become:

    mov ax, dx     ;Original number
    shr ax, 8
    and al, 15     ;Keep 4 bits
    add al, '0'    ;Make text
    cmp al, '9'
    jbe .LessA     ;Already fine for '0' to '9'
    add al, 7      ;Bridge the gap to reach 'A' to 'F'
.LessA:
    mov [HEX_OUT + 3], al

For the next hexdigit this would become:

    mov ax, dx     ;Original number
    shr ax, 12
    and al, 15     ;Keep 4 bits
    add al, '0'    ;Make text
    cmp al, '9'
    jbe .LessA     ;Already fine for '0' to '9'
    add al, 7      ;Bridge the gap to reach 'A' to 'F'
.LessA:
    mov [HEX_OUT + 2], al

This rapidly got longer than is good for us, so using a loop will be much better.
Next solution will start from the high end but the end result will be no different.

    mov bx, 2      ;Position for most significant digit
.Next:
    ror dx, 4      ;Bring digit in lowest 4 bits
    mov al, dl     ;Copy number
    and al, 15     ;Keep 4 bits
    add al, '0'    ;Make text
    cmp al, '9'
    jbe .LessA     ;Already fine for '0' to '9'
    add al, 7      ;Bridge the gap to reach 'A' to 'F'
.LessA:
    mov [HEX_OUT + bx], al
    inc bx
    cmp bx, 6      ;Did we fill chars at +2 +3 +4 +5 ?
    jb  .Next      ;Not yet

Because there are 4 iterations in this loop and the number in DX is rotated 4x each time, DX will hold the original value in the end. No need to preserve it.


jmp endi;

What's this supposed to achieve? This is jumping to data and that's certainly not executable code! If you want an endless loop then simply write:

jmp $

The other file, that you say is working with other modules, is a mess!!
Everybody keeps neglecting this, but the BIOS teletype function requires the BH register to have the desired display page. Therefore it's always a bad idea to use BX as the string pointer.
Here's a good solution that doesn't require you to change all of your existing code (concerning the use of BX):

print_string:
    pusha
    mov     si, bx
    mov     bh, 0      ;Display page 0
    ;mov     bl, 7      ;Color if this were a graphical screen
    cld                ;Required to use LODSB correctly
    jmp     .start
  .write:
    mov     ah, 0x0E   ;BIOS.Teletype
    int     0x10
  .start:
    lodsb              ;Increments the pointer automatically
    cmp     al, 0      ;Comparing for null
    jne     .write
    popa
    ret



回答2:


There's code on the Russian side of Stack Overflow https://ru.stackoverflow.com/questions/924141/%d0%a0%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d1%81-%d0%b4%d0%b8%d1%81%d0%ba%d0%be%d0%bc-int-13h-bios for conversion of hex byte to string that's cleaner. Here's the snippet:

mov bh, 0x00
mov bl, ah
shr bl, 0x04
mov al, [bx+hex_nums]
mov [error_code_hex], al
and ah, 0x0F
mov bl, ah
mov ah, [bx+hex_nums]
mov [error_code_hex+1], ah
hex_nums: db "0123456789ABCDEF"

error_code_hex is where it prints the hex character. It basically takes the 4 bit as a sequence to reference the bytes of the ASCII hex sequence. Has anyone made this work?



来源:https://stackoverflow.com/questions/46872873/nasm-module-to-convert-hex-into-string-and-print-it-out-assembles-but-not-worki

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!