私は最近、バッファとさまざまなアセンブリ演算子の RAW 16 進数に相当するものを使用して、C++ で動的関数を実装しようとしています。簡単なジャンプを説明するには:
byte * buffer = new buffer[5];
*buffer = '0xE9'; // Hex for jump
*(uint*)(buffer + 1) = 'address destination';
私は組み立ての経験はありませんが、非常に単純な機能を作成するのに十分な知識があります。現在、生メモリに cdecl 関数を作成しています。問題は、スタックを(メモリ用に)どれだけプッシュしたいのかわからないことですsub
。例として、この関数を見てみましょう:
int MyTest(int x, int y) { return x + y; }
long TheTest(int x, int y)
{
return MyTest(x, 5);
}
08048a20 <_Z6TheTestii>:
_Z6TheTestii():
8048a20: 55 push %ebp
8048a21: 89 e5 mov %esp,%ebp
8048a23: 83 ec 18 sub $0x18,%esp
8048a26: c7 44 24 04 05 00 00 movl $0x5,0x4(%esp)
8048a2d: 00
8048a2e: 8b 45 08 mov 0x8(%ebp),%eax
8048a31: 89 04 24 mov %eax,(%esp)
8048a34: e8 c2 ff ff ff call 80489fb <_Z6MyTestii>
8048a39: c9 leave
8048a3a: c3 ret
ご覧のとおり、最初は C++ コードで、以下は「TheTest」関数の ASM です。スタックが 24 (0x18) バイトにプッシュされていることがすぐにわかります (前述のように、私はアセンブリの使用経験がないため、正しい用語を使用していないか、完全に正しいとは限りません)。これは私には意味がありません。2 つの異なる整数のみが使用されているのに、なぜ 24 バイトが必要なのですか? 変数 'x' が使用され、これは 4 バイトであり、値 '5' も 4 バイトを使用します (これは cdecl であるため、呼び出し関数が関数の引数に関するメモリを処理することを思い出してください) 24 を補いません... .
ここで、アセンブリ出力について本当に疑問に思う追加の例を示します。
int NewTest(int x, char val) { return x + val; }
long TheTest(int x, int y)
{
return NewTest(x, (char)6);
}
08048a3d <_Z6TheTestiiii>:
_Z6TheTestiiii():
8048a3d: 55 push %ebp
8048a3e: 89 e5 mov %esp,%ebp
8048a40: 83 ec 08 sub $0x8,%esp
8048a43: c7 44 24 04 06 00 00 movl $0x6,0x4(%esp)
8048a4a: 00
8048a4b: 8b 45 08 mov 0x8(%ebp),%eax
8048a4e: 89 04 24 mov %eax,(%esp)
8048a51: e8 ca ff ff ff call 8048a20 <_Z7NewTestic>
8048a56: c9 leave
8048a57: c3 ret
ここでの唯一の違い (値を除く) は、整数の代わりに「char」(1 バイト) を使用していることです。次にアセンブリ コードを見ると、これはスタック ポインタを 8 バイトだけプッシュします。これは、前の例から16バイトの違いです。徹底した C++ の人間として、何が起こっているのかわかりません。誰かが私にこの件について教えてくれたら本当にありがたいです!
注: ASM の本を読む代わりにここに投稿する理由は、この1 つの関数にアセンブリを使用する必要があるためです。だから、40行のコードのために本全体を読みたくありません...
編集:私はプラットフォーム依存性も気にしません.Linux 32ビットだけを気にします:)