摘要

这篇文章适合的是以下两种人群

  • 你决定脱离IDEs环境下的开发以及已经准备好将所有的嵌入式开发直接基于GNU ARM Toolchain下进行,于此同时你正在寻找合适的入门指导
  • 你想学习了解更多关于自己在PC上编写的代码是如何被编译以及在对应的嵌入式芯片中运行

无论你是属于以上的哪一类型开发者,希望这篇文章能提供一个好的开始以及正确的方向。

当我想学习更多关于GNU ARM Toolchain的知识时,我想脱离IDE的开发环境进行开发时,但现实是我很难找到好的资料或者文档能够指导我做这样的事情. 获取到的相关技术文档都是比较难懂的,需要花很多时间进行理解学习. 而在这篇文章中将以更易于理解的角度讲述我所学习到的知识点. 希望你能喜欢这篇文章也能达到你的期望.

我在写这篇文章的时候是一步一步从易到难的,对于有一定基础的读者可以选择性的掉过自己以及掌握的章节,让我们开始吧!

二进制文件是如何生成的

理解你写的源代码以及原厂提供的Libraries是如何生成二进制文件(executables)进而可以运行在微控制器(microcontroller)上是非常重要的一点.

我相信阅读本文的你,已经有足够的经验来了解编译器、汇编器和链接器是如何协同工作生成最终的目标文件。为了让我们能初步回忆起来,让我们简单地看看一个典型的工具链以及源代码是如何从一个阶段到下一个阶段的转换.

如下所以的截图简单描述了这个过程.


如上图所示,整个过程分为三个步骤: 编译、链接、重定位.

Step#1: 交叉编译

在这一步骤中,所有的源文件都是基于高级语言(C or C++)进行编写的,是从高级语言转换为机器可以理解的机器码. 如果你是曾经学习过汇编语言的开发者,一定是熟悉汇编语言中常见的4种类型的基础操作:

  • 在内存中,将一个值从一个位置移动到另外一个
  • 对存储在内存中的值进行算术运算
  • 对这些值进行逻辑运算
  • 从一个可执行的位置跳转到另外一个
    这些汇编指令也成为助记符,而每一个汇编指令多有对应的二进制描述. 例如,一个加法运算,可能在微控制器中二进制(binary)表示为11001010b0. 而编译器的作用就是将这些源文件转化为一系列的二进制指令,而转换生成的文件叫目标文件(Object file).

因此,编译器的作用就是将高级语言编写的代码翻译成机器可以理解的机器码.

编译器 VS 交叉编译器

从汇编语言转换为机器码,会因不同的处理器而产生不同。例如一个相关的加法指令在32bit的处理器下可能表示为10101111110000111000100011101001b!

这种翻译也取决于处理器的架构,例如ARM 架构和X86的架构,操作码就是不用的,另外都是ARM架构下的芯片也会有架构上的不同. 再补充一句,例如低端的ARM M0芯片的架构就和中端的ARM M3芯片的体系架构不同.

因此交叉编译器的职责是将在一台机器下编写的代码翻译成二进制文件在另外一台机器上运行.

编译器和交叉编译器最大的区别是: 交叉编译器编译生成的二进制文件只能在目标机器上运行,而不能在本机(执行交叉编译器指令的PC)上运行!

Step2: 链接目标文件

在单个文件被编译成目标文件后,接下来是将他们链接到一个二进制文件中. 我们编写的代码通常是被分为3个部分(段),被放到3个存储桶中(在这里我们称之为段).

  • .text
  • .data
  • .bss
    .text 段存放或者说加载的是我们所写的代码,.data段存放的是初始化的全局变量而.bss段是存放着未初始化的全局变量.

大家都知道的是,高级编程语言赋予了我们将整个工程分为多个模块或者文件进行编写我们的代码. 如果你没能将你的工程分文多个文件或者模块进行开发,那么祝你好运!!

连接器的作用是将这些目标文件拼接到一个二进制文件中. 那这是怎么做到的呢? 其实链接器仅仅是简单的将目标文件中的所有的单个.text数据放到一个大的.text段,对于.data、.bss也是做了同样的操作(简单点来说就是将每一个目标中的各段给整合一起)

