/ sfoolish_post / 嵌入式调试过程中交叉编译工具的使用

嵌入式调试过程中交叉编译工具的使用

2013-09-04 posted in [嵌入式]

本文讲述了嵌入式开发过程中交叉编译工具的使用及实际开发过程中的注意事项,并简单介绍了几个常用二进制工具命令的使用。

编译测试程序

一些注意事项:

1. [必须] 不要对执行文件做 strip 符合信息操作,至少做一下备份。 strip 后就找不到函数名了。因为对象文件链接时顺序是不固定的,所以相同源码每次编译出来的结果,一般情况下都是不一样的。
2. [可选] 去除 -O2 等 gcc 优化选项,
3. [可选] 编译时添加 -g 选项,-g 选项会在编译程序的时候添加调试信息。 2,3 两个可选项一般情况下,只能在调试定位问题时使用。 上述命令,选项对可执行文件大小产生较大的改变。在嵌入式类,内存敏感的场景调试过程中,还要考虑执行文件大小改变对系统运行的影响。

编译选项对执行文件的影响

-g 选项

-g 选项会在编译程序的时候添加调试相关的 section 。有了调试 section 对执行文件反汇编后,可以看到 C 代码和汇编代码结合的混合代码。

$ cat gdb_test.c 
```
    static void segmentation_fault(void)
    {
        *(int *)0 = 0;
    }
    
    static void func(void)
    {
        segmentation_fault();
    }
    
    int main(int argc, char *argv[])
    {
        func();
    
        return 0;
    }
```
$ arm-linux-uclibcgnueabi-gcc -g -o gdb_test gdb_test.c
$ arm-linux-uclibcgnueabi-objdump -S gdb_test
```
    ... ...
    # 000083c4 是函数起始地址,segmentation_fault 为函数名
    000083c4 <segmentation_fault>:
    static void segmentation_fault(void)
    {
        # 83c4 指令地址, e52db004 为指令码, push {fp} 为 arm 指令, ; (str fp, [sp, #-4]!) 为注释
        83c4:       e52db004        push    {fp}            ; (str fp, [sp, #-4]!)
        83c8:       e28db000        add     fp, sp, #0      ; 0x0
        *(int *)0 = 0;
        83cc:       e3a03000        mov     r3, #0  ; 0x0
        83d0:       e3a02000        mov     r2, #0  ; 0x0
        83d4:       e5832000        str     r2, [r3]
    }
        83d8:       e28bd000        add     sp, fp, #0      ; 0x0
        83dc:       e8bd0800        pop     {fp}
        83e0:       e12fff1e        bx      lr
    
    000083e4 <func>:
    
    static void func(void)
    {
        83e4:       e92d4800        push    {fp, lr}
        83e8:       e28db004        add     fp, sp, #4      ; 0x4
        segmentation_fault();
        83ec:       ebfffff4        bl      83c4 <segmentation_fault>
    }
        83f0:       e8bd8800        pop     {fp, pc}
    
    000083f4 <main>:
    
    int main(int argc, char *argv[])
    {
        83f4:       e92d4800        push    {fp, lr}
        83f8:       e28db004        add     fp, sp, #4      ; 0x4
        83fc:       e24dd008        sub     sp, sp, #8      ; 0x8
        8400:       e50b0008        str     r0, [fp, #-8]
        8404:       e50b100c        str     r1, [fp, #-12]
            func();
        8408:       ebfffff5        bl      83e4 <func>
    
            return 0;
        840c:       e3a03000        mov     r3, #0  ; 0x0
    }
        8410:       e1a00003        mov     r0, r3
        8414:       e24bd004        sub     sp, fp, #4      ; 0x4
        8418:       e8bd8800        pop     {fp, pc}
    ... ...
```

通过 readelf 查看到是否添加 -g 选项,对生成可执行文件内容的影响。

