一 获得二进制文件里符号的工具
1 代码
#include<iostream>
using namespace std;
class Test{
public:
int Hello(){
cout<<"Hello world!"<<endl;
return 0;
}
};
int main(){
Test test;
int iRet=test.Hello();
cout<<"iRet="<<iRet<<endl;
return 0;
}
2 makefile
test:test.o
g++ test.o -o test
test.o:test.cpp
g++ -c test.cpp
3 编译并查看
[root@localhost 0406]# make
g++ -c test.cpp
g++ test.o -o test
[root@localhost 0406]# nm test
0000000000601064 B __bss_start
0000000000601190 b completed.6345
U __cxa_atexit@@GLIBC_2.2.5
0000000000601060 D __data_start
0000000000601060 W data_start
0000000000400800 t deregister_tm_clones
0000000000400870 t __do_global_dtors_aux
0000000000600de8 t __do_global_dtors_aux_fini_array_entry
0000000000400a18 R __dso_handle
0000000000600df8 d _DYNAMIC
0000000000601064 D _edata
0000000000601198 B _end
0000000000400a04 T _fini
0000000000400890 t frame_dummy
0000000000600dd8 t __frame_dummy_init_array_entry
0000000000400bd0 r __FRAME_END__
0000000000601000 d _GLOBAL_OFFSET_TABLE_
0000000000400941 t _GLOBAL__sub_I_main
w __gmon_start__
0000000000400708 T _init
0000000000600de8 t __init_array_end
0000000000600dd8 t __init_array_start
0000000000400a10 R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000600df0 d __JCR_END__
0000000000600df0 d __JCR_LIST__
w _Jv_RegisterClasses
0000000000400a00 T __libc_csu_fini
0000000000400990 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
00000000004008bd T main
0000000000400830 t register_tm_clones
00000000004007d0 T _start
0000000000601068 D __TMC_END__
0000000000400904 t _Z41__static_initialization_and_destruction_0ii
0000000000400956 W _ZN4Test5HelloEv
U _ZNSolsEi@@GLIBCXX_3.4
U _ZNSolsEPFRSoS_E@@GLIBCXX_3.4
U _ZNSt8ios_base4InitC1Ev@@GLIBCXX_3.4
U _ZNSt8ios_base4InitD1Ev@@GLIBCXX_3.4
0000000000601080 B _ZSt4cout@@GLIBCXX_3.4
U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@@GLIBCXX_3.4
0000000000601191 b _ZStL8__ioinit
U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@@GLIBCXX_3.4
4 说明
第一列是当前符号的地址。
第二列是当前符号的类型。
第三列是当前符号的名称。
_ZN4Test5HelloEv这样的符号,可能不明白其含义,这里介绍一个小技巧,加上-C,就可以把难以识别的符号,转换为便于阅读的符号TestHello().这个主意是C++的mangle机制导致的,加上-C就是指定列出符号是demangle了。
0000000000400956 W Test::Hello()
U std::ostream::operator<<(int)@@GLIBCXX_3.4
U std::ostream::operator<<(std::ostream& (*)(std::ostream&))@@GLIBCXX_3.4
U std::ios_base::Init::Init()@@GLIBCXX_3.4
U std::ios_base::Init::~Init()@@GLIBCXX_3.4
nm命令作用:
1 判断指定程序中有没有定义指定的符号(比较常用的方式:nm -C proc|grep symbol)
2 解决程序编译时undefined reference的错误,以及mutiple definition的错误。
3 查看某个符号的地址,以及在进程空间的大概位置(bss、data、text区)
二 减少目标文件大小的工具
1 减肥命令
[root@localhost 0406]# ll
total 24
-rw-r--r--. 1 root root 69 May 1 08:52 makefile
-rwxr-xr-x. 1 root root 9224 May 12 08:22 test
-rw-r--r--. 1 root root 258 May 1 08:52 test.cpp
-rw-r--r--. 1 root root 3328 May 12 08:22 test.o
[root@localhost 0406]# strip test
[root@localhost 0406]# ll
total 20
-rw-r--r--. 1 root root 69 May 1 08:52 makefile
-rwxr-xr-x. 1 root root 6288 May 12 08:30 test
-rw-r--r--. 1 root root 258 May 1 08:52 test.cpp
-rw-r--r--. 1 root root 3328 May 12 08:22 test.o
执行命令后,大小减少了近1/3。strip命令能从ELF文件中有选择性地除去行号信息、重定位信息、调试段、typchk段、注释段、文件头以及所有或部分符号表。但一旦使用该命令,则很难调试文件符号。因此,通常只在已经调试和测试过的生成模块上使用strip命令,来减少对象文件所需的存储量开销。