x / 2 + 100 *(a + b)-3 /(c + d)+ e * eアセンブリ

Oct 21 2020

次のアルゴリズムを記述します:x / 2 + 100 *(a + b)-3 /(c + d)+ e * e次のことを知っている:a、c-ワード、b、d-バイト、e-ダブルワード、x-qword

    mov eax, dword [x]
    mov edx, dword [x + 4] ; edx:eax = x
    mov ebx, 2
    idiv ebx ; eax = edx:eax / ebx = x / 2
    mov ebx, eax ; save the result in ebx so we can do the other operations
    mov al, [b]
    cbw ; ax = b
    add ax, [a] ; ax = a + b
    mov dx, 100
    imul dx ; dx:ax = ax * dx = 100 * (a + b)
    push dx
    push ax
    pop eax ; 100 * (a + b)
    add ebx, eax ; ebx = x / 2 + 100 * (a + b)
    mov al, [d] ; al = d
    cbw ; ax = d
    add ax, word [c] ; ax = c + d
    mov cx, ax ; cx = c + d
    mov ax, 3
    cwd
    idiv cx ; ax = dx:ax / cx 
    cwd
    push dx
    push ax
    pop eax ; eax = 3 / (c + d)
    sub ebx, eax
    mov eax, ebx
    cdq ; edx:eax = x / 2 + 100 * (a + b) - 3 / (c + d)
    mov ebx, eax
    mov ecx, edx ; ecx:edx = x / 2 + 100 * (a + b) - 3 / (c + d)
    mov eax, [e]
    imul dword [e] ; edx:eax = e * e
    add eax, ebx
    adc edx, ecx
    mov dword [result + 0], eax 
    mov dword [result + 4], edx

不必要に複雑にしましたか?

回答

6 SepRoland Oct 22 2020 at 03:52

次のアルゴリズムを記述します:x / 2 + 100 *(a + b)-3 /(c + d)+ e * e

a, c - word,
b, d - byte,
e - doubleword,
x - qword

最大数は64ビット(xはqword)であるため、最終結果も64ビットである必要があります。

最初の操作は、xのqwordを2で除算することでしたEBX。レジスタ内の商を移動したため、この結果は1つのdwordに収まると予想しているようです。この仮定を行うことはできません。さらに悪いことに、商が32ビットに収まらない場合、除算によって除算例外が簡単に発生する可能性があります。
解決策として、2で割ることは、実際には単に右にシフトするだけであることに注意する必要があります。

mov   ebx, [x]
mov   ebp, [x + 4] ; EBP:EBX is x
sar   ebp, 1
rcr   ebx, 1       ; EBP:EBX is x / 2

これは、他の計算をEBP:EBX使用に追加するには、他の計算もスケールアップする必要があることを意味します。

add   ebx, ...
adc   ebp, ...

加算は結合法則であるため、e * e部分を計算することから始めることができます。式を再配置せず、最終的にレジスタをさらに移動する必要がありました。大したことではありませんが、私のやり方はもっと良いです:

mov   eax, [e]
imul  eax
add   ebx, eax
adc   ebp, edx

次に100 *(a + b)が来る:

movsx eax, word [a]
movsx edx, byte [b]
add   eax, edx       ; eax = a + b
mov   edx, 100
imul  edx            ; edx:eax = 100 * (a + b)
add   ebx, eax
adc   ebp, edx

3 /(c + d)はあなたにお任せします...

...そして最後に終わりは次のようになります:

sub   ebx, eax
sbb   ebp, edx
mov   [result + 0], ebx 
mov   [result + 4], ebp

不必要に複雑にしましたか?

  • 異なる操作の間に空白行を挿入しなかったため、プログラムを読むのは少し難しかったです。

  • 関連するレジスタがすでにサイズを暗示している場合は、サイズタグ(バイト、ワード、dword)を書き込む必要はありません。mov dword [result + 0], eaxDWORDタグ冗長です。

  • プログラム内のコメントを互いに上に揃えるのが最善です。

  • 次のようなタイプミスを避けるために、注意深く読み直してください。

      mov ecx, edx ; ecx:edx = x / 2 + 100 * (a + b) - 3 / (c + d)
    

    する必要がありますECX:EBX。

  • 正方形を計算するには:レジスタに数値をロードしたら、同じレジスタを乗算して、次のようにメモリを再度使用する必要はありません。

      mov   eax, [e]
      imul  eax        ; Don't write "imul dword [e]"