数値(var a)を別の数値(var b)で足して乗算を行うforループを作成しようとしています。アセンブリの乗算ループが間違った高い数値を返す
どこが間違っていますか?私はロジックを実行していると私は問題が何であるか把握することはできません。
数値(var a)を別の数値(var b)で足して乗算を行うforループを作成しようとしています。アセンブリの乗算ループが間違った高い数値を返す
どこが間違っていますか?私はロジックを実行していると私は問題が何であるか把握することはできません。
TL:DR:あなたはEAXをゼロにせず、ADD命令はメモリオペランドを使用しています。
デバッガを使用してください。あなたは、EAXが最初からゼロではなかったことを簡単に見てきました。 asmをデバッグするためのgdbの使い方のヒントについては、x86タグwikiの一番下を参照してください。
私はx86-64 System V ABIを使用していると思いますので、args(aとb)は%ediと%esiにあります。
関数の開始時に、argsを保持しているもの以外のレジスタは、ガベージを含んでいるとみなすべきです。 であるレジスタの高い部分でさえも、あなたのargsを保持するはゴミを含むことがあります。 (この規則の例外:unofficially, narrow args are sign or zero extended to 32-bit by the caller)
どちらargがポインタであるので、あなたがそれらを逆参照いけません。 add (%edi, %eax), %eax
は、32ビットアドレスをEDI + EAXとして計算し、そこから32ビットをロードします。 EAX(デスティネーションオペランド)にそのワードを追加します。
整数argをポインタとして使用しているので、あなたのプログラムがsegfaultになっていないことに驚いています。
多くのx86命令(ADDなど)では、デスティネーション・オペランドは書き込み専用ではありません。 add %edi, %eax
はです。私はあなたがadd %src1, %src2, %dst
のような命令を持っているかもしれない3オペランドRISC構文と混ざっていると思います。
x86には、BMI2 bzhi
のような最新の拡張機能が追加されていますが、通常の指示はすべて破壊的なデスティネーションの2オペランドです。 (あなたはそのコメントを持っているあなたも、別のレジスタに結果を置くことができます。LEA is great for saving MOV instructions by doing shift+add and a mov all in one instruction, using the addressing mode syntax and machine-code encoding.
。代わりに、アドレスからの読み込みのために、それはそうlea (%edi, %eax), %eax
が働くだろう。先のアドレスを格納LEAを除いie eax = sum + (a x 4bits)
はあなたがそこに何を言ってるのか見当もつかないが、aが4バイト(ないビット)である。。言っていない、とあなたは何によって(%のEDI)を乗じていない。
楽しみのためだけに、ここでの方法です私はあなたの関数を書くだろう(もし私が避けなければならなかったimul %edi, %esi
/mov %esi, %eax
)。私は両方の引数が非負であると仮定し、単純にしておきます。 argsが符号付き整数の場合、b
が負の場合は-b
回ループする必要があります。追加コードが必要です。
# args: int a(%edi), int b(%esi) # comments are important for documenting inputs/outputs to blocks of code
# return value: product in %eax
# assumptions: b is non-negative.
times:
xor %eax, %eax # zero eax
test %esi, %esi # set flags from b
jz loop_end # early-out if it's zero
loop: # do{
add %edi, %eax # sum += a,
dec %esi # b-- (setting flags based on the result, except for CF so don't use ja or jb after it)
jge loop # }while(b>=0)
loop_end:
ret
インデントスタイルに注意してください。そのため、分岐ターゲットを簡単に見つけることができます。ループ内で命令のために余分なインデントを行う人もいます。
あなたのやり方はうまくいきますが(正しい場合)、私のやり方では、asm(余分なレジスタや上限を保持する必要はありません)ではカウントダウンが簡単です。また、冗長な比較を避ける。しかし、少なくとも動作するコードを書くのが快適になるまで、最適化について心配する必要はありません。
これは擬似コードであり、念頭に置いてください。
mov X,ebx <- put into EBX your counter, your B
mov Y,edx <- put into EDX your value, your A
mov 0,eax <- Result
loop:
add eax,edx
dec ebx
jnz loop <- While EBX is not zero
上記の実装は、EAXへの貴重な価値をもたらします。あなたのコードは、eaxの初期化が欠落しているようです。
EBXを使用する場合は、発信者の値を保存/復元する必要があります。それでOPはECXを使用したのです。しかし、あなたはEAXが最初からガベージを保持していることは間違いありません。それはOPコードの問題の1つです。 –
コードを削除して質問をしないでください。それは無意味な答えになります。 –