C/C++代码通过编译后会生成elf文件,里面包含了平台、代码、数据,调试信息等。linux
编译过程参考:https://blog.csdn.net/qq_39815222/article/details/108526580网络
1. elf文件格式
- ELF Header
连接后的elf文件有三种类型,分别是可重定位文件rel(包含适合于与其余目标文件连接来建立可执行文件,或者共享目标文件的代码和数据);可执行文件exec(包含适合于执行的的一个程序,此文件规定了exec()如何建立一个程序的进程映像);共享目标文件dyn(包含可在两种上下文连接的代码和数据,如linux中已.so结尾的文件)
简写为Ehdr, 包含如下信息:
e_ident[**] //elf标识
e_type; //elf类型(上述三种类型)
e_ machine; //目标文件体系类型,即运行架构,如x8六、riscv、arm等
e_version; //目标文件版本
e_entry; //elf入口地址
e_ phoff; //程序头部偏移
e_shoff; //节区头部偏移
e_flags;
e_ehsize; //ELF格式头部大小
e_phentsize; //程序头部表项大小
e_phnum; //程序头表项个数,即segment数
e_shentsize; //节区头部表项大小
e_shnum; //节区表项个数,即section数
e_shstrndx;架构
- Program Header Table
简写为Phdr,包含如下信息:
p_type; //segment类型
p_offset; //segment在文件中的偏移
p_vaddr; //segment虚地址
p_paddr; //物理地址
p_filesz; //文件中segment字节数
p_memsz; //内存中segment字节数
p_flags;
p_align;ide
- segment
内容包括text segment,data segment等,segment包含多个section,
- .text
已编译程序的指令代码段 - .rodata
ro表明read only,表示只读数据 - .data
已初始化的C程序全局变量和静态局部变量。C程序普通变量在运行是被保存在堆栈中,既不在.data中,也不在.bss中,此外,若是变量初始化值为0,也可能会放到bss段。 - .bss
未初始化的C程序变量和静态局部变量。目标文件格式区分初始化和未初始化变量是为了空间效率,在ELF文件中.bss段不占据实际的存储器空间,仅仅是一个占位符。 - .debug
调试符号表,调试器用此段的信息帮助调试
简称sym,包含如下信息:
st_name;
st_value;
st_size;
st_info;
st_other;
st_shndx;函数
- section header table
简称Shdr,包含信息:
sh_name; //节区名称,字符串表索引值
sh_type; //节区种类,如rel*
sh_flags; //
sh_addr; /地址
sh_offset; //输出节区第一个字节偏移
sh_size; //节区大小
sh_link; //给出字节头部表索引连接
sh_info; //给出节区附加信息
sh_addralign; //对齐约束
sh_entsize; //给出对于某些有固定项目的大小,如符号表工具
2. elf的内存加载
实际上,编译后的elf文件的加载在不一样平台上的状况是不同的。url
- 对于含有文件系统和动态加载功能操做系统的CPU
elf文件会经过某种方式(FTP或者网络文件系统)被写入到OS的文件系统。spa
首先先说明一下OS的启动。对该类型CPU来讲,其操做系统kernel已经存储在硬盘中了,上电后bootloader会对CPU进行初始化,随后就会将操做系统镜像加载到SRAM特定的地址,随后CPU整个的控制权所有移交给kernel。操作系统
OS接管系统后,会进一步初始化并挂载文件系统,此时kernel即可加载文件系统中的elf文件。kernel首先将该文件加载到CPU中的SRAM,完成相应的初始化后将控制权交给应用程序。.net
- 对于简单操做系统和无操做系统的CPU
该类型的CPU因为不能提供加载功能,所以在生成elf文件后须要使用二进制处理工具objcopy将elf文件转换成bin文件,而后经过相应的烧写工具将该文件写入flash中。
如有操做系统,则须要将目标程序和OS并在一块儿编译和连接,目标程序只做为操做系统的一个内部函数调用。此状况下,操做系统的启动通常不须要单独的bootloader去加载,在上电完成初始化后就直接跳转到操做系统的代码。
- 对于静态连接的内存加载:
对于以静态连接形式编译的程序,因为其已是一个完整的不依赖于任何其余东西的可执行程序,能够直接被执行。 - 对于动态连接的内存加载工做步骤:
loader程序将elf文件读入内存,而后启动连接器程序根据elf文件头的说明,将其所须要的其余程序段找到读入内存并装配在一块儿(类似段融合,而后从新编排符号表和重定位表,并根据重定位表来作重定位)。装配完后返回loader程序继续执行,而后loader直接跳转到装配完成的程序中的入口地址处执行。
本文分享 CSDN - KGback。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。