$ arm-linux-uclibcgnueabi-gcc -o gdb_test gdb_test.c    
$ arm-linux-uclibcgnueabi-readelf -S gdb_test        
```
    There are 23 section headers, starting at offset 0x11bc:
    
    Section Headers:
      [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
      [ 0]                   NULL            00000000 000000 000000 00      0   0  0
      [ 1] .interp           PROGBITS        00008134 000134 000014 00   A  0   0  1
      [ 2] .hash             HASH            00008148 000148 00004c 04   A  3   0  4
      [ 3] .dynsym           DYNSYM          00008194 000194 0000e0 10   A  4   1  4
      [ 4] .dynstr           STRTAB          00008274 000274 00007b 00   A  0   0  1
      [ 5] .rel.plt          REL             000082f0 0002f0 000010 08   A  3   7  4
      [ 6] .init             PROGBITS        00008300 000300 000010 00  AX  0   0  4
      [ 7] .plt              PROGBITS        00008310 000310 00002c 04  AX  0   0  4
      [ 8] .text             PROGBITS        0000833c 00033c 0000e0 00  AX  0   0  4
      [ 9] .fini             PROGBITS        0000841c 00041c 000010 00  AX  0   0  4
      [10] .eh_frame         PROGBITS        0000842c 00042c 000004 00   A  0   0  4
      [11] .init_array       INIT_ARRAY      00010f3c 000f3c 000004 00  WA  0   0  4
      [12] .fini_array       FINI_ARRAY      00010f40 000f40 000004 00  WA  0   0  4
      [13] .jcr              PROGBITS        00010f44 000f44 000004 00  WA  0   0  4
      [14] .dynamic          DYNAMIC         00010f48 000f48 0000b8 08  WA  4   0  4
      [15] .got              PROGBITS        00011000 001000 000014 04  WA  0   0  4
      [16] .data             PROGBITS        00011014 001014 000008 00  WA  0   0  4
      [17] .bss              NOBITS          0001101c 00101c 000004 00  WA  0   0  1
      [18] .comment          PROGBITS        00000000 00101c 0000c4 00      0   0  1
      [19] .ARM.attributes   ARM_ATTRIBUTES  00000000 0010e0 00002d 00      0   0  1
      [20] .shstrtab         STRTAB          00000000 00110d 0000ad 00      0   0  1
      [21] .symtab           SYMTAB          00000000 001554 000490 10     22  54  4
      [22] .strtab           STRTAB          00000000 0019e4 0001bb 00      0   0  1
    Key to Flags:
      W (write), A (alloc), X (execute), M (merge), S (strings)
      I (info), L (link order), G (group), x (unknown)
      O (extra OS processing required) o (OS specific), p (processor specific)
```
$ arm-linux-uclibcgnueabi-gcc -g -o gdb_test gdb_test.c 
$ arm-linux-uclibcgnueabi-readelf -S gdb_test    
```       
    There are 31 section headers, starting at offset 0x14fc:
    
    Section Headers:
      [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
      [ 0]                   NULL            00000000 000000 000000 00      0   0  0
      [ 1] .interp           PROGBITS        00008134 000134 000014 00   A  0   0  1
      [ 2] .hash             HASH            00008148 000148 00004c 04   A  3   0  4
      [ 3] .dynsym           DYNSYM          00008194 000194 0000e0 10   A  4   1  4
      [ 4] .dynstr           STRTAB          00008274 000274 00007b 00   A  0   0  1
      [ 5] .rel.plt          REL             000082f0 0002f0 000010 08   A  3   7  4
      [ 6] .init             PROGBITS        00008300 000300 000010 00  AX  0   0  4
      [ 7] .plt              PROGBITS        00008310 000310 00002c 04  AX  0   0  4
      [ 8] .text             PROGBITS        0000833c 00033c 0000e0 00  AX  0   0  4
      [ 9] .fini             PROGBITS        0000841c 00041c 000010 00  AX  0   0  4
      [10] .eh_frame         PROGBITS        0000842c 00042c 000004 00   A  0   0  4
      [11] .init_array       INIT_ARRAY      00010f3c 000f3c 000004 00  WA  0   0  4
      [12] .fini_array       FINI_ARRAY      00010f40 000f40 000004 00  WA  0   0  4
      [13] .jcr              PROGBITS        00010f44 000f44 000004 00  WA  0   0  4
      [14] .dynamic          DYNAMIC         00010f48 000f48 0000b8 08  WA  4   0  4
      [15] .got              PROGBITS        00011000 001000 000014 04  WA  0   0  4
      [16] .data             PROGBITS        00011014 001014 000008 00  WA  0   0  4
      [17] .bss              NOBITS          0001101c 00101c 000004 00  WA  0   0  1
      [18] .comment          PROGBITS        00000000 00101c 0000c4 00      0   0  1
      [19] .debug_aranges    PROGBITS        00000000 0010e0 000020 00      0   0  1
      [20] .debug_pubnames   PROGBITS        00000000 001100 00001b 00      0   0  1
      [21] .debug_info       PROGBITS        00000000 00111b 0000a2 00      0   0  1
      [22] .debug_abbrev     PROGBITS        00000000 0011bd 00006e 00      0   0  1
      [23] .debug_line       PROGBITS        00000000 00122b 000041 00      0   0  1
      [24] .debug_frame      PROGBITS        00000000 00126c 00006c 00      0   0  4
      [25] .debug_str        PROGBITS        00000000 0012d8 000060 01  MS  0   0  1
      [26] .debug_loc        PROGBITS        00000000 001338 000081 00      0   0  1
      [27] .ARM.attributes   ARM_ATTRIBUTES  00000000 0013b9 00002d 00      0   0  1
      [28] .shstrtab         STRTAB          00000000 0013e6 000115 00      0   0  1
      [29] .symtab           SYMTAB          00000000 0019d4 000530 10     30  64  4
      [30] .strtab           STRTAB          00000000 001f04 0001bb 00      0   0  1
    Key to Flags:
      W (write), A (alloc), X (execute), M (merge), S (strings)
      I (info), L (link order), G (group), x (unknown)
      O (extra OS processing required) o (OS specific), p (processor specific)
```

