1. Build的四个阶段
1) 预处理:gcc -E (cpp)
选项:-D -U -I -M -g3 (output macro info for debugger)
2) 编译: gcc -S (cc1)
优化选项:-O0, -O1, -O2, -O3, -Os
一个关于优化级别选项的对比例子,
不优化编译
>gcc -g2 memset.c
查看产生的汇编代码,
>objdump -dS a.out
优化编译
>gcc -g2 -O3 memset.c
建议不要在测试阶段打开优化。
gdb信息选项:
-g == -g2
-g3 include symbols and extra.
下面显示了不同的级别产生的代码的大小。
在产生的ELF(Executable & Library Format, magic is /x7FELF, man 5 elf)文件中,debug信息占到若干个section,
使用objdump -W可以查看具体的debug段信息。
3) 汇编: gcc -c (as)
可以使用-m(achine)选项指定产生目标平台的代码。
4) 链接: ld
insertion of libraries(static) or reference(dynamic).
选项:
-l -L -shared -static
在release阶段,可以strip掉debug信息, “-d”选项只删除掉调试符号信息。
2. Parse ELF tools
1) objdump
常用选项: -d(反汇编代码段),-g -W (显示调试信息), -S(同-d,显示源文件),-s(以十六进制格式显示所有段) ,-t(显示符号表),-x(显示所有头部信息)
2) readelf
3) nm: 显示符号表,要求不能被strip过
4) ldd: resolve shared library dependencies
举例说明,
动态库的load可以分为装载时和运行时(dl_open),下面是运行时装载动态库的例子。
3. gdb
3种使用模式:
1) start a binary in the debugger, gdb a.out
2) running process attachment, gdb a.out PID
3) post-mortem, core file analysis, gdb a.out core
常用命令总结:
break, bt(backtrack of stack call of current thread), disass, i r, stepi, info threads, r, c, p, x(dump memory from address)
关于core文件
1) ulimit -c -s -t
注意编译器在编译程序时,本身也是需要栈空间的。可以使用函数getrlimit, setrlimit来get/set resource limits。
2) core文件的格式
man 5 core to reference the naming rule of core dump files.
注意:如果发生了core,但是gdb backtrace找不到在哪个函数core了,可以先ldd这个程序,看依赖于哪些动态链接库,然后nm动态链接库并且搜索core的地址的前几位,基本就可确定在哪个函数core了。一般的text段以0x8***开始。
对于正在运行的程序,可以通过检查maps文件来确定so的地址范围, 例如