Welcome 微信登录

首页 / 操作系统 / Linux / Linux平台代码覆盖率测试-编译过程自动化及对链接的解释

Content0. 序1. 生成各个文件的步骤1.1 未加入覆盖率测试选项1.1.1 编译步骤1.1.2 目标文件的符号表1.2 加入覆盖率测试选项1.2.1 编译步骤1.2.2 目标文件的符号表1.3 gcc verbose选项2. 编译自动化2.1 使用collect2的makefile2.2 不使用collect2的makefile3. 关于链接的讨论3.1 链接顺序讨论3.2 错误链接顺序的例子4. 额外的话5. 小结  0. 序 "Linux平台代码覆盖率测试-GCC插桩前后汇编代码对比分析"一文中的编译过程能否自动化?能否使用makefile的方式进行?其链接过程使用ld或者collect2如何? ——这将是本文讨论的重点。本文gcc版本为gcc-4.1.2。 1. 生成各个文件的步骤 1.1 未加入覆盖率测试选项 1.1.1 编译步骤 (1) 预处理:生成test.i文件 # cpp test.c -o test.i    //或者# cpp test.c > test.i     //或者# gcc -E test.c -o test.i (2) 编译:生成test.s文件 # gcc -S test.i (3) 汇编:生成test.o文件 # as -o test.o test.s     //或者# gcc -c test.s -o test.o (4) 链接:生成可执行文件test # gcc -o test test.o 或者,
# /usr/libexec/gcc/i386-RedHat-linux/4.1.2/collect2 --eh-frame-hdr --build-id -m elf_i386 --hash-style=gnu -dynamic-linker /lib/ld-linux.so.2 /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crti.o /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbegin.o -L/usr/lib/gcc/i386-redhat-linux/4.1.2 -L/usr/lib/gcc/i386-redhat-linux/4.1.2 -L/usr/lib/gcc/i386-redhat-linux/4.1.2/../../.. -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crtn.o test.o -o test
因/usr/lib/gcc/i386-redhat-linux/4.1.2/../../..就是/usr/lib,因此,也可以简写为。
/usr/libexec/gcc/i386-redhat-linux/4.1.2/collect2 --eh-frame-hdr --build-id -m elf_i386 --hash-style=gnu -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbegin.o -L/usr/lib/gcc/i386-redhat-linux/4.1.2 -L/usr/lib/gcc/i386-redhat-linux/4.1.2 -L/usr/lib -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o /usr/lib/crtn.o test.o -o test
1.1.2 目标文件的符号表 可通过如下命令查看test.o中的符号表。//后是笔者加入的注释。
# objdump -t test.o test.o:     file format elf32-i386 SYMBOL TABLE:00000000 l    df *ABS*  00000000 test.c00000000 l    d  .text  00000000 .text00000000 l    d  .data  00000000 .data00000000 l    d  .bss   00000000 .bss00000000 l    d  .rodata        00000000 .rodata00000000 l    d  .note.GNU-stack        00000000 .note.GNU-stack00000000 l    d  .comment       00000000 .comment00000000 g     F .text  0000005f main00000000         *UND*  00000000 puts    //就是undefined,故需要连接其他的目标文件 # nm test.o00000000 T main    //T即为text symbol,大写表示global         U puts    //就是undefined,故需要连接其他的目标文件 

1.2 加入覆盖率测试选项 1.2.1 编译步骤 步骤同上,只是在编译生成test.s文件时加上"-fprofile-arcs -ftest-coverage"覆盖率测试选项即可。 另外,使用collect2的链接步骤稍有不同,需要链接gcov静态库(libgcov.a)。如下。
# /usr/libexec/gcc/i386-redhat-linux/4.1.2/collect2 --eh-frame-hdr --build-id -m elf_i386 --hash-style=gnu -dynamic-linker /lib/ld-linux.so.2 /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crti.o /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbegin.o test.o -L/usr/lib/gcc/i386-redhat-linux/4.1.2 -L/usr/lib/gcc/i386-redhat-linux/4.1.2 -L/usr/lib/gcc/i386-redhat-linux/4.1.2/../../.. -lgcov -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crtn.o -o test
或者简写为。
/usr/libexec/gcc/i386-redhat-linux/4.1.2/collect2 --eh-frame-hdr --build-id -m elf_i386 --hash-style=gnu -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbegin.o test.o -L/usr/lib/gcc/i386-redhat-linux/4.1.2 -L/usr/lib/gcc/i386-redhat-linux/4.1.2 -L/usr/lib -lgcov -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o /usr/lib/crtn.o -o test
当然,命令亦会完成链接并生成可执行文件。# gcc -o test test.o -lgcov libgcov.a位于/usr/lib/gcc/i386-redhat-linux/4.1.2目录。 1.2.2 目标文件的符号表 看看加入覆盖率测试选项后的目标文件test.o中的符号表。
# objdump -t test.o test.o:     file format elf32-i386 SYMBOL TABLE:00000000 l    df *ABS*  00000000 test.c00000000 l    d  .text  00000000 .text00000000 l    d  .data  00000000 .data00000000 l    d  .bss   00000000 .bss00000000 l    d  .rodata        00000000 .rodata000000eb l     F .text  00000014 _GLOBAL__I_0_main00000000 l    d  .ctors 00000000 .ctors00000000 l    d  .note.GNU-stack        00000000 .note.GNU-stack00000000 l    d  .comment       00000000 .comment00000000 g     F .text  000000eb main00000000         *UND*  00000000 puts              //就是undefined,故需要连接其他的目标文件,下同00000000         *UND*  00000000 __gcov_merge_add00000000         *UND*  00000000 __gcov_init # nm test.o000000eb t _GLOBAL__I_0_main    //t即为text symbol,小写表示local         U __gcov_init          //就是undefined,故需要连接其他的目标文件,下同         U __gcov_merge_add00000000 T main         U puts
1.3 gcc verbose选项 这是如何知道的呢?——gcc命令-v选项即可。# gcc -v test.c [-o test]# gcc -fprofile-arcs -ftest-coverage -v test.c [-o test][]表示出现0次或1次。
-v,即verbose选项,以下是中的解释,原文更贴切,此处不翻译。
The "-v" option can also be used to display detailed information about the exact sequence of commands used to compile and link a program.