汇编乘法运算64位

时间:2012-11-27 22:52:18

标签: c++ c assembly x86

我在装配时遇到以下行为的麻烦。 我正在组装IA32。假设-4(%ebp)= x和-8(%ebp)= y并且我已经从用户获得它们(两个32位长)。 这是代码:

format1:    .string "Multiply : %u * %u = %llu\n"
format2:    .string "Divide : %u / %u = %u\n"

# operation multiply
movl    -4(%ebp),   %eax
mull    -8(%ebp)
pushl   %edx
pushl   %eax
pushl   -8(%ebp)
pushl   -4(%ebp)
pushl   $format1
call    printf

# operation divide
movl    -4(%ebp),    %eax   
divl    -8(%ebp)
pushl    %eax
pushl   -8(%ebp)
pushl   -4(%ebp)
pushl   $format2
    call    printf

乘法结果在%llu中的原因是因为我希望能够将2个长数相乘并打印结果,即使它达到64个字节。 而且在%edx中,mull命令保存了64字节结果的“其他32个字节”,因此我需要将它推送到堆栈以及printf。 例如我想要这个输出:

 Multiply : 4000000000 * 2 = 16000000000

另外,我希望3和4的除法运算返回X.YZ结果。 (尾数不超过2个数字,没有四舍五入) e.g。

Divide : 3 / 4 = 0.75

表示19和1000:

Divide : 19 / 1000 = 0.01

和8和2:

Divide : 8 / 2 = 4.00

我真的尝试过很多但没有成功。 非常感谢! :)

3 个答案:

答案 0 :(得分:0)

mull用于整数乘法,divl用于整数除法。对于浮点数,您可以使用浮点指令fmulfdiv

另一种方法是像Jerry Coffin在他的评论中建议的那样,在每个整数乘法之前缩放因子,例如。 100,并将得到的整数视为100 * 100 = 10000倍太大。

答案 1 :(得分:0)

乘法should work as-is。 如何划分得到浮点结果我已经answered in your other question。 如果您只需要将它们打印成两位数,则可以使用相应的格式字符串。

更新:显示截断为两位数的工作代码:

.comm x,4,4
.comm y,4,4

.section    .rodata

format1:    .string "Div : %d / %d = %.2f\n"
format2:    .string "Mod : %d %% %d = %d\n"
format3:    .string "Multiply : %u * %u = %llu\n"
format4:    .string "%d %d"
const100:   .int 100

.text
.globl  main
.type   main, @function
main:
    subl $32, %esp # allocate space, preserve alignment

    movl $format4, (%esp)
    movl $x, 4(%esp)
    movl $y, 8(%esp)
    call scanf

# operation divide
    fildl x
    fimul const100
    fidivl y
# truncate to integer
# use this if current FPU rounding mode
# is known to be truncate
#   frndint
# otherwise use this
    fnclex
    fnstcw (%esp)       # save a copy to modify
    fnstcw 2(%esp)      # and a copy to preserve
    orw $0x0c00, (%esp) # rounding mode = truncate
    fldcw (%esp)        # activate
    frndint             # do the truncate
    fldcw 2(%esp)       # restore original
# end of truncate code
    fidiv const100
    fstpl 12(%esp) # x / y

    movl $format1, (%esp)
    movl x, %eax
    movl %eax, 4(%esp)
    movl y, %eax
    movl %eax, 8(%esp)
    call printf

# operation modulo
    movl x, %eax
    cltd
    idivl y
    movl $format2, (%esp)
    movl x, %eax
    movl %eax, 4(%esp)
    movl y, %eax
    movl %eax, 8(%esp)
    movl %edx, 12(%esp)
    call printf

# operation multiply
    movl x, %eax
    mull y
    movl $format3, (%esp)
    movl x, %ecx
    movl %ecx, 4(%esp)
    movl y, %ecx
    movl %ecx, 8(%esp)
    movl %eax, 12(%esp)
    movl %edx, 16(%esp)
    call printf

    addl $32, %esp
    xor %eax, %eax
    ret

See in operation

答案 2 :(得分:0)

您可以找到一些有用的示例here

以下是如何将两个 32位数与 64 位结果相乘[Linux,GCC]的示例:

#include <stdio.h>

char *fr = "MUL %u * %u = %llu\n";

int main()
{
        __asm__ (
                        "subl $0x14, %esp\n\t"
                        "movl $10, %eax\n\t"
                        "movl %eax, 0x4(%esp)\n\t"
                        "movl $100, %ebx\n\t"
                        // Multimpy two 32bit values and save 64bit result in edx:eax
                        "mull %ebx\n\t"

                        // Call printf
                        "movl fr, %esi\n\t"
                        "movl %esi, (%esp)\n\t"
                        "movl %ebx, 0x8(%esp)\n\t"
                        "movl %eax, 0xC(%esp)\n\t"
                        "movl %edx, 0x10(%esp)\n\t"
                        "call printf\n\t"
                        "addl $0x14, %esp\n\t");

        return 0;
}

gcc -m32 ./ttt.c; ./a.out
MUL 10 * 100 = 1000

对于除法,您需要将数据转换为浮点值并使用fdiv指令。

PS。 push更改%esp,因此您必须对恢复堆栈指针执行pop相同的次数。否则你会得到未定义的行为。