2012-08-27 10 views
6

外部依存関係がなく、constデータセクションのみのCファイルがあるとしましょう。私はこのファイルをコンパイルして、関数ポインタを使って関数を使用する別のプログラムでロードできるバイナリBLOBを取得します。バイナリコードのオブジェクトファイル

のは例を見てみましょう、ここで私はそれが、その後f1.bin、f1.oし、コンパイル、およびprog内でこの ようにそれを使用したい

static const unsigned char mylut[256] = { 
    [0 ... 127] = 0, 
    [128 ... 255] = 1, 
}; 

void f1(unsigned char * src, unsigned char * dst, int len) 
{ 
    while(len) { 
     *dst++ = mylut[*src++]; 
     len--; 
    } 
} 

fictionnalバイナリモジュール、f1.cです.c

int somefunc() { 
    unsigned char * codedata; 
    f1_type_ptr f1_ptr; 
    /* open f1.bin, and read it into codedata */ 

    /* set function pointer to beginning of loaded data */ 
    f1_ptr =(f1_type_ptr)codedata; 

    /* call !*/ 
    f1_ptr(src, dst, len); 
} 

私はf1.cからf1.oに行くと、位置の独立性を得るために-fPICが必要になると思います。 f1oからf1.binに行くのに、 を使用できるフラグまたはリンカースクリプトは何ですか?

説明:

私はダイナミックリンクについて知っています。動的リンクはこの場合不可能です。リンクステップは、可能であれば、ロードされたデータにキャストfuncポインタである必要があります。

OSがサポートされていないものとします。もし可能であれば、私は例えば のf1をPC関連のアドレスでアセンブリに書きます。

+0

は、あなたが共有オブジェクト・ファイルを使用することができることを知っていますか? .cファイルを.soにコンパイルした後、 'dlopen()'をプログラムにロードし、関数ポインタ 'dlsym()'を関数に渡します。その後、それを呼び出すことができます。 –

+0

libcとダイナミックリンクを忘れましょう – shodanex

+0

'f1.bin'は動的に(つまり実行時に)ロードされますか?次に、共有ライブラリを構築し、ldopen()+ ldsym()または他のモジュールローダー(gmoduleなど)を使用する必要があります。何か他の方法でやろうとすると、潜在的なセキュリティの脅威(データセグメントの実行など)のために難しくなり、拒否される可能性があります。 –

答えて

2

共有ライブラリ(Windowsの場合.dll、Linuxの場合は.so)を構築することを検討する必要があります。

このようなlibにビルドします:あなたのコードから動的ライブラリをロードしたい場合は、機能のdlopen(3)たdlsym(3)を見て

gcc -c -fPIC test.c 
gcc -shared test.o -o libtest.so 

を。

それともあなたがプログラムを、コンパイル時にライブラリをリンク構築したい場合は

gcc -c main.c 
gcc main.o -o <binary name> -ltest 

編集:私は本当に私は何を言われてについてはよく分からない

ここでは、これはあなたの研究の進歩の手がかりを与えることができる...

dlsymをのdlopenと、あなたは、関数のアドレスを見つけるためにの.oファイルからシンボルテーブルを読み込むしようとすることができ、その後、のmmap読むと、メモリ内のオブジェクト・ファイルと実行権限を。そして、あなたが見つけたアドレスでロードされたコードを実行できるはずです。しかし、このコードであなたが満たすことができる他の依存関係には注意してください。他のあなたはDLLまたはSOを使用して検討すべきであると述べたとしてあなたは、manページのすべてのelf(5)

+0

私は正確に動的リンクを使いたくないので、それに応じて質問を編集しました – shodanex

+0

** dlopen **と** dlsym **は動的リンクを意味しません(あなたのプログラムはライブラリにリンクされないので、それに依存しておらず、図書館は編集中には必要ない)。関数** dlopen **はライブラリをロードし、** dlsym **はあなたが提供したシンボル名に基づいて関数のアドレスを返します。 – phsym

+0

dlsymは、ライブラリファイルを分析し、マッピングなどを実行するために、OS提供のダイナミックリンカを呼び出すことを意味します。 – shodanex

6

ファーストをチェックすることができます

あなたが本当にこれをしたい場合は、リンカースクリプトを置き換える必要があります。このような何か(非常によくテストされていませんが、私はそれがうまくいくと思う):次に

ENTRY(_dummy_start) 
SECTIONS 
{ 
    _dummy_start = 0; 
    _GLOBAL_OFFSET_TABLE_ = 0; 
    .all : { 
     _all = .; 
     LONG(f1 - _all); 
     *(.text .text.* .data .data.* .rodata .rodata.*) 
    } 
} 

でコンパイルします。

$ gcc -c -fPIC test.c 

とのリンク:

$ ld -T script.ld test.o -o test.elf 

とのバイナリブロブを抽出:

$ objcopy -j .all -O binary test.elf test.bin 

おそらくsomスクリプトの説明を歓迎します:

  • ENTRY(_dummy_start)これで、プログラムがエントリポイントを持たないという警告が表示されなくなりました。
  • _dummy_start = 0;これは、前の行で使用されたシンボルを定義します。値は使用されません。
  • _GLOBAL_OFFSET_TABLE_ = 0;これは、別のリンカーエラーを防ぎます。私はあなたが本当にこのシンボルが必要と思わないので、0と定義することができます。
  • .allこれはあなたのBLOBのすべてのバイトを集めるセクションの名前です。このサンプルでは、​​すべて.text,.dataおよび.rodataセクションが一緒になります。あなたが複雑な機能を持っている場合は、さらに多くのものが必要かもしれません。この場合、objdump -x test.oはあなたの友人です。
  • LONG(f1 - _all)本当に必要はありませんが、あなたの関数のblobへのオフセットを知りたいですか?オフセット0になると仮定することはできません。この行では、ブロブの最初の4バイトはシンボルf1(あなたの関数)のオフセットになります。 64ビットポインタを使用している場合は、LONGQUADに変更してください。

UPDATE:そして今quick'n'dirtyテスト(それが動作します!):

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/mman.h> 

typedef void (*f1_t)(char *a, char *b, int len); 
f1_t f1; 

int main() 
{ 
    char *blob = (char*)valloc(4096); 
    FILE *f = fopen("test.bin", "rb"); 
    fread(blob, 1, 4096, f); 
    fclose(f); 

    unsigned offs = *(unsigned*)blob; 
    f1 = (f1_t)(blob + offs); 
    mprotect(blob, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); 
    char txt[] = "¡hello world!"; 
    char txt2[sizeof(txt)] = ""; 
    f1(txt, txt2, sizeof(txt) - 1); 
    printf("%s\n%s\n", txt, txt2); 
    return 0; 

} 
+0

他のシンボル(標準ライブラリなど)作られています。 – AProgrammer

+0

@AProgrammer:しかし、OPは具体的には_no external dependency_と言っているので、おそらく必要ありません。もし彼がどんな図書館にもアクセスするならば、彼は静的にBLOB内のすべての図書館をリンクしなければならないでしょう。 – rodrigo

関連する問題