那么在连接器完成工作后,我们将得到机器能够读取和执行的二进制文件.

Step3: 重定向二进制文件

现在我们已经生成了单个的二进制文件,但我们还需要以某种方式来重新组织这些信息以使它能够兼容我们微控制器所期望的. 不同内存大小的微控制器与之对应的内存映射也会不同. 如果你有注意过使用过芯片的Datasheet,你会发现有一部分文档会描述到"Memory maps". 下面的截图是以 STM32F401 为例子展示了该芯片的内存映射.

如上面截图所示,地址从0x0000 0000 到0xFFFF FFFF已经被分配为RAM,Flash memory以及外设(peripherals). 定位器的作用是为.text, .data, .bass标记正确的地址,那么当所有内容被加载到flash后,当微控制器上电时会将.data中的数据拷贝到RAM. 将需要运行的数据从Flash拷贝(加载)到RAM中的代码就叫启动代码.

启动代码

在几乎所有的微控制器的工程文件中通常都会有一个特殊文件叫启动文件(startup file). 这个文件通常命名为"startup.asm" 或者 “startup.c”(stands for C Runtime).

通常微控制器一上电,在芯片设计上会先开始在预定义的位置开始执行代码,通常那个位置是0x0000 0000 而这就是启动代码的位置.

启动代码的作用就是在芯片上电后将系统应用代码起始点及应用层代码main()函数的地址.(通俗的说法)

