一、交叉编译
我们下载到开发板上的镜像文件,往往都是开源代码,先移植,然后编译成机器码之后形成的镜像,接下来的几节我们主要讨论,如何移植这些文件。
(一)编译原理
1、机器码
CPU只能识别机器码,机器码缺点:
1)容易写错
2)不能移植,机器码在不同处理器的含义不同
2、汇编语言
机器码的符号化,一一对应。很好的解决了读写的问题,但也不能移植。不同CPU支持的指令集不同,因此汇编指令不能移植到不同的CPU中。
3、c语言
不区分平台,编译器和CPU一一对应。
arm编译器就是我们说的交叉编译器。
(二)GCC的编译过程
1、test可执行文件
2、在C语言中以#开头的是预处理指令,不能被CPU执行,即不能汇编和编译。
3、以;结尾的是CPU可以直接执行的语句。
4、//注释,不能编译也不能执行。
5、预处理后的文件,宏定义被替换,头文件被展开
7、目标文件-二进制代码
8、链接库
库也是编译好的二进制文件
test.c:
v.c:
在目标文件生成可执行文件时,将两个文件合并。
(三)交叉编译的概念
编译工具:
.so:共享库
.a:静态库
库是分架构的,交叉编译内的库是在交叉编译时链接的,ubuntu上的库是在x86编译时链接的。
二、ELF文件格式
(一)ELF概念
Linux下编译出来的文件-ubuntu
Linux/unix也支持其他格式的可执行文件,但在嵌入式领域,基本是ELF格式。
除了可执行语句和全局变量,Linux加载和管理ELF格式的文件,所以ELF还存储了很多其他信息,如符号表(C函数名,汇编标识符),调试信息(-g-GDB调试信息)等。
(二)ELF文件操作的命令
与交叉编译器不同,Linux下的readelf和arm-none-linux-gnueabi-readelf 使用效果相同。
(三)BIN文件
interface.bin
ELF一般是运行在应用层的文件,是基于Linux系统的。BIN文件是可以直接运行CPU之上的。
BIN文件只包括CPU识别的信息。只包括机器码和全局变量。
同一个C语言代码,.bin文件要比.elf文件小。但是.elf文件中的其他信息不会加载到内存,也不会被CPU执行。
三、交叉编译工具链常用工具
(一)size
text:代码段,汇编指令编译生成的机器码
data:全局变量,静态局部变量
int a = 100;
bss:未初始化的全局变量和静态局部变量
bss段内的变量会统一清零,方便后面赋值。
int a;a = 100;
区分ll命令:ll命令是整个ELF文件的大小,size命令是能够在CPU上运行的变量和代码。
不同编译器编译出来的代码大小也不同。
(二)nm命令
函数名在链接时可以指示函数地址,在执行时没有作用。函数名在编译的时候存放在符号表中。
*(三)strip瘦身命令
在执行过程中,符号表不会被加载到内存,也不会加载到CPU执行,因此可以对生成的可执行文件瘦身,将符号表减掉。
对嵌入式开发很重要,可以节省磁盘空间。
不同编译器的strip不同。
符号表的意义:
.o目标文件状态下可以查看函数名。
(四)objdump
区分编译器。
反汇编:机器码-汇编
实现的可能性:汇编和机器码一一对应,汇编不可以再回推。
(五)objcopy
区分处理器。
ELF是Linux系统下生成的文件,BIN是可以直接运行在CPU之上的。
gcc默认生成的是ELF文件,将ELF中的文件删除附加信息可以得到,命令中有填充空隙对其格式的过程。
作业
1.简述GCC编译C语言程序的步骤及每一步的主要工作?
2.简述ELF格式文件与BIN格式文件的主要区别是什么?
3.简述交叉编译工具链中strip及objdump工具的主要用途是什么?
1、
1)预处理:将头文件展开,宏定义替换。
2)编译:将C语言代码编译成汇编代码,生成汇编代。码文件。
3)汇编:将汇编代码转换成机器码,生成目标文件
4)链接库:目标文件和所需的附加目标文件链接起来,最终生成可执行文件。
2、
BIN文件一般直接运行在CPU之上的可执行文件,只包括CPU能识别的指令和数据,ELF是在Linux系统下的,需要Linux系统加载和管理才能运行,除了代码和数据段,还存储了和系统相关的其他信息。
3、strip瘦身指令,丢弃目标文件中的符号表;objdump从目标文件中显示信息。objdump -d+文件名->将目标文件反汇编。