主要是在如何解析 ELF 格式的文件。
objdump
-h, --section-headers, --headers
查看目标文件的头部信息。
-x, --all-headers
显示所有的头部信息,包括了符号表和重定位表,等价于 -a -f -h -p -r -t 。
-s, --full-contents
显示所请求段的全部信息,通常用十六进制表示,默认只会显示非空段。
-d, --disassemble
反汇编,一般只反汇编含有指令的段。
-t, --syms
显示符号表,与nm类似,只是显示的格式不同,当然显示与文件的格式相关,对于ELF如下所示。
00000000 l d .bss 00000000 .bss
00000000 g .text 00000000 fred
readelf
用于读取 ELF 格式文件,包括可执行程序和动态库,常用参数如下。
-a --all
显示所有信息,等价于-h -l -S -s -r -d -V -A -I
-h --file-header
文件头信息;
-l --program-headers
程序的头部信息;
-S --section-headers
各个段的头部信息;
-s --syms
显示符号表,也就是.symtab段;
-e --headers
全部头信息,等价于-h -l -S;
-x, --hex-dump=<number or name>
十六进制方式打印某个段;
示例用法:
----- 读取dynstr段,包含了很多需要加载的符号,每个动态库后跟着需要加载函数
$ readelf -p .dynstr hello
----- 以十六进制方式读取dynstr段
$ readelf -x .dynstr hello
----- 查看是否含有调试信息
$ readelf -S hello | grep debug
objcopy
用于转换目标文件。
-S / --strip-all
不从源文件中拷贝重定位信息和符号信息到输出文件(目的文件)中去。
-I bfdname/--input-target=bfdname
明确告诉程序源文件的格式是什么,bfdname是BFD库中描述的标准格式名。
-O bfdname/--output-target=bfdname
使用指定的格式来写输出文件(即目标文件),bfdname是BFD库中描述的标准格式名,
如binary(raw binary 格式)、srec(s-record 文件)。
-R sectionname/--remove-section=sectionname
从输出文件中删掉所有名为section-name的段。
上一步的 strip 命令只能拿掉一般 symbol table,有些信息还是沒拿掉,而这些信息对于程序的最终执行没有影响,如: .comment
.note.ABI-tag
.gnu.version
就是完全可以去掉的。
所以说程序还有简化的余地,我们可以使用 objcopy 命令把它们抽取掉。
$ objcopy -R .comment -R .note.ABI-tag -R .gnu.version hello hello1
nm
用来显示指定文件中的符号信息,可以是对象文件、可执行文件、动态库等。
符号
第二列标示了符号的类型,大写表示为全局变量,小写则表示为局部的变量。
I
对另一个符号的间接引用,一般为动态库。T
位于代码区。
当出现了 I
指定的符号时,另外比较常见的是通过 @
指定版本号,例如 memcpy@@GLIBC_2.14
或者 memcpy@GLIBC_2.2.5
,