GNU-ARM程序开发(一)----GNU开发环境和工具

什么是GNU
GNU计划,又称革奴计划。是由Richard Stallman在1983年9月27日公开发起的。目标是创建一套完全免费、自由的操作系统,基本原则是源代码共享及思想共享。
所有在GNU计划下开发的软件均为GNU软件。
为保证GNU软件可以自由地“使用、复制、修改和发布”,所有GNU软件都在一份在禁止其他人添加任何限制的情况下授权所有权利给任何人的协议条款,GNU通用公共许可证(GNU General Public License,GPL)。
GPL条款下发布的一些主要的GNU项目软件有:
GCC:GNU编译器集,包括GNU C编译器。
G++:C++编译器,是GCC的一部分。
GDB:源代码级的调试器。
GNU make:UNIX make命令的免费版本。
GNU Emacs:文本编辑器及环境。
bash:命令解释器(shell)。

 本地程序开发(PC--X86)
GNU工具:
/usr/bin/{gcc、g++、as、ld等}
库文件:
/usr/lib/lib*.so
头文件:
/usr/include
交叉开发(ARM)
GNU工具:
/usr/local/arm/arm920t/bin/
arm-angstrom-linux-gnueabi-gcc
arm-angstrom-linux-gnueabi-as
库文件:
/usr/local/arm/arm920t/arm-angstrom-linux-gnueabi/lib/
头文件:
/usr/local/arm/arm920t/arm-angstrom-linux-gnueabi/include

 

Linux环境下开发C/C++程序的工具主要是GNU工具,GNU工具集包括:
编译工具
:把一个源程序编译为一个可执行程序
调试工具:能对执行程序进行源码或汇编级调试
软件工程工具:用于协助多人开发或大型软件项目的管理,如 make、CVS、Subvision
其他工具:用于把多个目标文件链接成可执行文件的链接器,或者用作格式转换的工具。

cpp:
进行预处理,对源代码文件中的文件包含(include)、预编译语句(如宏定义define等)进行分析;
cc1:
进行编译,生成.s为后缀的汇编文件;
as:
进行汇编,汇编语言文件经过预编译和汇编之后都生成以.o为后缀的目标文件;
ld:
进行链接,所有的目标文件被安排在可执行程序中的恰当的位置。同时,该程序所调用到的库函数也从各自所在的档案库中链接到合适的地方。

GNU二进制工具

addr2line:把程序地址转换为文件名和行号
ar:建立、修改、提取归档文件
as:主要用来编译GNU C编译器gcc输出的汇编文件,产生的目标文件由链接器ld连接。
c++filt:连接器使用它来过滤C++ 和Java 符号,防止重载函数冲突。
ld:GNU链接器。
nm:列出目标文件中的符号。
objcopy:文件格式转换。
objdump:显示一个或者更多目标文件的信息,主要用来反编译。
ranlib:产生归档文件索引,并将其保存到这个归档文件中。在索引中列出了归档文件各成员所定义的可重分配目标文件。
readelf:显示elf格式可执行文件的信息。
size:列出目标文件每一段的大小以及总体的大小。默认情况下,对于每个目标文件或者一个归档文件中的每个模块只产生一行输出。
strings:打印某个文件的可打印字符串。默认情况下,只打印目标文件初始化和可加载段中的可打印字符;对于其它类型的文件它打印整个文件的可打印字符,这个程序对于了解非文本文件的内容很有帮助。
strip:丢弃目标文件中的全部或者特定符号,减小文件体积。

写一测试程序:

 

#include<stdio.h>
int main()
{
	return 0;
}
readelf
readelf可以显示elf格式可执行文件的信息。ELF格式是UNIX系统实验室作为应用程序二进制接口开发的。ELF格式是Unix/Linux平台上应用最广泛的二进制工业标准之一。
查看可执行文件“test”的头信息

[root@localhost testGNU]# readelf -h test
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x8048280
  Start of program headers:          52 (bytes into file)
  Start of section headers:          1836 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         7
  Size of section headers:           40 (bytes)
  Number of section headers:         28
  Section header string table index: 25
size
小以及总体的大小。
size有两种输出格式,一种为“sysv”,另一种为“berkeley”,默认为berkeley的格式。第一种格式可以用“-A”或者“--format=sysv”指定,第二种格式用“-B”或“--format=berkeley”指定:
$ size test –A
$ size test -B
[root@localhost testGNU]# size test
   text    data     bss     dec     hex filename
    803     248       8    1059     423 test
