0

我被困在一个练习问题上,我需要读取一个整数,将其加 1 并打印出结果。在这个问题上:linux nasm 程序集打印从零到 100 的所有数字,用户 Gunner 提到了 dwtoa。我假设这是一个可调用的函数。那么这个 dwtoa 函数是什么?如果它实际上是一个可调用函数,我在哪里可以得到它(我的意思是如何在我的代码中实现它?)?

提前致谢。

4

1 回答 1

3

嗯,你得写……或者借一个别人已经写好的。后者更容易(C库有这样的函数,而且很容易从asm调用),但前者更“有趣”。(如果你喜欢那种东西——嘿,有些人会做填字游戏)

div指令非常慢。有一种更好的方法是基于乘以倒数和“反向乘法”。这很复杂。我们等着div。:)

div ebx

如果我们安排了我们的号码,比如 1234、ineax和10in ebx,我们现在将有 123ineax和 4in edxebx保持不变)。实际上,我们希望edxdiv...

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 无论如何,应该给您一些可以使用的东西。玩得开心!:)

于 2012-11-07T12:36:43.913 回答