目录
ELF (Executable and Linkable Format)文件
GCC编译链接过程:
gcc -E hello.c -o hello.i
gcc -S hello.i –o hello.s
gcc –c hello.s –o hello.o //-c只编译不链接
gcc hello.s –o hello //链接,生成可执行文件
/*其他gcc编译选项*/
-static // 静态编译,禁止使用动态链接库
-shared // 生成动态链接库,尽可能的链接动态链接库
-L dir // 动态链接库的搜索路径
-lname // 小写l 向gcc传入一个依赖的库文件,可能是动态库 or 静态库。库的实际名称:lib[name].so or lib[name].a
-fpic // 生成位置无关代码, position independent code
-I // 大写的i,添加gcc编译头文件搜索路径
ELF (Executable and Linkable Format)文件
/*elf header*/
#define EI_NIDENT 16
typedef struct elf32_hdr{
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry; /* Entry point */
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
} Elf32_Ehdr;
/*program header table*/
typedef struct elf32_phdr {
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
} Elf32_Phdr;
/*section header table*/
typedef struct elf32_shdr {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
} Elf32_Shdr;
elf header (这个应该是x86 CPU的?, 针对ARM CPU 微小变动?) | ||
---|---|---|
e_ident | 0-3:magic number :0x7f, E, L ,F 4:0)非法,1)32bit,2)64bit 5:0)非法,1)小端, 2)大端 6:verison, must be 1 7-15: 未使用字节, must be 0 | |
e_type | 文件类型: ET_NONE(0):未知的文件格式; | |
e_machine | ET_NONE(0):未知的处理器架构; EM_M32(1):AT&T WE 32100; EM_SPARC(2):SPARC; EM_386(3):Intel 80386; EM_68K(4):Motorola 68000; EM_88K(5):Motorola 88000; EM_860(6):Intel 80860; EM_MIPS(7):MIPS RS3000大端; EM_MIPS_RS4_BE(10):MIPS RS4000大端; 其他,预留; | |
e_version |
| |
e_entry | 程序的虚拟入口地址,如果文件没有对应的入口可以为0; | |
e_phoff | program header table offest | |
e_shoff | section header table offest | |
e_flags | 处理器相关标志位 | |
e_ehsize | ELF文件头大小; | 52bytes |
e_phentsize | program header table 中单项的大小 | |
e_phnum | program header table 总项数 | |
e_shentsize | section header table 中单项的大小 | |
e_shnum | section header table 总项数 | |
e_shstrndx | section header table 中 节名称字符串表 所在节的索引; |
program header table | ||
---|---|---|
p_type | PT_NULL(0):当前项未使用,项中的成员是未定义的,需要忽略当前项; | PT_LOAD(1): 代码段 PT_LOAD(1): 数据段 PT_DYNAMIC(2): (如果 -staic静态编译,不包含该段) PT_INTERP(3): 【就是一个字符串,程序解释器的绝对路径,如下图占用19(0x13)个字节存储该路径】 PT_NOTE(4): PT_PHDR(6):【如下图:32 * 9 = 0x120个字节】 |
p_offset | 当前段相对于 文件的offest | |
p_vaddr | 该段映射到虚拟地址的起始地址 | |
p_paddr | 对于linux来说没用? | ??? |
p_filesz | 段在文件中占用的大小 | |
p_memsz | 段在内存中占用的大小 | |
p_flags | 段的相关标志 | |
p_align | 段加载到内存中,起始地址的对齐大小 |
section header table | ||
---|---|---|
sh_name | 节的名称在 .shstrtab 中的index | 系统自带的section 的名称都是 . 开头。 自定义的section 不使用 . 开头。 |
sh_type | SHT_NULL(0):当前节是非活跃的,没有一个对应的具体的节内存; | |
sh_flags |
| |
sh_addr | 如果当前节需要被装载到内存,则当前项存储当前节映射到内存的首地址,否则应该为0; | |
sh_offset | 相对于的文件的offest | |
sh_size | section 的大小 | |
sh_link | 该section 依赖的 section 的index | |
sh_info | section 的附加信息 | |
sh_addralign | 地址对齐 | |
sh_entsize | 某些节是一个数组,此项表示数组每一项的大小 | ES 列 |
符号表
typedef struct elf32_sym{
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
} Elf32_Sym;
elf32_sym | ||
---|---|---|
st_name | 符号名称,是符号名在字符串表中的index; | |
st_value | 对于应用程序和共享库来说,其为符号的链接地址。 | 对于.symtab里面的符号,编译链接时确定。 对于.dynsym里面的符号,动态链接时确定。 |
st_size | 符号大小??? | |
st_info | 符号属性,符号类型 | |
st_other | ||
st_shndx | 仅仅对于重定位文件有用 |
静态库( .a)
-
静态库是一组 目标文件( .o)的集合,多个目标文件打包形成的文件;
-
linux静态库链接命名: lib[real_name].a
生成静态库:
gcc -c function1.c function1.o //生成REL (Relocatable file)
gcc -c function2.c function2.o //生成REL (Relocatable file)
ar -crv libfunction.a function1.o function2.o //ar是打包工具
// .a 和 .o 文件 使用readelf工具查看, 都属于 REL (Relocatable file) 文件
动态链接库 ( .so)
- 动态库在内存中只有一份,所有进程共享。(数据段每个进程都有一份,代码指令共享)
- 动态库跨进程共享,需要内核的支持。进程的虚拟地址映射到相同的页面上,该页面存放了共享库。
- linux默认的库文件搜索路径: ./lib /usr/lib
- 配置动态链接库的搜索路径的环境变量:LD_LIBRARY_PATH,该环境变量不是默认缺省的配置。
-
LD_LIBRARY_PATH环境变量存放的也是目录列表,目录之间用冒号:分隔,最后的圆点.表示当前目录,与PATH的格式相同,export LD_LIBRARY_PATH=目录1:目录2:目录3:......目录n:.
-
-
动态库的调用
-
显示调用
-
隐式调用
-
参考链接
1. https://blog.csdn.net/GrayOnDream/article/details/124564129