[root@localhost testGNU]# size test -A
test  :
section          size        addr
.interp            19   134512916
.note.ABI-tag      32   134512936
.gnu.hash          32   134512968
.dynsym            64   134513000
.dynstr            69   134513064
.gnu.version        8   134513134
.gnu.version_r     32   134513144
.rel.dyn            8   134513176
.rel.plt           16   134513184
.init              23   134513200
.plt               48   134513224
.text             408   134513280
.fini              28   134513688
.rodata            12   134513716
.eh_frame           4   134513728
.ctors              8   134517828
.dtors              8   134517836
.jcr                4   134517844
.dynamic          200   134517848
.got                4   134518048
.got.plt           20   134518052
.data               4   134518072
.bss                8   134518076
.comment          276           0
Total            1335


nm
nm可以列出目标文件中的符号。用法虽然简单,但是功能很强大。
nm可以列出的符号:

R 只读符号
N 调试符号
D 已经初始化的变量的符号
T Text段的符号。子程序都是这种符号
U 未定义的符号。例如文件中引用了不存在的函数
S 未初始化的符号,比如定义了一个全局变量int a;则a的符号就是这种类型
libsupc++ 提供支持C++语言的库函数
R 只读符号

nmdemo.c实例

#include<stdio.h>
static int i_a;
int i_b;
const c_c=3;
char *buf="Demo for study nm tools!";
extern int i_e;
 
void function_1()
{
 printf("Any string you want!\n");
}
 
int num_add(int a1,int a2)
{
 return a1+a2;
}

nm使用
$ gcc –g –O –c nmdemo.c
$ nm –A nmdemo.o

[root@localhost testGNU]# gcc -g -O -c nmdemo.c 
[root@localhost testGNU]# ls
nmdemo.c  nmdemo.c~  nmdemo.o  test  test.c  test.i  test.o  test.s
[root@localhost testGNU]# nm -A nmdemo.o
nmdemo.o:00000000 D buf
nmdemo.o:00000000 R c_c
nmdemo.o:0000000b T function_1
nmdemo.o:00000004 C i_b
nmdemo.o:00000000 T num_add
nmdemo.o:         U puts


nm使用
$ nm –Aa nmdemo.o

[root@localhost testGNU]# nm -Aa nmdemo.o
nmdemo.o:00000000 b .bss
nmdemo.o:00000000 n .comment
nmdemo.o:00000000 d .data
nmdemo.o:00000000 N .debug_abbrev
nmdemo.o:00000000 N .debug_aranges
nmdemo.o:00000000 N .debug_frame
nmdemo.o:00000000 N .debug_info
nmdemo.o:00000000 N .debug_line
nmdemo.o:00000000 N .debug_loc
nmdemo.o:00000000 N .debug_pubnames
nmdemo.o:00000000 N .debug_str
nmdemo.o:00000000 n .note.GNU-stack
nmdemo.o:00000000 r .rodata
nmdemo.o:00000000 r .rodata.str1.1
nmdemo.o:00000000 t .text
nmdemo.o:00000000 D buf
nmdemo.o:00000000 R c_c
nmdemo.o:0000000b T function_1
nmdemo.o:00000004 C i_b
nmdemo.o:00000000 a nmdemo.c
nmdemo.o:00000000 T num_add
nmdemo.o:         U puts


nm使用
“a”选项会把调试符号也列出来。默认状态下调试符号不会被列出。
“l”选项会把源代码中对应的行号也列出
$ nm –Aal nmdemo.o

