ELF(Executable and Linkable Format,即可执行可链接文件格式),是目前常见的Linux、 Android可执行文件、共享库(.so)、目标文件( .o)以及Core 文件均为此格式。 # nm nm命令是linux下自带的特定文件分析工具,一般用来检查分析二进制文件、库文件、可执行文件中的符号表,返回二进制文件中各段的信息。 ```bash [yz@bogon ~]$ nm ~/postgresql/pg_bin/bin/postgres 0000000000926880 r a1 0000000000926800 r a2 0000000000926780 r a3 0000000000926700 r a4 0000000000926680 r a5 0000000000926600 r a6 0000000000ba87a0 b abbrevcache 000000000078e0d0 T AbortBufferIO 000000000057d580 T AbortCurrentTransaction 0000000000ba2700 b abortedRecPtr U abort@@GLIBC_2.2.5 000000000057d650 T AbortOutOfAnyTransaction …… 0000000000a03cc0 r alert.8094 …… ``` ## nm输出内容解析 第二列中字符所对应的含义: ``` A :符号的值是绝对值,不会被更改 B或b :未被初始化的全局数据,放在.bss段 D或d :已经初始化的全局数据 G或g :指被初始化的数据,特指small objects I :另一个符号的间接参考 N :debugging 符号 p :位于堆栈展开部分 R或r :属于只读存储区 S或s :指为初始化的全局数据,特指small objects T或t :代码段的数据,.test段 U :符号未定义 W或w :符号为弱符号,当系统有定义符号时,使用定义符号,当系统未定义符号且定义了弱符号时,使用弱符号。 ? :unknown符号 ``` 列出 .so 的函数: ``` nm -D libtest.so ``` # ar ar命令用于建立或修改备存文件,或是从备存文件中抽取文件。 ar可让您集合许多文件,成为单一的备存文件。在备存文件中,所有成员文件皆保有原来的属性与权限。 例如,显示所有对象文件(.o文件)的列表: ```bash [yz@bogon ~]$ ar -t ~/postgresql/pg_bin/lib/libpq.a fe-auth-scram.o fe-connect.o fe-exec.o fe-lobj.o fe-misc.o fe-print.o fe-protocol3.o fe-secure.o fe-trace.o legacy-pqsignal.o libpq-events.o pqexpbuffer.o fe-auth.o ``` ## ar选项 * d:从库中删除模块。按模块原来的文件名指定要删除的模块。如果使用了任选项v则列出被删除的每个模块。 * m:该操作是在一个库中移动成员。当库中如果有若干模块有相同的符号定义(如函数定义),则成员的位置顺序很重要。如果没有指定任选项,任何指定的成员将移到库的最后。也可以使用'a','b',或'I'任选项移动到指定的位置。 * p:显示库中指定的成员到标准输出。如果指定任选项v,则在输出成员的内容前,将显示成员的名字。如果没有指定成员的名字,所有库中的文件将显示出来。 * q:快速追加。增加新模块到库的结尾处。并不检查是否需要替换。'a','b',或'I'任选项对此操作没有影响,模块总是追加的库的结尾处。如果使用了任选项v则列出每个模块。 这时,库的符号表没有更新,可以用'ar s'或ranlib来更新库的符号表索引。 * r:在库中插入模块(替换)。当插入的模块名已经在库中存在,则替换同名的模块。如果若干模块中有一个模块在库中不存在,ar显示一个错误消息,并不替换其他同名模块。默认的情况下,新的成员增加在库的结尾处,可以使用其他任选项来改变增加的位置。 * t:显示库的模块表清单。一般只显示模块名。 * x:从库中提取一个成员。如果不指定要提取的模块,则提取库中所有的模块。 # objdump 实例: ```bash [yz@bogon ~]$ objdump -h ~/postgresql/pg_bin/bin/postgres /home/yz/postgresql/pg_bin/bin/postgres: 文件格式 elf64-x86-64 节: Idx Name Size VMA LMA File off Algn 0 .interp 0000001c 00000000004002a8 00000000004002a8 000002a8 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 1 .note.gnu.build-id 00000024 00000000004002c4 00000000004002c4 000002c4 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 2 .note.ABI-tag 00000020 00000000004002e8 00000000004002e8 000002e8 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 3 .gnu.hash 000139c4 0000000000400308 0000000000400308 00000308 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 .dynsym 0003b058 0000000000413cd0 0000000000413cd0 00013cd0 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 5 .dynstr 0002cfe3 000000000044ed28 000000000044ed28 0004ed28 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 6 .gnu.version 00004eb2 000000000047bd0c 000000000047bd0c 0007bd0c 2**1 CONTENTS, ALLOC, LOAD, READONLY, DATA 7 .gnu.version_r 00000110 0000000000480bc0 0000000000480bc0 00080bc0 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA …… ``` objdump命令是Linux下的反汇编目标文件或者可执行文件的命令,它还有其它作用,用于分析ELF文件: * -f:显示test的文件头信息 * -d:反汇编test中的需要执行指令的那些section * -D:与-d类似,但反汇编test中的所有section * -h:显示test的Section Header信息 * -x:显示test的全部Header信息 * -s:除了显示test的全部Header信息,还显示他们对应的十六进制文件代码。 列出 .so 的函数 ``` objdump -tT libtest.so ``` # 参考 * [绝对强大的三个linux指令: ar, nm, objdump](https://www.cnblogs.com/mydriverc/p/7346608.html) * [查看Linux下库文件(a, so)中函数、变量](https://www.cnblogs.com/clovershell/p/13131514.html)