前面学习了选择从那里进行加载代码,接着下来,我们将要了解CPU是怎么样运行编译的代码。通过前面的学习,我们知道通过编译器的编译,会生成可运行的代码,然后通过JLINK下载到STM32的FLASH里,再通过配置CPU的引导管脚,实现选择内部FLASH来加载代码。但是CPU是怎么样来加载代码,并运行的呢?
其实不同类型的CPU运行代码的方式不一样,STM32的运行方式是这样的,CPU 将从地址 0x0000 0000 获取栈顶值,然后从始于 0x0000 0004 的自举存储器开始执行代码。前面已经把0x800 0000的FLASH地址配置为启动的存储器,因此就会从这里偏移位置0取得栈顶值,从偏移位置4取得第一行执行代码。根据这个要求,那么每个项目工程的启动文件,必须是这样设置才可以运行。来看工程里的startup_stm32f40_41xxx.s文件,这个文件就是STM32F407运行的第一个文件,它编译出来的代码,就是被第一行执行的,因此它是采用汇编语言来编写的。也许有人问为什么不采用 C语言 来编写,非要使用汇编语言来编写?其实还真不能使用C语言来编写,因为CPU运行时,根本没有具备C语言的运行环境,所以不能直接运行C语言编译出来的代码,必须通过汇编语言来建立C语言的运行环境才可以运行C语言编译出来的代码。这个汇编语言文件是库文件里的一部分,它的目录路径是
Libraries\CMSIS\Device\ST\STM32F4xx\Source\Templates\arm\startup_stm32f40_41xxx.s。
这个文件里的内容比较多,并且是汇编语言,要看懂它,需要下些功夫才可以。前面说到CPU会从偏移位置0处来加载栈顶值,那么在这个汇编文件里是怎么样实现把栈顶的值放到偏移位置0的呢?现在来打开这个文件,查看到如下图:
可以从这里看到__initial_sp变量放在第一个位置,意味着这个变量的值会放在这个区域的第一个位置,这样确保了栈顶值保存在这段代码布局的首位置了。但是你也许问编译器怎么样知道这段代码一定会放在首位置,而不是放置在存储器的后面位置呢?如果没有的特别的声明,编译器还真可能把它放置在任何位置上的,并不是首位置。关键之处,是项目里还有一个编译连接的说明文件,它叫做project.sct,这个文件主要用来指定ARM连接器在生成映像文件时如何分配RO,RW,ZI等数据的存放地址,在我的工程里采用默认的文件,内容如下:
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00080000 { ; load region size_region
ER_IROM1 0x08000000 0x00080000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00020000 { ; RW data
.ANY (+RW +ZI)
}
}
在这里看到,加载代码和执行代码的地址,就是前面设置FLASH的地址,紧接下来会看到下面这行:
*.o (RESET, +First)
这行的意思就是说,把所有目标文件.o结尾的代码,都放置在这里,但是要把标识为RESET段的代码放置在最前面,因此这里明确地说明RESET的代码放在首位置,就是偏移0的位置。那么回过头来看一下启动的汇编文件,如下:
在这里看到AREA后面紧跟着一个RESET名称,也就是说这段代码区域就被命名为RESET了,当编译器看到这个名称,就会把这段代码放置在存储器的首位置,这样CPU就会从这里获得栈顶值,就可以开始加载代码进行运行了,从偏移4的位置,也就是Reset_Handler的值,把它放到CPU的执行指令寄存器,就进入代码运行了。
https://blog.csdn.net/caimouse/article/details/51749579
以上所述就是小编给大家介绍的《玩转STM32(14)运行第一行代码》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 一行代码让你的Python运行速度提高100倍!Python真强!
- 一行一行源码分析清楚AbstractQueuedSynchronizer
- 一行一行手敲webpack4配置
- HashMap源码全解析从一道面试题说起:请一行一行代码描述下hashmap put方法
- 幻术,一行代码实现镂空效果
- 一行代码逃逸 Safari 沙箱
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JUnit Recipes中文版
陈浩等译 / 电子工业 / 2006-9 / 69.00元
《JUnit Recipes中文版:程序员实用测试技巧》主要介绍了在Java开发中使用JUnit进行单元测试的各种方法、原则、技巧与实践。本书出自开发一线专家之手,本着实用的原则,涵盖各类Java开发中应用JUnit的实用技巧,内容丰富、全面深入;无论对于需要应用JUnit进行单元测试的一线Java开发人员,还是JUnit入门、进阶者,本书都是一本不可多得的实用指南。这本书介绍了大量的JUnit实......一起来看看 《JUnit Recipes中文版》 这本书的介绍吧!