嵌入式Linux开发学习笔记:编译与调试
1.摘要
这篇文章是嵌入式开发学习笔记的第四篇,介绍了嵌入式Linux开发要用到的编译工具及调试工具。初学嵌入式开发一定要注意搞清楚交叉编译工具链的概念以及每部分的作用,否则会走非常非常多的弯路。
2. 编译
2.1. 概念
编译的概念很容易混淆,在《编译原理》教材中,编译指的是词法分析到产生目标代码的过程,而在现代编译器中,这个过程被拓展了。现代编译器的主要工作流程包括:源代码 (source code) → 预处理器 (preprocessor) → 编译器 (compiler) → 汇编程序 (assembler) → 目标代码 (object code) → 链接器 (Linker) → 可执行程序 (executables),
2.2. 过程
2.2.1. 预处理
预处理程序名为cpp,它的主要工作:
处理include
展开宏定义
处理条件编译命令
输出.i文件
2.2.2. 编译
编译器程序名为ccl,它的主要工作为:
生成汇编代码
输出.S文件
2.2.3. 汇编
汇编器程序名为as,它的主要工作为:
生成二进制代码
输出.o文件
2.2.4. 连接
连接器程序名为ld,它的主要工作为:
生成可执行文件
2.2.5. ELF与BIN
ELF ELF = Executable and Linkable Format,可执行连接格式,是UNIX系统实验室(USL)作为应用程序二进制接口(Application Binary Interface,ABI)而开发和发布的。
简单的说,ELF是linux下的一种可执行文件,类似于windows下的EXE文件(但是它一般不会写扩展名)。也就是说,使用编译器编译出来的可执行文件是依附于Linux系统的。
在嵌入式开发时,假如需要编译bootloader这类不在linux下运行的程序,就需要将ELF文件中的汇编代码提取出来,直接把二进制机器码放入内存执行,这个二进制的内存镜像就是bin文件。
2.3. 工具
2.3.1. gcc
GCC(GNU Compiler Collection,GNU编译器集合)是一套由GNU工程开发的支持多种编程语言的编译器。
对于C/C++语言来说,它支持由预处理到连接的所有流程,也就是说,gcc的输入是c/c++源代码,输出是linux下的可执行文件。
常用参数:
-DMACRO 定义宏
总体
-c 只编译,不链接成为可执行文件
-S 编译后停止,不进行汇编
-E 预处理后停止
-o 输出文件名
-v 显示输出信息
警告选项
-Wall 生成所有警告信息
-w 不生成警告信息
调试选项
-g 加入调试信息
优化选项
-O 对程序进行优化(运行快,编译慢)
-O2 更优化
-O3 更更优化
-O0 不优化
连接器选项
-l名称 在连接时装载lib名称.a的函数库
-L 目录名 将目录加入lib中
-nostartfiles 不连接系统标准启动文件
-nostdlib 不连接系统标准启动文件和标准库文件
编译内核、bootloader等
-static 静态链接库文件
动态库 .so
静态库 .a
-shared 生成一个共享OBJ文件
-Xlinker option
把选项option传递给连接器
传递带参选项需要连用两次
-Wl,option
把option穿给连接器
逗号分割多个选项
-u symbol
使连接器认为取消了symbol的符号定义,从而连接库获得定义
目录选项
-I 目录名 将目录加入include中
-I- 同时搜索<file>形式头文件
-Ldir 在-I选项的搜索路径中增加dir目录
-Bprefix 在何处寻找可执行文件、库文件以及编译器的数据文件
2.3.2. makefile
一个工程一般会有多个c/c++文件,编译一个程序需要反复的编译每个模块,最后将它们连接起来。makefile是一个用于管理编译过程的工具。makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。
makefile包括两部分:
工程编译过程的定义文件makefile,这个文件里定义了工程中所有文件的编译过程。
执行工具make,它的功能是读取工程的makefile文件并按照其中的规则执行编译过程。
makefile的使用:
参考http://www.chinaunix.net/old_jh/23/408225.html
2.3.3. objdump
显示二进制文件信息
参数
-d 反汇编可执行段
-D 反汇编所有段
-EB或-EL 指定字节序
-f 显示文件头部摘要信息
-h 显示目标文件各个段的头部摘要
-i 显示支持的目标文件格式和cpu架构
-j name 仅显示指定section的信息
-m machine 指定反汇编时使用的架构
2.3.4. objcopy
二进制文件格式转换工具,常用于elf至二进制转换(ELF-BIN)。
objdump -O binary boot.elf boot.bin
3. 交叉编译与工具链
交叉编译,简单地说,就是在一个平台上生成另一个平台上的可执行代码。这里需要注意的是 所谓 平台,实际上包含两个概念:体系结构(Architecture)、操作系统(Operating System)。同一个体系结构可以运行不同的操作系统;同样,同一个操作系统也可以在不同的体系结构上运行。
交叉编译工具与普通编译器很类似,主要区别在于每种交叉编译工具都包含了固定的体系结构与操作系统,例如生成运行在arm结构,linux操作系统下的可执行文件的gcc编译器的名字为arm-linux-gcc。
交叉编译工具链是一个由编译器、连接器和解释器组成的综合开发环境。交叉编译工具主要由 binutils、gcc 和 glibc 几个部分组成。
其中:
gcc(gnu collect compiler)是一组编译工具的总称。它主要完成的工作任务是“预处理”和“编译”,以及提供了与编译器紧密相关的运行库的支持,如libgcc_s.so、libstdc++.so等。
binutils提 供了一系列用来创建、管理和维护二进制目标文件的工具程序,如汇编(as)、连接(ld)、静态库归档(ar)、反汇编(objdump)、elf结构分 析工具(readelf)、无效调试信息和符号的工具(strip)等。通常,binutils与gcc是紧密相集成的,没有binutils的 话,gcc是不能正常工作的。
glibc是gnu发布的libc库,也即c运行库。glibc是linux 系统中最底层的api(应用程序开发接口),几乎其它任何的运行库都会倚赖于glibc。glibc除了封装linux操作系统所提供的系统服务外,它本 身也提供了许多其它一些必要功能服务的实现。有时出于减小 libc 库大小的考虑,你也可以用别的 c 库来代替 glibc,例如 uClibc、dietlibc 和 newlib。
建立一个交叉编译工具链是一个相当复杂的过程,如果你不想自己经历复杂的编译过程,网上有一些编译好的可用的交叉编译工具链可以下载。
具体建立交叉编译工具链的过程网上有很多,这里就不写了。
4. 调试
linux下调试程序的主要工具为GDB,虽然功能很强但是用惯了图形界面的人来说是个痛苦的适应过程。另外也有ddd这个图形化调试工具,不过推广度似乎不那么高。
常用GDB指令:
run 运行
file 打开程序
break(b) 断点
函数名
行号
文件名:行号
行号 if 条件
list(l) 查看程序
info break 查看断念
delete 断点编号 删除断点
next 单步运行(不进入子函数)
step 单步运行(进入子函数)
continue 继续运行程序
print 变量名 查看指定变量治
finish 运行程序直到当前函数结束
watch 变量名 对指定变量进行监控
quit 退出gdb
本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可,转载请注明作者及原网址。
抱歉,暂停评论。