2012-03-15 39 views
8

この質問は私が以前に尋ねたanother questionから続く。要するに、完全にリンクされた2つの実行可能ファイルを1つの完全にリンクされた実行可能ファイルにマージする試みです。違いは、前の質問では、オブジェクトファイルを完全にリンクされた実行可能ファイルにマージすることです。これは、手動で再配置を処理する必要があるためです。2つのバイナリ実行可能ファイルをマージするにはどうすればよいですか?

example-target.c

#include <stdlib.h> 
#include <stdio.h> 

int main(void) 
{ 
    puts("1234"); 
    return EXIT_SUCCESS; 
} 

example-embed.c

#include <stdlib.h> 
#include <stdio.h> 

/* 
* Fake main. Never used, just there so we can perform a full link. 
*/ 
int main(void) 
{ 
    return EXIT_SUCCESS; 
} 

void func1(void) 
{ 
    puts("asdf"); 
} 

私の目標は、最終的な実行可能ファイルを生成するために、これらの2つの実行をマージすることで、私は以下のファイルで持っているもの

example-targetと同じですが、さらにmainfunc1があります。

BFDライブラリの観点からは、各バイナリはセクションのセットから構成されています(とりわけ)。私が直面した最初の問題の1つは、これらのセクションが競合するロード・アドレスを持っていたということです(それをマージすると、セクションが重複するようになります)。

これを解決するために、example-targetをプログラムで分析して、各セクションのロードアドレスとサイズの一覧を取得しました。私はexample-embedについて同じことを行い、example-embed.cのためにlinker commandを動的に生成するためにこの情報を使用しました。すべてのセクションがexample-targetのいずれのセクションとも重複しないアドレスで確実にリンクされています。したがって、example-embedは実際にはこのプロセスで2回完全にリンクされています.1回はセクション数とサイズを決定し、もう一度セクション違反がないと保証するためにexample-targetとリンクします。私のシステムで

、生産リンカのコマンドは次のとおりです。

-Wl,--section-start=.new.interp=0x1004238,--section-start=.new.note.ABI-tag=0x1004254, 
--section-start=.new.note.gnu.build-id=0x1004274,--section-start=.new.gnu.hash=0x1004298, 
--section-start=.new.dynsym=0x10042B8,--section-start=.new.dynstr=0x1004318, 
--section-start=.new.gnu.version=0x1004356,--section-start=.new.gnu.version_r=0x1004360, 
--section-start=.new.rela.dyn=0x1004380,--section-start=.new.rela.plt=0x1004398, 
--section-start=.new.init=0x10043C8,--section-start=.new.plt=0x10043E0, 
--section-start=.new.text=0x1004410,--section-start=.new.fini=0x10045E8, 
--section-start=.new.rodata=0x10045F8,--section-start=.new.eh_frame_hdr=0x1004604, 
--section-start=.new.eh_frame=0x1004638,--section-start=.new.ctors=0x1204E28, 
--section-start=.new.dtors=0x1204E38,--section-start=.new.jcr=0x1204E48, 
--section-start=.new.dynamic=0x1204E50,--section-start=.new.got=0x1204FE0, 
--section-start=.new.got.plt=0x1204FE8,--section-start=.new.data=0x1205010, 
--section-start=.new.bss=0x1205020,--section-start=.new.comment=0xC04000 

(私はセクション名の衝突を避けるためにobjcopy --prefix-sections=.new example-embedobjを使用して.newでセクション名を接頭辞ことに注意してください。)

私はその後、生成するいくつかのコードを書きました新しい実行可能ファイル(objcopySecurity Warriorの両方からいくつかのコードを借用)。新しい実行可能ファイルが持っている必要があります。

  • example-targetのすべてのセクションとexample-embed
  • example-targetからすべてのシンボルとexample-embed

コードのすべてのシンボルが含まれているシンボルテーブルのすべてのセクションを私は書いた:

#include <stdlib.h> 
#include <stdio.h> 
#include <stdbool.h> 
#include <bfd.h> 
#include <libiberty.h> 

struct COPYSECTION_DATA { 
    bfd *  obfd; 
    asymbol ** syms; 
    int  symsize; 
    int  symcount; 
}; 

void copy_section(bfd * ibfd, asection * section, PTR data) 
{ 
    struct COPYSECTION_DATA * csd = data; 
    bfd *    obfd = csd->obfd; 
    asection *  s; 
    long    size, count, sz_reloc; 

    if((bfd_get_section_flags(ibfd, section) & SEC_GROUP) != 0) { 
     return; 
    } 

    /* get output section from input section struct */ 
    s  = section->output_section; 
    /* get sizes for copy */ 
    size  = bfd_get_section_size(section); 
    sz_reloc = bfd_get_reloc_upper_bound(ibfd, section); 

    if(!sz_reloc) { 
     /* no relocations */ 
     bfd_set_reloc(obfd, s, NULL, 0); 
    } else if(sz_reloc > 0) { 
     arelent ** buf; 

     /* build relocations */ 
     buf = xmalloc(sz_reloc); 
     count = bfd_canonicalize_reloc(ibfd, section, buf, csd->syms); 
     /* set relocations for the output section */ 
     bfd_set_reloc(obfd, s, count ? buf : NULL, count); 
     free(buf); 
    } 

    /* get input section contents, set output section contents */ 
    if(section->flags & SEC_HAS_CONTENTS) { 
     bfd_byte * memhunk = NULL; 
     bfd_get_full_section_contents(ibfd, section, &memhunk); 
     bfd_set_section_contents(obfd, s, memhunk, 0, size); 
     free(memhunk); 
    } 
} 

