ELF符号表分析

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)来指定其节头表索引值。
关于符号表第一表项的内容,下文会提到。
ELF符号表分析
文章图片

A symbol table entry has the following format.
一个符号表表项的数据结构定义如下:
ELF符号表分析
文章图片

/* Symbol table entry.*/typedef struct { Elf32_Wordst_name; /* Symbol name (string tbl index) */ Elf32_Addrst_value; /* Symbol value */ Elf32_Wordst_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_Wordst_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_Addrst_value; /* Symbol value */ Elf64_Xwordst_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。
ELF符号表分析
文章图片

* 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并且没有意义。
ELF符号表分析
文章图片

* 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.
一个符号的绑定属性决定了该符号在链接阶段的可见性以及链接时的处理方式。
例如全局符号和本地符号的链接可见性是不同的,而当出现同名的全局符号和弱符号时,链接器会做出相应的处理(这点可参考下文对全局符号和弱符号不同点的描述)。
ELF符号表分析
文章图片

* 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.
一个符号的类型为该符号关联的实体进行分类。
ELF符号表分析
文章图片

* 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文件)指定符号的可见性属性,但其实可见性属性控制的是一个符号在运行时的解析行为。
ELF符号表分析
文章图片

* 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 STV_PROTECTED 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_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 STB_LOCAL binding by the link-editor when the relocatable object is included in an executable file or shared object.

Symbol Values Symbol table entries for different object file types have slightly different interpretations for the st_value member.
在不同的目标文件中,对成员st_value的意义解释也是不同的。
  • In relocatable files, st_value holds alignment constraints for a symbol whose section index is SHN_COMMON.
在可重定位文件中,若符号的st_shndx等于SHN_COMMON,则st_value的值代表的是该符号的对齐字节数。
  • 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.
