一 : objdump: 功能最丰富的二进制分析工具。
/usr/local/linaro-armv8l-eabi-2017.08-gcc7.1/bin/arm-eabi-objdump -D -S libnetx.a > a.s
objdump -x -j .bss demoApp,对bss节进行反汇编操作。
注意如果是交叉编译,需要用编译时使用的toolchain的objdump。
比如:/usr/local/linaro-armv8l-eabi-2017.08-gcc7.1/bin/arm-eabi-objdump
1)-a或者–archive-headers
这个参数起到的作用和ar命令相似,用来看一个.a静态库文件中包含了哪些目标文件。
2)-f或者–file-headers
输出目标ELF文件头中包含的信息
表明这是个ELF文件,支持处理器指令集是armv5te,等等。总体来说,信息量有限。
3)-h或者–[section-]headers
输出目标文件中节表(Section Table)中所包含的所有节头(Section Header)的信息,例如:
可以看到,这个文件共有18个有效节区。从中,我们可以了解到每个节区的名字,大小,和文件头的偏移位置,对齐属性,以及其它的一些属性。
4)-x或者–all-headers
显示目标文件的所有头的信息,包括ELF文件头、程序头(Program Header)和节头(Section Header)。除了这些头之外,还包括动态节区(Dynamic Section)和符号表(Symbol Table)内的信息。例如:
5)-d或者–disassemble
反汇编目标ELF文件中包含可执行指令的哪些节区中的内容,例如:
如果有汇编语言的功底,就可以通过这个命令来探究目标文件中每个函数的实现逻辑,非常的方便。
6)-D或者–disassemble-all
-D与前面的-d类似,唯一的不同是,用-D会反汇编目标ELF文件中的所有内容,而前面的-d只会反汇编可执行代码的部分。
7)-s或者–full-contents
显示目标文件每个节区的二进制完整内容,对应的会显示该内容在目标文件中的偏移位置,还有将内容转换成ASCII码的形式
8)-S或者–source
混合显示源码和汇编代码,如果编译目标文件的时候指定了-g参数的话,效果会非常明显。否则,和-d参数没有什么区别,事实上-S参数默认包含了-d参数。
9)-t或者–syms
输出目标文件的符号表(Symbol Table),即目标ELF文件中名字叫做.symtab节内的内容。
10)-T或者–dynamic-syms
输出目标文件的动态符号表(Dynamic Symbol Table),即目标ELF文件中名字叫做.dynsym节内的内容,例如:
通过这张表内的信息,可以看出由本ELF文件中导出的符号,和需要从别的动态库中导入的符号。如果第三列显示“UND”表明这个符号在本ELF文件中未定义,也就是说这个符号要从别的动态库中导入,其它的情况表明这个符号由本ELF文件中定义。
11)-r或者–reloc
显示目标文件的静态重定位入口。
12)-R或者–dynamic-reloc
显示目标文件的动态重定位入口,例如:
这个参数仅仅对于动态目标文件有意义,比如动态库文件(.so)。
13)-j或者–section=
表示只显示名字为“NAME”节区中的内容。
14 : -p : 可以查看动态节信息,(查看DT_RPATH, DT_RUNPATH设置)
三:file工具 : 可以查看任何文件的详细信息
四: size程序 : 可以快速获取ELF节的字节长度信息,包括text, data, bss等节。
五:ldd命令: 可以显示出客户二进制文件启动时需要静态加载的动态库的完整列表(即加载时依赖项)。链接器会将直接依赖项的列表写入二进制文件的ELF格式字段中,ldd会扫描二进制文件并找到这些信息。ldd命令会根据依赖库的名称,根据运行时搜索规则找到库文件的实际位置,并列出。但ldd不能列出dlopen打开的库文件。objdump工具同样可以实现该功能,objdump -p xxx.elf | grep NEEDED 或者 readelf -d xxx.elf | grep NEEDED 这两个命令只会读取elf文件的直接依赖项,不会分析依赖项的依赖库,但ldd命令会一直递归分析所以直接依赖项所有依赖的项。
六 : nm命令 : 可以列出二进制文件的符号列表。如果二进制文件包含c++,默认会打印出经过名称修饰的符号名。对共享库而言,不仅会列出导出符号,也会列出所有符号。
nm -D xxx : 只列出动态节中的符号。(即共享库中导出的或对外可见的符号)
nm -C xxxx : 列出未经过名称修饰的格式。
nm -D –no-demangle <二进制文件> : 打印出共享库中名称修饰后的动态符号。
nm -A <库文件路径>/* | grep symbol-name 该命令可以在相同目录下的二进制文件中搜索某符号。
nm -u <二进制文件> : 列出库中未定义的符号(这个库文件本身并不包含该符号,但期望在运行时加载的其他动态库中提供。)
七: readelf : readelf的功能,objdump基本都能实现
readefl -h 可以打印出库中每个目标文件的ELF头信息
readelf -S 用于列出所有的节。
readelf –symbols 列出所有符号。
readelf –dyn-syms 只列出动态符号。
readelf -d 可以列出动态节的信息,比如DT_RPATH ,DT_RUNPATH
readelf -r 可以查看重定位节的信息。
readefl -x 可以指定某个节,并显示其数据的十六进制转储信息。
readelf -segments 命令可以显示ELF二进制文件的段信息。
readelf -debug-dump=line file_path | wc -l 查看二进制文件调试信息。
八:ldconfig工具
ldconfig可以指定装载器运行时的搜索路径。我们经常将ldconfig命令行实用程序作为软件包安装过程的最后一步来执行,将共享库文件的路径作为参数输入给ldconfig,ldconfig会搜索共享库路径,并更新用于记录这些信息的文件:
/etc/ld.so.conf文件 : 包含了一组目录列表,默认会扫描里面的库文件
/etc/ld.so.cache文件:将多个路径作为输入参数传递给ldconfig时,ldconfig会将整个扫描过程中查找到的动态库的文件名以ascii文本列表的形式写入这个文件。
九:chrpath工具 可以修改ELF二进制文件的rpath(DT_RPATH字段),可以在DT_RPATH原始字符串长度范围内对其进行修改。 可以删除原有的DT_RPATH字段。
十:patchelf工具 :
不属于标准仓库的一部分,可以修改和设置runpath(DT_RUNPATH字段)。不受原始runpath长度的限制。
patchelf --set-rpath <one or more paths> <executable>
//one or more paths 可以定义多个路径,用冒号分隔
十一: strip命令:
可以清除所有动态加载过程中不需要的库文件符号。
运行时分析工具:
一:strace :
可以追踪由进程产生的系统调用与进程接收的信号。
二:addr2line
可以将运行时地址转换为地址所对应的源代码文件信息和行号。当且仅当使用调试模式构建二进制文件,即-g-o0编译器选项,可以帮助分析程序崩溃信息,比如程序崩溃时程序计数器地址会打印到终端,
#00 pc 0000d8cc6 /usr/mylibs/libxyz.so
addr2line -C -f -e /usr/mylibs/libxyz.so 0000d8cc6
//输出内容如下 /projects/mylib/src/mylib.c: 45
静态库工具:
静态库的大多数功能都可以使用ar归档工具完成。不仅可以将目标文件合并成静态库,也可以列出这些目标文件的内容,或是移除个别的目标文件,或是使用较新的版本替代这些目标文件。
//创建静态库
ar -rcs <库文件名> <目标文件列表>
ar -rcs libmystatic.a first.o second.o third.o fourth.o
//列出静态库中的目标文件
ar -t <库文件名>
//从目标中删除文件
ar -d libmystatic.a first.o
//将目标加入库文件
ar -r libmystatic.a first.o