void define_section(bfd * ibfd, asection * section, PTR data) 
{ 
    bfd *  obfd = data; 
    asection * s = bfd_make_section_anyway_with_flags(obfd, 
      section->name, bfd_get_section_flags(ibfd, section)); 
    /* set size to same as ibfd section */ 
    bfd_set_section_size(obfd, s, bfd_section_size(ibfd, section)); 

    /* set vma */ 
    bfd_set_section_vma(obfd, s, bfd_section_vma(ibfd, section)); 
    /* set load address */ 
    s->lma = section->lma; 
    /* set alignment -- the power 2 will be raised to */ 
    bfd_set_section_alignment(obfd, s, 
      bfd_section_alignment(ibfd, section)); 
    s->alignment_power = section->alignment_power; 
    /* link the output section to the input section */ 
    section->output_section = s; 
    section->output_offset = 0; 

    /* copy merge entity size */ 
    s->entsize = section->entsize; 

    /* copy private BFD data from ibfd section to obfd section */ 
    bfd_copy_private_section_data(ibfd, section, obfd, s); 
} 

void merge_symtable(bfd * ibfd, bfd * embedbfd, bfd * obfd, 
     struct COPYSECTION_DATA * csd) 
{ 
    /* set obfd */ 
    csd->obfd  = obfd; 

    /* get required size for both symbol tables and allocate memory */ 
    csd->symsize = bfd_get_symtab_upper_bound(ibfd) /********+ 
      bfd_get_symtab_upper_bound(embedbfd) */; 
    csd->syms  = xmalloc(csd->symsize); 

    csd->symcount = bfd_canonicalize_symtab (ibfd, csd->syms); 
    /******** csd->symcount += bfd_canonicalize_symtab (embedbfd, 
      csd->syms + csd->symcount); */ 

    /* copy merged symbol table to obfd */ 
    bfd_set_symtab(obfd, csd->syms, csd->symcount); 
} 

bool merge_object(bfd * ibfd, bfd * embedbfd, bfd * obfd) 
{ 
    struct COPYSECTION_DATA csd = {0}; 

    if(!ibfd || !embedbfd || !obfd) { 
     return FALSE; 
    } 

    /* set output parameters to ibfd settings */ 
    bfd_set_format(obfd, bfd_get_format(ibfd)); 
    bfd_set_arch_mach(obfd, bfd_get_arch(ibfd), bfd_get_mach(ibfd)); 
    bfd_set_file_flags(obfd, bfd_get_file_flags(ibfd) & 
      bfd_applicable_file_flags(obfd)); 

    /* set the entry point of obfd */ 
    bfd_set_start_address(obfd, bfd_get_start_address(ibfd)); 

    /* define sections for output file */ 
    bfd_map_over_sections(ibfd, define_section, obfd); 
    /******** bfd_map_over_sections(embedbfd, define_section, obfd); */ 

    /* merge private data into obfd */ 
    bfd_merge_private_bfd_data(ibfd, obfd); 
    /******** bfd_merge_private_bfd_data(embedbfd, obfd); */ 

    merge_symtable(ibfd, embedbfd, obfd, &csd); 

    bfd_map_over_sections(ibfd, copy_section, &csd); 
    /******** bfd_map_over_sections(embedbfd, copy_section, &csd); */ 

    free(csd.syms); 
    return TRUE; 
} 

int main(int argc, char **argv) 
{ 
    bfd * ibfd; 
    bfd * embedbfd; 
    bfd * obfd; 

    if(argc != 4) { 
     perror("Usage: infile embedfile outfile\n"); 
     xexit(-1); 
    } 

    bfd_init(); 
    ibfd  = bfd_openr(argv[1], NULL); 
    embedbfd = bfd_openr(argv[2], NULL); 

    if(ibfd == NULL || embedbfd == NULL) { 
     perror("asdfasdf"); 
     xexit(-1); 
    } 

    if(!bfd_check_format(ibfd, bfd_object) || 
      !bfd_check_format(embedbfd, bfd_object)) { 
     perror("File format error"); 
     xexit(-1); 
    } 

    obfd = bfd_openw(argv[3], NULL); 
    bfd_set_format(obfd, bfd_object); 

    if(!(merge_object(ibfd, embedbfd, obfd))) { 
     perror("Error merging input/obj"); 
     xexit(-1); 
    } 

    bfd_close(ibfd); 
    bfd_close(embedbfd); 
    bfd_close(obfd); 
    return EXIT_SUCCESS; 
} 

