资讯详情

嵌入式的常用工具链

嵌入式开发中的常用工具gcc已经做了一定的总结,但是并不是只有gcc一个有用的工具,其中比较重要的工具有: 1、addr2line用于地址翻译,可以采用该工具判断某一个地址所在的函数,这样便于在出现错误时进行核对,检查函数的基本功能是否正确的实现。但是该工具只对存在调试信息的目标文件有效。通过该命令可以将某一地址确定到具体的函数。 通常被使用的形式为: addr2line 0x080c1000 -f -e objtarget 其中的选项分别表示:-f表示显示函数 -e表示后面对应的可执行文件 该工具在c++中用于确定重载函数的函数原型有一定的效果,众所周知在C++中函数的重载在编译器下的差别主要是通过一定的前缀实现的,采用addr2line可以将前缀去掉得到定义中的函数原型。 基本的实现方法:addr2line address --demangle=gnu-v3 -f -e objtarget,其中选项--demangle=gnu-v3是还原的主要原因。 2、ar归档器,用于静态库的生成。 ar csr libname.a objname.o 3、nm 符号显示器,用来列出程序中的符号,这个符号显示器的好处可以分析数据的存储区域。由于nm工具列出了程序中符号的类型,可以根据符号类型,了解符号是在数据段,未初始化数据段还是在代码段,同样可以分析静态数据的所在的具体位置,这样也就知道了为什么在函数调用结束以后数据还能被保存,而不是被释放。

/*nmtest.c*/ 1 #include<stdio.h> 2 3 int global1; 4 int global2 = 3; 5 6 static int static_global1 = 1; 7 8 static int static_global2 = 3; 9 10 void foo () 11 { 12 static int internal1; 13 static int internal2; 14 15 time (0); 16 } 17 18 static void bar () 19 { 20 21 } 22 23 int main () 24 { 25 int local1; 26 int local2 = 3; 27 28 foo (); 29 30 return 0; 31 } ~ 上面的代码存在各种数据,全局变量,全局静态变量,局部变量,静态局部变量等,我们可以采用nm找到各个符号的存储位置。

下面是采用nm的实现效果:nm -n objtarget

w _Jv_RegisterClasses w __gmon_start__ U __libc_start_main@@GLIBC_2.0 U time@@GLIBC_2.0 08048290 T _init 08048300 T _start 08048330 t __do_global_dtors_aux 08048390 t frame_dummy 080483f0 T __libc_csu_init 08048450 T __libc_csu_fini 08048455 T __i686.get_pc_thunk.bx 08048460 t __do_global_ctors_aux 0804848c T _fini 080484a8 R _fp_hw 080484ac R _IO_stdin_used 080484b0 R __dso_handle 08048550 r __E_END__ 08049554 d __CTOR_LI__ 08049554 d __init_array_end 08049554 d __init_array_start 08049558 d __CTOR_END__ 0804955c d __DTOR_LIST__ 08049560 D __DTOR_END__ 08049564 d __JCR_END__ 08049564 d __JCR_LIST__ 08049568 d _DYNAMIC 08049634 d _GLOBAL_OFFSET_TABLE_ 0804964c D __data_start 0804964c W data_start 0804965c A __bss_start 0804965c A _edata 0804965c b completed.5530 08049660 b dtor_idx.5532 08049670 A _end 上面的红色部分就是我们的几个变量,其中我们可以发现主要存在三列数据,分别是地址,以及所在段(.text,.data,.bss等),最后是符号名,函数名,全局变量,静态数据都是符号。

其中第二列的字母分别表示对应的段:

A 表示不会改变的,即使在链接过程中

B 表示.bss段

C 表示没有被初始化的公共符号

D 表示.data段

N 表示符号用于调试

P 表示符号位域一个栈中

R 表示在只读数据段中

T和t 表示在代码段中,对于函数名作为符号,若是"T"表示为非静态函数,而"t"表示为静态函数

U 表示没有定义

根据上面的说明分析上面的结果可以知道对于静态变量不是存储在.data段中就是存储在.bss段中,具体的根据是否初始化判断。全局变量的分配也与是否初始化有关,不是存在于.data中就是在.bss中,而局部变量不能通过nm看到。

