少なくとも最適化が有効になっていない場合、関数にはプリアンブルとポストアンブルがあります。それを見てください:
Project46.dpr.13: asm
0041A1F4 55プッシュebp
0041A1F5 8BEC mov ebp,esp
0041A1F7 83C4F8 追加 esp、-$08
0041A1FA 8945F8 mov [ebp-$08],eax
Project46.dpr.14: CMP EAX、0
0041A1FD 83F800 cmp eax,$00
Project46.dpr.15: JNZ 囲碁
0041A200 7506 jnz $0041a208
Project46.dpr.16: MOV EAX、-1
0041A202 B8FFFFFFFF mov eax,$ffffffff
Project46.dpr.17: RET
0041A207 C3 ret
Project46.dpr.19: BSR EBX、EAX
0041A208 0FBDD8 bsr ebx,eax
Project46.dpr.20: MOV EAX、EBX
0041A20B 89D8 mov eax,ebx
Project46.dpr.21: RET
0041A20D C3 ret
Project46.dpr.22: 終わり;
0041A20E 8B45FC mov eax,[ebp-$04]
0041A211 59 ポップ ecx
0041A212 59 ポップ ecx
0041A213 5D ポップ ebp
0041A214 C3 ret
したがって、プリアンブルはスタック フレームを設定します。レジスタを保存し、レジスタとレジスタebp
の両方を変更します。ポストアンブルにも注意してください。保存されたレジスタを復元するには、そのコードを実行する必要があります。ebp
esp
これに対処する通常の方法は、 を使用する代わりに関数の最後にジャンプすることret
です。したがって、次のようにコードを記述します。
function MSb(const Val: Integer): Integer;
asm
CMP EAX, 0
JNZ @@go
MOV EAX, -1
JMP @@exit
@@go:
BSR EBX, EAX
MOV EAX, EBX
@@exit:
end;
このようにして、ポストアンブルが確実に実行されるようにします。プリアンブルが確実に実行されるようにするには、この方法でコードを記述する習慣を身に付ける必要があります。
さて、それ以上に、質問で言及した問題は、実際には asm ラベルではなく Pascal ラベルの使用に関連するコンパイラのバグに関連していると思われます。まあ、これはコンパイラのバグかもしれませんが、Pascal ラベルを使用するのは単なる間違いかもしれません。次のプログラムを検討してください。
{$APPTYPE CONSOLE}
function MSb(const Val: Integer): Integer;
asm
CMP EAX, 0
JNZ @@Go
MOV EAX, -1
JMP @@exit
@@Go:
BSR EBX, EAX
MOV EAX, EBX
@@exit:
end;
function MSb2(const Val: Integer): Integer;
label
Go;
asm
CMP EAX, 0
JNZ Go
MOV EAX, -1
RET
Go:
BSR EBX, EAX
MOV EAX, EBX
end;
begin
Writeln(Msb(0));
Writeln(Msb(1));
Writeln(Msb2(0));
Writeln(Msb2(1));
Readln;
end.
最適化してコンパイルした場合の出力は次のとおりです。
-1
0
-1
4
それで、それはどうですか4
?Msb2
さて、本質的にあなたのコードである のアセンブルされたコードを見てみましょう:
004059E8 83F800 cmp eax,$00
004059EB 7506 jnz $004059f3
004059ED B8FFFFFFFF mov eax,$ffffffff
004059F2 C3 ret
004059F3 0FBDD8 bsr ebx,eax
004059F6 89D8 mov eax,ebx
004059F8 8BC2 mov eax,edx
004059FA C3 ret
いったいなぜ、値edx
が割り当てられていない揮発性レジスタの値がeax
、関数が戻る直前に移動されるのですか。これがあなたが報告している問題です。私の推測では、Pascal ラベルの使用がアセンブラを混乱させているようです。asm ラベルに固執します。
のアセンブルされたコードは次のMsb
とおりです。
004059D4 83F800 cmp eax,$00
004059D7 7506 jnz $004059df
004059D9 B8FFFFFFFF mov eax,$ffffffff
004059DE C3 ret
004059DF 0FBDD8 bsr ebx,eax
004059E2 89D8 mov eax,ebx
004059E4 C3 ret
そのほうが似てる!ここに post-able がないことをコンパイラがどのように認識しているかに注意してjmp @@exit
くださいret
。