系统启动(一) 冰山之下
说bootloader之前,最好能温故而知新一下,想一想,我们之前玩的51单片机,stm32单片机,它们是怎么启动的。
无非是上电后,CPU开始取指令,总线按照寻址的命令,取出flash中的一条指令,然后译指,ALU执行运算,最后把结果写到CPU寄存器或者
ram中去。
但是考虑下面这样一段代码,我们可以挖出更多的问题:
1 #include <stdio.h> 2 3 int a[10] = {1,2,3,4,5,6,7,8,9,10}; 4 int main() 5 { 6 int i = 0 ; 7 for(i = 0; i < 10; i++) { 8 a[i] = 0; 9 } 10 return 0; 11 }
上述c文件,编译后,会生成.o目标文件,目标文件中会有很多段,比如text段,data段,bss段等,和平台的运行库链接后会生成hex可执行文件
我们烧录到板子的flash中的正是这些可执行文件。那么问题来了,全局变量a在data段(STM32中叫做RW段),但是在系统运行前,它是在rom里的,当代码运行到对a[i] 执行赋值操作时,a就在ram里面了,这中间发生了什么?谁把a[10] 从flash中搬到内存中了吗?
是的,CPU上电后,的确是从ROM中读取代码运行的,但是在运行我们的代码之前,CPU会运行一段特殊的代码,会把flash中RW段的数据从ROM中复制到RAM中,并在RAM中分配一段空间存放ZI段的内容,然后把ZI段的内容全部初始化为0,加载完毕后,正式开始执行主体程序。
这里面这段特殊的代码,不知你是否还有印象,就是那个startup_xxx.s文件。关于startup.s, 值得好好深入研究一番,但是不在本文的重点内容中。只是,这件事里面需要引起我们的思考,也就是我们的代码在编译链接的时候,其实所有的符号的地址已经确定了,比如我在程序里访问a[0]
绝对是,直接操作某个确切的地址的,那么也就是说,搬运的时候,应该是会根据具体的地址往sram中搬运的。至于是不是这样,后面专栏中会进一步探讨。