大话 elf 格式! -- 可连接elf 格式
来源:互联网 发布:dota2和lol的区别 知乎 编辑:程序博客网 时间:2024/06/09 04:01
生成一个bin文件,一个连接elf, 一个共享elf文件
elf 格式,网上内容介绍的不少, 能不能结合一种实际的,简单的练习来说明事情.
这里,我需要一个魔法棒,变出一个简单的可连接elf文件 和一个简单的可共享elf文件!
练习:
$ echo 1234 |xxd -r -ps > 1.bin$ objcopy -I binary -O elf64-x86-64 -B i386 1.bin 1.o$ gcc -shared -o 1.so 1.o
简单的3条命令,生成了3个文件
1.bin (二进制文件)
1.o( 可连接elf文件)
1.so( 动态连接库elf文件).
此处应有掌声!
注意, objcopy 不使用-B 指明 arch, 可以生成1.o, 但连接为动态库会出问题.
$ objcopy -I binary -O elf64-x86-64 1.bin 1.o$ gcc -shared -o 1.so 1.o/usr/bin/ld: unknown architecture of input file `1.o' is incompatible with i386:x86-64 outputcollect2: error: ld returned 1 exit status
看一看文件大小.
$ ll 1.*-rw-rw-r-- 1 hjj hjj 8 6月 26 11:35 1.bin-rw-rw-r-- 1 hjj hjj 610 6月 26 12:21 1.o-rwxrwxr-x 1 hjj hjj 7828 6月 26 11:54 1.so*
我简单的8个bytes二进制文件, 竟生成了610字节的可连接文件,
更可怕的是生成了近8K 的可加载文件, 这些文件内容都是什么呢?
连接elf 是可以供gcc 或 ld 连接成执行文件或共享对象的文件.
可连接文件概揽.
objdump -s 1.o1.o: file format elf64-x86-64Contents of section .data: 0000 12345678 9abcdef0 .4Vx....
$ xxd 1.o0000000: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF............0000010: 0100 0000 0100 0000 0000 0000 0000 0000 ................0000020: 0000 0000 0000 0000 7000 0000 0000 0000 ........p.......0000030: 0000 0000 4000 0000 0000 4000 0500 0200 ....@.....@.....0000040: 1234 5678 9abc def0 002e 7379 6d74 6162 .4Vx......symtab0000050: 002e 7374 7274 6162 002e 7368 7374 7274 ..strtab..shstrt0000060: 6162 002e 6461 7461 0000 0000 0000 0000 ab..data........0000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................0000080: 0000 0000 0000 0000 0000 0000 0000 0000 ................0000090: 0000 0000 0000 0000 0000 0000 0000 0000 ................00000a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................00000b0: 1b00 0000 0100 0000 0300 0000 0000 0000 ................00000c0: 0000 0000 0000 0000 4000 0000 0000 0000 ........@.......00000d0: 0800 0000 0000 0000 0000 0000 0000 0000 ................00000e0: 0100 0000 0000 0000 0000 0000 0000 0000 ................00000f0: 1100 0000 0300 0000 0000 0000 0000 0000 ................0000100: 0000 0000 0000 0000 4800 0000 0000 0000 ........H.......0000110: 2100 0000 0000 0000 0000 0000 0000 0000 !...............0000120: 0100 0000 0000 0000 0000 0000 0000 0000 ................0000130: 0100 0000 0200 0000 0000 0000 0000 0000 ................0000140: 0000 0000 0000 0000 b001 0000 0000 0000 ................0000150: 7800 0000 0000 0000 0400 0000 0200 0000 x...............0000160: 0800 0000 0000 0000 1800 0000 0000 0000 ................0000170: 0900 0000 0300 0000 0000 0000 0000 0000 ................0000180: 0000 0000 0000 0000 2802 0000 0000 0000 ........(.......0000190: 3a00 0000 0000 0000 0000 0000 0000 0000 :...............00001a0: 0100 0000 0000 0000 0000 0000 0000 0000 ................00001b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................00001c0: 0000 0000 0000 0000 0000 0000 0300 0100 ................00001d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................00001e0: 0100 0000 1000 0100 0000 0000 0000 0000 ................00001f0: 0000 0000 0000 0000 1500 0000 1000 0100 ................0000200: 0800 0000 0000 0000 0000 0000 0000 0000 ................0000210: 2700 0000 1000 f1ff 0800 0000 0000 0000 '...............0000220: 0000 0000 0000 0000 005f 6269 6e61 7279 ........._binary0000230: 5f31 5f62 696e 5f73 7461 7274 005f 6269 _1_bin_start._bi0000240: 6e61 7279 5f31 5f62 696e 5f65 6e64 005f nary_1_bin_end._0000250: 6269 6e61 7279 5f31 5f62 696e 5f73 697a binary_1_bin_siz0000260: 6500 e.
结合 readelf -a 1.o
可以分析出这个1.o 文件,
还好,该文件只添加了elf 头部信息, 并添加了3个符号, 还算一种紧凑的格式.
节区划分,
$ readelf -S 1.oThere are 5 section headers, starting at offset 0x70:Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .data PROGBITS 0000000000000000 00000040 0000000000000008 0000000000000000 WA 0 0 1 [ 2] .shstrtab STRTAB 0000000000000000 00000048 0000000000000021 0000000000000000 0 0 1 [ 3] .symtab SYMTAB 0000000000000000 000001b0 0000000000000078 0000000000000018 4 2 8 [ 4] .strtab STRTAB 0000000000000000 00000228 000000000000003a 0000000000000000 0 0 1
第一个空节区可以看做是elf-header占位区,64byte
构造了一个.data 节区,
.data 区8个字节, 顶起了这610个字节的可连接elf文件,
.shstrtab 表是必须有的,
符号表区sh_link表示使用的字符串表的段下标。
符号表区sh_info为2,说明本地符号最大下标是1.
符号的概念
符号是为连接而生的. 创建符号是为了引用符号,也有符号仅为显示信息.
你一定要深刻理解”符号”的概念哦.
符号有名称和值的概念, 符号有类型,
变量和函数地址都可以用符号来表达, 外部变量,外部函数都是用外部符号表示的.
外部符号地址为0, 表示现在还不能确定它们的具体地址.
节名称, 文件名称也可以用符号来表达.
符号表:
$ readelf -s 1.oSymbol table '.symtab' contains 5 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 SECTION LOCAL DEFAULT 1 2: 0000000000000000 0 NOTYPE GLOBAL DEFAULT 1 _binary_1_bin_start 3: 0000000000000008 0 NOTYPE GLOBAL DEFAULT 1 _binary_1_bin_end 4: 0000000000000008 0 NOTYPE GLOBAL DEFAULT ABS _binary_1_bin_size
它包含了5个符号,
typedef struct
{
Elf64_Word st_name; /* Symbol name (string tbl index) */
unsigned char st_info; /* Symbol type and binding */
unsigned char st_other; /* Symbol visibility */
Elf64_Section st_shndx; /* Section index */
Elf64_Addr st_value; /* Symbol value */
Elf64_Xword st_size; /* Symbol size */
} Elf64_Sym;
0,1 是无名的, 有的符号无名!, 0 是固定的空, 1是节区名称,因其index为1,故知是”.data”区
三个有名符号_binary_1_bin_start,_binary_1_bin_end,_binary_1_bin_size
意义也很明确,分别表示二进制数据的开始位置,结束位置和大小.
_binary_1_bin_size 开始位置被定义为0, 将来会被重定位, size 是ABS (absolute 符号)
定义符号是为了将来有人使用, 就这样了.!
我忽然想把 .strtab 从.o 文件中提取出来, 好查一下,到底有多少个字符串!
我用如下命令:
最简单的可连接文件. 再小就不是标准elf了,
hjj@hjj-Inspiron:~/MyTest/test6$ ll str1.o -rw-rw-r-- 1 hjj hjj 208 6月 26 12:09 str1.ohjj@hjj-Inspiron:~/MyTest/test6$ xxd str1.o0000000: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF............0000010: 0100 3e00 0100 0000 0000 0000 0000 0000 ..>.............0000020: 0000 0000 0000 0000 5000 0000 0000 0000 ........P.......0000030: 0000 0000 4000 0000 0000 4000 0200 0100 ....@.....@.....0000040: 002e 7368 7374 7274 6162 0000 0000 0000 ..shstrtab......0000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................0000060: 0000 0000 0000 0000 0000 0000 0000 0000 ................0000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................0000080: 0000 0000 0000 0000 0000 0000 0000 0000 ................0000090: 0100 0000 0300 0000 0000 0000 0000 0000 ................00000a0: 0000 0000 0000 0000 4000 0000 0000 0000 ........@.......00000b0: 0b00 0000 0000 0000 0000 0000 0000 0000 ................00000c0: 0100 0000 0000 0000 0000 0000 0000 0000 ................
hjj@hjj-Inspiron:~/MyTest/test6$ readelf -S str1.oThere are 2 section headers, starting at offset 0x50:Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .shstrtab STRTAB 0000000000000000 00000040 000000000000000b 0000000000000000 0 0 1
进一步阅读:
可连接elf文件重定位信息,
.text,.bss,.rodata节区
section 节头的sh_link, sh_info 信息
readelf -S
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 1] .text PROGBITS 0000000000000000 00000040
0000000000000020 0000000000000000 AX 0 0 1
[ 2] .rela.text RELA 0000000000000000 00000598
0000000000000030 0000000000000018 11 1 8
……
[11] .symtab SYMTAB 0000000000000000 00000478
0000000000000108 0000000000000018 12 9 8
[12] .strtab STRTAB 0000000000000000 00000580
0000000000000014 0000000000000000 0 0 1
重定位表的Link,Info
它的”Link”表示符号表的下标,
它的”Info”表示它作用于哪个段。
比如”.rela.text”, Link=11, Info=1, 符号表从11节取,作用于1节
符号表的Link,Info
符号表Link是说字符串表的索引,
符号表Info 的含义,
经查英文资料,为: One greater than the symbol table index of the last local symbol (binding STB_LOCAL).
是说比本地bind 符号大1, 说明这个文件的本地bind符号(节名)最大为8.
readelf -s 或者 objdump -t 可以看到本地bind符号.
重定位信息是连接器把.o文件 或者加载器把.so文件连接在一起的依据.
一个重定位表同时也是ELF的一个段,那么这个段的类型(sh_type)就是”RELA”类型的,
链接文件.o 中相对位置重定位信息
链接文件.o 中程序如何访问外部全局数据.本地全局数据及本地静态变量.
答: 一视同仁,统一按外部符号处理! 需要重定位信息
访问外部数据,偏移确定不下来. 所以先用0填充,并填写符号重定位信息.
访问本模块数据,虽然地址偏移可以确定, 但由于连接时各模块节会合并, 所以将来地址偏移还是不能确定
访问本地静态变量, 同访问本地模块数据,由于连接时各模块节会合并,所以地址还是不能确定,也需要重新定位.
用法举例: (相对寻址) R_X86_64_PC32
8b 05 00 00 00 00 mov 0x0(%rip),%eax # a
共享对象.so 中的重定位信息.
我们只考虑PIC 的so,此是linux 下标准的so
so 文件中, 考察其symbol, 只关心size!=0的symbol, size=0是外部符号或系统内部符号,我们无兴趣.
so 文件中, 不能有代码重定位, 只能有数据重定位.
.rela.dyn 重定位 .got 中数据, 通常是外部数据地址,本地数据地址,本地函数地址.
.rela.plt 重定位 .got.plt 中数据, 通常是外部函数地址.
有点cpu例如arm, 把.got, .got.plt 都合并为一个.got
本地数据地址,本地函数地址(绝对地址)由于模块加载位置不同,是需要rebase 的
外地数据地址,外地函数地址由加载器填充.
每定义一个变量或者函数都会引入一个符号, 这个符号叫本地符号, 本地符号其值就是本地地址,
在可连接文件中,对本地符号的引用也是不确定的,也需要重定位信息, 当把它们连接好后,本地符号就没有
作用了,可以把本地符号消除.
- 大话 elf 格式! -- 可连接elf 格式
- 大话 elf 格式! -- 共享elf 格式
- ELF格式
- ELF格式
- ELF格式
- elf格式
- elf格式学习总结
- ELF格式学习笔记
- ELF格式学习
- 文章标题:elf 格式
- 可执行文件elf的格式
- ELF 文件的格式
- elf 格式解析
- elf格式分析
- elf和coff格式
- 目的檔格式 (ELF)
- 目的檔格式 (ELF)
- 关于ELF格式
- MFC线程使用
- LOG4j配置
- 整数划分(递归)
- ubuntu下安装postfix出现configuration界面,但是按确定没反应,就一直卡在配置界面
- ViewPager
- 大话 elf 格式! -- 可连接elf 格式
- iOS开发--项目学习过程知识点集合
- (2)Java语言,JDK,JRE简介
- static关键字 java
- okhttp
- kaldi 中安装GridEngine的一些注意事项
- Spark如何读取Hbase特定查询的数据
- viewPager适配器
- 如何深入理解Java内存回收机制?