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は整数の除算用です。浮動小数点数の場合、浮動小数点命令fmulとを使用できますfdiv

それを行う別の方法は、ジェリー・コフィンが彼のコメントで示唆しているように、それぞれ整数乗算の前に係数をスケーリングすることです。100で処理し、結果の整数を100 * 100=10000倍大きすぎるものとして扱います。

于 2012-11-27T23:10:46.717 に答える
0

乗算はそのまま機能するはずです。浮動小数点の結果を得るために分割する方法私はあなたの他の質問ですでに答えました。2桁で印刷するだけでよい場合は、適切なフォーマット文字列を使用できます。

更新:2桁への切り捨てを示す作業コード:

.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

ここでいくつかの有用な例を見つけることができます

以下は、 2 つの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 に答える