源代码:
int printf(const char * format,...);
int global_init_var=84;
int global_uninit_var;
void func1(int i){
printf("%d\n",i);
}
int main(void){
static int static_var=85;
static int static_var2;
int a=1;
int b;
func1(static_var+static_var2+a+b);
return a;
}
头文件结构:
[email protected]:~/c/static$ objdump -h SimpleSection.o
SimpleSection.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000053 00000000 00000000 00000034 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000008 00000000 00000000 00000088 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000004 00000000 00000000 00000090 2**2
ALLOC
3 .rodata 00000004 00000000 00000000 00000090 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .comment 0000002a 00000000 00000000 00000094 2**0
CONTENTS, READONLY
5 .note.GNU-stack 00000000 00000000 00000000 000000be 2**0
CONTENTS, READONLY
6 .eh_frame 00000058 00000000 00000000 000000c0 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
生成的汇编语言和代码段内容:
karl@ubuntu:~/c/static$ objdump -s -d SimpleSection.o
SimpleSection.o: file format elf32-i386
Contents of section .text:
0000 5589e583 ec188b45 08894424 04c70424 U......E..D$...$
0010 00000000 e8fcffff ffc9c355 89e583e4 ...........U....
0020 f083ec20 c7442418 01000000 8b150400 ... .D$.........
0030 0000a100 00000001 c28b4424 1801c28b ..........D$....
0040 44241c01 d0890424 e8fcffff ff8b4424 D$.....$......D$
0050 18c9c3 ...
Contents of section .data:
0000 54000000 55000000 T...U...
Contents of section .rodata:
0000 25640a00 %d..
Contents of section .comment:
0000 00474343 3a202855 62756e74 7520342e .GCC: (Ubuntu 4.
0010 382e342d 32756275 6e747531 7e31342e 8.4-2ubuntu1~14.
0020 30342920 342e382e 3400 04) 4.8.4.
Contents of section .eh_frame:
0000 14000000 00000000 017a5200 017c0801 .........zR..|..
0010 1b0c0404 88010000 1c000000 1c000000 ................
0020 00000000 1b000000 00410e08 8502420d .........A....B.
0030 0557c50c 04040000 1c000000 3c000000 .W..........<...
0040 1b000000 38000000 00410e08 8502420d ....8....A....B.
0050 0574c50c 04040000 .t......
Disassembly of section .text:
00000000 <func1>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 18 sub $0x18,%esp
6: 8b 45 08 mov 0x8(%ebp),%eax
9: 89 44 24 04 mov %eax,0x4(%esp)
d: c7 04 24 00 00 00 00 movl $0x0,(%esp)
14: e8 fc ff ff ff call 15 <func1+0x15>
19: c9 leave
1a: c3 ret
0000001b <main>:
1b: 55 push %ebp
1c: 89 e5 mov %esp,%ebp
1e: 83 e4 f0 and $0xfffffff0,%esp
21: 83 ec 20 sub $0x20,%esp
24: c7 44 24 18 01 00 00 movl $0x1,0x18(%esp)
2b: 00
2c: 8b 15 04 00 00 00 mov 0x4,%edx
32: a1 00 00 00 00 mov 0x0,%eax
37: 01 c2 add %eax,%edx
39: 8b 44 24 18 mov 0x18(%esp),%eax
3d: 01 c2 add %eax,%edx
3f: 8b 44 24 1c mov 0x1c(%esp),%eax
43: 01 d0 add %edx,%eax
45: 89 04 24 mov %eax,(%esp)
48: e8 fc ff ff ff call 49 <main+0x2e>
4d: 8b 44 24 18 mov 0x18(%esp),%eax
51: c9 leave
52: c3 ret
段说明:
- 代码段第一列为偏移量,中间代码段中的内容(16进制),往下为代码段的汇编指令。可以看到代码段中的内容和会汇编指令的序列一样。代码段的长度也和头文件结构中的长度(0x53)相同。
- 数据段(data)保存的是初始化了的全局变量和局部静态变量。程序中有两个变量,
global_init_var
和static_var
,共八个字节。和头文件结构中的data段大小一样。 - rodata段存放的是只读数据,const修饰的变量和字符串常量(
%d\n
)。 - bss段存放的是未初始化的全局变量和局部静态变量。
观察文件头:
[email protected]:~/c/static$ readelf -h SimpleSection.o
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2‘s complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 376 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 40 (bytes)
Number of section headers: 13
Section header string table index: 10
32位文件头数据结构:/usr/include/elf.h
#define EI_NIDENT (16)
typedef struct
{
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type; /* Object file type */
Elf32_Half e_machine; /* Architecture */
Elf32_Word e_version; /* Object file version */
Elf32_Addr e_entry; /* Entry point virtual address */
Elf32_Off e_phoff; /* Program header table file offset */
Elf32_Off e_shoff; /* Section header table file offset */
Elf32_Word e_flags; /* Processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size in bytes */
Elf32_Half e_phentsize; /* Program header table entry size */
Elf32_Half e_phnum; /* Program header table entry count */
Elf32_Half e_shentsize; /* Section header table entry size */
Elf32_Half e_shnum; /* Section header table entry count */
Elf32_Half e_shstrndx; /* Section header string table index */
} Elf32_Ehdr;
- Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 ,这个16字节魔术数对应了ELF文件的平台属性,字长,字节序,版本等。操作系统在加载的时候会确认魔术数是否正确,如果不正确,会拒绝加载。
- e_type ELF文件类型。
/* Legal values for e_type (object file type). */
#define ET_NONE 0 /* No file type */
#define ET_REL 1 /* Relocatable file */
#define ET_EXEC 2 /* Executable file */
#define ET_DYN 3 /* Shared object file */
#define ET_CORE 4 /* Core file */
段表
[email protected]:~/c/static$ readelf -S SimpleSection.o
There are 13 section headers, starting at offset 0x178://注意在文件头中,Start of section headers的值为十进制。
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000034 000053 00 AX 0 0 1
[ 2] .rel.text REL 00000000 0004e8 000028 08 11 1 4
[ 3] .data PROGBITS 00000000 000088 000008 00 WA 0 0 4
[ 4] .bss NOBITS 00000000 000090 000004 00 WA 0 0 4
[ 5] .rodata PROGBITS 00000000 000090 000004 00 A 0 0 1
[ 6] .comment PROGBITS 00000000 000094 00002a 01 MS 0 0 1
[ 7] .note.GNU-stack PROGBITS 00000000 0000be 000000 00 0 0 1
[ 8] .eh_frame PROGBITS 00000000 0000c0 000058 00 A 0 0 4
[ 9] .rel.eh_frame REL 00000000 000510 000010 08 11 8 4
[10] .shstrtab STRTAB 00000000 000118 00005f 00 0 0 1
[11] .symtab SYMTAB 00000000 000380 000100 10 12 11 4
[12] .strtab STRTAB 00000000 000480 000066 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
- 段表其实是一个段结构体的数组。
- 段表描述符结构:
typedef struct
{
Elf32_Word sh_name; /* Section name (string tbl index) */
Elf32_Word sh_type; /* Section type */
Elf32_Word sh_flags; /* Section flags */
Elf32_Addr sh_addr; /* Section virtual addr at execution */
Elf32_Off sh_offset; /* Section file offset */
Elf32_Word sh_size; /* Section size in bytes */
Elf32_Word sh_link; /* Link to another section */
Elf32_Word sh_info; /* Additional section information */
Elf32_Word sh_addralign; /* Section alignment */
Elf32_Word sh_entsize; /* Entry size if section holds table */
} Elf32_Shdr;
- 对于编译器和链接器来说,主要决定段的属性的是段的类型(
sh_type
)和段的标志位(sh_flags
). - 段类型:
/* Legal values for sh_type (section type). */
#define SHT_NULL 0 /* Section header table entry unused */
#define SHT_PROGBITS 1 /* Program data */
#define SHT_SYMTAB 2 /* Symbol table */
#define SHT_STRTAB 3 /* String table */
#define SHT_RELA 4 /* Relocation entries with addends */
#define SHT_HASH 5 /* Symbol hash table */
#define SHT_DYNAMIC 6 /* Dynamic linking information */
#define SHT_NOTE 7 /* Notes */
#define SHT_NOBITS 8 /* Program space with no data (bss) */
#define SHT_REL 9 /* Relocation entries, no addends */
#define SHT_SHLIB 10 /* Reserved */
#define SHT_DYNSYM 11 /* Dynamic linker symbol table */
#define SHT_INIT_ARRAY 14 /* Array of constructors */
#define SHT_FINI_ARRAY 15 /* Array of destructors */
#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */
#define SHT_GROUP 17 /* Section group */
#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
#define SHT_NUM 19 /* Number of defined types. */
- 段标志:段的标志位(
sh_flag
) 段的标志位表示该段在进程虚拟地址空间中的属性,比如是否可写,是否可执行等。
/* Legal values for sh_flags (section flags). */
#define SHF_WRITE (1 << 0) /* Writable */
#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */
#define SHF_EXECINSTR (1 << 2) /* Executable */
#define SHF_MERGE (1 << 4) /* Might be merged */
#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */
- 分析文件头,能够得到短表和短表字符串表的位置,从而了解整个ELF文件。
符号表
- 查看目标文件的符号表:ELF文件中的符号表往往是文件中的一个段,段名一般叫”.symtab”。
karl@ubuntu:~/c/static$ nm SimpleSection.o
00000000 T func1
00000000 D global_init_var
00000004 C global_uninit_var
0000001b T main
U printf
00000004 d static_var.1378
00000000 b static_var2.1379
- 符号表的结构很简单,它是一个
Elf32_Sym
结构(32位ELF文件)的数组,每个Elf32_Sym
结构对应一个符号。
/* Symbol table entry. */
typedef struct
{
Elf32_Word st_name; /* Symbol name (string tbl index) */
Elf32_Addr st_value; /* Symbol value */
Elf32_Word st_size; /* Symbol size */
unsigned char st_info; /* Symbol type and binding */
unsigned char st_other; /* Symbol visibility */
Elf32_Section st_shndx; /* Section index */
} Elf32_Sym;
- 符号类型和绑定信息(
st_info
) 该成员低4位表示符号的类型(Symbol Type),高28位表示符号绑定信息(Symbol Binding) - 绑定信息:
/* Legal values for ST_BIND subfield of st_info (symbol binding). */
#define STB_LOCAL 0 /* Local symbol 局部符号,对于目标文件的外部不可见*/
#define STB_GLOBAL 1 /* Global symbol 全局符号,外部可见*/
#define STB_WEAK 2 /* Weak symbol 弱引用*/
#define STB_NUM 3 /* Number of defined types. */
#define STB_LOOS 10 /* Start of OS-specific */
#define STB_GNU_UNIQUE 10 /* Unique symbol. */
#define STB_HIOS 12 /* End of OS-specific */
#define STB_LOPROC 13 /* Start of processor-specific */
#define STB_HIPROC 15 /* End of processor-specific */
- 符号的类型
/* Legal values for ST_TYPE subfield of st_info (symbol type). */
#define STT_NOTYPE 0 /* Symbol type is unspecified 未知类型符号*/
#define STT_OBJECT 1 /* Symbol is a data object 该符号是个数据对象,比如变量、数组等*/
#define STT_FUNC 2 /* Symbol is a code object 该符号是个函数或其他可执行代码*/
#define STT_SECTION 3 /* Symbol associated with a section 该符号表示一个段,这种符号必须是STB_LOCAL的*/
#define STT_FILE 4
/* Symbol‘s name is file name 该符号表示文件名,一般都是该目标文件所对应的源文件名,它一定是STB_LOCAL类型的,
并且它的st_shndx一定是SHN_ABS*/
#define STT_COMMON 5 /* Symbol is a common data object */
#define STT_TLS 6 /* Symbol is thread-local data object*/
#define STT_NUM 7 /* Number of defined types. */
#define STT_LOOS 10 /* Start of OS-specific */
#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */
#define STT_HIOS 12 /* End of OS-specific */
#define STT_LOPROC 13 /* Start of processor-specific */
#define STT_HIPROC 15 /* End of processor-specific */
- 符号所在段
st_shndx
)如果符号定义在本目标文件中,那么这个成员表示符号所在的段在段表中的下标,但是如果符号不是定义在本目标文件中,或者对于有些特殊符号,sh_shndx的值有些特殊。
#define SHN_UNDEF 0
/* Undefined section
符号块未定义,在本目标文件被引用到,但是定义在其他目标文件中*/
#define SHN_ABS 0xfff1
/* Associated symbol is absolute
表示该符号包含了一个绝对的值。比如表示文件名的符号就属于这种类型的*/
#define SHN_COMMON 0xfff2
/* Associated symbol is common
表示该符号是一个“COMMON块”类型的符号,一般来说,未初始化的全局符号定义就是这种类型的
*/
查看SimpleSection.o中的符号表详细信息
[email protected]:~/c/static$ readelf -s SimpleSection.o
Symbol table ‘.symtab‘ contains 16 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FILE LOCAL DEFAULT ABS SimpleSection.c
2: 00000000 0 SECTION LOCAL DEFAULT 1
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 SECTION LOCAL DEFAULT 4
5: 00000000 0 SECTION LOCAL DEFAULT 5
6: 00000004 4 OBJECT LOCAL DEFAULT 3 static_var.1378
7: 00000000 4 OBJECT LOCAL DEFAULT 4 static_var2.1379
8: 00000000 0 SECTION LOCAL DEFAULT 7
9: 00000000 0 SECTION LOCAL DEFAULT 8
10: 00000000 0 SECTION LOCAL DEFAULT 6
11: 00000000 4 OBJECT GLOBAL DEFAULT 3 global_init_var
12: 00000004 4 OBJECT GLOBAL DEFAULT COM global_uninit_var
13: 00000000 27 FUNC GLOBAL DEFAULT 1 func1
14: 00000000 0 NOTYPE GLOBAL DEFAULT UND printf
15: 0000001b 56 FUNC GLOBAL DEFAULT 1 main
时间: 2024-11-06 11:41:13