为什么这个汇编语言程序以相反的顺序打印十六进制数字? [英] Why does this assembly language program print hex digits in reverse order?

查看:276
本文介绍了为什么这个汇编语言程序以相反的顺序打印十六进制数字?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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



在下面的程序中,测试编号是'0x6bf1'。程序打印数字,但是十六进制数字反转,即'01fb6'。我无法弄清楚为什么 - 有人能给我一个提示吗? (这不是家庭作业btw)。

  [org 0x7c00]; BIOS将bootloader加载到地址0x7c00 

mov dx,0x6bf1
call print_hex
jmp $;打印结果后挂起

print_hex:

mov cl,0
mov bx,HEX_OUT
add bx,2;在'0x'之后开始写

循环:

cmp cl,16
je终于
mov ax,dx
shr ax, cl
和ax,0x000f
add ax,0x30
cmp ax,0x39
jg add_7
mov byte [bx],al
add bx,1 ;增加下一轮的写入地址
add cl,4;下一轮增量位移
jmp循环

add_7:;处理字母(A-F)

add ax,0x07
mov byte [bx],al
add bx,1;增加下一轮的写入地址
add cl,4;下一轮增量位移
jmp循环


终于:

mov bx,HEX_OUT
调用print_string
ret

print_string:
mov ah,0x0e;设置为BIOS Teletype例程
mov dx,bx

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

出口:
ret

HEX_OUT:db'0x0000',0

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


解决方案

感谢 Michael Petch 和<玛格丽特布鲁姆你已经知道你的代码出了什么问题。解决方案是有一个循环:

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






由于这不是作业,我们可以进一步学习,并学会编写更好的代码。主循环的主体效率低下,因为您在没有必要的情况下重复执行多条指令。

  mov cl,12 
循环:
mov ax,dx
shr ax,cl
和al,0x0F
add al,0
cmp al,9
jng isDigit
add al,7;处理字母(A-F)
isDigit:
mov byte [bx],al
inc bx;增加下一轮的写地址
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;设置BIOS BIOS Teletype Routine - 函数编号
mov bh,0;设置为BIOS Teletype例程 - 显示页面
jmp TestEnd
print_loop:
int 0x10
inc si
TestEnd:
mov al,[si]
cmp al,0
jne print_loop
ret


I've been following lecture notes on how to write an operating system and have been getting to grips with assembly language, specifically NASM. (Lecture notes here, for interest: https://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf)

One of the first tasks is to write a program that will print to the screen an ASCII representation of a 16-bit hexadecimal number.

In the program below, the test number is '0x6bf1'. The program prints the number, but with the hex digits reversed, i.e. '01fb6'. I cannot figure out why - would someone be able to give me a hint? (This isn't homework btw).

[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

解决方案

Thanks to the comments by Michael Petch and Margaret Bloom you already know what was wrong with your code. The solution is to have a loop like:

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


Since this isn't homework we can go a bit further and learn to write better code. The body of the main loop is inefficient because you repeat a number of instructions where this isn't necessary. See how much smaller the code gets by just jumping over the addition with 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

Please note that I used AL instead of AX. The upper byte of AX at these points in the program has no relevant content. Furthermore using AL reduces the code size. Using inc bx rather than add bx,1 also reduces code size.

The BIOS Teletype function has BH as an argument, so best not use BX to iterate over the string when outputting the result.
Why do you load the character 2 times (once in CL, once in AL)?
See how I've put the test for the end of the string near the end of the loop? This saves unnecessary jumping around. In future programs that you'll write this will become an important detail.

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

这篇关于为什么这个汇编语言程序以相反的顺序打印十六进制数字?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