NASM 将十六进制转换为字符串并打印出来的模块。组装但未按预期工作
NASM module to convert hex into string and print it out. Assembles but not working as expected
我正在尝试编写一个简单的汇编代码以将十六进制值显示到屏幕上。有两个文件 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
mov ax,0x0001
and ax,dx
add ah,48
mov byte [HEX_OUT+5],ah
在上面的代码片段中,您只在需要保留 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 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;
这应该达到什么目的?这是跳转到 data 并且那肯定不是可执行代码!如果你想要一个无限循环然后简单地写:
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
Stack Overflow https://ru.whosebug.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 十六进制序列的字节。有人做过这个吗?
我正在尝试编写一个简单的汇编代码以将十六进制值显示到屏幕上。有两个文件 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
mov ax,0x0001 and ax,dx add ah,48 mov byte [HEX_OUT+5],ah
在上面的代码片段中,您只在需要保留 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 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;
这应该达到什么目的?这是跳转到 data 并且那肯定不是可执行代码!如果你想要一个无限循环然后简单地写:
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
Stack Overflow https://ru.whosebug.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 十六进制序列的字节。有人做过这个吗?