将十六进制数转换为汇编语言中的十六进制字符串(NASM)(调试)

Convert hexadecimal number to hexadecimal string in assembly language (NASM) (debug)

好的,在其他人将此问题标记为重复之前。让我说得很清楚,这更像是一个调试问题,而不是一个逻辑问题。据我所知,逻辑是正确的,因为如果我在每次操作后单独打印 bx 寄存器中的值,那么我会得到正确的输出。问题是将结果存储在 bx 寄存器中应该改变它所持有的内存位置,这是 而不是 发生的。


所以,我这几天在学习汇编语言,在NASM。我正在关注一个 pdf 文档,它要求您打印一个十六进制数(将十六进制数转换为十六进制字符串,然后打印它)。

我已经编写了代码,但它似乎没有打印出正确的十六进制数。另一方面,如果我只是在下面的代码片段中打印变量 FINAL_ST 而没有调用 INIT (这是将十六进制数字转换为十六进制字符串的开始),它工作正常并打印 0x0000.

我搜索了很多次都没有结果。

我发现 gdb 可用于调试 nasm 程序,但当输出为 .bin 文件时我无法理解如何使用它。

我也尝试为这段代码构建一个控制流图来理解执行流,但找不到合适的工具。 :(

代码:

[org 0x7c00]

mov ax, 0x19d4
mov bx, FINAL_ST + 5

; jmp PRINTER ; works :/
jmp INIT

NUM:
    add dx, 0x0030
    mov [bx], dx
    jmp CONT

ALPHA:
    add dx, 0x0037
    mov [bx], dx
    jmp CONT

CONT:
    dec bx
    shr ax, 4
    cmp ax, 0x0000
    jne INIT
    je PRINTER

INIT:
    mov dx, 0x000f
    and dx, ax
    cmp dx, 0x000a
    jl NUM
    jge ALPHA       

;STRING PRINTER
PRINTER:
    mov bx, FINAL_ST
    mov ah, 0x0e
    jmp PRINT ; this doesn't work

PRINT:
    mov al, [bx]
    int 0x10
    inc bx
    cmp byte[bx], 0x00
    jne PRINT

FINAL_ST:
    db "0x0000", 0x00  

END:

times 510 - ($ - $$) db 0
dw 0xaa55

使用的命令:

nasm boot_hex1.asm -f bin -o boot_hex1.bin

qemu-system-x86_64 boot_hex1.bin

我得到的输出为 0x1,而预期输出为 0x19D4

您的问题出在如下两行:

mov [bx], dx

这会将 DX 中的 16 位值移动到 BX 中指定的地址。由于 x86 是小尾数法,因此在每次迭代时都会将 DL 移动到 [BX] 并将 DH 移动到 [BX+1]你的循环。由于 DH 在您的代码中始终为零,因此在将每个字符写入 FINAL_ST 缓冲区后,NUL 会终止字符串。

问题是您实际上是在用 DL 中的 byte 更新 BX 指向的内存。将两行更改为:

mov [bx], dl

我有 的 Whosebug 答案。提示 #1 是:

When the BIOS jumps to your code you can't rely on CS,DS,ES,SS,SP registers having valid or expected values. They should be set up appropriately when your bootloader starts. You can only be guaranteed that your bootloader will be loaded and run from physical address 0x00007c00 and that the boot drive number is loaded into the DL register.

您至少应将 DS 设置为零,因为您使用的是 0x7c00 的 ORG(原点)。您不能假设 BIOS 在将控制权转移到您的引导加载程序之前会将 DS 设置为零。它在 QEMU 中工作,因为它的 BIOS 恰好在 DS 中已经具有值 0x0000。并非所有硬件和模拟器都能保证这一点。

如果有人需要,这里有一个有工作解决方案的过程...

; Use: convert a hex value into a string
; Input: hex value(+10), string pointer(+12)
; Output: None
HEX_BINARY_LEN equ 4
ALPHA_MIN equ 000ah
ALPHA_ASCII equ 55
DECIMAL_ASCII equ 48
HEX_VALUE equ 10
STRING_PTR equ 12
;----------------------------------------------------------------
proc hexToString
push bp 
push bx
push ax
push dx
mov bp, sp 

    mov bx, [bp + STRING_PTR]
    add bx, 3 ; because we start from the end
    mov ax, [bp + HEX_VALUE]

digitLoop:
    mov dx, 000fh
    and dx, ax
    cmp dx, ALPHA_MIN
    ;----------------------------
    jge alphaDigit
        add dx, DECIMAL_ASCII
        mov [bx], dl
    jmp wasDecimalDigit
    ;--------------------
alphaDigit:
        add dx, ALPHA_ASCII
        mov [bx], dl

wasDecimalDigit:
    ;----------------------------

    dec bx
    shr ax, HEX_BINARY_LEN
    cmp ax, 0000h
jne digitLoop

mov sp, bp 
pop dx
pop ax
pop bx
pop bp 
retn 6
endp hexToString
;----------------------------------------------------------------