問題の声明
「不明な」関数名を書いたとき、どういう意味でしたか? これは、関数の名前、そのパラメーター、そして最終的には呼び出し規約が、プログラムの実行中にのみ知られることを意味します。 彼女に挑戦しましょう! =)
次に、cdecl標準に従って関数を呼び出そうとします。
ウィキペディアの抜粋:
cdecl呼び出し規約は、x86アーキテクチャの多くのCシステムで使用されています。 cdeclでは、関数パラメーターは右から左の順にスタックにプッシュされます。 関数の戻り値はEAXレジスタに返されます(x87レジスタST0に返される浮動小数点値を除く)。 レジスターEAX、ECX、およびEDXは、この関数で使用できます。
一般に、パラメーターはスタックを逆の順序で渡され、結果の値は浮動小数点数を除いてEAXになります-x87疑似スタックになります。
作業計画を作成します。
1)メモリ内にバッファを生成します。これは変更せずに、スタック上のワードごと(4バイト)にできます。
2)呼び出す関数のアドレスを見つける
3)単語に従ってスタックバッファに置く
4)関数を呼び出す
5)結果を引き出す
行こう!
私たちは何を持っています:
1)char * sName-ここに関数の名前があります
2)int N-パラメーターの数
3)enum CParamType {cptNone = 0、cptPointer、cptInt、cptDouble}-可能なデータ型-これまでのところ、これらに限定します
4)CParamType Params []-パラメータタイプのリスト
5)void * ParamList []-実際には、パラメーターを持つ変数へのポインター
6)CParamType RetType-結果データ型
7)void * Ret-結果をスローするメモリへのポインタ
8)enum CCallConvention {cccNone = 0、cccCDecl、cccStdCall、cccFastCall}-呼び出し規約の種類
9)CCallConvention conv-呼び出し規約。 まず、cdecl関数のみを呼び出します
これは、私たちが呼び出す必要がある広告の必要十分なリストです。
C / C ++では、この操作を実装する手段がないため、アセンブラに頼る必要があります。
1.バッファーを作成する
まず、単語の数を数えます。 すべてが単純です-void *、int-4バイト-1ワード、double-8バイト-2ワード。
Copy Source | Copy HTML int WordCount= 0 ; for ( int i= 0 ,i<N,i++) { switch (Params[i]) { case cptPointer: case cptInt: WordCount++; break ; case cptDouble: WordCount+= 2 ; break ; } }
Copy Source | Copy HTML int WordCount= 0 ; for ( int i= 0 ,i<N,i++) { switch (Params[i]) { case cptPointer: case cptInt: WordCount++; break ; case cptDouble: WordCount+= 2 ; break ; } }
Copy Source | Copy HTML int WordCount= 0 ; for ( int i= 0 ,i<N,i++) { switch (Params[i]) { case cptPointer: case cptInt: WordCount++; break ; case cptDouble: WordCount+= 2 ; break ; } }
Copy Source | Copy HTML int WordCount= 0 ; for ( int i= 0 ,i<N,i++) { switch (Params[i]) { case cptPointer: case cptInt: WordCount++; break ; case cptDouble: WordCount+= 2 ; break ; } }
Copy Source | Copy HTML int WordCount= 0 ; for ( int i= 0 ,i<N,i++) { switch (Params[i]) { case cptPointer: case cptInt: WordCount++; break ; case cptDouble: WordCount+= 2 ; break ; } }
Copy Source | Copy HTML int WordCount= 0 ; for ( int i= 0 ,i<N,i++) { switch (Params[i]) { case cptPointer: case cptInt: WordCount++; break ; case cptDouble: WordCount+= 2 ; break ; } }
Copy Source | Copy HTML int WordCount= 0 ; for ( int i= 0 ,i<N,i++) { switch (Params[i]) { case cptPointer: case cptInt: WordCount++; break ; case cptDouble: WordCount+= 2 ; break ; } }
Copy Source | Copy HTML int WordCount= 0 ; for ( int i= 0 ,i<N,i++) { switch (Params[i]) { case cptPointer: case cptInt: WordCount++; break ; case cptDouble: WordCount+= 2 ; break ; } }
Copy Source | Copy HTML int WordCount= 0 ; for ( int i= 0 ,i<N,i++) { switch (Params[i]) { case cptPointer: case cptInt: WordCount++; break ; case cptDouble: WordCount+= 2 ; break ; } }
Copy Source | Copy HTML int WordCount= 0 ; for ( int i= 0 ,i<N,i++) { switch (Params[i]) { case cptPointer: case cptInt: WordCount++; break ; case cptDouble: WordCount+= 2 ; break ; } }
Copy Source | Copy HTML int WordCount= 0 ; for ( int i= 0 ,i<N,i++) { switch (Params[i]) { case cptPointer: case cptInt: WordCount++; break ; case cptDouble: WordCount+= 2 ; break ; } }
Copy Source | Copy HTML int WordCount= 0 ; for ( int i= 0 ,i<N,i++) { switch (Params[i]) { case cptPointer: case cptInt: WordCount++; break ; case cptDouble: WordCount+= 2 ; break ; } }
Copy Source | Copy HTML int WordCount= 0 ; for ( int i= 0 ,i<N,i++) { switch (Params[i]) { case cptPointer: case cptInt: WordCount++; break ; case cptDouble: WordCount+= 2 ; break ; } }
Copy Source | Copy HTML int WordCount= 0 ; for ( int i= 0 ,i<N,i++) { switch (Params[i]) { case cptPointer: case cptInt: WordCount++; break ; case cptDouble: WordCount+= 2 ; break ; } }
Copy Source | Copy HTML int WordCount= 0 ; for ( int i= 0 ,i<N,i++) { switch (Params[i]) { case cptPointer: case cptInt: WordCount++; break ; case cptDouble: WordCount+= 2 ; break ; } }
カウントされます。 メモリを割り当てる:
void* Buffer = new char[4*WordCount];
バッファを埋めます:void *、int-変更せずに置き、単語をダブルスワップします。
Copy Source | Copy HTML
- int offset = 0 ;
- ダブル x;
- for ( int i = 0 、i <N、i ++)
- {
- スイッチ (Params [i])
- {
- ケース cptPointer:
- ケース cptInt:
- *( int *)(buf + offset)= *(( int *)(ParamList [i]));
- オフセット+ = 4 ;
- 休憩 ;
- ケース cptDouble:
- x = *(( double *)(((DTMain *)(v-> T))-> pData));
- memcpy(buf + offset + 4 、&x、 4 );
- memcpy(buf + offset、( char *)&x + 4、4 );
- オフセット+ = 8 ;
- 休憩 ;
- }
- }
コメントすることは何もないと思います。 offset-バッファによるオフセット。
2.関数のアドレスを調べる
ここではすべてが非常に簡単です。
void* addr = dlsym(NULL,sName);
最初のパラメーターはライブラリー記述子です。 現在のコンテキストで検索する場合はNULL。
dlfcn.hを接続し、リンクパラメーターに-ldlを追加することを忘れないでください。
3.単語に従ってバッファをバッファに配置します
ふう。 最も興味深いこと。
スタックを使用するには、当然アセンブラが必要です。 私はgnuコンパイラーを使用しているため、AT&T構文を使用するアセンブラーは機能しません。自分自身はあまり好きではありませんが、選択する必要はありません。
Copy Source | Copy HTML
- asm( "\ <br/> movl $ 0、%% eax; \ <br/> movl%2、%% ebx; \ <br/> movl%3、%% ecx; \ <br/> l1:cmpl% %ecx、%% eax; \ <br/> je l2; \ <br/> pushl(%% ebx、%% eax、4); \ <br/> addl $ 1、%% eax; \ <br/> jmp l1; "
- : "= r" (b)
- : "r" (addr)、 "r" ( バッファー )、 "g" (WordCount)
- : "%eax"
- );
ループを作成します:ecx(WordCount)が0になるまで、単語をスタックに配置してecxを減らします。
4.関数を呼び出します
やる
l2: call *%1;
スタックを埋めた後。 %1は、関数(addr)へのポインターです。
5.結果を返す
2つのオプションがあります:結果全体または分数。 合意によると、デフォルトでは結果は%eaxになりますが、浮動小数点の場合はx87 all-stackになります。
1)結果全体
movl %%eax, %0;
ここで、%0は結果変数です。
2)浮動小数点オプション
理論的には、ここでST(0)から回答を削除する必要があります。 これまでのところ、私はこれを行うことができませんでした。 コメントで可能な解決策を見たいと思います。 事前に感謝します。
さて、それだけです! タスクは本当に簡単ではありませんでした。 誰かがこの投稿を必要としていることを願っています。
PSインタプリタを書くためにこれらすべてが必要です。
_________
テキストはHabraで準備されます
UPD:ソースを強調