8

この質問は、私が以前に尋ねた別の質問に続くものです。要するに、これは2つの完全にリンクされた実行可能ファイルを1つの完全にリンクされた実行可能ファイルにマージする私の試みの1つです。違いは、前の質問がオブジェクトファイルを完全にリンクされた実行可能ファイルにマージすることを扱っていることです。これは、手動で再配置を処理する必要があることを意味するため、さらに困難です。

私が持っているのは次のファイルです:

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が、さらに別のmainとを含む最終的な実行可能ファイルを生成することfunc1です。

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

これを解決するために私がしたことは、example-targetプログラムで分析して、各セクションのロードアドレスとサイズのリストを取得することでした。次に、同じことを行い、この情報を使用してリンカーコマンドexample-embed動的に生成しました。このコマンドにより、すべてのセクションがのどのセクションとも重複しないアドレスでリンクされるようになります。したがって、実際にはこのプロセスで2回完全にリンクされます。1回はセクションの数とサイズを決定するため、もう1回はセクションとの衝突がないことを保証するためにリンクします。example-embed.cexample-targetexample-embedexample-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

(セクション名の衝突を避けるために、セクション名の前に.newusingを付けていることに注意してください。)objcopy --prefix-sections=.new example-embedobj

次に、新しい実行可能ファイルを生成するためのコードを作成しました(objcopySecurity Warriorbookの両方からコードを借用しました)。新しい実行可能ファイルには次のものが必要です。

  • のすべてのセクション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および)が必要です。embedbfdobfd

  • format / arch / mach/fileフラグと開始アドレスをからibfdにコピーしますobfd
  • ibfdとの両方からのセクションを定義embedbfdしますobfd。BFDでは、すべてのセクションが作成される前に作成されることが義務付けられているため、セクションの作成は個別に行われます。
  • 両方の入力BFDのプライベートデータを出力BFDにマージします。BFDは多くのファイル形式よりも一般的な抽象概念であるため、基になるファイル形式に必要なすべてを包括的にカプセル化できるとは限りません。
  • ibfdとのシンボルテーブルで構成される結合シンボルテーブルを作成し、embedbfdこれをのシンボルテーブルとして設定します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

私のシステムで1708は、次のelf.cとおりです。

BFD_ASSERT (elf_dynsymtab (abfd) == 0);

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

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

私はELFレイヤーに精通していませんが、これは動的シンボルテーブルを読み取る際の問題であると思います(または、おそらく存在しないと言っています)。とりあえず、必要な場合を除いて、ELFレイヤーに直接手を伸ばさなくても済むようにしています。私のコードまたは概念のいずれかで、私が間違っていることを誰かに教えてもらえますか?

役立つ場合は、リンカーコマンド生成のコードまたはサンプルバイナリのコンパイル済みバージョンを投稿することもできます。


これは非常に大きな質問であると認識しており、そのため、私を助けてくれる人には適切に報酬を与えたいと思います。誰かの助けを借りてこれを解決することができれば、500以上のボーナスを授与できてうれしいです。

4

1 に答える 1

1

なぜこれをすべて手動で行うのですか?すべてのシンボル情報(バイナリを適切な方法で編集する場合に必要)があるとすると、実行可能ファイルを個別のオブジェクトファイル(たとえば、関数ごとに1つのオブジェクトファイル)に分割する方が簡単ではないでしょうか。編集して、再リンクしますか?

于 2012-03-15T16:03:44.350 に答える