【问题标题】:Why does this assembly language program print hex digits in reverse order?为什么这个汇编语言程序以相反的顺序打印十六进制数字?
【发布时间】:2016-10-20 07:15:42
【问题描述】:

我一直在学习如何编写操作系统的讲义,并且已经掌握了汇编语言,特别是 NASM。 (讲义在这里,感兴趣的:https://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf

首要任务之一是编写一个程序,将 16 位十六进制数字的 ASCII 表示打印到屏幕上。

在下面的程序中,测试编号是'0x6bf1'。程序打印数字,但十六进制数字颠倒,即“01fb6”。我不知道为什么 - 有人能给我一个提示吗? (顺便说一句,这不是家庭作业)。

[org 0x7c00]            ; BIOS loads bootloader to address 0x7c00

mov dx, 0x6bf1
call print_hex
jmp $                    ; Hang after printing result

print_hex:

mov cl, 0
mov bx, HEX_OUT
add bx, 2            ; To start writing after '0x'

loop:

cmp cl, 16
je finally
mov ax, dx
shr ax, cl
and ax, 0x000f
add ax, 0x30
cmp ax, 0x39
jg add_7
mov byte [bx], al
add bx, 1            ; Increment write address for the next round
add cl, 4            ; Increment bit shift for the next round
jmp loop

add_7:               ; Handles letters (A-F)

add ax, 0x07
mov byte [bx], al
add bx, 1            ; Increment write address for the next round
add cl, 4            ; Increment bit shift for the next round
jmp loop


finally:

mov bx, HEX_OUT
call print_string
ret

print_string:
mov ah, 0x0e         ; Set up for BIOS Teletype Routine
mov dx, bx

print_loop:
mov cl, [bx]
cmp cl, 0
je exit
mov al, [bx]
int 0x10
add bx, 1
jmp print_loop

exit:
ret

HEX_OUT: db '0x0000',0

; padding and magic BIOS number
times 510-($-$$) db 0
dw 0xaa55

【问题讨论】:

  • 因为您正在处理从最低有效位到最高有效位的十六进制数字。
  • 嗨迈克尔,我真的不知道怎么做,你介意解释一下吗?
  • @sav0h 试试这条线索:将mov cl, 0 更改为mov cl, 16mov cl, 12 并相应地调整循环。仔细检查退出条件!
  • 使用 shr ax, cl and ax, 0x000f (然后在循环之前将 4 添加到 CL )。您似乎正在将您的数字从高位移到低位,然后处理低 4 位。因为您正在将处理数字从最不重要的十六进制转移到最重要的位置。这就像取十进制数 1234 并除以 1 并打印低位 (4) 然后除以 10 并打印低位 (3) 然后除以 100 并打印低位 (2) 然后除以 1000 和打印低位 (1)。结果将是 4321
  • 哦...多么明显。不敢相信我没有看到。谢谢两位!

标签: assembly hex nasm x86-16


【解决方案1】:

感谢Michael PetchMargaret Bloom 的cmets,您已经知道您的代码出了什么问题。解决方案是有一个像这样的循环:

    mov  cl, 12
Loop:
    mov  ax, dx
    shr  ax, cl
    ...
    sub  cl, 4
    jnb  Loop

由于这不是家庭作业,我们可以更进一步,学习编写更好的代码。主循环的主体效率低下,因为您重复了许多不必要的指令。只需用 7 跳过加法即可查看代码变小了多少:

    mov  cl, 12
Loop:
    mov  ax, dx
    shr  ax, cl
    and  al, 0x0F
    add  al, "0"
    cmp  al, "9"
    jng  isDigit
    add  al, 7         ; Handles letters (A-F)
isDigit:
    mov  byte [bx], al
    inc  bx            ; Increment write address for the next round
    sub  cl, 4
    jnb  Loop

请注意,我使用了AL 而不是AX。程序中这些点AX的高字节没有相关内容。此外,使用AL 可以减少代码大小。使用inc bx 而不是add bx,1 也可以减少代码大小。

BIOS Teletype 函数有BH 作为参数,所以在输出结果时最好不要使用BX 来遍历字符串。
为什么要加载角色 2 次(一次在 CL,一次在 AL)?
看看我如何将字符串末尾的测试放在循环末尾附近?这样可以避免不必要的跳跃。在您将来编写的程序中,这将成为一个重要的细节。

print_string:
    mov  si, bx
    mov  ah, 0x0E      ; Set up for BIOS Teletype Routine - function number
    mov  bh, 0         ; Set up for BIOS Teletype Routine - display page
    jmp  TestEnd
print_loop:
    int  0x10
    inc  si
TestEnd:
    mov  al, [si]
    cmp  al, 0
    jne  print_loop
    ret

【讨论】:

猜你喜欢
  • 2011-12-19
  • 2020-07-11
  • 2014-03-24
  • 2020-11-25
  • 2020-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-10
相关资源
最近更新 更多