问题
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