2.交叉工具链
一、交叉工具链:
交叉工具链,其实他有两个含义,一个就是交叉工具,所谓的交叉工具就是运行的环境和编译的环境不是在一体的。就像我们现在,编译裸机程序是在pc机上面执行的。可我们运行程序是在开发板。链,就是很多的意思,就是一个工具的集合。在我们前面配置arm-linux-gcc的工具中。在/usr/local/arm/4.3.2/bin的目录下有很多编译工具。例如图1-1:
图1.-1 交叉工具链
下面我们来写一个简单的程序,用这些工具编译。
Hello.c:
#include <stdio.h>
void main(){
printf("hello fish! ");
}
这是一个简单的hello程序。首先我们先用我们熟悉的gcc编译并执行。图1-2:
图1-2
我们看到程序正常运行。输出了内容。
接下来我们用刚安装的交叉工具来编译运行。图1-3:
图1-3
我们看见程序出错了。提示的信息是不能运行的二进制文件。这就奇怪了。这是为啥呢?其实呢。我在前面已经提过了,arm-linux-*工具,编译的程序是在开发板运行的。其实我们可以通过:file 文件名.来查看该应用程序运行的平台。图1-4:
图1-4
可以看到信息,hello是gcc编译生成的是运行在x86架构的,hello1是arm-linux-gcc编译生成的是运行在ARM架构的。
接下来我们把hello1拷贝到开发板运行看看。
我已在开发板烧写好了linux系统,通过u盘,把hello1拷贝到开发板。然后插入开发板的usb口。在终端可以看见提示信息,这是因为我们的linux带有usb驱动,当我们的usb插进去的时候,它检测到了usb,加载好了驱动。现在我们进入u盘,运行hello1程序。图1-5.这时仍然提示错误。如下:
这是为啥呢?这是我们的开发板缺少程序运行时需要的动态库,因为我刚才编译的时候没有加-static属性。加上-static属性重新编译。图1-6:
图1-6
可以看到,这次加入了-static条件,编译生成的hello2程序比hello1大了许多,就是因为把运行需要的库文件都静态链接进来了。同样拷贝到u盘,可以看到顺利运行。图1-7:
图1-7
二、交叉工具链的详述:
1.arm-linux-gcc编译器:
前面,可以看到gcc和arm-linux-gcc工具的编译条件都是一样的。可为什么编译出来的应用程序会运行在不同的平台呢?这是因为,他们两个在编译的时候引用的头文件不同。传统的gcc是默认去/usr/include寻找它需要的头文件。图1-8:
图1-8头文件
而arm-linux-gcc寻找的头文件的目录不同。首先使用arm-linux-gcc –help查看它的使用:图1-9:
图1-9
注意到参数-print-search-dirs就是显示寻找头文件的参数目录。加上该参数得到一下信息图1-10:
图1-10
从上面的显示看到arm-linux-gcc默认是到我们安装arm-linux-gcc的目录去找头文件的。
2.arm-linux-ld:
arm-linux-ld是链接器,下面介绍它的使用。
首先先用arm-linux-gcc生成中间文件.o文件。图2-1:
arm-linux-gcc -g -c led.S
图2-1
在上面的参数中-g表示可以用gdb来调试信息,-c是只编译不链接。最后生成led.o中间文件。接下来就是使用arm-linux-ld把该文件链接成elf文件:图2-2:
arm-linux-ld -Tled.lds -o led.elf led.o
图2-2
上面语句的意思是利用arm-linux-ld链接器,按照-T指定的链接器脚本,把生成的led.o(如果有多个.o文件,在后面继续加上),链接成led.elf文件。
3.arm-linux-readelf:
利用该工具可以查看生成的.elf文件的内容:
执行:arm-linux-readelf -a led.elf。-a参数是all的意思,表示查看所有信息:图2-3:
图2-3
从上面看到elf文件有一个固定的头:ELF Header:然后:
Data: 2's complement, little endian
是表示他是运行在小端处理器的。
Machine: ARM
是表示他是运行在ARM平台的。
所以当运行一个程序出错的时候,当检查完语法没问题,仍然不能运行的时候,就应该用readelf查看一下这些信息是否符合。如果上面的两种检查完了之后还是不能运行。接下来就是查看需要的库是否存在。使用的命令:
arm-linux-readelf -d hello
运行结果:图2-4:
图2-4
上面显示了该hello应用程序需要的库是libc.so.6.如果没有该库,该程序运行不了。
4.arm-linux-objdump:
ARM反汇编器。
上面已经使用arm-linux-gcc编译产生了可执行文件hello2.现在对它进行反汇编。命令:
arm-linux-objdump -D -S hello2 >mydump
该命令的意思是将hello2可执行程序反汇编,输出到mydump文件。执行之后会在该目录下产生一个mydump文件:图2-5:
打开可以看到对应的汇编代码:
但是,都是汇编代码,看起来还是非常困难。可以在编译的时候加上-g调试信息的参数,这样反汇编之后会有部分的c代码存在。这样可以让我们更加容易看懂程序。
图2-5
可以看到加上-g编译,反汇编后,在汇编代码里居然有c代码出现。在上面的代码中printf("hello fish! ");的汇编实现就是它下面两行。源代码:
5.最后一个是文件格式转换工具:arm-linux-objcopy:
从上面的操作知道,汇编代码通过arm-linux-gcc -g -c led.S,把一个汇编文件转化为一个led.o文件,接着使用:arm-linux-ld -Tled.lds -o led.elf led.o,把led.o利用led.lds脚本,链接成一个led.elf文件。但是elf文件无法在板子运行,必须转化为.bin格式的二进制文件。这就是arm-linux-objcopy的功能:
arm-linux-objcopy -O binary led.elf led.bin
图2-6:
图2-6