連結使用的符號
在連結的過程中,函式名和變數名統稱為符號,連結的過程就是目標檔案之間的對地址的引用,即對函式和變數地址的引用。
使用 nm
命令檢視目標檔案的符號:
[root@localhost simple-secion-linux-elf]# nm SimpleSection.o
0000000000000000 T func1
0000000000000000 D global_init_var
0000000000000004 C global_uninit_var
0000000000000024 T main
U printf
0000000000000004 d static_var.2058
0000000000000000 b static_var2.2059
複製程式碼
ELF符號的結構體,定義於“/usr/include”
/* 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;
複製程式碼
Elf32_Sym成員的定義解釋:

st_info(符號繫結資訊),低4位表示符號型別(Symbol Type),高28位表示符號繫結資訊(Symbol Binding) 

st_shndx(符號所在段) 如果符號是定義在目標檔案中,那麼符號的意思就是符號所在的段的在段表中的下標 ,此外還有幾種特殊的定義如下:

st_value(符號值) 符號如果是一個函式或者變數,符號值表示函式或者變數的地址,特殊地st_value還有以下幾種可能:
- 在目標檔案中,符號型別不是COMMON型別(st_shndx!=SHN_COMMON),st_value表示符號在段中的偏移,即符號位於st_shndx所在的段偏移st_value,在該例子中的global_init_var、func1、main都屬於這種型別。
- 在目標檔案中,符號型別是COMMON型別(st_shndx=SHN_COMMON),st_value表示符號的對其屬性,在該例子中的global_uninit_var的Value值為0000000000000004,表示對其長度為4位元組,即為global_uninit_var型別(int)的位元組長度
- 在可執行檔案中,st_value表示符號的虛擬地址,動態連結需要使用到
使用 readelf -s
命令檢視目標檔案的所有符號詳細資訊
[root@localhost simple-secion-linux-elf]# readelf -s SimpleSection.o
Symbol table '.symtab' contains 16 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS SimpleSection.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000004 4 OBJECT LOCAL DEFAULT 3 static_var.2058
7: 0000000000000000 4 OBJECT LOCAL DEFAULT 4 static_var2.2059
8: 0000000000000000 0 SECTION LOCAL DEFAULT 7
9: 0000000000000000 0 SECTION LOCAL DEFAULT 8
10: 0000000000000000 0 SECTION LOCAL DEFAULT 6
11: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 global_init_var
12: 0000000000000004 4 OBJECT GLOBAL DEFAULT COM global_uninit_var
13: 0000000000000000 36 FUNC GLOBAL DEFAULT 1 func1
14: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND printf
15: 0000000000000024 57 FUNC GLOBAL DEFAULT 1 main
複製程式碼
使用 readelf -S
檢視目標檔案的所有段資訊,後面分析符號資訊的時候會作為參照使用到。
[root@localhost simple-secion-linux-elf]# readelf -S SimpleSection.o
There are 13 section headers, starting at offset 0x1a0:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .text PROGBITS 0000000000000000 00000040
000000000000005d 0000000000000000 AX 0 0 4
[ 2] .rela.text RELA 0000000000000000 000006c8
0000000000000078 0000000000000018 11 1 8
[ 3] .data PROGBITS 0000000000000000 000000a0
0000000000000008 0000000000000000 WA 0 0 4
[ 4] .bss NOBITS 0000000000000000 000000a8
0000000000000004 0000000000000000 WA 0 0 4
[ 5] .rodata PROGBITS 0000000000000000 000000a8
0000000000000004 0000000000000000 A 0 0 1
[ 6] .comment PROGBITS 0000000000000000 000000ac
000000000000002d 0000000000000001 MS 0 0 1
[ 7] .note.GNU-stack PROGBITS 0000000000000000 000000d9
0000000000000000 0000000000000000 0 0 1
[ 8] .eh_frame PROGBITS 0000000000000000 000000e0
0000000000000058 0000000000000000 A 0 0 8
[ 9] .rela.eh_frame RELA 0000000000000000 00000740
0000000000000030 0000000000000018 11 8 8
[10] .shstrtab STRTAB 0000000000000000 00000138
0000000000000061 0000000000000000 0 0 1
[11] .symtab SYMTAB 0000000000000000 000004e0
0000000000000180 0000000000000018 12 11 8
[12] .strtab STRTAB 0000000000000000 00000660
0000000000000066 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
複製程式碼
該例子中的幾個重要的符號解釋:
-
func1 和 main 定義與目標檔案中,Ndx值為1表示位於程式碼段中(參照 readelf -S 結果中的 [Nr] 值 )
Bind值為GLOBAL,表示符號繫結資訊為全域性符號,外部可見
Type值為FUNC,表示符號類四個函式或其他可執行程式碼
Size值表示符號大小
Value符號所在的地址 -
printf符號在目標檔案中沒有定義,所以Ndx值為UND
-
global_init_var符號是已初始化的全域性變數,Ndx值為3表示位於.data資料段,
Bind值為OBJECT,表示符號型別為STT_OBJECT,變數陣列的符號型別都為該值
Size為4,表示符號大小佔用4位元組
Value為0,表示該符號位於Ndx段的第0個位置 -
global_uninit_var Ndx值為COM表示位於COMMON段,全域性未初始化的符號是這種型別的
-
有部分Name未定義的符號,符號名就是段名,比如Num為2、Ndx為1的的符號表示.text段,他的符號名就是段名
-
SimpleSection.c符號的Ndx為ABS、Type為FILE,表示檔名的符號