0

私はこれを読んでいて、どこにロードするかを指定せずに、値を別の場所 (st0、st1、次に st0 に戻す) に fld ロードする例を示していることに気付きました。私は、フィールドが整数をロードする手段にすぎないため、同様の方法で機能すると想定しています(または、とにかくそれが私の理解です)が、間違っている可能性があります。私の質問は次のとおりです。fld、より具体的には、値をロードする場所はどこですか? 使用する fpu レジスタを指定するパラメータはありますか、それとも 8 をループするだけですか、それともまったく別の方法がありませんか?

私が具体的に取り組んでいるコードは、3 つの数値を乗算しようとしています。1 つの方法として、st0 にロードし、次に st1 にロードし、次に st2 にロードし、次に fmul st0 と st1 (結果は st0)、次に fmul st0 と st2 にロードすることを想定しています。コードは次のとおりです。

mov dword [ebp-8], 4
mov dword [ebp-12], ecx
fild dword [ebp-4]
fild dword [ebp-8]
fild dword [ebp-12]
fmul st0, st1
fmul st0, st2
fistp dword [ebp-8]
mov eax, dword [ebp-8]

ecx = 5 および [ebp-4] = 5

OllyDbg を使用すると、このコードがクラッシュします。00000069 でアクセス違反があったことがわかりますが、現在、それはどのレジスタにも含まれていません。

そうです、フィールドが値をロードする場所を指定する方法はありますか、どこに行くべきかを理解する良い方法はありますか?これをループで実行している場合、何かが変わりますか?

--EDIT 3-- ほとんど修正されました。大きなことの 1 つはfmul、値を にプッシュしないことです。st0にあるものを上書きするだけst0です。新しいコード:

mov dword [ebp-8], ecx
fild dword [ebp-4]
fild dword [four]
fild dword [ebp-8]
fmul st1
fmul st2
fistp dword [ebp-12]
mov eax, dword [ebp-12]

ecxこれはループして== 2 になるまで減分し、次にfild2 と 1 を試みるとbad -NAN FFFF C0000000 00000000、前と同じ結果になります。3 が 2 または 1 とどのように異なるのか (小さいこと以外) はわかりませんが、それは悪い値を与え始めるときです。ERROR_MOD_NOT_FOUND がスローされたことに注意する必要がありますが、すべての cpu および fpu レジスタにアクセスできる必要があるため、その意味がよくわかりません。

--EDIT 2-- Parham Alvani がドキュメンテーションで示したように、ポップを修正しました。

mov dword [ebp-8], ecx      ; moves eax (starts as 5) into local var (fild can't take a cpu register)
fild dword [ebp-4]          ; starts as 5, moves down with outer loop
fild dword [four]           ; the integer 4
fild dword [ebp-8]          ; starts as 5, moves down with inner loop
fmul st0, st1               ; 0 := 0 * i
fmul st0, st3
fistp dword [ebp-12]        ; move st0 to local var
mov eax, dword [ebp-12]     ; move local var to eax

これは 5 回押してからbad -NAN FFFF C0000000 000000002 回押します。 fmul何もしていないようです (おそらく値が悪いため)。値をロードするより良い方法はありますか? で何か間違っているようですが、最初のリンクで提供されている例によると、ここfild定義されているように、 st0 にプッシュするだけです。fild

--EDIT 1-- Jester が示唆したように、ループごとに fpu スタックからポップしています。

mov dword [ebp-8], 4
mov dword [ebp-12], ecx
fild dword [ebp-4]
fild dword [ebp-8]
fild dword [ebp-12]
fmul st0, st1
fmul st0, st2
fstp st2
fstp st1
fistp dword [ebp-8]
mov eax, dword [ebp-8]

このコードはまだクラッシュします。00000009 でアクセス違反、st0 ~ 4 は 0、st5 = 100、st6 = 4、st7 = 4

4

1 に答える 1

1

元のコードは正しいです。ロードされた値を x87 スタックにプッシュしますfldfildこのプッシュは、常に値を st0 に置き、st0 の古い値を st1 に、古い st1 を st2 に、というように移動します。

fild dword [ebp-4]   ; st0 = x
fild dword [ebp-8]   ; st1 = x, st2 = y
fild dword [ebp-12]  ; st2 = x, st1 = y, st0 = z
fmul st0, st1        ; st2 = x, st1 = y, st0 = z * y
fmul st0, st2        ; st2 = x, st1 = y, st0 = z * y * x
fistp dword [ebp-8]  ; st1 = x, st0 = y

ebp悪い場所を指している、または投稿した部分ではなく、コードの別の部分に誤りがあるために、コードがクラッシュする可能性があります。どの命令がクラッシュしたかはわかりません。クラッシュの瞬間、プログラム カウンター (pc) はクラッシュした命令を指しています。

あなたのコードを短いプログラムに入れ、OpenBSD/amd64 マシンの gdb で正常に実行しました。

section .data
    dd 0
    dd 0
    dd 5
space:

section .text
global main
main:
    mov ebp, space
    mov ecx, 5
    mov dword [ebp-8], 4
    mov dword [ebp-12], ecx
    fild dword [ebp-4]
    fild dword [ebp-8]
    fild dword [ebp-12]
    fmul st0, st1
    fmul st0, st2
    fistp dword [ebp-8]
    mov eax, dword [ebp-8]
    int 3

組み立てて実行するには:

$ nasm -felf64 fmul3.s && gcc -nopie -o fmul3 fmul3.o 
$ gdb fmul3
...
(gdb) run
...
Program received signal SIGTRAP, Trace/breakpoint trap.
...
(gdb) x/3wd (char *)&space - 12
0x601000 <__data_start>:        5       100     5
(gdb) print (int)$rax
$1 = 100

プログラムは 5 * 4 * 5 = 100 を正常に乗算しました。

于 2018-01-08T23:47:43.647 に答える