您好,欢迎访问三七文档
1目标文件及链接2C/C++源文件cc1/g++头文件汇编文件as目标文件生成库连接命令文件可重定位模块ldar用户库库列表可执行程序34目标文件是什么样的?目标文件中的内容至少有编译后的机器指令代码、数据。没错,除了这些内容以外,目标文件中还包括了链接时所须要的一些信息,比如符号表、调试信息、字符串等。5目标文件的格式(ABI)?符号修饰标准、变量内层布局、函数调用方式等这些跟可执行代码二进制兼容性相关的内容称为ABI(ApplicationBinaryInterface)。我们常见的ABI格式:A.outCOFFPEELF一般目标文件将这些信息按不同的属性,以“节”(Section)的形式存储,有时候也叫“段”(Segment)。6a.outexechead.text.data.rel.text.rel.data.symtab.strtabstructexec{unsignedlonga_midmag;unsignedlonga_text;unsignedlonga_data;unsignedlonga_bss;unsignedlonga_syms;unsignedlonga_entry;unsignedlonga_trsize;unsignedlonga_drsize;};a.out是早期unix系统使用的可执行文件格式,由AT&T设计,由其格式和头部结构可以看出,a.out格式非常紧凑,只包含程序运行的必须信息(代码、数据),每个节的顺序是固定的,这种结构这种结构缺乏扩展性,如不能包含“现代”可执行文件中常见的调试信息。现在基本上已被ELF格式取代。A.Out目标文件的格式7COFF(文件头部)OptionHeader(可选文件头部)Section1Header(节头部)……SectionnHeader(节头部)RawDataforSection1(节数据)RawDataforSectionn(节数据)RelocationInfoforSect.1(节重定位数据)RelocationInfoforSect.n(节重定位数据)LineNumbersforSect.1(节行号数据)LineNumbersforSect.n(节行号数据)SymbolTableStringTableCOFF目标文件的格式8ImageDosHeader(IMAGE_DOS_HEADER)ImageDosStubPEFILEHeader(IMAGE_NT_HEADERS)ImageHeader(IMAGE_FILE_HEADER)ImageOptionalHeader(IMAGE_OPTIONAL_HEADER32)SectionTableIMAGE_SECTION_HEADER[].text.data.drective.debug&SothersectionsSymbolTablePE目标文件的格式9ELF头.text.rodata.data.bss.rel.text.rel.data.debug.line.strtab.symtab.shstrtabELF目标文件的格式10intglobal_init_var=84;intglobal_uninit_var;voidfunc1(inti){printf(%d\n,i);}intmain(void){staticintstatic_var=85;staticintstatic_var2;inta=1;intb;func1(static_var+static_var2+a+b);returna;}FileHeader.text.data.bssSimpleSection.c11SimpleSection.o各段信息$objdump-hSimpleSection.oSimpleSection.o:fileformatelf32-i386Sections:IdxNameSizeVMALMAFileoffAlgn0.text0000005b0000000000000000000000342**2CONTENTS,ALLOC,LOAD,RELOC,READONLY,CODE1.data000000080000000000000000000000902**2CONTENTS,ALLOC,LOAD,DATA2.bss000000040000000000000000000000982**2ALLOC3.rodata000000040000000000000000000000982**0CONTENTS,ALLOC,LOAD,READONLY,DATA4.comment0000002a00000000000000000000009c2**0CONTENTS,READONLY5.note.GNU-stack000000000000000000000000000000c62**0CONTENTS,READONLY12$objdump-s-dSimpleSection.o00000000func1:0:55push%ebp1:89e5mov%esp,%ebp3:83ec08sub$0x8,%esp6:8b4508mov0x8(%ebp),%eax9:89442404mov%eax,0x4(%esp)d:c7042400000000movl$0x0,(%esp)14:e8fcffffffcall15func1+0x1519:c9leave1a:c3ret0000001bmain:1b:8d4c2404lea0x4(%esp),%ecx1f:83e4f0and$0xfffffff0,%esp22:ff71fcpushl-0x4(%ecx)25:55push%ebp26:89e5mov%esp,%ebp28:51push%ecx29:83ec14sub$0x14,%esp2c:c745f401000000movl$0x1,-0xc(%ebp)33:8b1504000000mov0x4,%edx39:a100000000mov0x0,%eax3e:8d0402lea(%edx,%eax,1),%eax41:0345f4add-0xc(%ebp),%eax44:0345f8add-0x8(%ebp),%eax47:890424mov%eax,(%esp)4a:e8fcffffffcall4bmain+0x304f:8b45f4mov-0xc(%ebp),%eax52:83c414add$0x14,%esp55:59pop%ecx56:5dpop%ebp57:8d61fclea-0x4(%ecx),%esp5a:c3retSimpleSection.o反汇编代码13ELF文件结构描述ELF头.text.rodata.data.bss.rel.text.rel.data.debug.line.strtab.symtab.shstrtab段头表Elf32_Ehdre_shoffe_shentsizee_shnume_shstrndxElf32_Shdrsh_namesh_addrsh_offsetsh_sizeElf32_Symst_namest_sizest_infost_shndx14ELF文件头typedefstruct{unsignedchare_ident[16];Elf32_Halfe_type;//Elf32_Halfe_machine;Elf32_Worde_version;Elf32_Addre_entry;//Elf32_Offe_phoff;Elf32_Offe_shoff;Elf32_Worde_flags;Elf32_Halfe_ehsize;Elf32_Halfe_phentsize;Elf32_Halfe_phnum;Elf32_Halfe_shentsize;Elf32_Halfe_shnum;Elf32_Halfe_shstrndx;}Elf32_Ehdr;-描述了字的大小-产生此文件的系统的字节次序-目标文件的类型-机器类型-节头表的位置-其它15段头表段头表-目标文件中各节的位置和大小-处于目标文件的末尾ELF头.text.rodata.data.bss.rel.text.rel.data.debug.line.strtab.symtab.shstrtab段头表16-text节被编译程序的机器代码-rodata节诸如printf语句中的格式串和switch语句的跳转表等只读数据-data节已初始化的全局变量-bss节(.comm节)未初始化的全局变量在目标文件中不占实际的空间ELF头.text.rodata.data.bss.symtab.rel.text.rel.data.debug.line.strtab节头表0描述目标文件的节节17typedefstruct{Elf32_Wordsh_name;Elf32_Wordsh_type;Elf32_Wordsh_flags;Elf32_Addrsh_addr;Elf32_Offsh_offset;Elf32_Wordsh_size;Elf32_Wordsh_link;Elf32_Wordsh_info;Elf32_Wordsh_addralign;Elf32_Wordsh_entsize;}Elf32_Shdr;段描述符(SectionheaderDescriptor)每个段描述符都对应一个段18SimpleSection.o段表信息$readelf-SSimpleSection.oThereare11sectionheaders,startingatoffset0x118:SectionHeaders:[Nr]NameTypeAddrOffSizeESFlgLkInfAl[0]NULL0000000000000000000000000[1].textPROGBITS0000000000003400005b00AX004[2].rel.textREL0000000000042800002808914[3].dataPROGBITS0000000000009000000800WA004[4].bssNOBITS0000000000009800000400WA004[5].rodataPROGBITS0000000000009800000400A001[6].commentPROGBITS0000000000009c00002a00001[7].note.GNU-stackPROGBITS000000000000c600000000001[8].shstrtabSTRTAB000000000000c600005100001[9].symtabSYMTAB000000000002d00000f01010104[10].strtabSTRTAB000000000003c00000660000119SimpleSection.o的段表及所有段的位置和长度20符号表&字符串表typedefstruct{Elf32_Wordst_name;Elf32_Addrst_value;Elf32_Wordst_size;unsignedcharst_info;unsignedcharst_other;Elf32_Halfst_shndx;}Elf32_Sym;offset+0+1+2+3+4+5+6+7+8+9+0\0shared\0sw+10ap\0+2021模块之间组装一个程序要想在内存中运行,除了编译之外还要经过链接和装入这两个步骤。从程序员的角度来看,引入这两个步骤带来的好处就是可以直接在程序中使用printf和errno这种有意义的函数名和变量名,而不用明确指明printf和errno在标准C库中的地址。当然,为了将程序员从早期直接使用地址编程的梦魇中解救出来,编译器和汇编器在这当中做出了革命性的贡献。编译器和汇编器的出现使得程序员可以在程序中使用更具意义的符号来为函数和变量命名,这样使得程序在正确性和可读性等方面都得到了极大的
本文标题:目标文件及链接
链接地址:https://www.777doc.com/doc-642677 .html