2

簡単に言うと、ELF バイナリの .text セクションを 1 つの関数で表す整数の配列があります。この機能を実行したい。コマンドを実行する前に、次のコマンドを実行しました。

mprotect(function, sHeader.sh_size, PROT_EXEC | PROT_READ | PROT_WRITE);

パーミッションの問題を解決するかもしれないと考えていますが、実行しようとするとセグメンテーション違反が発生します:

int (*fp)(int, int) = (int (*)(int, int))getFunc("t.o");
int a = 2;
int b = 3;
cout << fp(a, b) << "\n";

しかし、実行しようとするとセグメンテーション違反が発生します:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000603010 in ?? ()

私が逃したものはありますか?

実行しようとしている関数の objdump:

0000000000000000 <mult>:
mult():
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   89 7d fc                mov    %edi,-0x4(%rbp)
   7:   89 75 f8                mov    %esi,-0x8(%rbp)
   a:   8b 45 fc                mov    -0x4(%rbp),%eax
   d:   0f af 45 f8             imul   -0x8(%rbp),%eax
  11:   5d                      pop    %rbp
  12:   c3                      retq   
4

2 に答える 2

3

ELFオブジェクト ファイルには再配置情報が含まれており、おそらくその.textセクションには再配置されるコードが含まれているため、コードはそのままでは実行されません。objdumpおよびコマンドを使用して、readelfそれを探索します。本当にこの方法でロードしたい場合は、再配置情報を処理する必要がありますが、これは複雑で、プロセッサー固有で、面倒です。これに何週間も費やしたい場合は、 x86-64 ABIを調べてください。ただし、 then を使用dlopenする.sodlsymがはるかに簡単です (はセグメントを から -eddlopenした後に再配置を行う ため)。以下を参照してください。mmapt.so

x86-64 ABI は以前はhttp://x86-64.org/documentation/abi.pdfにありましたが、そのサイトは現在機能していません。

とはgetFunc? 室内での引越しはどうするt.ot.so共有オブジェクト (たとえば でコンパイル)を持ってから、 dlopen(3)gcc -Wall -fPIC -O -shared t.c -o t.so使用してそれをロードできないのはなぜですか?dlsym(3)

typedef int functionsig_t (int, int);
void* dlh = dlopen("./t.so", RTLD_NOW);
if (!dlh) {
   fprintf(stderr, "dlopen t.so failed with %s\n", dlerror());
   exit(EXIT_FAILURE);
};
functionsig_t* fp = (functionsig_t*) dlsym(dlh, "myfunc");
if (!fp) {
   fprintf(stderr, "dlsym myfunc failed with %s\n", dlerror());
   exit(EXIT_FAILURE),
}
// now you can call fp
int res = (*fp) (1,2);

返されたfpコール スタック フレームが存在しない場合は、任意の関数を使用してからのセグメントを取得できt.soます。特に大量の共有オブジェクトがない場合は、呼び出しを避けることができます(通常、プロセスのアドレス空間のわずかなリークが発生します。pid 1234 のプロセスのファイルを参照してください)。dlclose(dlh);munmapt.sodlclose/proc/1234/mapsdlopen

プラグインがメイン プログラムから関数を呼び出す場合、t.soそのメイン プログラムを-rdynamicオプションにリンクするldか、gcc

t.soC++ ソースからコンパイルされた場合、宣言する必要があります。

 extern "C" int myfunc(int,int);

によって行われた名前マングリングのためg++

私のmanydl.cdlopenプログラムは、Linux プロセスで何十万もの -s を実行できることを示しています。これは、「ランダムな」C コードを生成し、それをいくつかの にコンパイルし、そのファイル.sodlopen-ing し.so、それを何度も繰り返すことによって機能します。

.cまたは.ccコードをプラグインにコンパイルする負担を避けたい場合は、 LLVMasmjitlibjitGNU lightningなど.soを使用したインメモリ ジャスト イン タイム コード生成を検討できます。

于 2013-01-12T08:05:01.593 に答える
2

あなたは引っ越しを逃しています。バイナリには絶対アドレスは含まれていませんが、オフセットが含まれています。

バイナリがロードされると、OS は割り当てられたセグメント アドレスをバイナリのオフセットに追加することによって、関数ポインタ (および他のすべてのシンボル) を再配置します。

于 2013-01-12T08:00:13.980 に答える