带 -g 选项生成的执行文件会变大。

$ arm-linux-uclibcgnueabi-gcc -o gdb_test gdb_test.c    
$ ls -lh gdb_test
```
    -rwxrwxr-x 1 sfoolish sfoolish 7.0K Apr 19 15:18 gdb_test
```
$ arm-linux-uclibcgnueabi-gcc -g -o gdb_test gdb_test.c 
$ ls -lh gdb_test
```
    -rwxrwxr-x 1 sfoolish sfoolish 8.2K Apr 19 15:18 gdb_test
```

-O2 选项

gcc -O2 等优化选项可能导致部分函数调用关系被优化,而且优化后的汇编代码更精简也就更难分析(一般情况下也不用看)。

$ arm-linux-uclibcgnueabi-gcc -g -O2 -o gdb_test gdb_test.c 
$ arm-linux-uclibcgnueabi-objdump -S gdb_test
```
    ... ...
    000083c4 <main>:
    static void segmentation_fault(void)
    {
        *(int *)0 = 0;
        83c4:       e3a03000        mov     r3, #0  ; 0x0
    int main(int argc, char *argv[])
    {
            func();
    
            return 0;
    }
        83c8:       e1a00003        mov     r0, r3
    static void segmentation_fault(void)
    {
        *(int *)0 = 0;
        83cc:       e5833000        str     r3, [r3]
    int main(int argc, char *argv[])
    {
            func();
    
            return 0;
    }
        83d0:       e12fff1e        bx      lr
    ... ...
```

strip 对执行文件的影响

用 readelf 查看 strip 对执行文件的影响。

