ldd、objdump、nm、strings、strip等工具

鸟窝 2018-11-13 19:40

最近在做Docker镜像的时候发现镜像文件非常大,需要找出程序的依赖库,减少程序的大小,所以整理了一下相关的工具。基本上这些工具都在GNU Binutils中。

GNU Binary Utilities或binutils是一整套的编程语言工具程序,用来处理许多格式的目标文件。当前的版本原本由在Cygnus Solutions的程序员以Binary File Descriptor library(libbfd)所撰写。这个工具程序通常搭配GCC、make、和GDB这些程序来使用。

它包含20个左右的工具,本文介绍了我在创建Docker镜像的时候的使用的几种工具。

ldd

ldd不是GNU Binutils工具集中的一个工具,但是却是一个非常有用的工具, 它可以显示程序或者共享库所需的共享库。

例如:

12345
   # ldd mainlinux-vdso.so.1 =>  (0x00007ffc88fd4000)libpthread.so.0 => /lib64/libpthread.so.0 (0x00007faee13b8000)libc.so.6 => /lib64/libc.so.6 (0x00007faee0feb000)/lib64/ld-linux-x86-64.so.2 (0x00007faee15d4000)

依照ldd得手册, 有时候ldd会通过执行程序来获取依赖信息,对于来源不明的程序,执行这些程序可能会带来风险,所以对于来源不明的程序,可以使用objdump来分析。

objdump

onjdump可以显示目标文件的信息,可以通过参数控制要显示的内容。

比如-p可以显示文件头内容, 通过grep可以查看依赖的库。

1234
# objdump -p  main|grep GLIBC0x09691a75 0x00 02 GLIBC_2.2.50x09691972 0x00 03 GLIBC_2.3.20x09691a75 0x00 04 GLIBC_2.2.5

甚至可以查看-T可以查看动态符号表的内容:

1234567891011121314
# objdump -T  main|grep GLIBC0000000000000000      DO *UND*	0000000000000000  GLIBC_2.2.5 stderr0000000000000000      DO *UND*	0000000000000000  GLIBC_2.2.5 fwrite0000000000000000      DO *UND*	0000000000000000  GLIBC_2.2.5 vfprintf0000000000000000      DO *UND*	0000000000000000  GLIBC_2.2.5 fputc0000000000000000      DO *UND*	0000000000000000  GLIBC_2.2.5 abort0000000000000000      DO *UND*	0000000000000000  GLIBC_2.2.5 pthread_mutex_lock0000000000000000      DO *UND*	0000000000000000  GLIBC_2.3.2 pthread_cond_wait0000000000000000      DO *UND*	0000000000000000  GLIBC_2.2.5 pthread_mutex_unlock0000000000000000      DO *UND*	0000000000000000  GLIBC_2.3.2 pthread_cond_broadcast0000000000000000      DO *UND*	0000000000000000  GLIBC_2.2.5 pthread_create0000000000000000      DO *UND*	0000000000000000  GLIBC_2.2.5 nanosleep0000000000000000      DO *UND*	0000000000000000  GLIBC_2.2.5 pthread_detach......

nm

nm显示目标文件的符号。

12345678910111213141516171819202122
# nm go/bin/glide |more0000000000908680 r andMask0000000000901d00 r bswapMask00000000009036c0 r BSWAP_SHUFB_CTL0000000000b000e0 B bufio.ErrAdvanceTooFar0000000000b000f0 B bufio.ErrBufferFull0000000000b00100 B bufio.ErrFinalToken0000000000b00110 B bufio.ErrInvalidUnreadByte0000000000b00120 B bufio.ErrInvalidUnreadRune0000000000b00130 B bufio.ErrNegativeAdvance0000000000b00140 B bufio.ErrNegativeCount0000000000b00160 B bufio.errNegativeRead0000000000b00170 B bufio.errNegativeWrite0000000000b00150 B bufio.ErrTooLong00000000004d9140 T bufio.init0000000000b21120 B bufio.initdone.00000000004d6510 T bufio.(*Reader).Buffered00000000004d59d0 T bufio.(*Reader).Discard00000000004d5590 T bufio.(*Reader).fill00000000004d57c0 T bufio.(*Reader).Peek00000000004d5b70 T bufio.(*Reader).Read......

strings

strings显示文件中的可打印字符。

1234
# strings main|grep GLIBCGLIBC_2.2.5GLIBC_2.3.2GLIBC_2.2.5

strip

通过上面的工具,可以分析出文件的依赖库,创建Docker镜像的时候只需把所需的依赖库加进去即可。

如果程序本身比较大,可以将程序压缩,去掉不需要的一些数据, 比如使用strip进行裁剪。

你可以通过参数控制要丢掉的哪些符号。
比如去除符号表和行号信息:

1
strip main

libtool

Linux下的GNU Libtool是一种属于GNU建构系统的GNU程序设计工具,用来产生便携式的库。这里引用libtool手册的说明:

1
libtool --mode=compile gcc -g -O -c foo.c

MacOS下的libtool时另外一个工具,可以用来创建库:

12
libtool -dynamic -o c.dylib a.o b.o libtool -static -o c.a a.o b.o

ar

可以对静态库做创建、修改和提取的操作。

123
ar rv libNAME.a file1.o file2.oar -d lib.a conflict.oar -x lib.a

otool

比nm更强大,mac还有一个对应的图形化工具——MachOView。

查看依赖动态库:

1
otool -L a.out

查看反汇编代码段:

1
otool -v -t a.out

[返回] [原文链接]