Symbol Table
An object file's symbol table holds information needed to locate and relocate a program's symbolic definitions and references. A symbol table index is a subscript into this array. Index 0 both designates the first entry in the table and serves as the undefined symbol index. The contents of the initial entry are specified later in this section.
ELF檔案中的“符号表(symbol table)”包含的是程式中的符号資訊 -- 這些符号代表的或許是定義(例如定義全局變量時使用的變量名,或者定義函數時使用的函數名),或許代表的是引用(例如使用關鍵字extern聲明的變量或函數時使用的符号名稱)。當代表的是定義時,在連結階段連結器需要為它們重定位;當代表的是引用時,在連結階段連結器需要在其他編譯子產品定位到該符号的定義。
符号表其實是所有符号資訊的集合統稱,即符号表是所有符号資訊一起組成的一個數組,是以一個符号表索引(symbol table index) 對應該數組中的一個(符号表)表項。
其中,索引值0有雙重含義:一般情況下代表的意思是指代符号表的第一個表項,然而一個未定義符号卻也使用STN_UNDEF(數值為0)來指定其節頭表索引值。
關于符号表第一表項的内容,下文會提到。
A symbol table entry has the following format.
一個符号表表項的資料結構定義如下:
/* 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;
typedef struct
{
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 */
} Elf64_Sym;
* st_name 符号名稱
This member holds an index into the object file's symbol string table, which holds the character representations of the symbol names. If the value is non-zero, it represents a string table index that gives the symbol name. Otherwise, the symbol table entry has no name.
st_name成員其實不是一個字元串,而是一個數值,代表的是目标檔案中 字元串表 中的一個索引值, 那裡才真正存儲着該符号的名稱對應的字元串。如果st_name成員數值不為0,則代表該符号有符号名稱。否則,說明該符号沒有名稱。
NOTE:External C symbols have the same names in C and object files' symbol tables.
注意:在C程式中的 具有外部連結屬性的符号 的名稱 和 最後生成的目标檔案中的符号表中的符号名稱 是相同的,這點與C++不同。
* st_value 符号數值
This member gives the value of the associated symbol. Depending on the context, this may be an absolute value, an address, and so on; details appear below.
st_value成員給出了相應的符号值。這個符号值具體是什麼意思,是要依據上下文的(主要依據不同的符号屬性和不同的目标檔案),也許是個絕對值,也許是個位址值,等等。
* st_size 符号大小
Many symbols have associated sizes. For example, a data object's size is the number of bytes contained in the object. This member holds 0 if the symbol has no size or an unknown size.
很多類型的符号都是有大小屬性的。例如,一個資料對象的大小指的是它實際在目标檔案中占的位元組數。st_size成員如果是0的話,說明這個符号在目标檔案中不占用任何位元組數(例如common symbols)或者目前是未知大小的(例如undefined symbols)。
* st_info 符号的類型 和 綁定屬性
This member specifies the symbol's type and binding attributes. A list of the values and meanings appears below. The following code shows how to manipulate the values for both 32 and 64-bit objects.
成員st_info指定了符号的類型(低四位)和綁定屬性(高四位)。不同的符号類型/符号綁定屬性以及意義将在下文列出。下面的宏分别展現了如何操作成員st_info。通過st_info得到類型和綁定屬性,以及如何通過類型和綁定屬性而得到st_info。
* st_other 符号的可見性
This member currently specifies a symbol's visibility. A list of the values and meanings appears below. The following code shows how to manipulate the values for both 32 and 64-bit objects. Other bits contain 0 and have no defined meaning.
st_other成員目前指定符号的可見性屬性。不同的可見性屬性值以及意義将在文章後續給出。下面的宏分别展示了在32位和64位機器上如何操作st_other。除了低兩位,其餘的位都為0并且沒有意義。
* st_shndx 符号(關聯的節)的節頭表索引值
Every symbol table entry is defined in relation to some section. This member holds the relevant section header table index. As the sh_link and sh_info interpretation table and the related text describe, some section indexes indicate special meanings.
每一個符号表項所代表的特定符号資訊都是和一個特定的 “節” 相關聯的,st_shndx成員代表的就是這個特定“節”的節頭表索引(比如一個定義的全局變量global,那麼符号global的屬性st_shndx值應該就是.data節所對應的節頭表索引;定義的函數foo,那麼符号foo的屬性st_shndx值應該就是.text節所對應的節頭表索引)。部分符号的節頭表索引會有特殊的含義。
If this member contains SHN_XINDEX, then the actual section header index is too large to fit in this field. The actual value is contained in the associated section of type SHT_SYMTAB_SHNDX.
如果這個成員的值是SHN_XINDEX時,證明該符号關聯的節的節頭表索引值過大,超出了st_shndx所能代表的最大數值。那麼真正的節頭表索引值存儲在一個類型為SHT_SYMTAB_SHNDX的擴充節中。
Symbol Binding
A symbol's binding determines the linkage visibility and behavior.
一個符号的綁定屬性決定了該符号在連結階段的可見性以及連結時的處理方式。
例如全局符号和本地符号的連結可見性是不同的,而當出現同名的全局符号和弱符号時,連結器會做出相應的處理(這點可參考下文對全局符号和弱符号不同點的描述)。
* STB_LOCAL 本地符号
Local symbols are not visible outside the object file containing their definition. Local symbols of the same name may exist in multiple files without interfering with each other.
當一個符号的綁定屬性是STB_LOCAL時,則表明該符号的連結屬性是internal的,對其他目标檔案來說是不可見的,即不可通路。是以不同的目标檔案中的本地符号可以同名,它們彼此不會幹擾對方。
* STB_GLOBAL 全局符号
Global symbols are visible to all object files being combined. One file's definition of a global symbol will satisfy another file's undefined reference to the same global symbol.
當一個符号的綁定屬性是STB_GLOBAL時,則表明該符号的連結屬性是external的,對其他目标檔案來說是可見的,即可以通路。
* STB_WEAK 弱符号
Weak symbols resemble global symbols, but their definitions have lower precedence.
當一個符号的綁定屬性是STB_WEAK時,則表明該符号是個弱符号,它和全局符号有類似的地方,即連結屬性也是external的。但是連結器處理弱符号的優先級相對全局符号要低,即當全局符号和弱符号同名時,連結器最後使用全局符号而忽略弱符号。
* STB_LOOS through STB_HIOS
Values in this inclusive range are reserved for operating system-specific semantics.
* STB_LOPROC through STB_HIPROC
Values in this inclusive range are reserved for processor-specific semantics. If meanings are specified, the processor supplement explains them.
Global and weak symbols differ in two major ways.
全局符号和弱符号的差別主要在兩個方面。
When the link editor combines several relocatable object files, it does not allow multiple definitions of STB_GLOBAL symbols with the same name. On the other hand, if a defined global symbol exists, the appearance of a weak symbol with the same name will not cause an error. The link editor honors the global definition and ignores the weak ones. Similarly, if a common symbol exists (that is, a symbol whose st_shndx field holds SHN_COMMON), the appearance of a weak symbol with the same name will not cause an error. The link editor honors the common definition and ignores the weak ones.
當連結器連結若幹可重定位檔案時,它是不允許具有STB_GLOBAL屬性的符号以相同名字進行重複定義的。而如果一個已定義的全局符号存在,則即便另一個具有相同名字的弱符号存在也不會引起錯誤。連結器将認可全局符号的定義而忽略弱符号的定義。與此類似的,如果一個符号被放在COMMON塊(就是說這個符号的st_shndx成員的值為SHN_COMMON),則一個同名的弱符号也不會引起錯誤。連結器同樣認可放在COMMON塊符号的定義而忽略其他的弱符号。
-----------------------------------------------------------------------
>>> STB_GLOBAL > SHN_COMMON > STB_WEAK
-----------------------------------------------------------------------
When the link editor searches archive libraries [see ``Archive File'' in Chapter 7], it extracts archive members that contain definitions of undefined global symbols. The member's definition may be either a global or a weak symbol. The link editor does not extract archive members to resolve undefined weak symbols. Unresolved weak symbols have a zero value.
在連結靜态庫的情況下:
(1)當連結器遇到一個未定義的全局符号(global symbol)時,連結器會去提取靜态庫,試圖找到這個符号定義。在靜态庫中,這個符号可以是全局符号,也可以是弱符号。
(2)當連結器遇到一個未定義的弱符号(weak symbols)時,連結器是不會去提取靜态庫的,而是直接将該弱符号的值賦為0。(可以參考文章《Fun with weak symbols》。試驗結果發現:如果引用了靜态庫中的非弱符号,那麼即使連結器遇到了一個未定義的弱符号,依然會去靜态庫中解析符号)
NOTE: The behavior of weak symbols in areas not specified by this document is implementation defined. Weak symbols are intended primarily for use in system software. Applications using weak symbols are unreliable since changes in the runtime environment might cause the execution to fail.
注意: 弱符号在上述規則之外地方的行為是實作相關的。弱符号主要用于系統軟體中,不推薦在應用程式中使用弱符号,因為在運作時,弱符号很容易被覆寫掉。
In each symbol table, all symbols with STB_LOCAL binding precede the weak and global symbols. As ``Sections'', above describes, a symbol table section's sh_info section header member holds the symbol table index for the first non-local symbol.
在符号表中,不同綁定屬性的符号所在位置是不同的 -- 所有的本地符号都被安放在符号表的前頭,緊接着的才是全局符号和弱符号。前文提到過,一個符号表節對應的節頭表項的節頭表成員sh_info中的數值代表的是第一個綁定屬性為非STB_LOCAL的符号的符号表索引值(即最後一個綁定屬性為STB_LOCAL符号的符号表索引值加1)。
Symbol Types
A symbol's type provides a general classification for the associated entity.
一個符号的類型為該符号關聯的實體進行分類。
* STT_NOTYPE
The symbol's type is not specified.
當符号類型是STT_NOTYPE時,表明該符号未指定類型或者目前還不知道該符号的類型。
* STT_OBJECT
The symbol is associated with a data object, such as a variable, an array, and so on.
當符号類型是STT_OBJECT時,表明該符号關聯的實體是個資料對象,例如一個變量,數組等。
* STT_FUNC
The symbol is associated with a function or other executable code.
當符号類型是STT_FUNC時,表明該符号關聯的實體是個函數或者其他的可執行代碼。
* STT_SECTION
The symbol is associated with a section. Symbol table entries of this type exist primarily for relocation and normally have STB_LOCAL binding.
當符号類型是STT_SECTION時,表明該符号關聯的實體是個節。一般符号表中的一個符号是這個類型時,主要是用于重定位的目的,并且其綁定屬性一般情況下是STB_LOCAL。
* STT_FILE
Conventionally, the symbol's name gives the name of the source file associated with the object file. A file symbol has STB_LOCAL binding, its section index is SHN_ABS, and it precedes the other STB_LOCAL symbols for the file, if it is present.
通常情況下,當一個符号的類型是STT_FILE時,這個符号的名稱就是該目标檔案相關聯的源檔案的名稱。這種類型的符号的綁定屬性是STB_LOCAL的,與它相關的節的節頭表索引值為SHN_ABS,并且如果在符号表中存在此種符号的話,那麼其位置排在本地符号(STB_LOCAL)的前頭。
* STT_COMMON
The symbol labels an uninitialized common block. See below for details.
當符号類型是STT_COMMON時,表明該符号是個公用塊資料對象,并且這個公用塊在目标檔案中實際是未被配置設定空間的。
* STT_TLS
The symbol specifies a Thread-Local Storage entity. When defined, it gives the assigned offset for the symbol, not the actual address. Symbols of type STT_TLS can be referenced by only special thread-local storage relocations and thread-local storage relocations can only reference symbols with type STT_TLS. Implementation need not support thread-local storage.
當符号的類型是STT_TLS時,表明該符号對應變量存儲線上程局部存儲内。
* STT_LOOS through STT_HIOS
Values in this inclusive range are reserved for operating system-specific semantics.
* STT_LOPROC through STT_HIPROC
Values in this inclusive range are reserved for processor-specific semantics. If meanings are specified, the processor supplement explains them.
Function symbols (those with type STT_FUNC) in shared object files have special significance. When another object file references a function from a shared object, the link editor automatically creates a procedure linkage table entry for the referenced symbol. Shared object symbols with types other than STT_FUNC will not be referenced automatically through the procedure linkage table.
連結器對那些存在于共享庫中的函數符号(即那些符号類型為STT_FUNC的符号)有特殊的處理。當其它的目标檔案引用了共享庫中的函數時,連結器會自動的為這個引用符号建立一個 程式連接配接表(PLT)表項。而共享庫中符号類型為非STT_FUNC的符号則不是通過 程式連接配接表(PLT)自動通路。例如,可執行程式引用共享庫中的共享對象(即符号類型為STT_OBJECT的符号)時,連結器會建立一個copy reloc來解決。
Symbols with type STT_COMMON label uninitialized common blocks. In relocatable objects, these symbols are not allocated and must have the special section index SHN_COMMON (see below). In shared objects and executables these symbols must be allocated to some section in the defining object.
當一個符号的類型是STT_COMMON時,則表明該符号是個公用塊資料對象,且這個公用塊在目标檔案中實際是未被配置設定空間。在可重定位檔案中,并不會為這些符号配置設定空間,并且與之相關的節的節頭表索引值必須是SHN_COMMON。但是在共享庫和可執行檔案中,這些符号必須在相應的節(bss)中配置設定空間。
In relocatable objects, symbols with type STT_COMMON are treated just as other symbols with index SHN_COMMON. If the link-editor allocates space for the SHN_COMMON symbol in an output section of the object it is producing, it must preserve the type of the output symbol as STT_COMMON.
在可重定位檔案中,對符号類型是STT_COMMON的符号的處理方式跟那些與之相關節的節頭表索引值為SHN_COMMON的符号的處理方式是一樣的。如果連結器在生成可執行檔案或者共享庫時,為這類符号配置設定了空間的話(.bss),那麼必須保留該符号的類型為STT_COMMON.(why? -- 下文給出)
When the dynamic linker encounters a reference to a symbol that resolves to a definition of type STT_COMMON, it may (but is not required to) change its symbol resolution rules as follows: instead of binding the reference to the first symbol found with the given name, the dynamic linker searches for the first symbol with that name with type other than STT_COMMON. If no such symbol is found, it looks for the STT_COMMON definition of that name that has the largest size.
當動态連結器(/lib/ld-linux.so.2)遇到一個符号引用是指向符号類型是STT_COMMON的符号定義時,那麼動态連結器也許(但是并不推薦這樣做)會改變符号解析的法則如下:并不會像其它類型的符号一樣,将該引用綁定到第一個同名的符号定義,而是先搜尋類型為非STT_COMMON的符号定義,如果存在則綁定到該符号定義。如果不存在,那麼動态連結器這才在符号類型為STT_COMMON的定義中搜尋,并且最終選擇占用記憶體空間最大的那個。
Symbol Visibility
A symbol's visibility, although it may be specified in a relocatable object, defines how that symbol may be accessed once it has become part of an executable or shared object.
盡管我們可以在編譯階段(通過在source code中或者編譯器選項指定符号的可見性)和靜态連結階段(通過export list檔案)指定符号的可見性屬性,但其實可見性屬性控制的是一個符号在運作時的解析行為。
* STV_DEFAULT
The visibility of symbols with the STV_DEFAULT attribute is as specified by the symbol's binding type. That is, global and weak symbols are visible outside of their defining component (executable file or shared object). Local symbols are hidden, as described below. Global and weak symbols are also preemptable, that is, they may by preempted by definitions of the same name in another component.
當符号的可見性是STV_DEFAULT時,那麼該符号的可見性由符号的綁定屬性決定。這類情況下,(可執行檔案和共享庫中的)全局符号和弱符号預設是外部可通路的,本地符号預設外部是無法被通路的。但是,可見性是STV_DEFAULT的全局符号和弱符号是可被覆寫的。什麼意思?舉個最典型的例子,共享庫中的可見性值為STV_DEFAULTD的全局符号和弱符号是可被可執行檔案中的同名符号覆寫的。
NOTE: An implementation may restrict the set of global and weak symbols that are externally visible.
注意:一個具體的實作可能會限制對外可通路的全局符号和弱符号的數量。
* STV_PROTECTED
A symbol defined in the current component is protected if it is visible in other components but not preemptable, meaning that any reference to such a symbol from within the defining component must be resolved to the definition in that component, even if there is a definition in another component that would preempt by the default rules. A symbol with STB_LOCAL binding may not have STV_PROTECTED visibility. If a symbol definition with STV_PROTECTED visibility from a shared object is taken as resolving a reference from an executable or another shared object, the SHN_UNDEF symbol table entry created has STV_DEFAULT visibility.
當符号的可見性是STV_PROTECTED時,它是外部可見的,這點跟可見性是STV_DEFAULT的一樣,但不同的是它是不可覆寫的。這樣的符号在共享庫中比較常見。不可覆寫意味着如果是在該符号所在的共享庫中通路這個符号,那麼就一定是通路的這個符号,盡管可執行檔案中也會存在同樣名字的符号也不會被覆寫掉。
規定綁定屬性為STB_LOCAL的符号的可見性不可以是STV_PROTECTED。
NOTE: The presence of the
flag on a symbol in a given load module does not affect the symbol resolution rules for references to that symbol from outside the containing load module.
STV_PROTECTED
* STV_HIDDEN
A symbol defined in the current component is hidden if its name is not visible to other components. Such a symbol is necessarily protected. This attribute may be used to control the external interface of a component. Note that an object named by such a symbol may still be referenced from another component if its address is passed outside.
A hidden symbol contained in a relocatable object must be either removed or converted to
STB_LOCAL
binding by the link-editor when the relocatable object is included in an executable file or shared object.
當符号的可見性是STV_HIDDEN時,證明該符号是外部無法通路的。這個屬性主要用來控制共享庫對外接口的數量。需要注意的是,一個可見性為STV_HIDDEN的資料對象,如果能擷取到該符号的位址,那麼依然是可以通路或者修改該資料對象的。
在可重定位檔案中,如果一個符号的可見性是STV_HIDDEN的話,那麼在連結生成可執行檔案或者共享庫的過程中,該符号要麼被删除,要麼綁定屬性變成STB_LOCAL。
* STV_INTERNAL
The meaning of this visibility attribute may be defined by processor supplements to further constrain hidden symbols. A processor supplement's definition should be such that generic tools can safely treat internal symbols as hidden.
An internal symbol contained in a relocatable object must be either removed or converted to
binding by the link-editor when the relocatable object is included in an executable file or shared object.
STB_LOCAL
Symbol Values
Symbol table entries for different object file types have slightly different interpretations for the st_value member.
在不同的目标檔案中,對成員st_value的意義解釋也是不同的。
在可重定位檔案中,若符号的st_shndx等于SHN_COMMON,則st_value的值代表的是該符号的對齊位元組數。
- In relocatable files, st_value holds alignment constraints for a symbol whose section index is SHN_COMMON.
在可重定位檔案中,若一個符号是已定義的,那麼st_value的值代表的是該符号其所在的節中的偏移量 -- 當然了,這個節是由st_shndx指定的。
- In relocatable files, st_value holds a section offset for a defined symbol. st_value is an offset from the beginning of the section that st_shndx identifies.
在可執行檔案和共行庫中,一個已定義符号的st_value的值不再是一個節偏移量,而是一個虛拟位址,因為動态連結器需要知道符号的記憶體位址。 -- 因為虛拟位址是與節無關的,是以這種情況下,我們不需要關心st_shndx的值。
- In executable and shared object files, st_value holds a virtual address. To make these files' symbols more useful for the dynamic linker, the section offset (file interpretation) gives way to a virtual address (memory interpretation) for which the section number is irrelevant.
Although the symbol table values have similar meanings for different object files, the data allows efficient access by the appropriate programs.
綜合以上三點可知,在不同的目标檔案中st_value的值代表的含義不同。這樣設計是有原因的:在靜态連結階段,連結器需要的是符号在檔案中的位置資訊,而在程式運作時,動态連結器需要的是卻符号在記憶體中的位置資訊。
以下程式用于輸出ELF所有符号的資訊(即sh_type為SHT_SYMTAB或者SHT_DYNSYM),模仿readelf的--syms選項:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <link.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <elf.h>
#include <error.h>
#include <errno.h>
#define ELFW(type) _ELFW (ELF, __ELF_NATIVE_CLASS, type)
#define _ELFW(e,w,t) _ELFW_1 (e, w, _##t)
#define _ELFW_1(e,w,t) e##w##t
static const char *st_type(unsigned int stype)
{
switch (stype) {
case STT_NOTYPE: return "NOTYPE";
case STT_OBJECT: return "OBJECT";
case STT_FUNC: return "FUNC";
case STT_SECTION: return "SECTION";
case STT_FILE: return "FILE";
case STT_COMMON: return "COMMON";
case STT_TLS: return "TLS";
case STT_LOOS ... STT_HIOS: return "OS_SPEC";
case STT_LOPROC ... STT_HIPROC: return "PROC_SPEC";
default: return "<unknown symbol type>";
}
}
static const char *st_bind(unsigned int stbind)
{
switch (stbind) {
case STB_LOCAL: return "LOCAL";
case STB_GLOBAL: return "GLOBAL";
case STB_WEAK: return "WEAK";
// case STB_GNU_UNIQUE: return "UNIQUE";
case STB_LOOS ... STB_HIOS: return "OS";
case STB_LOPROC ... STB_HIPROC: return "PROC";
default: return "<unknown symbol bind>";
}
}
static const char *st_vis(unsigned int svis)
{
switch (svis) {
case STV_DEFAULT: return "DEFAULT";
case STV_INTERNAL: return "INTERNAL";
case STV_HIDDEN: return "HIDDEN";
case STV_PROTECTED: return "PROTECTED";
default: return "<unknown symbol vis>";
}
}
static const char *st_shndx(unsigned int shndx)
{
static char s_shndx[32];
switch (shndx) {
case SHN_UNDEF: return "UND";
case SHN_ABS: return "ABS";
case SHN_COMMON: return "COMMON";
case SHN_LOPROC ... SHN_HIPROC: return "PRC";
case SHN_LOOS ... SHN_HIOS: return "OS";
default:
(void)snprintf(s_shndx, sizeof(s_shndx), "%u", shndx);
return (const char *)s_shndx;
}
}
static void print_syms(ElfW(Shdr) *shdrs, const char *shstrtab,
const char *shname, ElfW(Sym) *syms, size_t entries, const char *strtab)
{
printf("Symbol table '%s' contains %zu entries:\n", shname, entries);
printf("%7s%9s%14s%5s%8s%6s%9s%5s\n", "Num:", "Value", "Size", "Type",
"Bind", "Vis", "Ndx", "Name");
for (size_t i = 0; i < entries; i++) {
ElfW(Sym) *sym = &syms[i];
printf("%6zu:", i);
printf(" %16.16jx", (uintmax_t)sym->st_value);
printf(" %5ju", (uintmax_t)sym->st_size);
printf(" %-7s", st_type(ELFW(ST_TYPE)(sym->st_info)));
printf(" %-6s", st_bind(ELFW(ST_BIND)(sym->st_info)));
printf(" %-8s", st_vis(ELFW(ST_VISIBILITY)(sym->st_other)));
printf(" %3s", st_shndx(sym->st_shndx));
if (strcmp("SECTION", st_type(ELFW(ST_TYPE)(sym->st_info))) == 0) {
printf(" %s", shstrtab + shdrs[sym->st_shndx].sh_name);
} else {
printf(" %s", strtab + sym->st_name);
}
printf("\n");
}
}
int main(int argc, char *argv[])
{
int fd;
char *file_mmbase;
struct stat file_status;
size_t fsize;
ElfW(Ehdr) *ehdr;
ElfW(Shdr) *shdrs;
size_t shnum, shstrndx;
const char *shstrtab;
// [ 6] .dynstr STRTAB 0000000000000468 000468 0000dd 00 A 0 0 1
// [32] .strtab STRTAB 0000000000000000 003d28 000322 00 0 0 1
// [33] .shstrtab STRTAB 0000000000000000 00404a 00013e 00 0 0 1
if (argc != 2) {
error(EXIT_FAILURE, 0, "Usage: %s file-name", argv[0]);
}
if ((fd = open(argv[1], O_RDONLY)) < 0) {
error(EXIT_FAILURE, errno, "open %s failed", argv[1]);
}
if (fstat(fd, &file_status) < 0) {
error(EXIT_FAILURE, errno, "get file %s info err", argv[1]);
}
fsize = (size_t)file_status.st_size;
if ((file_mmbase = mmap(NULL, fsize, PROT_READ,
MAP_PRIVATE, fd, (off_t)0)) == MAP_FAILED) {
error(EXIT_FAILURE, errno, "mmap file %s err", argv[1]);
}
ehdr = (ElfW(Ehdr) *)file_mmbase;
shdrs = (ElfW(Shdr) *)(file_mmbase + ehdr->e_shoff);
shnum = ehdr->e_shnum == 0 ? shdrs[0].sh_size : ehdr->e_shnum;
shstrndx = ehdr->e_shstrndx == SHN_XINDEX ? shdrs[0].sh_link : ehdr->e_shstrndx;
shstrtab = file_mmbase + shdrs[shstrndx].sh_offset;
for (size_t i = 0; i < shnum; i++) {
ElfW(Shdr) *shdr = &shdrs[i];
if (shdr->sh_type == SHT_SYMTAB || shdr->sh_type == SHT_DYNSYM) {
const char *shname = shstrtab + shdr->sh_name;
ElfW(Sym) *syms = (ElfW(Sym *))(file_mmbase + shdr->sh_offset);
size_t entries = shdr->sh_size / shdr->sh_entsize;
// sh_info: One greater than the symbol table index of
// the last local symbol (binding STB_LOCAL).
// printf("shdr->sh_info = %u\n", shdr->sh_info);
// sh_link: .strtab or .dynstr (The section header index of
// the associated string table.)
const char *strtab = file_mmbase + shdrs[shdr->sh_link].sh_offset;
print_syms(shdrs, shstrtab, shname, syms, entries, strtab);
}
}
(void)munmap(file_mmbase, fsize);
(void)close(fd);
exit(EXIT_SUCCESS);
}
程式輸出結果如下:
[00:26:[email protected]:/tmp]$ readelf --syms --wide print_symbol
Symbol table '.dynsym' contains 18 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
8: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
9: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
10: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
11: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
12: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
13: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
14: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
15: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
16: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
17: 0000000000000000 0 FUNC WEAK DEFAULT UND [email protected]_2.2.5 (2)
Symbol table '.symtab' contains 82 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000238 0 SECTION LOCAL DEFAULT 1
2: 0000000000000254 0 SECTION LOCAL DEFAULT 2
3: 0000000000000274 0 SECTION LOCAL DEFAULT 3
4: 0000000000000298 0 SECTION LOCAL DEFAULT 4
5: 00000000000002b8 0 SECTION LOCAL DEFAULT 5
6: 0000000000000468 0 SECTION LOCAL DEFAULT 6
7: 000000000000053a 0 SECTION LOCAL DEFAULT 7
8: 0000000000000560 0 SECTION LOCAL DEFAULT 8
9: 0000000000000580 0 SECTION LOCAL DEFAULT 9
10: 0000000000000640 0 SECTION LOCAL DEFAULT 10
11: 0000000000000760 0 SECTION LOCAL DEFAULT 11
12: 0000000000000780 0 SECTION LOCAL DEFAULT 12
13: 0000000000000850 0 SECTION LOCAL DEFAULT 13
14: 0000000000000860 0 SECTION LOCAL DEFAULT 14
15: 0000000000001320 0 SECTION LOCAL DEFAULT 15
16: 0000000000001330 0 SECTION LOCAL DEFAULT 16
17: 0000000000001590 0 SECTION LOCAL DEFAULT 17
18: 0000000000001600 0 SECTION LOCAL DEFAULT 18
19: 0000000000201d60 0 SECTION LOCAL DEFAULT 19
20: 0000000000201d68 0 SECTION LOCAL DEFAULT 20
21: 0000000000201d70 0 SECTION LOCAL DEFAULT 21
22: 0000000000201f60 0 SECTION LOCAL DEFAULT 22
23: 0000000000202000 0 SECTION LOCAL DEFAULT 23
24: 0000000000202020 0 SECTION LOCAL DEFAULT 24
25: 0000000000000000 0 SECTION LOCAL DEFAULT 25
26: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
27: 0000000000000890 0 FUNC LOCAL DEFAULT 14 deregister_tm_clones
28: 00000000000008d0 0 FUNC LOCAL DEFAULT 14 register_tm_clones
29: 0000000000000920 0 FUNC LOCAL DEFAULT 14 __do_global_dtors_aux
30: 0000000000202020 1 OBJECT LOCAL DEFAULT 24 completed.7696
31: 0000000000201d68 0 OBJECT LOCAL DEFAULT 20 __do_global_dtors_aux_fini_array_entry
32: 0000000000000960 0 FUNC LOCAL DEFAULT 14 frame_dummy
33: 0000000000201d60 0 OBJECT LOCAL DEFAULT 19 __frame_dummy_init_array_entry
34: 0000000000000000 0 FILE LOCAL DEFAULT ABS print_symbol.c
35: 000000000000096a 139 FUNC LOCAL DEFAULT 14 st_type
36: 00000000000009f5 103 FUNC LOCAL DEFAULT 14 st_bind
37: 0000000000000a5c 77 FUNC LOCAL DEFAULT 14 st_vis
38: 0000000000000aa9 145 FUNC LOCAL DEFAULT 14 st_shndx
39: 0000000000202040 32 OBJECT LOCAL DEFAULT 24 s_shndx.4238
40: 0000000000000b3a 575 FUNC LOCAL DEFAULT 14 print_syms
41: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
42: 00000000000017bc 0 OBJECT LOCAL DEFAULT 18 __FRAME_END__
43: 0000000000000000 0 FILE LOCAL DEFAULT ABS
44: 0000000000001310 15 FUNC LOCAL DEFAULT 14 fstat
45: 0000000000201d68 0 NOTYPE LOCAL DEFAULT 19 __init_array_end
46: 0000000000201d70 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC
47: 0000000000201d60 0 NOTYPE LOCAL DEFAULT 19 __init_array_start
48: 0000000000001590 0 NOTYPE LOCAL DEFAULT 17 __GNU_EH_FRAME_HDR
49: 0000000000201f60 0 OBJECT LOCAL DEFAULT 22 _GLOBAL_OFFSET_TABLE_
50: 0000000000001300 2 FUNC GLOBAL DEFAULT 14 __libc_csu_fini
51: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
52: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
53: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable
54: 0000000000202000 0 NOTYPE WEAK DEFAULT 23 data_start
55: 0000000000202010 0 NOTYPE GLOBAL DEFAULT 23 _edata
56: 0000000000001320 0 FUNC GLOBAL DEFAULT 15 _fini
57: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
58: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
59: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
60: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
61: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
62: 0000000000202000 0 NOTYPE GLOBAL DEFAULT 23 __data_start
63: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
64: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
65: 0000000000202008 0 OBJECT GLOBAL HIDDEN 23 __dso_handle
66: 0000000000001330 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used
67: 0000000000001290 101 FUNC GLOBAL DEFAULT 14 __libc_csu_init
68: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
69: 0000000000202060 0 NOTYPE GLOBAL DEFAULT 24 _end
70: 0000000000000860 43 FUNC GLOBAL DEFAULT 14 _start
71: 0000000000202010 0 NOTYPE GLOBAL DEFAULT 24 __bss_start
72: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
73: 0000000000000d79 1301 FUNC GLOBAL DEFAULT 14 main
74: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
75: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
76: 0000000000001310 15 FUNC GLOBAL HIDDEN 14 __fstat
77: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
78: 0000000000202010 0 OBJECT GLOBAL HIDDEN 23 __TMC_END__
79: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
80: 0000000000000000 0 FUNC WEAK DEFAULT UND [email protected]@GLIBC_2.2.5
81: 0000000000000760 0 FUNC GLOBAL DEFAULT 11 _init
[00:26:[email protected]:/tmp]$ ./print_symbol print_symbol
Symbol table '.dynsym' contains 18 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND putchar
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __errno_location
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND mmap
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND snprintf
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND close
8: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main
9: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strcmp
10: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
11: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __fxstat
12: 0000000000000000 0 FUNC GLOBAL DEFAULT UND munmap
13: 0000000000000000 0 FUNC GLOBAL DEFAULT UND error
14: 0000000000000000 0 FUNC GLOBAL DEFAULT UND open
15: 0000000000000000 0 FUNC GLOBAL DEFAULT UND exit
16: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
17: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize
Symbol table '.symtab' contains 82 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000238 0 SECTION LOCAL DEFAULT 1
2: 0000000000000254 0 SECTION LOCAL DEFAULT 2
3: 0000000000000274 0 SECTION LOCAL DEFAULT 3
4: 0000000000000298 0 SECTION LOCAL DEFAULT 4
5: 00000000000002b8 0 SECTION LOCAL DEFAULT 5
6: 0000000000000468 0 SECTION LOCAL DEFAULT 6
7: 000000000000053a 0 SECTION LOCAL DEFAULT 7
8: 0000000000000560 0 SECTION LOCAL DEFAULT 8
9: 0000000000000580 0 SECTION LOCAL DEFAULT 9
10: 0000000000000640 0 SECTION LOCAL DEFAULT 10
11: 0000000000000760 0 SECTION LOCAL DEFAULT 11
12: 0000000000000780 0 SECTION LOCAL DEFAULT 12
13: 0000000000000850 0 SECTION LOCAL DEFAULT 13
14: 0000000000000860 0 SECTION LOCAL DEFAULT 14
15: 0000000000001320 0 SECTION LOCAL DEFAULT 15
16: 0000000000001330 0 SECTION LOCAL DEFAULT 16
17: 0000000000001590 0 SECTION LOCAL DEFAULT 17
18: 0000000000001600 0 SECTION LOCAL DEFAULT 18
19: 0000000000201d60 0 SECTION LOCAL DEFAULT 19
20: 0000000000201d68 0 SECTION LOCAL DEFAULT 20
21: 0000000000201d70 0 SECTION LOCAL DEFAULT 21
22: 0000000000201f60 0 SECTION LOCAL DEFAULT 22
23: 0000000000202000 0 SECTION LOCAL DEFAULT 23
24: 0000000000202020 0 SECTION LOCAL DEFAULT 24
25: 0000000000000000 0 SECTION LOCAL DEFAULT 25
26: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
27: 0000000000000890 0 FUNC LOCAL DEFAULT 14 deregister_tm_clones
28: 00000000000008d0 0 FUNC LOCAL DEFAULT 14 register_tm_clones
29: 0000000000000920 0 FUNC LOCAL DEFAULT 14 __do_global_dtors_aux
30: 0000000000202020 1 OBJECT LOCAL DEFAULT 24 completed.7696
31: 0000000000201d68 0 OBJECT LOCAL DEFAULT 20 __do_global_dtors_aux_fini_array_entry
32: 0000000000000960 0 FUNC LOCAL DEFAULT 14 frame_dummy
33: 0000000000201d60 0 OBJECT LOCAL DEFAULT 19 __frame_dummy_init_array_entry
34: 0000000000000000 0 FILE LOCAL DEFAULT ABS print_symbol.c
35: 000000000000096a 139 FUNC LOCAL DEFAULT 14 st_type
36: 00000000000009f5 103 FUNC LOCAL DEFAULT 14 st_bind
37: 0000000000000a5c 77 FUNC LOCAL DEFAULT 14 st_vis
38: 0000000000000aa9 145 FUNC LOCAL DEFAULT 14 st_shndx
39: 0000000000202040 32 OBJECT LOCAL DEFAULT 24 s_shndx.4238
40: 0000000000000b3a 575 FUNC LOCAL DEFAULT 14 print_syms
41: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
42: 00000000000017bc 0 OBJECT LOCAL DEFAULT 18 __FRAME_END__
43: 0000000000000000 0 FILE LOCAL DEFAULT ABS
44: 0000000000001310 15 FUNC LOCAL DEFAULT 14 fstat
45: 0000000000201d68 0 NOTYPE LOCAL DEFAULT 19 __init_array_end
46: 0000000000201d70 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC
47: 0000000000201d60 0 NOTYPE LOCAL DEFAULT 19 __init_array_start
48: 0000000000001590 0 NOTYPE LOCAL DEFAULT 17 __GNU_EH_FRAME_HDR
49: 0000000000201f60 0 OBJECT LOCAL DEFAULT 22 _GLOBAL_OFFSET_TABLE_
50: 0000000000001300 2 FUNC GLOBAL DEFAULT 14 __libc_csu_fini
51: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
52: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
53: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable
54: 0000000000202000 0 NOTYPE WEAK DEFAULT 23 data_start
55: 0000000000202010 0 NOTYPE GLOBAL DEFAULT 23 _edata
56: 0000000000001320 0 FUNC GLOBAL DEFAULT 15 _fini
57: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
58: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
59: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
60: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
61: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
62: 0000000000202000 0 NOTYPE GLOBAL DEFAULT 23 __data_start
63: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
64: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
65: 0000000000202008 0 OBJECT GLOBAL HIDDEN 23 __dso_handle
66: 0000000000001330 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used
67: 0000000000001290 101 FUNC GLOBAL DEFAULT 14 __libc_csu_init
68: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
69: 0000000000202060 0 NOTYPE GLOBAL DEFAULT 24 _end
70: 0000000000000860 43 FUNC GLOBAL DEFAULT 14 _start
71: 0000000000202010 0 NOTYPE GLOBAL DEFAULT 24 __bss_start
72: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
73: 0000000000000d79 1301 FUNC GLOBAL DEFAULT 14 main
74: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
75: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
76: 0000000000001310 15 FUNC GLOBAL HIDDEN 14 __fstat
77: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.2.5
78: 0000000000202010 0 OBJECT GLOBAL HIDDEN 23 __TMC_END__
79: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
80: 0000000000000000 0 FUNC WEAK DEFAULT UND [email protected]@GLIBC_2.2.5
81: 0000000000000760 0 FUNC GLOBAL DEFAULT 11 _init
以下是利用libelf庫來輸出符号表的内容:
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <fcntl.h>
#include <gelf.h>
#include <stdint.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
static const char *st_type(unsigned int stype)
{
switch (stype) {
case STT_NOTYPE: return "NOTYPE";
case STT_OBJECT: return "OBJECT";
case STT_FUNC: return "FUNC";
case STT_SECTION: return "SECTION";
case STT_FILE: return "FILE";
case STT_COMMON: return "COMMON";
case STT_TLS: return "TLS";
case STT_LOOS ... STT_HIOS: return "OS_SPEC";
case STT_LOPROC ... STT_HIPROC: return "PROC_SPEC";
default: return "<unknown symbol type>";
}
}
static const char *st_bind(unsigned int stbind)
{
switch (stbind) {
case STB_LOCAL: return "LOCAL";
case STB_GLOBAL: return "GLOBAL";
case STB_WEAK: return "WEAK";
// case STB_GNU_UNIQUE: return "UNIQUE";
case STB_LOOS ... STB_HIOS: return "OS";
case STB_LOPROC ... STB_HIPROC: return "PROC";
default: return "<unknown symbol bind>";
}
}
static const char *st_vis(unsigned int svis)
{
switch (svis) {
case STV_DEFAULT: return "DEFAULT";
case STV_INTERNAL: return "INTERNAL";
case STV_HIDDEN: return "HIDDEN";
case STV_PROTECTED: return "PROTECTED";
default: return "<unknown symbol vis>";
}
}
static const char *st_shndx(unsigned int shndx)
{
static char s_shndx[32];
switch (shndx) {
case SHN_UNDEF: return "UND";
case SHN_ABS: return "ABS";
case SHN_COMMON: return "COMMON";
case SHN_LOPROC ... SHN_HIPROC: return "PRC";
case SHN_LOOS ... SHN_HIOS: return "OS";
default:
(void)snprintf(s_shndx, sizeof(s_shndx), "%u", shndx);
return (const char *)s_shndx;
}
}
static const char *get_symbol_name(Elf *pelf, size_t strtabndx, GElf_Sym *sym)
{
if (GELF_ST_TYPE(sym->st_info) == STT_SECTION) {
// get shstrndx
size_t shstrndx;
if (elf_getshdrstrndx(pelf, &shstrndx) == -1) {
errx(EXIT_FAILURE, "getshdrstrndx() failed: %s.", elf_errmsg(-1));
}
Elf_Scn *destscn;
GElf_Shdr destshdr;
if ((destscn = elf_getscn(pelf, sym->st_shndx)) == NULL) {
errx(EXIT_FAILURE, "elf_getscn() failed: %s.", elf_errmsg(-1));
}
if (gelf_getshdr(destscn, &destshdr) != &destshdr) {
errx(EXIT_FAILURE, "gelf_getshdr() failed: %s.", elf_errmsg(-1));
}
return elf_strptr(pelf, shstrndx, destshdr.sh_name);
}
return elf_strptr(pelf, strtabndx, sym->st_name);
}
static void print_syms(Elf *pelf, Elf_Scn *symscn, GElf_Shdr *symshdr)
{
Elf_Data *symdata;
if ((symdata = elf_getdata(symscn, NULL)) == NULL) {
errx(EXIT_FAILURE, "elf_getdata() failed: %s.", elf_errmsg(-1));
}
if (symdata->d_type != ELF_T_SYM) {
errx(EXIT_FAILURE, "Elf_Type is not ELF_T_SYM.");
}
if (symdata->d_size <= 0) {
errx(EXIT_FAILURE, "Section data size is wrong.");
}
assert(symshdr->sh_size == symdata->d_size);
// get shstrndx
size_t shstrndx;
if (elf_getshdrstrndx(pelf, &shstrndx) == -1) {
errx(EXIT_FAILURE, "getshdrstrndx() failed: %s.", elf_errmsg(-1));
}
const char *symshdrname = elf_strptr(pelf, shstrndx, symshdr->sh_name);
if (symshdrname == NULL) {
errx(EXIT_FAILURE, "elf_strptr() failed: %s,", elf_errmsg(-1));
}
size_t entries;
#if 0
// 1
entries = symshdr->sh_size / symshdr->sh_entsize;
#endif
#if 0
// 2
size_t entsize = gelf_fsize(pelf, ELF_T_SYM, 1, EV_CURRENT);
entries = symshdr->sh_size / entsize;
#endif
#if 1
// 3
size_t entsize = gelf_fsize(pelf, ELF_T_SYM, 1, EV_CURRENT);
entries = symdata->d_size / entsize;
#endif
printf("\nSymbol table '%s' contains %zu entries:\n", symshdrname, entries);
printf("%7s%9s%14s%5s%8s%6s%9s%5s\n", "Num:", "Value", "Size", "Type",
"Bind", "Vis", "Ndx", "Name");
for (size_t i = 0; i < entries; i++) {
GElf_Sym sym;
if (gelf_getsym(symdata, i, &sym) != &sym) {
errx(EXIT_FAILURE, "gelf_getsym() failed: %s.", elf_errmsg(-1));
}
printf("%6zu:", i);
printf(" %16.16jx", (uintmax_t)sym.st_value);
printf(" %5ju", (uintmax_t)sym.st_size);
printf(" %-7s", st_type(GELF_ST_TYPE(sym.st_info)));
printf(" %-6s", st_bind(GELF_ST_BIND(sym.st_info)));
printf(" %-8s", st_vis(GELF_ST_VISIBILITY(sym.st_other)));
printf(" %3s", st_shndx(sym.st_shndx));
// sh_info: One greater than the symbol table index of
// the last local symbol (binding STB_LOCAL).
// printf("shdr->sh_info = %u\n", shdr->sh_info);
// sh_link: .strtab or .dynstr (The section header index of
// the associated string table.)
printf(" %s\n", get_symbol_name(pelf, symshdr->sh_link, &sym));
}
}
int main(int argc, const char *argv[])
{
int fd, class;
Elf *pelf = NULL;
Elf_Scn *scn = NULL;
if (argc != 2)
errx(EXIT_FAILURE, "usage: %s file-name", argv[0]);
if (elf_version(EV_CURRENT) == EV_NONE)
errx(EXIT_FAILURE, "ELF library initializztion "
"failed: %s", elf_errmsg(-1));
if ((fd = open(argv[1], O_RDONLY, 0)) < 0)
errx(EXIT_FAILURE, "open \"%s\" failed", argv[1]);
if (!(pelf = elf_begin(fd, ELF_C_READ, NULL)))
errx(EXIT_FAILURE, "elf_begin() failed: %s", elf_errmsg(-1));
if (elf_kind(pelf) != ELF_K_ELF)
errx(EXIT_FAILURE, "\"%s\" is not an ELF object.", argv[1]);
// get elf class ()
if ((class = gelf_getclass(pelf)) == ELFCLASSNONE)
errx(EXIT_FAILURE, "getclass() failed: %s.", elf_errmsg(-1));
while ((scn = elf_nextscn(pelf, scn)) != NULL) {
GElf_Shdr shdr;
if (gelf_getshdr(scn, &shdr) != &shdr) {
errx(EXIT_FAILURE, "gelf_getshdr() failed: %s.", elf_errmsg(-1));
}
if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
print_syms(pelf, scn, &shdr);
}
}
(void)elf_end(pelf);
(void)close(fd);
exit(EXIT_SUCCESS);
}
參考連結:
《Symbol Table》《Symbol Table Section》
《Inside ELF Symbol Tables》
《Fun with weak symbols》
《Profiler adventures: resolving symbol addresses is hard!》
《OS Backtrace With Symbol Names》
《Executable and Linkable Format 101. Part 2: Symbols》
《Linking》