[root@localhost testGNU]# nm -Aal nmdemo.o
nmdemo.o:00000000 b .bss        /mnt/hgfs/share/C++_C/testGNU/nmdemo.c:12
nmdemo.o:00000000 n .comment    /mnt/hgfs/share/C++_C/testGNU/nmdemo.c:12
nmdemo.o:00000000 d .data
nmdemo.o:00000000 N .debug_abbrev       /mnt/hgfs/share/C++_C/testGNU/nmdemo.c:12
nmdemo.o:00000000 N .debug_aranges      /mnt/hgfs/share/C++_C/testGNU/nmdemo.c:12
nmdemo.o:00000000 N .debug_frame        /mnt/hgfs/share/C++_C/testGNU/nmdemo.c:12
nmdemo.o:00000000 N .debug_info /mnt/hgfs/share/C++_C/testGNU/nmdemo.c:12
nmdemo.o:00000000 N .debug_line /mnt/hgfs/share/C++_C/testGNU/nmdemo.c:12
nmdemo.o:00000000 N .debug_loc  /mnt/hgfs/share/C++_C/testGNU/nmdemo.c:12
nmdemo.o:00000000 N .debug_pubnames     /mnt/hgfs/share/C++_C/testGNU/nmdemo.c:12
nmdemo.o:00000000 N .debug_str  /mnt/hgfs/share/C++_C/testGNU/nmdemo.c:12
nmdemo.o:00000000 n .note.GNU-stack     /mnt/hgfs/share/C++_C/testGNU/nmdemo.c:12
nmdemo.o:00000000 r .rodata
nmdemo.o:00000000 r .rodata.str1.1
nmdemo.o:00000000 t .text       /mnt/hgfs/share/C++_C/testGNU/nmdemo.c:12
nmdemo.o:00000000 D buf /mnt/hgfs/share/C++_C/testGNU/nmdemo.c:5
nmdemo.o:00000000 R c_c /mnt/hgfs/share/C++_C/testGNU/nmdemo.c:4
nmdemo.o:0000000b T function_1  /mnt/hgfs/share/C++_C/testGNU/nmdemo.c:8
nmdemo.o:00000004 C i_b
nmdemo.o:00000000 a nmdemo.c
nmdemo.o:00000000 T num_add     /mnt/hgfs/share/C++_C/testGNU/nmdemo.c:12
nmdemo.o:         U puts        /mnt/hgfs/share/C++_C/testGNU/nmdemo.c:9


strip
strip用来丢弃目标文件中的全部或者特定符号,减小文件体积。对于嵌入式系统,这个命令必不可少。

[root@localhost testGNU]# vim nmdemo.c
[root@localhost testGNU]# ls -lh test
-rwxrwxrwx 1 root root 4.6K 12-08 13:11 test


strip -s  去除所有符号

[root@localhost testGNU]# strip -s test
[root@localhost testGNU]# ls -lh test
-rwxrwxrwx 1 root root 2.8K 12-08 13:11 test

 

strip使用
经过strip处理后的文件已经不包含符号了,可以使用nm加以验证。

[root@localhost testGNU]# nm nmdemo.o
00000000 D buf
00000000 R c_c
0000000b T function_1
00000004 C i_b
00000000 T num_add
         U puts
[root@localhost testGNU]# strip nmdemo.o
[root@localhost testGNU]# nm nmdemo.o
nm: nmdemo.o: no symbols


strings
strings用来打印某个文件的可打印字符串。

[root@localhost testGNU]# strings nmdemo.o
Any string you want!
Demo for study nm tools!

如果想显示文件名称,使用“f”选项。

[root@localhost testGNU]# strings -f nmdemo.o
nmdemo.o: Any string you want!
nmdemo.o: Demo for study nm tools!


objdump
objdump可以显示一个或者更多目标文件的信息,主要用来反编译。
-d  反汇编
-i BFD文件支持信息

[root@localhost testGNU]# objdump -d nmdemo.o

nmdemo.o:     file format elf32-i386

Disassembly of section .text:

00000000 <.text>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   8b 45 0c                mov    0xc(%ebp),%eax
   6:   03 45 08                add    0x8(%ebp),%eax
   9:   5d                      pop    %ebp
   a:   c3                      ret    
   b:   55                      push   %ebp
   c:   89 e5                   mov    %esp,%ebp
   e:   83 ec 08                sub    $0x8,%esp
  11:   c7 04 24 00 00 00 00    movl   $0x0,(%esp)
  18:   e8 fc ff ff ff          call   0x19
  1d:   c9                      leave  
  1e:   c3                      ret 

“-R”选项显示动态重定向的入口。


objcopy
objcopy可以进行目标文件格式转换。
转成bin文件

[root@localhost testGNU]# objcopy -O binary test test.bin
[root@localhost testGNU]# ls
nmdemo.c  nmdemo.c~  nmdemo.o  test  test.bin  test.c  test.i  test.o  test.s

 

addr2line
addr2line能够把程序地址转换为文件名和行号,前提是这个可执行文件包括调试符号。
如果可执行文件中没有包括调试符号,shell将返回??:0。
最常用的选项是“-e”用来指定文件名和地址。

08048384 T main
         U printf@@GLIBC_2.0
[root@localhost testGNU]# addr2line 08048384 -e  test
/mnt/hgfs/share/C++_C/testGNU/test.c:3
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值