1. 程式人生 > >ELF檔案-符號表

ELF檔案-符號表

目標檔案中的"符號表"(symbol table)中所包含的資訊用於定位和重定位程式中的符號定義和符號引用;目標檔案中的其它部分通過一個符號在這個表中的索引值來使用該符號;索引值從0開始計數,但值為0的索引表項(即第一項)並沒有實際的意義,它表示未定義的符號;用常量STN_UNDEF來表示未定義的符號;
符號表項(Symbol Table Entry)的格式使用結構體Elf32_Sym/Elf64_Sym描述:
struct Elf32_Sym
{
  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 */
};
struct Elf64_Sym
{
  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 */
};
------欄位解釋------
st_name:
符號的名字,但它並不是一個字串,而是字串表中的一個索引值,在字串表中該索引值的位置上存放的字串就是該符號名字的實際文字;如果此值不為0,則它就代表符號名字在字串表中的索引值;如果此值為0,則表示此符號沒有名字;

st_value:
符號的值;這個欄位的值沒有固定的型別,它可能代表一個數值,也可能是一個地址,具體要依據上下文來確定;
對於不同型別的目標檔案,符號表項的st_value的含義也有所不同:
A、在重定位檔案中,如果一個符號對應的節的索引值是SHN_COMMON,則它的st_value的值是這個節內容的位元組對齊數;
B、在重定位檔案中,如果一個符號是已定義的,則它的st_value值是該符號的起始地址在其所在節中的偏移量,而其所在的節的索引值由st_shndx欄位給出;
C、在可執行檔案和共享庫檔案中,符號的st_value欄位的值是一個虛擬地址,直接指向符號所在的記憶體位置;這時,st_shndx就不需要了;
如果一個可執行檔案中含有一個函式的引用,而這個函式被定義在一個共享目標檔案中,那麼在可執行檔案中,針對那個共享目標檔案的符號表中就應該含有這個函式的符號;符號表的st_shndx欄位的值為SHN_UNDEF,這就告訴動態連結器,這個函式的符號定義並不在可執行檔案中;如果已經在可執行檔案中給這個符號申請了一個函式連線表項,而且符號表項的st_value欄位的值不是0,那麼st_value欄位的值就將是函式連線表項中第一條指令的地址;否則,st_value欄位的值就是0;這個函式連線表項的地址被動態連結器用來解析函式地址;
st_size:
符號的大小;各種符號的大小各不相同,比如一個物件的大小就是它實際佔用的位元組數;如果一個符號的大小為0,或者大小未知,則這個值為0;
st_info:
符號的型別和屬性;該欄位由一系列的二進位制位構成,標識了"符號繫結(symbol binding)"、"符號型別(symbol type)"和"符號資訊(symbol information)"三種屬性;這三種屬性分別用下面的巨集來讀寫:
#define ELF32_ST_BIND(val)       (((unsigned char)(val))>>4)
#define ELF32_ST_TYPE(val)       ((val)&0xf)
#define ELF32_ST_INFO(bind,type) (((bind)<<4)+((type)&0xf))
#define ELF64_ST_BIND(val)       ELF32_ST_BIND(val)
#define ELF64_ST_TYPE(val)       ELF32_ST_TYPE(val)
#define ELF64_ST_INFO(bind,type) ELF32_ST_INFO((bind),(type))
符號繫結(Symbol Binding)屬性由巨集ELF32_ST_BIND來指定:
STB_LOCAL  = 0:本地符號;該符號只出現在本檔案中,在本檔案之外,該符號無效;所以,可在不同檔案中定義同名符號,它們且互不影響;
STB_GLOBAL = 1:全域性符號;當有多個檔案被連結在一起時,在所有檔案中,該符號都是可見的;
STB_WEAK   = 2:弱符號;類似於全域性符號,但是相對於STB_GLOBAL,它們的優先順序更低;
STB_NUM    = 3:已定義的型別的數量;
STB_LOOS   = 10;
STB_GNU_UNIQUE=10;
STB_HIOS   = 12;
STB_LOPROC = 13;
STB_HIPROC = 15;
在符號表中,不同屬性的符號所在的位置也不同,本地符號(STB_LOCAL)排在前面,全域性符號(STB_GLOBAL/STB_WEAK)排在後面;
符號型別(Symbol Types)屬性由巨集ELF32_ST_TYPE來指定:
STT_NOTYPE  = 0:本符號的型別未指定;
STT_OBJECT  = 1:本符號是一個數據物件;比如:變數、陣列,等等;
STT_FUNC    = 2:本符號是一個函式或其它的可執行程式碼;
STT_SECTION = 3:本符號與一個節相關聯,用於重定位;通常具有STB_LOCAL屬性;
STT_FILE    = 4:本符號是一個檔案符號,符號名字就是檔名字;具有STB_LOCAL屬性,它的節索引值是SHN_ABS;在符號表中如果存在本類符號的話,它會哦出現在所有STB_LOCAL類符號的前面;
STT_COMMON  = 5:本符號是一個通用的資料物件;
STT_TLS     = 6:本符號是一個執行緒本地資料物件;
STT_NUM     = 7:已定義的型別數量;
STT_LOOS    = 10;
STT_GNU_IFUNC=10;
STT_HIOS    = 12;
STT_LOPROC  = 13;
STT_HIPROC  = 15;
符號資訊(Symbol Information)屬性由巨集ELF32_ST_INFO來指定;格式定義如下:
struct Elf32_Syminfo
{
  Elf32_Half si_boundto; /* Direct bindings, symbol bound to */
  Elf32_Half si_flags;   /* Per symbol flags */
};
struct Elf64_Syminfo
{
  Elf64_Half si_boundto; /* Direct bindings, symbol bound to */
  Elf64_Half si_flags;   /* Per symbol flags */
};
/* Possible values for si_boundto.  */
SYMINFO_BT_SELF       = 0xffff /* Symbol bound to self */
SYMINFO_BT_PARENT     = 0xfffe /* Symbol bound to parent */
SYMINFO_BT_LOWRESERVE = 0xff00 /* Beginning of reserved entries */
/* Possible bitmasks for si_flags.  */
SYMINFO_FLG_DIRECT   = 0x0001 /* Direct bound symbol */
SYMINFO_FLG_PASSTHRU = 0x0002 /* Pass-thru symbol for translator */
SYMINFO_FLG_COPY     = 0x0004 /* Symbol is a copy-reloc */
SYMINFO_FLG_LAZYLOAD = 0x0008 /* Symbol bound to object to be lazy loaded */
/* Syminfo version values.  */
SYMINFO_NONE    = 0
SYMINFO_CURRENT = 1
SYMINFO_NUM     = 2
讀寫符號資訊:
#define ELF32_ST_VISIBILITY(o)     ((o) & 0x03)
#define ELF64_ST_VISIBILITY(o)     ELF32_ST_VISIBILITY (o)
STV_DEFAULT   = 0 /* Default symbol visibility rules */
STV_INTERNAL  = 1 /* Processor specific hidden class */
STV_HIDDEN    = 2 /* Sym unavailable in other modules */
STV_PROTECTED = 3 /* Not preemptible, not exported */
st_other:
該欄位暫未使用,在目標檔案中為0;
st_shndx:
任何一個符號表項的定義都與某一個"節"相聯絡,因為符號是為節而定義的,在節中被引用;該欄位指明瞭相關聯的節;該欄位的值是一個索引值,它指向相關聯的節在節頭部表中的索引位置;在重定位過程中,節的位置會改變,該欄位的值也隨之改變,繼續指向節的新位置;
該欄位指向下面三種特殊的節索引值時,本符號就具有如下特殊意義:
SHN_ABS:
符號的值是絕對的,具有常量性,在重定位過程中,此值不需要改變;
SHN_COMMON:
本符號所關聯的是一個還沒有分配的公共節,本符號的值規定了其內容的位元組對齊規則,與sh_addralign相似;也就是說,連結器會為本符號分配儲存空間,而且其起始地址是按st_value欄位的值對齊的;本符號的值指明瞭要分配你的位元組數;
SHN_UNDEF:
當一個符號指向第1個節(SHN_UNDEF)時,表明本符號在當前目標檔案中未定義,在連結過程中,連結器會找到此符號被定義的檔案,並把這些檔案連結在一起;

符號表首項:
索引為STN_UNDEF的符號表項的內容為全0,該項的所有欄位的值都為0,表示符號未定義;
#define STN_UNDEF 0