这个问题是从我之前问过的另一个问题开始的。 简而言之,这是我将两个完全链接的可执行文件合并为一个完全链接的可执行文件的尝试之一。 不同之处在于前一个问题涉及将一个目标文件合并到一个完全链接的可执行文件中,这个文件甚至更难,因为这意味着我需要手动处理重定位。
example-target.c :
#include <stdlib.h> #include <stdio.h> int main(void) { puts("1234"); return EXIT_SUCCESS; }
example-embed.c :
一个程序能读取自己的精灵部分吗?
ELF中的可写/可读段的分配是如何工作的?
文本重定位在共享对象?
#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"); }
我的目标是合并这两个可执行文件,生成一个与example-target相同的可执行文件,另外还有另一个main和func1 。
从BFD库的angular度来看,每个二进制文件都是由一组部分文件组成的。 我遇到的第一个问题是这些部分的加载地址冲突(如果我要合并它们,这些部分会重叠)。
我所做的解决这个问题的方法是通过编程的方式来分析example-target以获得每个部分的加载地址和大小的列表。 然后我做了同样的example-embed并使用这个信息来dynamic生成一个example-embed.c的链接器命令 ,确保它的所有部分链接在不与example-target任何部分重叠的地址上。 因此,在这个过程中example-embed实际上已经完全链接了两次:一次确定它们有多less个部分和多less个大小,再次确保与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为objcopy --prefix-sections=.new example-embedobj前缀部分名称,以避免部分名称冲突。)
然后,我写了一些代码来生成一个新的可执行文件(从objcopy和Security Warrior书借用了一些代码)。 新的可执行文件应该有:
example-target所有部分和example-embed所有部分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,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,&memhunk); bfd_set_section_contents(obfd,memhunk,size); free(memhunk); } } void define_section(bfd * ibfd,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,bfd_section_size(ibfd,section)); /* set vma */ bfd_set_section_vma(obfd,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,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,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 * 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,obfd); */ /* merge private data into obfd */ bfd_merge_private_bfd_data(ibfd,obfd); /******** bfd_merge_private_bfd_data(embedbfd,obfd); */ merge_symtable(ibfd,embedbfd,&csd); bfd_map_over_sections(ibfd,copy_section,&csd); /******** bfd_map_over_sections(embedbfd,&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 outfilen"); 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,obfd))) { perror("Error merging input/obj"); xexit(-1); } bfd_close(ibfd); bfd_close(embedbfd); bfd_close(obfd); return EXIT_SUCCESS; }
总结这段代码的function,需要2个input文件( ibfd和embedbfd )来生成一个输出文件( obfd )。
将格式/ arch / mach /文件标志和起始地址从ibfd到obfd
将ibfd和embedbfd部分定义为obfd 。 部分人口分开发生,因为BFD要求所有部分都是在任何开始填充之前创build的。
将两个inputBFD的私有数据合并到输出BFD。 由于BFD是许多文件格式的通用抽象,它不一定能够全面封装底层文件格式所需的一切。
创build由符号表ibfd和embedbfd组成的组合符号表,并将其设置为obfd的符号表。 这个符号表被保存,所以以后可以用来build立重定位信息。
将部分从ibfd复制到obfd 。 除了复制部分内容之外,这一步还涉及build立和设置重定位表。
在上面的代码中,一些行用/******** */注释掉了。 这些行处理example-embed的合并。 如果他们被注释掉了,那么会发生的是, obfd只是作为ibfd的副本而被ibfd 。 我已经testing了这个,它工作正常。 但是,一旦我把这些问题评论回来,就会发生问题。
使用完整合并的未注释版本,它仍然会生成一个输出文件。 这个输出文件可以用objdump检查,发现有两个input的所有部分,代码和符号表。 但是, 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.c 1708是:
BFD_ASSERT (elf_dynsymtab (abfd) == 0);
elf_dynsymtab是elf-bfd.h一个macros,用于:
#define elf_dynsymtab(bfd) (elf_tdata(bfd) -> dynsymtab_section)
我对ELF层不熟悉,但是我相信这是阅读dynamic符号表的一个问题(或者说它不存在)。 目前,我正试图避免直接进入ELF层,除非有必要。 有人能够在我的代码或概念上告诉我我在做什么错吗?
如果有帮助,我也可以发布链接器命令生成的代码或示例二进制文件的编译版本。
我意识到这是一个非常大的问题,因此,我想适当地奖励任何能够帮助我的人。 如果我能够在某人的帮助下解决这个问题,我很高兴获得500+奖金。
为什么ELF部分之间有空闲空间?
库初始化后从RAM中清除ELF部分
.got和.got.plt部分有什么区别?
为什么所有这些手动? 假设你有所有的符号信息(如果你想以一种理智的方式编辑二进制文件,你必须要这样做),将可执行文件分割成单独的目标文件(比如每个函数有一个目标文件)是不是更容易?编辑并重新链接它?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。