我被困在一个练习问题上,我需要读取一个整数,将其加 1 并打印出结果。在这个问题上:linux nasm 程序集打印从零到 100 的所有数字,用户 Gunner 提到了 dwtoa。我假设这是一个可调用的函数。那么这个 dwtoa 函数是什么?如果它实际上是一个可调用函数,我在哪里可以得到它(我的意思是如何在我的代码中实现它?)?
提前致谢。
嗯,你得写……或者借一个别人已经写好的。后者更容易(C库有这样的函数,而且很容易从asm调用),但前者更“有趣”。(如果你喜欢那种东西——嘿,有些人会做填字游戏)
div
指令非常慢。有一种更好的方法是基于乘以倒数和“反向乘法”。这很复杂。我们等着div
。:)
div ebx
如果我们安排了我们的号码,比如 1234、ineax
和10in ebx
,我们现在将有 123ineax
和 4in edx
(ebx
保持不变)。实际上,我们希望edx
在div
...
xor edx, edx
div ebx
如您所知,我们可以通过添加字符“0”(或十进制的 48 或 30h)将数字 4 转换为字符“4”。现在我们有了可以打印的东西!但我们还没有完全准备好打印它——我们正在倒退数字。有几种方法可以解决这个问题。我认为最简单的方法是将它们push
放在堆栈上pop
他们以正确的顺序关闭。另一种方法是继续将它们向后放入缓冲区并在最后执行“字符串反转”。另一种方法是从缓冲区的“末尾”开始并朝着前面工作(在每个字符之后减少您在缓冲区中的索引,而不是增加它)。这可能意味着当您用完数字时,您还没有完全处于缓冲区的开头。我们可以利用它来发挥我们的优势 - 如果您要在列中打印它们,右对齐的数字看起来不错。如果您认为这看起来不错(我不这样做),您也可以填充前导零(字符“0”,而不是数字 0)。
无论如何,我们已经安全地藏匿了“4”。一次又一次地循环div
(先做edx
零!)。现在我们有 12 英寸eax
和 3 英寸edx
。对 3 做一些事情,然后再返回div
。1 英寸eax
和 2 英寸edx
。同样,andeax
为零(edx
为 1)——此时我们完成了!div
如果我们与 9 比较,我们可以跳过最后一个eax
- 如果它更小,我们可以从而al
不是dl
. 每次都以相同的方式做更简单...
; mov eax, the number
; mov edi, the buffer (at least resb 10, please)
; call dwtoa
; mov edx, eax ; count
; mov ecx, buffer
; print it
dwtoa:
xor ecx, ecx ; for a counter
mov ebx, 10
pushloop:
xor edx, edx ; or mov edx, 0
div ebx
add edx, '0'
push edx
inc ecx ; count it
test eax, eax ; or cmp eax, 0
jnz pushloop
mov eax, ecx ; we'll return the count in eax
poploop:
pop edx
mov [edi], dl
inc edi
loop poploop
ret
那是我的想法(不是剪切和粘贴的),并且可能有错误。它非常草率 - 丢弃 C 想要保留的寄存器 - 不会像 C 想要的那样返回以零结尾的字符串......但我们没有使用 C,所以我们不在乎!:)
随意改进它以适应您的口味,或尝试不同的方法。
除非您有一个,否则您将需要一个“atoi”(或“atodw”以使用相同的命名约定),将用户输入的文本转换为数字。同样的想法,但我们从字符中减去“0”,将“到目前为止的结果”乘以 10,然后添加新数字……直到完成。
;-------------------
; atoi - converts string to (unsigned!) integer
; expects: buffer in edx
; returns: number in eax
atoi:
xor eax, eax ; clear "result"
.top:
movzx ecx, byte [edx]
inc edx
cmp ecx, byte 0
jz .done
cmp ecx, byte 10
jz .done
cmp ecx, byte '0'
jb .invalid
cmp ecx, byte '9'
ja .invalid
; we have a valid character - multiply
; result-so-far by 10, subtract '0'
; from the character to convert it to
; a number, and add it to result.
lea eax, [eax + eax * 4]
lea eax, [eax * 2 + ecx - '0']
jmp short .top
.invalid:
stc
.done:
ret
;--------------
那个是剪切和粘贴的,所以“应该”工作。它也可以改进。使用“有趣”的方式乘以十并添加转换为数字的新字符。此时,您的程序的“工作”包括:
add eax, 1
无论如何,应该给您一些可以使用的东西。玩得开心!:)