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

Assembly NASM模块将十六进制转换为字符串并打印出来。组装但未按预期工作,assembly,x86,nasm,bootloader,Assembly,X86,Nasm,Bootloader,我试图编写一个简单的汇编代码,将十六进制值输出到屏幕上。有两个文件print\u 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,4

我试图编写一个简单的汇编代码,将十六进制值输出到屏幕上。有两个文件
print\u 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
打印屏幕.asm
(使用其他模块):

在上面的代码片段中,您只保留了需要保留4位的一位。
当结果肯定在
AL
中时,您还可以在
AH
上进行添加
由于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
对于下一个六位数,这将成为:

    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
    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
    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 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
    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
    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 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
    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
    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 $

另一个文件,你说是与其他模块一起工作的,是一团混乱
每个人都忽略了这一点,但BIOS电传打字功能要求
BH
寄存器具有所需的显示页面。因此,使用
BX
作为字符串指针总是一个坏主意。
这里有一个很好的解决方案,它不需要您更改所有现有代码(关于使用
BX
):


在堆栈溢出的俄文端有一段代码,用于将十六进制字节转换为更干净的字符串。以下是片段:

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"

错误代码是它打印十六进制字符的地方。它基本上以4位作为序列来引用ASCII十六进制序列的字节。有人做过这项工作吗?

你一次只能屏蔽1位,而不是4位。另外,您将其保留在原位。当您执行
mov ax,0x0010;和ax,dx
?给一个例子加上一些值,看看结果是什么。@Jester我得用F.Dang愚弄我。谢谢。事实上,这些价值观也在不断变化。再次感谢。@Jester我可以使用循环吗??如果可能,如何向十六进制输出标签添加偏移量。是的,可以使用循环。您可以执行类似于
[HEX\u OUT+bx]
的操作,并且在
shr al,4
之前,0xF0
是冗余的。被屏蔽的比特即将被移出。使用AL而不是执行
mov-bl,ah
/
shr-bl,4
,保存
mov-bl,AL
指令也是毫无意义的。这样更好。你说“有人成功了吗?”是什么意思?你想问一个新问题吗?将AH转换为2位十六进制字符串看起来完全正常。除了
hex\u nums:
不能与代码对齐,否则这16个字节将被解码为指令!。您需要将查找表放在它自己的部分中,或者放在其他代码之后。@PeterCordes如果您在代码部分之前跳转,您可以将它放在代码部分。@Ачччаааааачаааааааа107。这段代码没有做到。我确实提到了另一节中的“其他代码之后”选项。相关: