0

我在装配中的以下操作时遇到了一些麻烦。我正在组装 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 个数字,并且不四舍五入)例如

Divide : 3 / 4 = 0.75

对于 19 和 1000:

Divide : 19 / 1000 = 0.01

对于 8 和 2:

Divide : 8 / 2 = 4.00

我真的很努力地得到结果,但没有成功。多谢!:)

4

3 回答 3

0

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

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

于 2012-11-27T23:10:46.717 回答
0

乘法应该按原样工作。如何除以得到浮点结果我已经在你的另一个问题中回答了。如果您只需要将它们打印到两位数,则可以使用适当的格式字符串。

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

.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

见操作

于 2012-11-27T23:12:55.860 回答
0

你可以在这里找到一些有用的例子

这是一个如何将两个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还原堆栈指针执行相同的次数。否则你会得到未定义的行为。

于 2012-11-27T23:49:17.300 回答