编译程序这一节分为四个步骤:
1、将 .s .c 文件变成 .o 文件,使用 arm-linux-gnueabihf-gcc;
arm-linux-gnueabihf-gcc -g -c leds.s -o led.o
上述命令就是将 leds.s 编译为 led.o,其中“ -g ”选项是产生调试信息,GDB 能够使用这些调试信息进行代码调试。“ -c ”选项是编译源文件,但是不链接。“-o”选项是指定编译产生的文件名字,这里我们指定 leds.s 编译完成以后的文件名字为 led.o。执行上述命令以后就会编译生成一个 led.o 文件,如下图所示;
2、将所有的 .o 文件连接为 .elf 文件,使用 arm-linux-gnueabihf-ld;
led.o 文件并不是我们可以下载到开发板中运行的文件,一个工程中所有的 C 文件和汇编文件都会编译生成一个对应的 .o 文件,需要将这.o 文件连接起来组合成可执行文件。
连接就是将所有的 .o 文件连接在一起,并且连接到指定的地方,本实验连接的时候要指定连接起始地址;连接起始地址就是代码运行的起始地址,对于 6ULL ,连接起始地址应该指向 RAM 地址,RAM 分为内部 RAM 和外部 RAM,内部 128KB 的 RAM 地址范围是0X900000~0X91FFFF;外部 RAM 也就是 DDR,现在使用板子 DDR 是 512MB,地址为 0X80000000 ~ 0X9FFFFFFF,裸机学习的过程中,连接地址选为0X87800000,方便以后的学习,因为后面 Uboot 的连接地址就是 0X87800000,统一使用 0X87800000 这个链接地址,不容易记混。那么要使用 DDR 的话,是不是要初始化,现在并没有进行 DDR 的初始化,怎么使用呢?其实对于 I.MX 来说,.bin 文件并不能直接运行,需要添加一个头部,这个头部包含了 DDR 的初始化,I.MX 系列 SOC 内部 boot ram 会从 SD卡、EMMC等外部存储中读取头部信息来初始化 DDR,并且将 .bin 文件拷贝到指定的地方(连接起始地址),.bin 的运行地址一点要和连接起始地址一致,位置无关代码除外。
arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
上述命令中“ -Ttext ”就是指定连接地址,“ -o ”指定连接生成的 .elf 文件名,这里我们命名为 led.elf,命令执行完以后,工程目录下会多一个 led.elf 文件;
3、将 .elf 文件转为 .bin 文件,使用 arm-linux-gnueabihf-objcopy;
arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
上述命令中,“ -O ”指定以什么格式输出,“ binary ”表示以二进制格式输出,“ -S ”表示不要复制源文件中的重定位信息和符号信息,“ -g ”表示不复制源文件中的调试信息,上述命令执行完成以后,工程目录如下图所示,终于等到了想要的东西 led.bin;
4、将 .elf 文件转为汇编,反汇编,使用 arm-linux-gnueabihf-objdump;
大多数情况下我们都是用 C 语言写例程的,有时候需要查看其汇编代码来调试代码,因此就需要进行反汇编;
arm-linux-gnueabihf-objdump -D led.elf > led.dis
上述代码中的“ -D ”表示反汇编所有的段,反汇编完成以后就会在当前目录下出现一个名为 led.dis 文件,如下图所示;
现在可以烧写程序了,其实在第三步完成之后就可以烧写程序了,第四步是为了调试代码。