4、objdump工具,该工具主要用于查看数据,可以查看目标文件的段(sections),可以查看目标文件的信息。通常使用的几个组合为:

4.1查看目标文件的段信息: objdump -h objtarget

4.2 查看目标文件的汇编代码: objdump -d objtarget

源码和汇编代码对照显示: objdump -S -d objtarget

4.3 查看具体段的信息: objdump -s -j .data(某一个段) objtarget 其中的-s表示显示具体的内容,而-j 表示选择某一个段。

4.4 查看程序的入口地址: objdump -f objtarget

5、段剪辑工具,可以操作具体的某一个段,可以删除和剪辑以及滤除调试信息等

5.1剪辑具体的某一段到一个新的目标文件: objcopy -j .data(某一个段) objtarget newtarget

5.2 删除具体的某一个段:objcopy -R .data(某一个段) objtarget newtarget

5.3 滤除调试信息 objcopy --strip-debug objtarget

通常是objdump 和objcopy 结合使用,这样就能得到具体的信息。采用上面的nmtest.c进行演示。

BFD: nmtest: warning: Empty loadable segment detected, is this intentional ?

[gong@Gong-Computer bintools]$ ls -a . .. arm_nmtest arm_nmtest.txt arm_test arm_test_cpp cppmain main.c newtarget nmtest nmtest.c onlytext string string.c target test

newtarget: file format elf32-i386

Sections: Idx Name Size VMA A File off Algn 0 .data 00000010 0804964c 0804964c 0000064c 2**2 COS, ALLOC, LOAD, DATA

newtarget: file format elf32-i386

Sections: Idx Name Size VMA LMA File off Algn 0 .text 0000018c 08048300 08048300 00000300 2**4 CNTS, ALLOC, LOAD, READONLY, CODE 1 .data 00000010 0804964c 0804964c 0000064c 2**2 CONTENTS, ALLOC, LOAD, DATA 2 .bss 00000014 0804965c 0804965c 0000065c 2**2 ALLOC BFD: newtarget: warning: Empty loadable segment detected, is this intentional ?

newtarget: file format elf32-i386

Sections: Idx Name Size VMA LMA File off Algn 0 .data 00000010 0804964c 0804964c 0000064c 2**2 CONTENTS, ALLOC, LOAD, DATA 1 .bss 00000014 0804965c 0804965c 0000065c 2**2 ALLOC 查看程序与对应的汇编代码:

ALLOC

nmtest: file format elf32-i386 Disassembly of section .init:

...

void foo () { 80483b4:55 push %ebp 80483b5:89 e5 mov %esp,%ebp 80483b7:83 ec 18 sub $0x18,%esp static int internal1; static int internal2;

time (0); 80483ba:c7 04 24 00 00 00 00 movl $0x0,(%esp) 80483c1:e8 2a ff ff ff call 80482f0 <time@plt> } 80483c6:c9 leave 80483c7:c3 ret

080483c8 <bar>:

static void bar () { 80483c8:55 push %ebp 80483c9:89 e5 mov %esp,%ebp } 80483cb:5d pop %ebp 80483cc:c3 ret

080483cd <main>:

int main () { 80483cd:55 push %ebp 80483ce:89 e5 mov %esp,%ebp 80483d0:83 e4 f0 and $0xfffffff0,%esp 80483d3:83 ec 10 sub $0x10,%esp int local1; int local2 = 3; 80483d6:c7 44 24 0c 03 00 00 movl $0x3,0xc(%esp) 80483dd:00

foo (); 80483de:e8 d1 ff ff ff call 80483b4 <foo>

return 0; 80483e3:b8 00 00 00 00 mov $0x0,%eax } ...

上面的就是通过objdump的反汇编代码。

滤除的效果如下:

nmtest: file format elf32-i386

Sections: Idx Name Size VMA LMA File off Algn 0 .interp 00000013 08048134 08048134 00000134 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 1 .note.ABI-tag 00000020 08048148 08048148 00000148 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 2 .note.gnu.build-id 00000024 08048168 08048168 00000168 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 3 .gnu.hash 00000020 0804818c 0804818c 0000018c 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 .dynsym 00000050 080481ac 080481ac 000001ac 2**2 CONTENTS, ALLOC, LOAD, READ

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台