NASM模块将十六进制转换为字符串并将其打印出来。装配但未按预期工作

时间:2017-10-22 10:11:13

标签: assembly x86 nasm bootloader

我正在尝试编写一个简单的汇编代码,将十六进制值吐出到屏幕上。有两个文件print_screen.asm正在与其他模块一起使用。我认为在尝试将十六进制转换为字符串时问题出在我的逻辑中。我的代码是:

[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(与其他模块合作):

 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

2 个答案:

答案 0 :(得分:3)

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

在上面的代码片段中,您只需保留一个位,您需要保留4位 当结果肯定在AH时,您也会在AL上添加 由于ASCII集的组织方式,您不能只是添加48来转换为十六进制。 '9'(57)的编码与'A'(65)的编码之间存在差距。您的代码需要考虑到这一点!

对于最不重要的十六进制数字:

    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

对于下一个hexdigit,这将成为:

    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

对于下一个hexdigit,这将成为:

    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

对于下一个hexdigit,这将成为:

    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

这对我们的影响很快,因此使用循环会更好。
下一个解决方案将从高端开始,但最终结果将没有什么不同。

    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

因为此循环中有4次迭代,DX中的数字每次旋转4次,所以DX将保留原始值。无需保留它。

jmp endi;

这应该达到什么目的?这是跳转到数据,这当然不是可执行代码!如果你想要无限循环,那么只需写下:

jmp $

你说的另一个文件正在与其他模块一起工作,这是一个烂摊子!
每个人都忽略了这一点,但BIOS电传打字功能要求BH寄存器具有所需的显示页面。因此,使用BX作为字符串指针总是一个坏主意 这是一个很好的解决方案,不需要您更改所有现有代码(关于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

答案 1 :(得分:0)

在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的俄语方面有代码将十六进制字节转换为更干净的字符串。这是代码段:

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是打印十六进制字符的位置。基本上,它使用4位作为序列来引用ASCII十六进制序列的字节。有人做过这项工作吗?