利用业余时间,自学了一点STM32编程,做过几个小玩具。但一直局限在裸机代码里,没有机会学习rtos,深以为憾。
春节闲在家里无聊,就翻了一下野火的教程,发现对rtt讲得很好,而且不需要硬件,只用软件仿真就可以学习,刚好利用这个机会入一下门。
过去我写裸机代码,主要就是用st公司的std库。std库包装得很好,再加上mdk5的pack management很好用,就没怎么关注底层。听说rtos要修改启动代码,看来汇编这个坎是绕不过了。只好突击了一下ARM的指令集,勉强能看懂源码。
读启动文件的源码,发现先是定义了堆栈地址,然后跳到SystemInit函数。SystemInit函数负责调节单片机时钟寄存器的值,并把时钟源由内部晶振切换到外部晶振,这部分很好理解。再之后就跳到了__main函数。这个函数我在文件系统里没有搜到源码,不管是c的还是汇编的都没有,估计被MDK5隐藏了。
以stm32f103c8t6和mdk5.24为例,我写了一个空的while循环作为main函数,然后compile、debug,看反汇编。
空的main函数:
int main(void)
{
while(1)
{
}
}
反汇编,assembly模式:
__main:
0x080000EC F000F802 BL.W __scatterload (0x080000F4)
0x080000F0 F000F82C BL.W __rt_entry (0x0800014C)
说明里面还有两个子函数__scatterload和__rt_entry。
看代码__scatterload还有两个子函数,分别为__scatterload_null和__scatterload_zeroinit。
__scatterload:
0x080000F4 A00A ADR r0,{pc}+4 ; @0x08000120
0x080000F6 E8900C00 LDM r0,{r10-r11}
0x080000FA 4482 ADD r10,r10,r0
0x080000FC 4483 ADD r11,r11,r0
0x080000FE F1AA0701 SUB r7,r10,#0x01
__scatterload_null:
0x08000102 45DA CMP r10,r11
0x08000104 D101 BNE 0x0800010A
0x08000106 F000F821 BL.W __rt_entry (0x0800014C)
0x0800010A F2AF0E09 ADR.W lr,{pc}-0x07 ; @0x08000103
0x0800010E E8BA000F LDM r10!,{r0-r3}
0x08000112 F0130F01 TST r3,#0x01
0x08000116 BF18 IT NE
0x08000118 1AFB SUBNE r3,r7,r3
0x0800011A F0430301 ORR r3,r3,#0x01
0x0800011E 4718 BX r3
0x08000120 0254 DCW 0x0254
0x08000122 0000 DCW 0x0000
0x08000124 0264 DCW 0x0264
0x08000126 0000 DCW 0x0000
__scatterload_zeroinit:
0x08000128 2300 MOVS r3,#0x00
0x0800012A 2400 MOVS r4,#0x00
0x0800012C 2500 MOVS r5,#0x00
0x0800012E 2600 MOVS r6,#0x00
0x08000130 3A10 SUBS r2,r2,#0x10
0x08000132 BF28 IT CS
0x08000134 C178 STMCS r1!,{r3-r6}
0x08000136 D8FB BHI 0x08000130
0x08000138 0752 LSLS r2,r2,#29
0x0800013A BF28 IT CS
0x0800013C C130 STMCS r1!,{r4-r5}
0x0800013E BF48 IT MI
0x08000140 600B STRMI r3,[r1,#0x00]
0x08000142 4770 BX lr
__scatterload_null分别将加载域起始地址(没太懂,看结果似乎是紧挨着main函数后的一个地址)、运行域(ram)起始地址、map大小和__scatterload_zeroinit入口地址取出,再跳到__scatterload_zeroinit。__scatterload_zeroinit负责将ram清空,并回到__scatterload_null,再跳到__rt_entry。
__rt_entry先调用__user_setup_stackheap函数建立堆栈。__user_setup_stackheap调用__user_initial_stackheap函数初始化堆栈。最后进入main函数,完成芯片的启动。
__rt_lib_init:
0x08000144 B51F PUSH {r0-r4,lr}
__rt_lib_init_alloca_1:
0x08000146 BD1F POP {r0-r4,pc}
__rt_lib_shutdown:
0x08000148 B510 PUSH {r4,lr}
__rt_lib_shutdown_cpp_1:
0x0800014A BD10 POP {r4,pc}
__rt_entry:
0x0800014C F000F831 BL.W __user_setup_stackheap (0x080001B2)
0x08000150 4611 MOV r1,r2
__rt_entry_li:
0x08000152 F7FFFFF7 BL.W __rt_lib_init (0x08000144)
__rt_entry_main:
0x08000156 F000F90B BL.W main (0x08000370)
0x0800015A F000F84F BL.W exit (0x080001FC)
__rt_exit:
0x0800015E B403 PUSH {r0-r1}
__rt_exit_ls:
0x08000160 F7FFFFF2 BL.W __rt_lib_shutdown (0x08000148)
__rt_exit_exit:
0x08000164 BC03 POP {r0-r1}
0x08000166 F000F857 BL.W _sys_exit (0x08000218)
0x0800016A 0000 MOVS r0,r0
__user_initial_stackheap:
0x08000188 4804 LDR r0,[pc,#16] ; @0x0800019C
0x0800018A 4905 LDR r1,[pc,#20] ; @0x080001A0
0x0800018C 4A05 LDR r2,[pc,#20] ; @0x080001A4
0x0800018E 4B06 LDR r3,[pc,#24] ; @0x080001A8
0x08000190 4770 BX lr
0x08000192 0000 DCW 0x0000
0x08000194 0311 DCW 0x0311
0x08000196 0800 DCW 0x0800
0x08000198 00ED DCW 0x00ED
0x0800019A 0800 DCW 0x0800
0x0800019C 0060 DCW 0x0060
0x0800019E 2000 DCW 0x2000
0x080001A0 0660 DCW 0x0660
0x080001A2 2000 DCW 0x2000
0x080001A4 0260 DCW 0x0260
0x080001A6 2000 DCW 0x2000
0x080001A8 0260 DCW 0x0260
0x080001AA 2000 DCW 0x2000
__use_two_region_memory:
0x080001AC 4770 BX lr
__rt_heap_escrow$2region:
0x080001AE 4770 BX lr
__rt_heap_expand$2region:
0x080001B0 4770 BX lr
__user_setup_stackheap:
0x080001B2 4675 MOV r5,lr
0x080001B4 F000F82C BL.W __user_libspace (0x08000210)
0x080001B8 46AE MOV lr,r5
0x080001BA 0005 MOVS r5,r0
0x080001BC 4669 MOV r1,sp
0x080001BE 4653 MOV r3,r10
0x080001C0 F0200007 BIC r0,r0,#0x07
0x080001C4 4685 MOV sp,r0
0x080001C6 B018 ADD sp,sp,#0x60
0x080001C8 B520 PUSH {r5,lr}
0x080001CA F7FFFFDD BL.W __user_initial_stackheap (0x08000188)
0x080001CE E8BD4020 POP {r5,lr}
0x080001D2 F04F0600 MOV r6,#0x00
0x080001D6 F04F0700 MOV r7,#0x00
0x080001DA F04F0800 MOV r8,#0x00
0x080001DE F04F0B00 MOV r11,#0x00
0x080001E2 F0210107 BIC r1,r1,#0x07
0x080001E6 46AC MOV r12,r5
0x080001E8 E8AC09C0 STM r12!,{r6-r8,r11}
0x080001EC E8AC09C0 STM r12!,{r6-r8,r11}
0x080001F0 E8AC09C0 STM r12!,{r6-r8,r11}
0x080001F4 E8AC09C0 STM r12!,{r6-r8,r11}
0x080001F8 468D MOV sp,r1
0x080001FA 4770 BX lr
exit:
0x080001FC B510 PUSH {r4,lr}
0x080001FE 4604 MOV r4,r0
0x08000200 F3AF8000 NOP.W
0x08000204 4620 MOV r0,r4
0x08000206 E8BD4010 POP {r4,lr}
0x0800020A F7FFBFA8 B.W __rt_exit (0x0800015E)
0x0800020E 0000 MOVS r0,r0
__user_libspace:
0x08000210 4800 LDR r0,[pc,#0] ; @0x08000214
0x08000212 4770 BX lr
0x08000214 0000 DCW 0x0000
0x08000216 2000 DCW 0x2000
_sys_exit:
0x08000218 4901 LDR r1,[pc,#4] ; @0x08000220
0x0800021A 2018 MOVS r0,#0x18
0x0800021C BEAB BKPT 0xAB
0x0800021E E7FE B 0x0800021E
0x08000220 0026 DCW 0x0026
0x08000222 0002 DCW 0x0002
现在是除夕夜,还有三分钟就大年初一了,祝有幸能看到这篇文字的人新春快乐。