将十六进制数转换为汇编语言中的十六进制字符串(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
;----------------------------------------------------------------
好的,在其他人将此问题标记为重复之前。让我说得很清楚,这更像是一个调试问题,而不是一个逻辑问题。据我所知,逻辑是正确的,因为如果我在每次操作后单独打印 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
我有
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
;----------------------------------------------------------------