先放几张图片
ff@ubuntu:~/app/0$ readelf -a a4
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400430
Start of program headers: 64 (bytes into file)
Start of section headers: 6704 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes) /** ELF文件头的大小, 对应上图的0x40 */
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 32
Section header string table index: 29
如果想减小program的体积,可以删除一些没有必要的section,
这里增加一个section,将一个变量放入到该section中,看,他与其他section不同的是前面没有"."
这是Gcc一个特色,如,把一个函数指针放入到特定的section,然后需要的时候拿出来使用
当然了,可以使用 KEEP 来强制连接器保留一些特定的 section,
如果想让该section中的内容按照名字来排序的话,可以使用SORT
如:
. = ALIGN(8);
KEEP(*(SORT(.scattered_array*)));
如:
const initcall_t *call;
for (call = initcall_begin; call < initcall_end; call++) {
ret = (*call)();
}
看到下面的 .interp section 可把我害惨了,它包含程序解释器的路径名,因为找不到动态连接器,结果整个系统都挂了
好,废话不多说,上正题
ELF Header
/usr/include/elf.h
好吧,下面就看看一个C source code 是怎么经过Gcc LLVM 发生化学变化后产生ELF的,
神奇的数字 8 在这里起不到 8 byte对齐了,好吧,搬起板凳 看戏吧! ? 哈哈
重点关注下面的 st_value 符号值, 看它是这么被生成的
417 typedef struct
418 {
419 Elf64_Word st_name; /* Symbol name (string tbl index) */
420 unsigned char st_info; /* Symbol type and binding */
421 unsigned char st_other; /* Symbol visibility */
422 Elf64_Section st_shndx; /* Section index */
423 Elf64_Addr st_value; /* Symbol value */
424 Elf64_Xword st_size; /* Symbol size */
425 } Elf64_Sym;
符号地址 = 符号所在的段基址 + 符号所在段内偏移
/* 该符号在本文件中未定义 */
if (sym_tab[sym_idx].st_shndx == SHN_UNDEF) {
....
} else
*where = rela->r_addend + sym_tab[sym_idx].st_value + vabase;