3

最近、Visual C++ でインライン アセンブリをいじっていましたが、スタック上のローカル変数に値を直接追加できるかどうか疑問に思っていました。次に例を示します。

push 5
add [esp], 7

これをしても大丈夫ですか?これを行うとランダムにいくつかの奇妙な問題が発生した原因を尋ねています(ただし、ほとんどの場合は正常に機能します)が、レジスタを通過しても、次のように問題はありません。

push 5
mov eax, [esp]
add eax, 7
mov [esp], eax
4

1 に答える 1

0

Vlad Krasnov が質問に対するコメントで述べているように、問題は、コンパイラ (および/またはアセンブラ) が のようなコードの引数のサイズを認識していないことに起因しますadd [esp], 7。この問題は、たとえばadd [esp], eax.

If you were the compiler, how would you interpret this instruction? You are asked to add 7 to the memory location ESP is pointing to. But neither 7, nor [esp] specify how large the arguments for the addition are. A byte? Two bytes? Four bytes? Even 8 bytes would have been a possibility if this wasn't inline assembly (isn't allowed in 64-bit code.)

Note that while ESP is 4 bytes, the memory location it points to can be of any size. The same goes for the immediate value 7, which can fit in any number of bytes.

解決策は、Vlad Krasnov がコメントで再度述べているように、オペランドのサイズを明示的に指定することです。お好みのアセンブラのドキュメントを確認してみてください。この場合、32 ビットの追加が必要な場合は、次のように記述しadd DWORD PTR [esp], 7ます。これは明らかに[esp]、メモリ内の DWORD (MASM では 32 ビット) を指していることを示しています。

また、x86 のすべての命令が、即値メモリ アドレスを含む形式をサポートしているわけではないことに注意してください。各命令について、使用しようとしている命令が実際に存在することを確認するために、" Intel Architectures Software Developer Manual ", volume 2 (命令セットのリファレンス) を確認できます。

また、(インライン アセンブリを使用しているため) コンパイラのアセンブリ出力を常に調べて、コンパイラが生成したコードが実際に意図したものであることを確認する必要があります。アセンブラ コードを生成するようにコンパイラに指示するのは非常に簡単で、非常に読みやすいです。

于 2013-03-22T11:48:49.440 に答える