gpt4 book ai didi

assembly - 显示 assembly 时间

转载 作者:行者123 更新时间:2023-12-02 19:58:02 24 4
gpt4 key购买 nike

您好,我正在尝试显示实际时间小时/分钟/秒,这是我的代码示例:

MOV AH, 2Ch
INT 21h

MOV AH, 0Eh

MOV AL, CH
INT 10h

MOV AL, 3Ah
INT 10h

MOV AL, CL
INT 10h

MOV AL, 3Ah
INT 10h

MOV AL, DH
INT 10h

ret

在这里您可以查看控制台正在显示的内容

enter image description here

最佳答案

请参阅标签wiki指令集引用手册,以及许多引用 Material 和教程的良好链接。

<小时/>

需要足够的代码才能将整数拆分为 ASCII 数字,您应该将其分解到函数中。

这是 @hobbs 的 print2Digits 函数的优化和错误修复版本。 (我还在他的答案中修正了版本,所以它也是正确的,但留下了这个版本的优化)。

print2Digits:
;; input in AL (0-99). (Or preferably already zero-extended to AX so we can omit CBW)
;; clobbers AX and DX
cbw ; zero AH. Sign-extending AL does the job because AL is only allowed to be 0-99.

mov dl, 10
div dl ; quotient in AL(first (high) digit), remainder in AH(second (low) digit)

add ax, 0x3030 ; add '0' to al and ah at the same time.
mov dl, ah ; save the 2nd digit

mov ah, 0x0E ; BIOS call #: print single character
int 0x10 ; print high digit first. Doesn't clobber anything, so AH still holds 0x0E after
mov al, dl
int 0x10 ; print the low digit 2nd
ret

由于我们使用 div 将整数拆分为两个以 10 为基数的数字,因此我们需要 ah 为零。即股息位于 AX 中,而不仅仅是 AL,而 AH 中可能存在垃圾。如果调用者将 movzx ax, ch 或其他操作归零 ah,我们可以保存 cbwmov ah,0 >.

(除了 8086 没有 movzx,所以你实际上需要 xor ax,ax/mov al, ch。 )

有一个 DOS 系统调用用于打印整个字符串,因此您可以将字符存储到一个小缓冲区中并一次打印它们,就像我在 AMD64 Linux FizzBuzz 中所做的那样。另请参阅How do I print an integer in Assembly Level Programming without printf from the c library?对于缓冲函数中更通用的 int->string 或 x86 tag wiki 中的其他多位数链接

<小时/>

可以使用 aam将 AL(而不是 AX)除以 10,避免首先将 AH 归零。在当前的 Intel 和 AMD CPU 上,它比 div r8 稍快。但是,它将结果放入 div 的相反寄存器中,这意味着 aam 之后有额外的指令。这平衡了 mov dl, 10cbw 的节省。

print2Digits:
;; input in AL (0-99). (Ignores AH because we use AAM instead of div)
;; clobbers AX and DX
aam ; like `div` by 10, but with the outputs reversed, and input from AL only
;; quotient in AH (high digit), remainder in AL(low digit). (Opposite to div)

add ax, 0x3030 ; add '0' to al and ah at the same time.
mov dl, al ; save the low digit
mov al, ah ; print high digit first

mov ah, 0x0E ; BIOS call #: print single character
int 0x10 ; print first digit. Doesn't clobber anything, so AH still holds 0x0E after
mov al, dl
int 0x10 ; print second digit
ret

即使我们想要存储到一个字符串(并调用一个打印字符串函数或系统调用),我们也必须在将 AX 存储到内存之前交换 al 和 ah (例如 xchg al, ah,或者在现代硬件上更有效,但需要 186:rol ax,8)。 div 在 AX 中以正确的顺序生成它们。

<小时/>

对于可用 32 位地址大小的 386,我们可以保存一条指令:

lea   dx, [eax + 0x3030]   ; need a 32bit addressing mode to use eax as a source reg.  Adds '0' to both digits at once, with a different destination.
mov al, dh ; then get ready to print the high byte first

lea 需要一个地址大小前缀和一个 2 字节 mod/rm,以及一个 32 位位移,因此它在代码大小上损失很大,但它确实节省了一条指令。

div 写入 ax 后使用 leaeax 读取在 Sandybridge 系列 CPU 上可能会更快,特别是。 Haswell 及更高版本,但在 Intel pre-SnB 上,部分寄存器停顿将使其更好地使用具有单独 add 和 mov 指令的纯 16 位版本。

当然,如果您确实关心性能,您会使用乘法逆元而不是实际除以 10。并且您通常不会编写进行传统 BIOS 调用的 16 位代码要么!

关于assembly - 显示 assembly 时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37129794/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com