typedefstruct{
Elf64_Word st_name;/* Symbol name (string tbl index) */unsignedchar st_info;/* Symbol type and binding */unsignedchar st_other;/* Symbol visibility */
Elf64_Section st_shndx;/* Section index */
Elf64_Addr st_value;/* Symbol value */
Elf64_Xword st_size;/* Symbol size */} Elf64_Sym;
/* How to extract and insert information held in the st_info field. */#defineELF32_ST_BIND(val)(((unsignedchar)(val))>>4)#defineELF32_ST_TYPE(val)((val)&0xf)#defineELF32_ST_INFO(bind, type)(((bind)<<4)+((type)&0xf))
1 2 3 4
1 2 3 4
STB = Symbol Table Bind,我們可以知道符號的作用範圍
#defineSTB_LOCAL0/* Local symbol */#defineSTB_GLOBAL1/* Global symbol */#defineSTB_WEAK2/* Weak symbol */#defineSTB_NUM3/* Number of defined types. */#defineSTB_LOOS10/* Start of OS-specific */#defineSTB_GNU_UNIQUE10/* Unique symbol. */#defineSTB_HIOS12/* End of OS-specific */#defineSTB_LOPROC13/* Start of processor-specific */#defineSTB_HIPROC15/* End of processor-specific */
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
STT = Symbol Table Type,我們可以知道符號的性質是什麼
#defineSTT_NOTYPE0/* Symbol type is unspecified */#defineSTT_OBJECT1/* Symbol is a data object */#defineSTT_FUNC2/* Symbol is a code object */#defineSTT_SECTION3/* Symbol associated with a section */#defineSTT_FILE4/* Symbol's name is file name */#defineSTT_COMMON5/* Symbol is a common data object */#defineSTT_TLS6/* Symbol is thread-local data object*/#defineSTT_NUM7/* Number of defined types. */#defineSTT_LOOS10/* Start of OS-specific */#defineSTT_GNU_IFUNC10/* Symbol is indirect code object */#defineSTT_HIOS12/* End of OS-specific */#defineSTT_LOPROC13/* Start of processor-specific */#defineSTT_HIPROC15/* End of processor-specific */
/* Special section indices. */#defineSHN_UNDEF0/* Undefined section */#defineSHN_LORESERVE0xff00/* Start of reserved indices */#defineSHN_LOPROC0xff00/* Start of processor-specific */#defineSHN_BEFORE0xff00/* Order section before all others
(Solaris). */#defineSHN_AFTER0xff01/* Order section after all others
(Solaris). */#defineSHN_HIPROC0xff1f/* End of processor-specific */#defineSHN_LOOS0xff20/* Start of OS-specific */#defineSHN_HIOS0xff3f/* End of OS-specific */#defineSHN_ABS0xfff1/* Associated symbol is absolute */#defineSHN_COMMON0xfff2/* Associated symbol is common */#defineSHN_XINDEX0xffff/* Index is in extra table. */#defineSHN_HIRESERVE0xffff/* End of reserved indices */
/* How to extract and insert information held in the st_info field. */#defineELF32_ST_BIND(val)(((unsignedchar)(val))>>4)#defineELF32_ST_TYPE(val)((val)&0xf)#defineELF32_ST_INFO(bind, type)(((bind)<<4)+((type)&0xf))
1 2 3 4
1 2 3 4
STB = Symbol Table Bind,我們可以知道符號的作用範圍
#defineSTB_LOCAL0/* Local symbol */#defineSTB_GLOBAL1/* Global symbol */#defineSTB_WEAK2/* Weak symbol */#defineSTB_NUM3/* Number of defined types. */#defineSTB_LOOS10/* Start of OS-specific */#defineSTB_GNU_UNIQUE10/* Unique symbol. */#defineSTB_HIOS12/* End of OS-specific */#defineSTB_LOPROC13/* Start of processor-specific */#defineSTB_HIPROC15/* End of processor-specific */
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
STT = Symbol Table Type,我們可以知道符號的性質是什麼
#defineSTT_NOTYPE0/* Symbol type is unspecified */#defineSTT_OBJECT1/* Symbol is a data object */#defineSTT_FUNC2/* Symbol is a code object */#defineSTT_SECTION3/* Symbol associated with a section */#defineSTT_FILE4/* Symbol's name is file name */#defineSTT_COMMON5/* Symbol is a common data object */#defineSTT_TLS6/* Symbol is thread-local data object*/#defineSTT_NUM7/* Number of defined types. */#defineSTT_LOOS10/* Start of OS-specific */#defineSTT_GNU_IFUNC10/* Symbol is indirect code object */#defineSTT_HIOS12/* End of OS-specific */#defineSTT_LOPROC13/* Start of processor-specific */#defineSTT_HIPROC15/* End of processor-specific */
1 2 3 4 5 6 7 8 9 10 11 12 13
1 2 3 4 5 6 7 8 9 10 11 12 13
因此我們可以得出
變數名稱
st_info
Bind
Type
data1
11
0x1 (STB_GLOBAL)
0x1 (STT_OBJECT)
data2
11
0x1 (STB_GLOBAL)
0x1 (STT_OBJECT)
func1
12
0x1 (STB_GLOBAL)
0x2 (STT_FUNC)
func2
12
0x1 (STB_GLOBAL)
0x2 (STT_FUNC)
以上是我們在 2-1 小節提到的部分。我們再用 readelf 來看看我們的符號表
readelf -s elf.o
1
1
Symbol table '.symtab' contains 12 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS elf.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 6
7: 0000000000000000 0 SECTION LOCAL DEFAULT 4
8: 0000000000000000 8 OBJECT GLOBAL DEFAULT 2 data1
9: 0000000000000008 8 OBJECT GLOBAL DEFAULT 2 data2
10: 0000000000000000 7 FUNC GLOBAL DEFAULT 1 func1
11: 0000000000000007 7 FUNC GLOBAL DEFAULT 1 func2
s2.o:(.data+0x0): multiple definition of `a'
s1.o:(.data+0x0): first defined here
1 2
1 2
我們可以發現,連結失敗,原因為全局變數只能有一種定義,a, b 是 strong symbol,相互可見,所以連結器不知道要定義成什麼。可由 readelf 驗證。
readelf -s s1.o
1
1
Symbol table '.symtab' contains 8 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS s1.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 4
7: 0000000000000000 4 OBJECT GLOBAL DEFAULT 2 a
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
readelf -s s2.o
1
1
Symbol table '.symtab' contains 8 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS s2.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 4
7: 0000000000000000 4 OBJECT GLOBAL DEFAULT 2 a
Symbol table '.symtab' contains 8 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS s1_static.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 4 OBJECT LOCAL DEFAULT 2 a
6: 0000000000000000 0 SECTION LOCAL DEFAULT 5
7: 0000000000000000 0 SECTION LOCAL DEFAULT 4
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
readelf -s s2.o
1
1
Symbol table '.symtab' contains 8 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS s2.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 4
7: 0000000000000000 4 OBJECT GLOBAL DEFAULT 2 a
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
readelf -s ss12.o
1
1
Symbol table '.symtab' contains 11 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 SECTION LOCAL DEFAULT 2
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 FILE LOCAL DEFAULT ABS s1_static.c
7: 0000000000000000 4 OBJECT LOCAL DEFAULT 2 a
8: 0000000000000000 0 FILE LOCAL DEFAULT ABS s2.c
9: 0000000000000004 4 OBJECT GLOBAL DEFAULT COM s
10: 0000000000000004 4 OBJECT GLOBAL DEFAULT 2 a
// function declaration#pragmaweak power2intpower2(int x);
1 2 3
1 2 3
__attribute__((weak))
// function declarationint__attribute__((weak))power2(int x);// orintpower2(int x)__attribute__((weak));// variable declaration;externint__attribute__((weak)) global_var;
1 2 3 4 5 6 7
1 2 3 4 5 6 7
對弱符號有些了解後,可以知道
弱符號不一定要被定義,但強符號一定要有定義。
弱符號可以被定義或初始化,只是當遇到另外一個同名的強符號會被覆蓋掉
這裡同樣也用 readelf 來觀察
// weak.c__attribute__((weak))intadd(int a,int b){return a + b;}
1 2 3 4 5
1 2 3 4 5
readelf -s weak.c
1
1
Symbol table '.symtab' contains 9 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS weak.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 6
7: 0000000000000000 0 SECTION LOCAL DEFAULT 4
8: 0000000000000000 20 FUNC WEAK DEFAULT 1 add
1 2 3 4 5 6 7 8 9 10 11
1 2 3 4 5 6 7 8 9 10 11
可以看到我們 add 被定義為弱符號,但我們的弱符號有定義。
再用稍微複雜一點的例子
staticint a =1;__attribute__((weak))intadd(int a,int b){return a + b;}__attribute__((weak))intf(){return-1;}intmain(){if(f()==-1){printf("func() not defined\n");exit(0);}else{printf("func() is defined\n");}}
Symbol table '.symtab' contains 8 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS define.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 4
7: 0000000000000004 4 OBJECT GLOBAL DEFAULT COM b
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
因為 b 不知道未來在連結時的情形,這種要分配到哪個section 相依於未來連結才會決定的狀況,一律先指定為 COM section