从上电到main()函数的执行,在这过程有一些重要的初始化动作被执行,行为如下:

  • 重要外设的初始化(flash等).
  • 将已经初始化的全局变量从flash中拷贝到内存中(我们不能做这个动作当代码已经被loading到微控制器中,因为内存是易失性存储.
  • 堆栈的初始化在空闲的内存上
  • 调用main()

在定位过程中,启动代码必须放在地址0x0000 0000 处,所有的部分必须标记正确的地址,这样微控制器才能完成剩下的动作.

在PC端的操作系统中,在程序加载和运行时执行此步骤(也称为加载时间). 这个定位步骤只适用于嵌入式程序,我们需要这段定位代码的特殊步骤来为各个部分分配地址,使链接器产生的可重定位的二进制代码可以被微控制器所运行

二进制文件的生成 PCs vs 微控制器(microcontrollers)

下面是一个简单的关于PCs和microcontrollers 生成二进制文件过程的对比.

PC Microcontrollers
仅仅需要两步: 编译和链接, 定位是在加载时间完成 需要3步: 编译、链接、定位(重定位)
需要本机编译 需要交叉编译
不需要启动代码 需要启动代码,而且每一个微控制器的启动代码可能不同

程序加载和调试

经过以上的文字的学习和理解,相信我们对如何为微控制器生成二进制文件内有了一定的理解了. 那让我们继续了解和学习下如何将代码加载到微控制器以及如何调试!!

将可执行的二进制文件加载到微控制器的闪存中

加载二进制文件到flash中!这一步骤官方的叫法为"In-System Programming"但是我们日常开发中常听到到的是"烧录"(Flashing).

在加载二进制文件后可以通过一个特殊的外设-调试控制器进行调试. 然而协议的实现不同的厂家会有不同,但好在最著名的两种协议是SWD和JTAG. 对于希望学习更多关于JTAG和SWD相关知识点的同学请通过下面链接进一步的学习.

JTAG vs SWD

以上的这些协议都可以看作是不同的信令语言. 你的PC是无法直接描述这些语言的,因此我们需要做些翻译的工作!调式的适配器接受来自USB的信号将其转换为微控制器可以读懂的JTAG/SWD信号.

因此我们可以通过电脑的USB端口通过调试适配器发送二进制文件。然后微控制器的调试控制器接收该数据并将其存储在flash中.

调试代码

我们日常用的IDEs(Keil/IAR)通常都会有些小按键(step in, step over 以及step out) 逐步运行代码. 这些动作也是通过调试控制器和适配器协助完成的. 当我们按下那些按键时,对应特殊的指令将会同步调试控制器传输到微控制器中.

其它的调试放方法也可以通过IDEs进行设置断点、读取寄存器or变量的内存值等等,这些请通过各自不同的IDEs进行进一步的学习.

GUN ARM Toolchain

学习到这一点,我希望你已经理解了GUN ARM Toolchain与它们同类的工具(PC端的gcc)只是略有不同. 接下来让我们来看看GNU ARN Toolchain中提供的一些工具,这些工具时生成可执行二进制文件的工具链一部分.

然后请从这个链接中下载GNU ARM Toolchain到你的计算机,让我们继续学习
GNU ARM Toolchain下载

在下载解压后,可以看到如下截图的目录文件:


我们需要关注时"bin"目录下的相关文件,那么让我们打开一个Linux下的终端来探索该目录下的可执行程序吧!

交叉工具链生成二进制文件


你可以看到上面截图中的几个可执行程序,我们重点需要关注的5个文件如下:

  1. arm-none-eabi-gcc
  2. arm-none-eabi-as
  3. arm-none-eabi-ld
  4. arm-none-eabi-objcopy
  5. arm-none-eabi-gdb
arm-none-eabi-gcc

GCC代表了GNU编译器集合。这是整个工具链主要的命令,一旦编译完成,它会调用链接器,链接器将不同的对象文件链接到一个大文件中,并通过上面给出的正确地址来定位它,并生成最终的可执行文件!

因此,GCC可以被认为是整个工具链的驱动程序,因为它可以负责整个过程,并将给定项目的所有源文件转换为一个最终可执行文件!

但我们可以使用如下所示的选项使其在整个过程的任何一点停止也就是只执行一部分:

arm-none-eabi-as

“as”代表汇编语言,它将汇编语言的助记符翻译成操作码.

arm-none-eabi-ld

“ld”是GNU的链接器和定位器的组合.

arm-none-eabi-objcopy

一个目标文件可以用几种格式生成。流行的格式包括**扩展链接器格式(.elf格式)**和通用对象文件格式(.coff)。但这些格式通常用于在PC机上运行二进制文件,它们包含一些关于二进制文件的额外信息.

对于微控制器,二进制文件通常是紧密打包的,没有任何额外的元数据。objcopy是负责获取elf或coff二进制文件的工具,并以一种可以在微控制器上烧录的方式打包它们!

arm-none-eabi-gdb

GDB,它是处理调试会话所需的调试服务器,GDB帮助翻译程序员的意图,比如:

  • 单步调试代码
  • 设置断点
  • 读取变量值
  • 读取内存中的值
  • 查看堆栈情况
    关于GDB的更深入描述,请查看其它资料进行学习.

相关的文章

下面时相关文章的链接,也许你会感兴趣!

Hardware, Software, Firmware, Middleware, Drivers, OS & Applications, The Difference?

Video: Embedded Software Engineer Interview Questions

Embedded Engineers Salaries In Europe

GNU ARM Toolchain 初学者入门指南相关推荐

  1. 用python公众号开书城步骤_资源 | 开放Python书籍:一本短小精悍的初学者入门指南...

    资源 | 开放Python书籍:一本短小精悍的初学者入门指南 作者:机器之心 来源:机器之心 公众号 分享到: 03-25 选自GitHub机器之心整理 参与:思源 如何快速熟悉 Python 编程一 ...

  2. oracle打patch,Oracle初学者入门指南-How to get Oracle Patch?

    Oracle初学者入门指南-How to get Oracle Patch? 怎样获得/找到Oracle的Patch,这是一个朋友在Itpub上问到的问题.他还举了一个生动的例子: 比如我要使用ora ...

  3. oracle把数据分开,Oracle初学者入门指南-系统与用户数据分离

    Oracle初学者入门指南-系统与用户数据分离 今天一个朋友的数据库出现问题,请我帮忙查看,其实问题本身很简单: Fri Jun 19 10:30:00 2006 ORA-1653: unable t ...

  4. 区块链编程初学者入门指南

    我有很多问题需要了解区块链Blockchain的工作原理.重要的是"我如何在其上构建应用程序dapp?".花了几个星期的时间挖掘,阅读和试验才最终了解.我找不到简短而全面的指南.现 ...

  5. Java初学者入门指南

    今天群里的Java编程初学者问我接触Java语言程序的时候,不知道该学习掌握哪些必要的基础知识.总结了零基础学习Java编程语言的几个基础知识要点.希望能够对刚入门的Java新手有帮助 一丶先了解什么 ...

  6. Oracle初学者入门指南-什么是 Metalink 或 MOS ?

    身为一个Oracle DBA,你可能经常看到老DBA们讲Metalink或者MOS,你必须知道这是什么. Metalink是Oracle的官方技术支持站点,其网址为: metalink.oracle. ...

  7. Oracle初学者入门指南-什么是Metalink -MOS ?

    身为一个Oracle DBA,你必须知道什么是Metalink. Metalink是Oracle的官方技术支持站点,其网址为: http://metalink.oracle.com. (Update: ...

  8. EasyAR 初学者入门指南(5)---录屏功能

    录屏功能成为了每个AR APP 的标配.确实,通过录屏技术我们可以记录我们当前操作手机时所看到的一些惊艳画面(尤其对于AR而言),目前市面上有许多的录屏集成方案,但单纯对于AR开发而言,EasyAR ...

  9. 区块链开发初学者编程入门指南

    我有很多问题需要了解区块链Blockchain的工作原理.重要的是"我如何在其上构建应用程序dapp?".花了几个星期的时间挖掘,阅读和试验才最终了解.我找不到简短而全面的指南.现 ...

  10. GNU ARM 汇编指令[转载]

    http://blog.sina.com.cn/s/blog_59b189220100au1k.html 第一部分 Linux下ARM汇编语法尽管在Linux下使用C或C++编写程序很方便,但汇编源程 ...

最新文章

  1. How to Run a Stress Test in JMeter
  2. HTML <div> 标签介绍
  3. ajax ssm 页面跳转_SSM用jq整合Ajax入门案例讲解
  4. 【路径规划】基于matlab改进的蚁群算法机器人栅格地图避障路径规划【含Matlab源码 905期】
  5. RQNOJ:PID3 Jam的计数法
  6. 4r照片尺寸是多大_4r照片尺寸(正常照片是5寸还是6寸)
  7. 国产计算机存储,全国产化存储AXD嵌入式存储芯片在全国产化计算机适配应用AXD安信达-国内领先的自主可控存储提供商...
  8. 笔记本无线上网卡的种类
  9. html5 聊天机器人,发挥你想象力,BotUI – 聊天机器人 JS 框架
  10. DNS服务器存在问题需要修复,dns服务(dns异常怎么都修复不了)
  11. JavaWeb--用户注册登录案例
  12. PokemonGo:LBS游戏开发
  13. Pytorch教程(1)
  14. Dom4j教程详解+XML详解(详解+举例)
  15. xp远程linux打印,在Ubuntu下访问xp打印机
  16. 解决对路径bin\roslyn..的访问被拒绝
  17. html5如何创建按钮button
  18. web前端各种浏览器版本测试工具-turbo
  19. 陈力:传智播客古代 珍宝币 泡泡龙游戏开发第39讲:PHP数据库编程MySQLi扩展库
  20. Python:网络爬虫爬取某表情包网站

热门文章

  1. html js 实现图片的简单分页功能
  2. STM32L4系列单片机如何使用RTC唤醒定时器进入Standby低功耗模式并唤醒+整机功耗测试
  3. python 贴吧小爬虫案例
  4. Pure Pursuit轨迹跟踪matlab程序
  5. 技嘉服务器主板装系统,技嘉主板bios设置图解教程
  6. 读书印记 - 《刘强东自述:我的经营模式》
  7. 轻松学,听说你还没有搞懂 Dagger2
  8. 爬虫自动定时获取查重结果并将结果发送至指定邮箱
  9. 西瓜创客的python_西瓜创客Python客户端
  10. MATLAB中simulink的模糊PID控制