このコードが何を要約すると、2つの入力ファイル(ibfdおよびembedbfd)を使用して出力ファイル(obfd)を生成します。

  • コピー形式/アーチ/マッハ/ファイルフラグとibfdからobfd
  • にアドレスを開始obfdibfdembedbfdの両方からのセクションを定義します。 BFDは、開始する前にすべてのセクションが作成されることを要求するため、セクションの集団は別々に発生します。
  • 両方の入力BFDのプライベートデータを出力BFDにマージします。 BFDは多くのファイル形式よりも一般的な抽象化であるため、基本的なファイル形式で必要とされるすべてを包括的にカプセル化することはできません。
  • シンボルテーブルibfdembedbfdで構成されるシンボルテーブルを作成し、これをシンボルテーブルobfdに設定します。このシンボルテーブルは、後で再配置情報の作成に使用できるように保存されます。
  • ibfdからobfdまでのセクションをコピーします。セクションの内容をコピーするだけでなく、このステップでは、再配置テーブルの作成と設定も行います。

上記のコードでは、一部の行は/******** */でコメントアウトされています。これらの行はexample-embedのマージを処理します。コメントアウトされている場合、obfdは単にibfdのコピーとして作成されます。私はこれをテストし、それは正常に動作します。しかし、いったん私はこれらの行をコメントしたら、問題が発生し始めます。

完全マージを行う非コメント版では、出力ファイルが生成されます。この出力ファイルはobjdumpで検査でき、両方の入力のセクション、コード、シンボルテーブルがすべてあることがわかります。しかし、objdumpは、と文句を言う:私のシステムでは

BFD: BFD (GNU Binutils for Ubuntu) 2.21.53.20110810 assertion fail ../../bfd/elf.c:1708 
BFD: BFD (GNU Binutils for Ubuntu) 2.21.53.20110810 assertion fail ../../bfd/elf.c:1708 

elf.c1708は次のとおりです。

BFD_ASSERT (elf_dynsymtab (abfd) == 0); 

elf_dynsymtabは用elf-bfd.hでマクロです:

#define elf_dynsymtab(bfd) (elf_tdata(bfd) -> dynsymtab_section) 

私は精通していませんよELF層ですが、これはダイナミックなシンボルテーブルを読むことに問題があると思います。 nt)。当面は、必要な場合を除いて、ELFレイヤーに直接到達する必要はありません。誰かが私のコードで、あるいは概念的に間違っていることを教えてくれますか?

もし有用であれば、私はリンカコマンド生成用のコードまたはサンプルバイナリのコンパイル済みバージョンを投稿することもできます。


私は、これは非常に大きな問題であり、このような理由のために、私はきちんとそれで私を助けることができている人を報いたいことを実現します。私が誰かの助けを借りてこれを解決することができれば、私は500以上のボーナスを授与させていただきます。

+3

なぜこれをやろうとしていますか?動機は何ですか? 2つのバイナリのソースコードはありますか?むしろ愚かなIMHOのようだ。 –

+1

@EdHealトップにあるリンクされた質問を他の質問にしてください。これにはいくつかの根拠があります。 –

+0

@EdHeal:私はターゲットを取り、それにユーザ定義のルーチンを挿入する(example-embedの役割を果たす)静的実行可能エディタを作成しています。そして、新しいバイナリのコードを静的に元に戻す(私はすでに逆アセンブラ/ CFG解析エンジンを作成しており、この注入がパズルの最後の部分であるように任意の指示を編集することもできます)。私が気にする必要がある用途のために、ユーザが定義したルーチンのソースコードにアクセスできるが、ターゲットはアクセスできないと仮定することができます。 –

答えて

1

なぜこれを手動で行うのですか?すべてのシンボル情報があることを考えれば、実行可能ファイルを別のオブジェクトファイル(関数ごとに1つのオブジェクトファイルなど)に分割するほうが簡単ではないでしょうか?編集して再リンクしますか?

+0

実行可能ファイルをソースコードなしのオブジェクトファイルに分割するにはどうすればよいですか?私は、シンボル情報が埋め込みオブジェクトに対して利用可能であると仮定することができますが、ターゲットに対しては使用できません(ただし、この仮定を最初に使用することができれば、それは問題ありません)。 –

+0

ELF実行ファイルは再配置情報とシンボルテーブルの両方を保持できます。両方の要素が存在する場合、シンボルテーブルがデータまたはコードであるかどうかを示すので、実行ファイルをオブジェクトファイルに分割するのは比較的簡単です。また、なぜ*実行可能ファイル*をマージしようとしていますか?オブジェクトファイルを挿入する方が簡単です。 – zvrba

+0

私は実行ファイルをマージしようとしていました。なぜなら、私がもはや移転に対処する必要がなくなったので、もっと簡単になると思ったからです。代わりにオブジェクトファイルを挿入する方法を見つけることができませんでした。実行可能ファイルをオブジェクトファイルに分割する方法は?ご注意いただきありがとうございます。 –

関連する問題