2012-01-15 9 views
4

私は興味深い考えがあります。私は単純なバイナリをダンプするためにobjdumpを使用していました。バイナリには多くの関数があります。これらの関数にリンクする別のCプログラムを作成することは可能ですか?入力と出力のパラメータを知っていると仮定します。いくつかの関数を通常のバイナリでリンクすることはできますか?

いくつかのより多くの情報: FILE1:

#include <stdio.h> 

int add(int x,int y) 
{ 
    return x+y; 
} 

int main(int argc, const char *argv[]) 
{ 
    printf("%d\n",add(3,4)); 
    return 0; 
} 

FILE2 test.cの:Test1.cに

#include <stdio.h> 

int main(int argc, const char *argv[]) 
{ 
    printf("%d\n",add(8,8)); 
    return 0; 
} 

gcc test.c -o test.exe 
gcc test1.c test.exe -o test1.exe 

出力:

ld: in test.exe, can't link with a main executable 
collect2: ld returned 1 exit status 

答えて

1

実用的な観点から、オブジェクト(.o)ファイルと実行可能ファイルの間にはほとんど違いがありません。オブジェクトファイルには、アンバウンドシンボルが含まれている可能性があります。実行ファイルには、オブジェクトファイルにそのような制限がないエントリポイントが含まれている必要があります。実行可能ファイルにはより完全なヘッダーがあります。実行可能ファイルには、リンク解決フェーズを経ているため、すべてのジャンプオフセットが解決されています。一部の機能が永久にインライン展開されている可能性があります。

だから理論的には、通常のリンク線ではなく、別の実行可能ファイルから関数を呼び出す実行可能ファイルを作成することができます。主な問題は、2番目の実行可能ファイルにエントリポイント(mainの機能)を持つことができず、(名前が衝突するため)元のファイルとリンクしていることです。

あなたの目標がオリジナルの関数を呼び出すことだけであれば、あなたは示唆していると思われる直接リンクとは異なる方法を使用することをお勧めします。共有ライブラリを作成してLD_PRELOAD環境変数に格納し、元の実行可能ファイルを呼び出す場合は、ライブラリを使用して(おそらく_mainシンボルを使用して)プログラムエントリを効果的にフックし、代替プログラムルーチンを呼び出すことができます。このライブラリは元のバイナリとともにロードされるので、元の関数をすべて呼び出すことができます。

バイナリから関数を呼び出す最も簡単な方法は、実行可能ファイルではなくオブジェクトファイルにリンクすることです。

+0

私は共有ライブラリとLD_PRELOADメソッドに興味があります。私が読むことができる詳細がいくつかありますか? – Patrick

+1

http://stackoverflow.com/questions/426230/what-is-the-ld-preload-trickがあなたを助けてくれるかもしれません... – Jason

+1

ここにいくつかの情報があります:http://lca2009.linux.org.au/slides /172.pdf – Jason

1

確かに、単にヘッダファイルを書くこと正しい関数シグネチャで使用したい関数の宣言を提供し、次にそれを含むあなたの関数を呼び出すCコードモジュールのヘッダファイル。次に、他のオブジェクトファイルをコンパイルしてリンクして、最終実行可能ファイルを作成します。

あなたがダンプしたオブジェクトファイルの関数は、あなたが作業しているプラ​​ットフォーム/コンパイラのABIと呼び出し規約に従っていることを前提としています。独自のエントリポイント(すなわち、main()関数)を含みます。第2の点に関しては、オブジェクトファイルは、基本的にスタンドアロン機能の「ライブラリ」でなければならない。つまり、実行可能ファイルにリンクすることはできません。

+0

私は.oファイルと簡単にリンクできます。しかし、私は実行可能ファイルでこれを実行できるかどうか疑問に思っていました。 – Patrick

+1

ああ、あなたのオブジェクトファイルに 'main()'が含まれているとは言わなかった...働かない、関数ライブラリのオブジェクトファイルでなければならない – Jason

+0

誰かがコンパイラ間の違いに言及する必要がある。 – Mikhail

2

私は恐れていません。

コンパイルされたバイナリファイルは、コード内の各シンボル参照を実行時アドレスに関連付けるリンカによる再配置フェーズで処理されています。

:あなたが再配置可能なオブジェクトにソースコードをコンパイルすることができます

gcc -cを使用
// main.c 
#include <stdio.h> 

int main() 
{ 
    printf("Hello World!"); 
    return 0; 
} 

あなたは違いを見つけるために簡単な実験を行うことができますが、ここでは出力「のHello World」プログラムです

$ gccの-c main.o

$ readelf -s main.o 

Symbol table '.symtab' contains 10 entries: 
    Num: Value Size Type Bind Vis  Ndx Name 
    0: 00000000  0 NOTYPE LOCAL DEFAULT UND 
    1: 00000000  0 FILE LOCAL DEFAULT ABS main.c 
    2: 00000000  0 SECTION LOCAL DEFAULT 1 
    3: 00000000  0 SECTION LOCAL DEFAULT 3 
    4: 00000000  0 SECTION LOCAL DEFAULT 4 
    5: 00000000  0 SECTION LOCAL DEFAULT 5 
    6: 00000000  0 SECTION LOCAL DEFAULT 7 
    7: 00000000  0 SECTION LOCAL DEFAULT 6 
    8: 00000000 29 FUNC GLOBAL DEFAULT 1 main 
    9: 00000000  0 NOTYPE GLOBAL DEFAULT UND printf 

main関数の値は、それがまだ移転されていないとLINできることを意味0x0の、あるここからあなたが見ることができます他の人と結婚する。

しかし、ときにgccコマンドでファイルをコンパイルし、生成された実行可能なものに:

$ gcc main.c 
$ readelf -s a.out | grep main 
    2: 00000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.0 (2) 
    39: 00000000  0 FILE LOCAL DEFAULT ABS main.c 
    51: 00000000  0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_ 
    62: 080483c4 29 FUNC GLOBAL DEFAULT 13 main 

今、あなたは関数mainのアドレスは、関数の実行時のアドレスである、0x80483c4に移転されています見ることができますコード。 a.outの生成は、他のものとリンクすることができなくなりました。これは実行時アドレス違反があるためです。

一般に、再配置フェーズはフェーズの後に失われるため、元に戻すことはできません。

詳細については、書籍Computer System: A Programmer's Prospectiveのリンク先の章を参照してください。この章は、リンクと再配置に多く含まれています。

+0

本を提案してくれてありがとう!私はそれを調べます。詳しい説明は – Patrick

+0

+1です。 –

関連する問題