【问题标题】:x86 nasm assembly, how to print multiplication result correctly?x86 nasm 程序集,如何正确打印乘法结果?
【发布时间】:2022-01-01 08:33:23
【问题描述】:

所以我在 Stack Overflow 上找到了很多答案,但我仍然无法让它工作。我的代码有什么问题?

        mov al, 12
        mov bl, 12
        mul bl          ; answer in ax
        aam

        mov bx, 10          ; Divisor constant
        xor cx, cx          ; Clear counter
        .a: xor dx, dx      ; Clear dx
            div bx          ; Divide ax with bx, quotient in al, remainder in ah 
            mov dh, ah      ; Move ah to dh, so we can push the 16 bit register of dx
            push dx         ; Push dx which contains the remainder
            inc cx          ; Increment counter
            test al, al     ; If al (the quotient) is not zero, loop again. 
            jnz .a          
        .b: pop dx          ; Pop the last remainder to dx from stack
            add dx, '0'     ; Add '0' to make it into character
            push cx         ; Push loop counter to stack so printing wont interfere with it
            mov eax, 4      ; 
            mov ebx, 1      ;
            mov ecx, edx    ; Print last popped character
            mov edx, 1      ;
            int 0x80        ;
            pop cx          ; Pop the loop counter back to cx
            loop .b         ; loop for as long as cx is not 0

【问题讨论】:

  • 删除aam。请注意,div bx(16 位除数)将余数留在 dx 商在 ax 中。即使剩余部分在ah 中,您也应该将其移至dl 而不是dh。照原样删除mov dh, ah 并将test al, al 更改为test ax, ax。此外,我相信 int 80h 服务 4 在ecx 中采用 pointer,而不是代码点。因此将pop dx 移动到pop cx 之后,并将mov ecx, edx 替换为lea ecx, [esp + 2](因此它将指向仍在堆栈内存中的dx 值)。
  • @ecm 你对其他东西是对的,但lea ecx, [esp + 2] 是不对的,因为它将一堆未知字符和一个段错误转储到终端。
  • 它可以与mov ecx, edx 一起使用吗?
  • 我忘记了add dx。将它从它所在的位置移到push dx 之前。此外,您还需要在 loop 前面添加地址大小前缀,以便它使用 16 位的 a16 地址大小,而不是您部分的默认 a32。那么你的.b循环应该是.b:\push cx\mov eax, 4\mov ebx, 1\lea ecx, [esp + 2]\mov edx, 1\int 80h\pop cx\pop dx\@987654353pop dx\@98765435353
  • 对每个字符进行单独的write 系统调用是非常低效的。相反,存储到堆栈上的缓冲区(按降序)并进行一次write 调用,如How do I print an integer in Assembly Level Programming without printf from the c library? 所示

标签: linux assembly x86 nasm


【解决方案1】:

AAM 指令可用于结果最多为 2 位的情况。在你的情况下 12 x 12 = 144,所以这是不行的。

您使用的转换循环几乎是正确的,但您正在混合与 DIV 指令相关的大小。如果给DIV 提供一个字节大小的操作数,那么该操作会将AX 除以该字节,余数将在AH 中。如果你给 DIV 一个字大小的操作数,那么该操作会将 DX:AX 除以该字,余数将在 DX 中。

因为您正在编写 32 位代码,所以最好也使用 32 位寄存器编写转换。

不要使用数字计数器,而是使用堆栈上的哨兵。显示时无需保留ECX。

显示函数需要ECX 中的指针。只需为此使用堆栈指针并在打印后弹出值。

    mov   al, 12
    mov   bl, 12
    mul   bl               ; answer in AX
    movzx eax, ax

    mov   ebx, 10          ; Divisor constant
    push  ebx              ; Sentinel
.a: xor   edx, edx
    div   ebx              ; Divide EDX:EAX with EBX, quotient EAX, remainder EDX 
    add   edx, '0'         ; Add '0' to make it into character
    push  edx
    test  eax, eax         ; If EAX (the quotient) is not zero, loop again. 
    jnz   .a

.b: mov   eax, 4
    mov   ebx, 1
    mov   ecx, esp
    mov   edx, 1
    int   0x80
    pop   eax
    cmp   dword [esp], 10  ; Is it the sentinel ?
    jne   .b               ; No, it's a digit
    pop   eax              ; Remove sentinel

虽然不是 32 码,Displaying numbers with DOS 有更多关于将数字转换为文本的信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-22
    • 1970-01-01
    • 2015-09-20
    • 2014-02-21
    • 1970-01-01
    相关资源
    最近更新 更多