在可执行文件和共行库中,一个已定义符号的st_value的值不再是一个节偏移量,而是一个虚拟地址,因为动态链接器需要知道符号的内存地址。 -- 因为虚拟地址是与节无关的,所以这种情况下,我们不需要关心st_shndx的值。
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 #include #include #include #include #include #include #include #include #include #include #include #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##tstatic 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 ""; } }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 ""; } }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 ""; } }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] .dynstrSTRTAB0000000000000468 000468 0000dd 00A001 // [32] .strtabSTRTAB0000000000000000 003d28 000322 00001 // [33] .shstrtabSTRTAB0000000000000000 00404a 00013e 00001 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:41@astrol:/tmp]$ readelf --syms --wide print_symbol
Symbol table '.dynsym' contains 18 entries:
Num:ValueSize TypeBindVisNdx Name
0: 00000000000000000 NOTYPELOCALDEFAULTUND
1: 00000000000000000 FUNCGLOBAL DEFAULTUND putchar@GLIBC_2.2.5 (2)
2: 00000000000000000 FUNCGLOBAL DEFAULTUND __errno_location@GLIBC_2.2.5 (2)
3: 00000000000000000 NOTYPEWEAKDEFAULTUND _ITM_deregisterTMCloneTable
4: 00000000000000000 FUNCGLOBAL DEFAULTUND mmap@GLIBC_2.2.5 (2)
5: 00000000000000000 FUNCGLOBAL DEFAULTUND printf@GLIBC_2.2.5 (2)
6: 00000000000000000 FUNCGLOBAL DEFAULTUND snprintf@GLIBC_2.2.5 (2)
7: 00000000000000000 FUNCGLOBAL DEFAULTUND close@GLIBC_2.2.5 (2)
8: 00000000000000000 FUNCGLOBAL DEFAULTUND __libc_start_main@GLIBC_2.2.5 (2)
9: 00000000000000000 FUNCGLOBAL DEFAULTUND strcmp@GLIBC_2.2.5 (2)
10: 00000000000000000 NOTYPEWEAKDEFAULTUND __gmon_start__
11: 00000000000000000 FUNCGLOBAL DEFAULTUND __fxstat@GLIBC_2.2.5 (2)
12: 00000000000000000 FUNCGLOBAL DEFAULTUND munmap@GLIBC_2.2.5 (2)
13: 00000000000000000 FUNCGLOBAL DEFAULTUND error@GLIBC_2.2.5 (2)
14: 00000000000000000 FUNCGLOBAL DEFAULTUND open@GLIBC_2.2.5 (2)
15: 00000000000000000 FUNCGLOBAL DEFAULTUND exit@GLIBC_2.2.5 (2)
16: 00000000000000000 NOTYPEWEAKDEFAULTUND _ITM_registerTMCloneTable
17: 00000000000000000 FUNCWEAKDEFAULTUND __cxa_finalize@GLIBC_2.2.5 (2)
Symbol table '.symtab' contains 82 entries:
Num:ValueSize TypeBindVisNdx Name
0: 00000000000000000 NOTYPELOCALDEFAULTUND
1: 00000000000002380 SECTION LOCALDEFAULT1
2: 00000000000002540 SECTION LOCALDEFAULT2
3: 00000000000002740 SECTION LOCALDEFAULT3
4: 00000000000002980 SECTION LOCALDEFAULT4
5: 00000000000002b80 SECTION LOCALDEFAULT5
6: 00000000000004680 SECTION LOCALDEFAULT6
7: 000000000000053a0 SECTION LOCALDEFAULT7
8: 00000000000005600 SECTION LOCALDEFAULT8
9: 00000000000005800 SECTION LOCALDEFAULT9
10: 00000000000006400 SECTION LOCALDEFAULT10
11: 00000000000007600 SECTION LOCALDEFAULT11
12: 00000000000007800 SECTION LOCALDEFAULT12
13: 00000000000008500 SECTION LOCALDEFAULT13
14: 00000000000008600 SECTION LOCALDEFAULT14
15: 00000000000013200 SECTION LOCALDEFAULT15
16: 00000000000013300 SECTION LOCALDEFAULT16
17: 00000000000015900 SECTION LOCALDEFAULT17
18: 00000000000016000 SECTION LOCALDEFAULT18
19: 0000000000201d600 SECTION LOCALDEFAULT19
20: 0000000000201d680 SECTION LOCALDEFAULT20
21: 0000000000201d700 SECTION LOCALDEFAULT21
22: 0000000000201f600 SECTION LOCALDEFAULT22
23: 00000000002020000 SECTION LOCALDEFAULT23
24: 00000000002020200 SECTION LOCALDEFAULT24
25: 00000000000000000 SECTION LOCALDEFAULT25
26: 00000000000000000 FILELOCALDEFAULTABS crtstuff.c
27: 00000000000008900 FUNCLOCALDEFAULT14 deregister_tm_clones
28: 00000000000008d00 FUNCLOCALDEFAULT14 register_tm_clones
29: 00000000000009200 FUNCLOCALDEFAULT14 __do_global_dtors_aux
30: 00000000002020201 OBJECTLOCALDEFAULT24 completed.7696
31: 0000000000201d680 OBJECTLOCALDEFAULT20 __do_global_dtors_aux_fini_array_entry
32: 00000000000009600 FUNCLOCALDEFAULT14 frame_dummy
33: 0000000000201d600 OBJECTLOCALDEFAULT19 __frame_dummy_init_array_entry
34: 00000000000000000 FILELOCALDEFAULTABS print_symbol.c
35: 000000000000096a139 FUNCLOCALDEFAULT14 st_type
36: 00000000000009f5103 FUNCLOCALDEFAULT14 st_bind
37: 0000000000000a5c77 FUNCLOCALDEFAULT14 st_vis
38: 0000000000000aa9145 FUNCLOCALDEFAULT14 st_shndx
39: 000000000020204032 OBJECTLOCALDEFAULT24 s_shndx.4238
40: 0000000000000b3a575 FUNCLOCALDEFAULT14 print_syms
41: 00000000000000000 FILELOCALDEFAULTABS crtstuff.c
42: 00000000000017bc0 OBJECTLOCALDEFAULT18 __FRAME_END__
43: 00000000000000000 FILELOCALDEFAULTABS
44: 000000000000131015 FUNCLOCALDEFAULT14 fstat
45: 0000000000201d680 NOTYPELOCALDEFAULT19 __init_array_end
46: 0000000000201d700 OBJECTLOCALDEFAULT21 _DYNAMIC
47: 0000000000201d600 NOTYPELOCALDEFAULT19 __init_array_start
48: 00000000000015900 NOTYPELOCALDEFAULT17 __GNU_EH_FRAME_HDR
49: 0000000000201f600 OBJECTLOCALDEFAULT22 _GLOBAL_OFFSET_TABLE_
50: 00000000000013002 FUNCGLOBAL DEFAULT14 __libc_csu_fini
51: 00000000000000000 FUNCGLOBAL DEFAULTUND putchar@@GLIBC_2.2.5
52: 00000000000000000 FUNCGLOBAL DEFAULTUND __errno_location@@GLIBC_2.2.5
53: 00000000000000000 NOTYPEWEAKDEFAULTUND _ITM_deregisterTMCloneTable
54: 00000000002020000 NOTYPEWEAKDEFAULT23 data_start
55: 00000000002020100 NOTYPEGLOBAL DEFAULT23 _edata
56: 00000000000013200 FUNCGLOBAL DEFAULT15 _fini
57: 00000000000000000 FUNCGLOBAL DEFAULTUND mmap@@GLIBC_2.2.5
58: 00000000000000000 FUNCGLOBAL DEFAULTUND printf@@GLIBC_2.2.5
59: 00000000000000000 FUNCGLOBAL DEFAULTUND snprintf@@GLIBC_2.2.5
60: 00000000000000000 FUNCGLOBAL DEFAULTUND close@@GLIBC_2.2.5
61: 00000000000000000 FUNCGLOBAL DEFAULTUND __libc_start_main@@GLIBC_2.2.5
62: 00000000002020000 NOTYPEGLOBAL DEFAULT23 __data_start
63: 00000000000000000 FUNCGLOBAL DEFAULTUND strcmp@@GLIBC_2.2.5
64: 00000000000000000 NOTYPEWEAKDEFAULTUND __gmon_start__
65: 00000000002020080 OBJECTGLOBAL HIDDEN23 __dso_handle
66: 00000000000013304 OBJECTGLOBAL DEFAULT16 _IO_stdin_used
67: 0000000000001290101 FUNCGLOBAL DEFAULT14 __libc_csu_init
68: 00000000000000000 FUNCGLOBAL DEFAULTUND __fxstat@@GLIBC_2.2.5
69: 00000000002020600 NOTYPEGLOBAL DEFAULT24 _end
70: 000000000000086043 FUNCGLOBAL DEFAULT14 _start
71: 00000000002020100 NOTYPEGLOBAL DEFAULT24 __bss_start
72: 00000000000000000 FUNCGLOBAL DEFAULTUND munmap@@GLIBC_2.2.5
73: 0000000000000d791301 FUNCGLOBAL DEFAULT14 main
74: 00000000000000000 FUNCGLOBAL DEFAULTUND error@@GLIBC_2.2.5
75: 00000000000000000 FUNCGLOBAL DEFAULTUND open@@GLIBC_2.2.5
76: 000000000000131015 FUNCGLOBAL HIDDEN14 __fstat
77: 00000000000000000 FUNCGLOBAL DEFAULTUND exit@@GLIBC_2.2.5
78: 00000000002020100 OBJECTGLOBAL HIDDEN23 __TMC_END__
79: 00000000000000000 NOTYPEWEAKDEFAULTUND _ITM_registerTMCloneTable
80: 00000000000000000 FUNCWEAKDEFAULTUND __cxa_finalize@@GLIBC_2.2.5
81: 00000000000007600 FUNCGLOBAL DEFAULT11 _init
[00:26:48@astrol:/tmp]$ ./print_symbol print_symbol
Symbol table '.dynsym' contains 18 entries:
Num:ValueSize TypeBindVisNdx Name
0: 00000000000000000 NOTYPELOCALDEFAULTUND
1: 00000000000000000 FUNCGLOBAL DEFAULTUND putchar
2: 00000000000000000 FUNCGLOBAL DEFAULTUND __errno_location
3: 00000000000000000 NOTYPEWEAKDEFAULTUND _ITM_deregisterTMCloneTable
4: 00000000000000000 FUNCGLOBAL DEFAULTUND mmap
5: 00000000000000000 FUNCGLOBAL DEFAULTUND printf
6: 00000000000000000 FUNCGLOBAL DEFAULTUND snprintf
7: 00000000000000000 FUNCGLOBAL DEFAULTUND close
8: 00000000000000000 FUNCGLOBAL DEFAULTUND __libc_start_main
9: 00000000000000000 FUNCGLOBAL DEFAULTUND strcmp
10: 00000000000000000 NOTYPEWEAKDEFAULTUND __gmon_start__
11: 00000000000000000 FUNCGLOBAL DEFAULTUND __fxstat
12: 00000000000000000 FUNCGLOBAL DEFAULTUND munmap
13: 00000000000000000 FUNCGLOBAL DEFAULTUND error
14: 00000000000000000 FUNCGLOBAL DEFAULTUND open
15: 00000000000000000 FUNCGLOBAL DEFAULTUND exit
16: 00000000000000000 NOTYPEWEAKDEFAULTUND _ITM_registerTMCloneTable
17: 00000000000000000 FUNCWEAKDEFAULTUND __cxa_finalize
Symbol table '.symtab' contains 82 entries:
Num:ValueSize TypeBindVisNdx Name
0: 00000000000000000 NOTYPELOCALDEFAULTUND
1: 00000000000002380 SECTION LOCALDEFAULT1
2: 00000000000002540 SECTION LOCALDEFAULT2
3: 00000000000002740 SECTION LOCALDEFAULT3
4: 00000000000002980 SECTION LOCALDEFAULT4
5: 00000000000002b80 SECTION LOCALDEFAULT5
6: 00000000000004680 SECTION LOCALDEFAULT6
7: 000000000000053a0 SECTION LOCALDEFAULT7
8: 00000000000005600 SECTION LOCALDEFAULT8
9: 00000000000005800 SECTION LOCALDEFAULT9
10: 00000000000006400 SECTION LOCALDEFAULT10
11: 00000000000007600 SECTION LOCALDEFAULT11
12: 00000000000007800 SECTION LOCALDEFAULT12
13: 00000000000008500 SECTION LOCALDEFAULT13
14: 00000000000008600 SECTION LOCALDEFAULT14
15: 00000000000013200 SECTION LOCALDEFAULT15
16: 00000000000013300 SECTION LOCALDEFAULT16
17: 00000000000015900 SECTION LOCALDEFAULT17
18: 00000000000016000 SECTION LOCALDEFAULT18
19: 0000000000201d600 SECTION LOCALDEFAULT19
20: 0000000000201d680 SECTION LOCALDEFAULT20
21: 0000000000201d700 SECTION LOCALDEFAULT21
22: 0000000000201f600 SECTION LOCALDEFAULT22
23: 00000000002020000 SECTION LOCALDEFAULT23
24: 00000000002020200 SECTION LOCALDEFAULT24
25: 00000000000000000 SECTION LOCALDEFAULT25
26: 00000000000000000 FILELOCALDEFAULTABS crtstuff.c
27: 00000000000008900 FUNCLOCALDEFAULT14 deregister_tm_clones
28: 00000000000008d00 FUNCLOCALDEFAULT14 register_tm_clones
29: 00000000000009200 FUNCLOCALDEFAULT14 __do_global_dtors_aux
30: 00000000002020201 OBJECTLOCALDEFAULT24 completed.7696
31: 0000000000201d680 OBJECTLOCALDEFAULT20 __do_global_dtors_aux_fini_array_entry
32: 00000000000009600 FUNCLOCALDEFAULT14 frame_dummy
33: 0000000000201d600 OBJECTLOCALDEFAULT19 __frame_dummy_init_array_entry
34: 00000000000000000 FILELOCALDEFAULTABS print_symbol.c
35: 000000000000096a139 FUNCLOCALDEFAULT14 st_type
36: 00000000000009f5103 FUNCLOCALDEFAULT14 st_bind
37: 0000000000000a5c77 FUNCLOCALDEFAULT14 st_vis
38: 0000000000000aa9145 FUNCLOCALDEFAULT14 st_shndx
39: 000000000020204032 OBJECTLOCALDEFAULT24 s_shndx.4238
40: 0000000000000b3a575 FUNCLOCALDEFAULT14 print_syms
41: 00000000000000000 FILELOCALDEFAULTABS crtstuff.c
42: 00000000000017bc0 OBJECTLOCALDEFAULT18 __FRAME_END__
43: 00000000000000000 FILELOCALDEFAULTABS
44: 000000000000131015 FUNCLOCALDEFAULT14 fstat
45: 0000000000201d680 NOTYPELOCALDEFAULT19 __init_array_end
46: 0000000000201d700 OBJECTLOCALDEFAULT21 _DYNAMIC
47: 0000000000201d600 NOTYPELOCALDEFAULT19 __init_array_start
48: 00000000000015900 NOTYPELOCALDEFAULT17 __GNU_EH_FRAME_HDR
49: 0000000000201f600 OBJECTLOCALDEFAULT22 _GLOBAL_OFFSET_TABLE_
50: 00000000000013002 FUNCGLOBAL DEFAULT14 __libc_csu_fini
51: 00000000000000000 FUNCGLOBAL DEFAULTUND putchar@@GLIBC_2.2.5
52: 00000000000000000 FUNCGLOBAL DEFAULTUND __errno_location@@GLIBC_2.2.5
53: 00000000000000000 NOTYPEWEAKDEFAULTUND _ITM_deregisterTMCloneTable
54: 00000000002020000 NOTYPEWEAKDEFAULT23 data_start
55: 00000000002020100 NOTYPEGLOBAL DEFAULT23 _edata
56: 00000000000013200 FUNCGLOBAL DEFAULT15 _fini
57: 00000000000000000 FUNCGLOBAL DEFAULTUND mmap@@GLIBC_2.2.5
58: 00000000000000000 FUNCGLOBAL DEFAULTUND printf@@GLIBC_2.2.5
59: 00000000000000000 FUNCGLOBAL DEFAULTUND snprintf@@GLIBC_2.2.5
60: 00000000000000000 FUNCGLOBAL DEFAULTUND close@@GLIBC_2.2.5
61: 00000000000000000 FUNCGLOBAL DEFAULTUND __libc_start_main@@GLIBC_2.2.5
62: 00000000002020000 NOTYPEGLOBAL DEFAULT23 __data_start
63: 00000000000000000 FUNCGLOBAL DEFAULTUND strcmp@@GLIBC_2.2.5
64: 00000000000000000 NOTYPEWEAKDEFAULTUND __gmon_start__
65: 00000000002020080 OBJECTGLOBAL HIDDEN23 __dso_handle
66: 00000000000013304 OBJECTGLOBAL DEFAULT16 _IO_stdin_used
67: 0000000000001290101 FUNCGLOBAL DEFAULT14 __libc_csu_init
68: 00000000000000000 FUNCGLOBAL DEFAULTUND __fxstat@@GLIBC_2.2.5
69: 00000000002020600 NOTYPEGLOBAL DEFAULT24 _end
70: 000000000000086043 FUNCGLOBAL DEFAULT14 _start
71: 00000000002020100 NOTYPEGLOBAL DEFAULT24 __bss_start
72: 00000000000000000 FUNCGLOBAL DEFAULTUND munmap@@GLIBC_2.2.5
73: 0000000000000d791301 FUNCGLOBAL DEFAULT14 main
74: 00000000000000000 FUNCGLOBAL DEFAULTUND error@@GLIBC_2.2.5
75: 00000000000000000 FUNCGLOBAL DEFAULTUND open@@GLIBC_2.2.5
76: 000000000000131015 FUNCGLOBAL HIDDEN14 __fstat
77: 00000000000000000 FUNCGLOBAL DEFAULTUND exit@@GLIBC_2.2.5
78: 00000000002020100 OBJECTGLOBAL HIDDEN23 __TMC_END__
79: 00000000000000000 NOTYPEWEAKDEFAULTUND _ITM_registerTMCloneTable
80: 00000000000000000 FUNCWEAKDEFAULTUND __cxa_finalize@@GLIBC_2.2.5
81: 00000000000007600 FUNCGLOBAL DEFAULT11 _init
以下是利用libelf库来输出符号表的内容:
#include #include #include #include #include #include #include #include #include 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 ""; } }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 ""; } }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 ""; } }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); } returnelf_strptr(pelf, strtabndx, sym->st_name); }static void print_syms(Elf *pelf, Elf_Scn *symscn, GElf_Shdr *symshdr) { Elf_Data *symdata; if ((symdata = https://www.it610.com/article/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》
【ELF符号表分析】《Linking》

    推荐阅读