使用makefile文件编译开发arm9前我想先要知道交叉编译工具选项的功能。这里主要介绍下面这几个工具:arm-linux-gcc、arm-linux-ld、arm-linux-objcopy、arm-linux-objdump等。
arm-linux-gcc的选项:
(1)-S:只预处理和编译,不汇编。生成的是 .s 汇编文件
eg:$ arm-linux-gcc -S -o main.s main.c
(2)-c:预处理、编译和汇编,不连接。生成的是 .o 目标文件
(3)-E:只做预处理
(4)-o:用于指定输出的文件名
(5)-Wall:打开所有需要警告的信息,比如忘了指定类型声明、使用了未声明的函数、未使用已声明的局部变量等等(默认不显示)
(6)-g:编译时会自动加入一些调试信息,方便对编译出来的程序进行调试
arm-linux-ld的选项:
-T:用于连接没有底层软件支持的程序(直接面向底层硬件的),例如bootloder、内核还有裸机程序等等。主要有两种使用方法:
(1)直接指定代码段、数据段、bss段的起始地址:-Ttext startaddr / -Tdata startaddr / -Tbss startaddr
eg: arm-linux-ld -Ttext 0x0000000 -g crt0.o leds.o -o leds_elf (-g可以不要的)
(2)使用连接脚本设置地址:其实是使用连接脚本文件file.lds来设置代码段(Ttext),数据段(Tdata),bss段(Tbss)的位置信息,也就是说通过这个连接脚本文件我们可以知道要输出的文件的内存布局
eg:arm-linux-ld -Tleds.lds crt0.o leds.o -o leds_elf
【 插叙一段关于.lds文件的知识。连接脚本的基本命令是 SECTIONS,一个sections命令里面包含了一个或多个段,从这些段中就可以了解到输入文件的组成部分是怎样放置的。
SECTIONS {
. = 0x00;
.text : { *(.text) }
.rodata ALIGN(4) : {*(.rodata)}
.data ALIGN(4) : { *(.data) }
.bss ALIGN(4) : { *(.bss) *(COMMON) }
}
连接脚本中段的必要格式:sec_name start ALIGN : {contents} start是重定位地址,上面的*是适配符
SECTIONS中第一行是给符号“.”赋予值,表示的是一个定位计数器,也表示设置当前的运行地址
test段:代码段
rodata段:存放C中的字符串和#define定义的常量(只读数据段),ALIGN(4)是起始运行地址设为4字节对齐
bss段:通常是指用来存放程序中未初始化的全局变量和静态变量的一块内存区域。特点是:可读写的,在程序执行之前BSS段会自动清0。所以,未初始的全局变量在程序执行之前已经成0了。作用:减小编译后的目标文件的体积大小,同时还可以节省存储设备。只有当目标文件被加载时,加载器用一个循环将bss段清零。
lds连接脚本的作用:(1)设置段的连接地址,即运行地址,用于重定位;(2)设置段的存储地址,AT(addr)指令
】
arm-linux-objcopy的选项:复制目标文件的内容到另一个文件中,可以进行文件的格式转换,一般都是用来将 .elf 文件转换成 .bin 文件格式
eg:arm-linux-objcopy -o binary -S leds_elf leds.bin
(-S不从源文件复制重定位信息和符号信息,如果有-g意思是不把源文件中的调试信息复制到目标文件中去,这些选项暂且可以不管先),-o binary是输出二进制文件的意思。
其他的工具选项到时候用到了再记录了...
-------------------------------------------------------------------------------------------------------------
Makefile的书写规则整理:
格式模板:
目标(target):依赖1 依赖2...
<Tab键>命令(command)
(注意:目标后面有个分号“:”,多个依赖之间要用一个空格隔开,如需要转行末尾加反斜线“\”,但是反斜线后面不能加空格)
当规则的目标是一个文件,在它的任何一个依赖文件被修改以后,在执行“make”时这个目标文件将会被重新编译或者重新连接。
定义和引用变量:
makefile文件中定义的一个变量和c语言的define宏定义很类似,变量引用的展开过程是完完整整的文本替换过程,就是说变量值的字符串被精确的展开在变量被引用的地方。
定义格式1:递归展开式变量
变量名 = 字符串1 字符串2
eg:objects = program.o foo.o utils.o(空格间隔)
定义格式2:直接展开式变量
变量名 := 字符串1 字符串2
区别:第1种格式前面定义变量可以引用后面才定义的变量,但是第2种不能够,否则相当于引用一个没有定义的变量,而这个没有定义的变量值默认是为0的
引用变量:$(变量名) 或 ${变量名}
eg:leds:$(objects)
arm-linux-gcc -o leds $(objects)
展开后就是:
leds:program.o foo.o utils.o
arm-linux-gcc -o ledsprogram.o foo.o utils.o
(变量名是单字符的情况时,例如"$PATH" 实际上是这样的意思"$(P)ATH")
追加变量值,就是说前面定义的变量,我在后面使用时须要添加一些变量的值,这个很容易懂,不多解释。追加后的变量定义方式遵从之前的方式。符号就是:“+=”。
定义命令包(依靠多行定义完成),这样可以方便多个规则使用同一串命令的情况。定义一个命令包的语法是以“define”开始,以“endef”结束,define后面的是命令包的名字。举个例子好懂一点。我想要在频幕打印我的编号123456:
define show_your_numbers
@echo 123
@echo 456
endef
结果就是:123456。需要注意的是每个命令独立成行,并且以Tab键开头。命令包的使用方法和使用变量一样$(命令包名)
自动化变量 :
$^:所有的依赖文件。而且这个变量会去除所有的重复的依赖目标
$@:该条规则中的目标,@代表目标
$<:该条规则中依赖目标的第一个依赖文件的名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。
下面这几个以后接触到了再写了。
$%:
$?:
$*:
$+:
通配符%的使用:
目标文件一般除了模式字符(%)以外需要包含某种文件名的特征字符(例如:“a%”、“%.o”、“%.a”等)
%.o:%.c
gcc –o $@ -c $<
解析:以.o结尾的目标文件依赖于对应的.c结尾的文件,目标@(即对应的.o文件)由第一个依赖文件编译生成
删除之前编译时产生的目标文件(.o文件),只需执行make clean。目标“clean”不是一个文件,因此不属于依赖,它仅仅代表执行一个动作的标识。这种目标叫做“伪目标”。伪目标可以用 .PHONY:clean 来显示说明,还有一点要注意的就是伪目标“clean”独立成行
注释符是#,且只能行注释
还在整理中····