$ arm-linux-uclibcgnueabi-strip  -s gdb_test
$ arm-linux-uclibcgnueabi-readelf -S gdb_test                       
```
    There are 21 section headers, starting at offset 0x11ac:
    
    Section Headers:
      [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
      [ 0]                   NULL            00000000 000000 000000 00      0   0  0
      [ 1] .interp           PROGBITS        00008134 000134 000014 00   A  0   0  1
      [ 2] .hash             HASH            00008148 000148 00004c 04   A  3   0  4
      [ 3] .dynsym           DYNSYM          00008194 000194 0000e0 10   A  4   1  4
      [ 4] .dynstr           STRTAB          00008274 000274 00007b 00   A  0   0  1
      [ 5] .rel.plt          REL             000082f0 0002f0 000010 08   A  3   7  4
      [ 6] .init             PROGBITS        00008300 000300 000010 00  AX  0   0  4
      [ 7] .plt              PROGBITS        00008310 000310 00002c 04  AX  0   0  4
      [ 8] .text             PROGBITS        0000833c 00033c 0000e0 00  AX  0   0  4
      [ 9] .fini             PROGBITS        0000841c 00041c 000010 00  AX  0   0  4
      [10] .eh_frame         PROGBITS        0000842c 00042c 000004 00   A  0   0  4
      [11] .init_array       INIT_ARRAY      00010f3c 000f3c 000004 00  WA  0   0  4
      [12] .fini_array       FINI_ARRAY      00010f40 000f40 000004 00  WA  0   0  4
      [13] .jcr              PROGBITS        00010f44 000f44 000004 00  WA  0   0  4
      [14] .dynamic          DYNAMIC         00010f48 000f48 0000b8 08  WA  4   0  4
      [15] .got              PROGBITS        00011000 001000 000014 04  WA  0   0  4
      [16] .data             PROGBITS        00011014 001014 000008 00  WA  0   0  4
      [17] .bss              NOBITS          0001101c 00101c 000004 00  WA  0   0  1
      [18] .comment          PROGBITS        00000000 00101c 0000c4 00      0   0  1
      [19] .ARM.attributes   ARM_ATTRIBUTES  00000000 0010e0 00002d 00      0   0  1
      [20] .shstrtab         STRTAB          00000000 00110d 00009d 00      0   0  1
    Key to Flags:
      W (write), A (alloc), X (execute), M (merge), S (strings)
      I (info), L (link order), G (group), x (unknown)
      O (extra OS processing required) o (OS specific), p (processor specific)
```
$ ls -lh gdb_test
```
    -rwxrwxr-x 1 sfoolish sfoolish 5.3K Apr 19 15:24 gdb_test
```

用 nm 查看 strip 对执行文件的影响

$ arm-linux-uclibcgnueabi-gcc -g -o gdb_test gdb_test.c 
$ arm-linux-uclibcgnueabi-nm -n gdb_test
```
             w _Jv_RegisterClasses
             U __uClibc_main
             U abort
    00008300 T _init
    0000833c T _start
    00008378 t __do_global_dtors_aux
    00008394 t frame_dummy
    # 000083c4 函数起始地址, t static 函数,segmentation_fault 函数名
    000083c4 t segmentation_fault
    000083e4 t func
    # 000083f4 函数起始地址, T global 函数,main 函数名
    000083f4 T main
    0000841c T _fini
    0000842c r __FRAME_END__
    0000842c A __exidx_end
    0000842c A __exidx_start
    00010f3c t __frame_dummy_init_array_entry
    00010f40 t __do_global_dtors_aux_fini_array_entry
    00010f44 d __JCR_END__
    00010f44 d __JCR_LIST__
    00010f48 d _DYNAMIC
    00011000 d _GLOBAL_OFFSET_TABLE_
    00011014 D __data_start
    00011014 W data_start
    00011018 D __dso_handle
    0001101c A __bss_start
    0001101c A __bss_start__
    0001101c A _edata
    0001101c b completed.5309
    00011020 A __bss_end__
    00011020 A __end__
    00011020 A _bss_end__
    00011020 A _end
```
$ arm-linux-uclibcgnueabi-strip -s gdb_test
$ arm-linux-uclibcgnueabi-nm -n gdb_test                
```
    arm-linux-uclibcgnueabi-nm: gdb_test: no symbols
```

运行测试程序生成 core 文件

# ulimit -c unlimited
# echo /mnt/gdb_test.core > /proc/sys/kernel/core_pattern  ;指定 core 生成路径,这步可选
# ./gdb_test
```
    Segmentation fault (core dumped)
```

sfoolish

About

sfoolish

爱生活,爱代码,爱折腾。。。