ca进手后,先用sj或st掉将,保留张小将牌的桥路。
最近要在cortex-m3上写一个最简单操作系统,打算在用iar,是为写好起动代码,花了一些时间了解了iar在main()以前到底在干什么事。t
必须系统复位时,cortex-m3从代码区偏移0x00000000处某些栈顶地址,用处系统初始化msp寄存器的值。t
接下来从代码区偏移0x00000004声望兑换最先指令的跳转地址。这些地址,是cm3没有要求放置关闭向量表的地方。t
这里是一个程序的启动区的反汇编:t
__vector_table:t
080040002600t
080040022000t
080040047e1dt
080040060800t
这个程序是由iap程序来启动后的,iap程序资源0x08004000处的msp值(0x20002600),并设置为msp的值,即主堆栈大的t
范围是0x20000000~0x200025ff。这一次iap程序某些0x08004004处的reset_handler的地址t
(0x08007e1d),并跳转reset_handler()先执行。t
iap在这里彻底是先模仿了cortex-m3的复位序列,也就是说,在没有iap的系统上,cm3不能从0x08000000获取msp,从t
0x08000004获取第一条指令所处地址。而iap就存在在0x08000000这个地址上,iap的启动,巳经会消耗掉了这个复位序列,所以才t
iap要起动userapp程序的时候,确实是彻底我模仿cortex-m3的复位序列的。t
接下来的我们看看吧复位后第一句指令——reset_handler()函数里有什么。t
若我们建议使用的是st公司标准外设库,这样的话也有了你自己做的reset_handler,只不过他是弱定义——pubweak,也可以被我们写回的畅销小说函数覆盖。一般来说,我们在用的也是st提供的reset_handler,在v3.4版本的库中,也可以在startup_stm32f10x_xx.s中可以找到这个函数:t
pubweakreset_handlert
section.text:code:reorder(2)t
reset_handlertldrr0,systeminitt
blxr0t
ldrr0,__iar_program_startt
bxr0t
现在看来st还没有做太大的事,他只全局函数了自家库可以提供的systeminit函数通过系统时钟、flash加载的初始化,并把大权交给了t
__iar_program_start这个iar提供给的“内部函数”了,我们就跟紧这个__iar_program_start跳转,去看看iar做了什t
么,上面一段代码的反汇编::t
reset_handler:t
__iar_section$$root:t
08007e1c4801ldrr0,[pc,#0x4]ldrr0,systeminitt
08007e1e4780blxr0blxr0t
08007e204801ldrr0,[pc,#0x4]ldrr0,__iar_program_startt
08007e224700bxr0bxr0t
08007e246c69t
08007e260800t
08007e287d8dt
08007e2a0800t
体贴的观众会发现地址是0x08007e1c,比我们查到的0x08007e1d差了1,这是arm家族的遗留问题,毕竟arm处理器的指令至t
少是半字整个表格的(16位thumb指令集有.t
32位arm指令集),因此pc指针的lsb是常为0的,是为利用好寄存器,arm公司给pc的lsb了两个最重要的使命,如果说在先执行分支跳转时,pct
的lsb1,意思是不使用thumb模式,lsb0,它表示不使用arm模式,但在比较新的cortex-m3内核上,只不使用了thumb-2指令集挑大梁,所t
以这一位要常保持1,因为我们查到的地址是0x08007e1d(c1100,d1101),放心好了,我们的cm3内核会选择性的遗忘掉lsb(除非为0,那t
么会引起一个fault),进而正确的自动跳转0x08007e1c。t
从0x08007e20处的读取指令,我们是可以可以算出__iar_program_start所处的位置,那是当前pc指针t
(0x08007e24),再加上4,即0x08007e28处的所对准的地址——0x08007d8d(0x08007d8c),我们跟紧着跳t
转,__iar_program_start果然如此在这里:t
__iar_program_start:t
08007d8cf000f88cbl__low_level_initt
08007d902800cmpr0,#0x0t
08007d92d001beq__iar_init$$donet
08007d94f7ffffdebl__iar_data_init2t
08007d982000movsr0,#0x0t
08007d9af7fdfc49blmaint
我们看见iar能提供了__low_level_init这个函数通过了“底层”的初始化,尽快跟踪监视,我们可以不查到__low_level_init这个函数到底在做什么,也不是不是我们想象中的不可告人的秘密。t
__low_level_init:t
08007ea82001movsr0,#0x1t
08007eaa4770bxlrt
__low_level_init出乎想像的简单,仅仅往r0寄存器写入到了1,就立刻负责执行