利用業餘時間,自學了一點STM32編程,作過幾個小玩具。但一直侷限在裸機代碼裏,沒有機會學習rtos,深覺得憾。編程
春節閒在家裏無聊,就翻了一下野火的教程,發現對rtt講得很好,並且不須要硬件,只用軟件仿真就能夠學習,恰好利用這個機會入一下門。函數
過去我寫裸機代碼,主要就是用st公司的std庫。std庫包裝得很好,再加上mdk5的pack management很好用,就沒怎麼關注底層。據說rtos要修改啓動代碼,看來彙編這個坎是繞不過了。只好突擊了一下ARM的指令集,勉強能看懂源碼。學習
讀啓動文件的源碼,發現先是定義了堆棧地址,而後跳到SystemInit函數。SystemInit函數負責調節單片機時鐘寄存器的值,並把時鐘源由內部晶振切換到外部晶振,這部分很好理解。再以後就跳到了__main函數。這個函數我在文件系統裏沒有搜到源碼,無論是c的仍是彙編的都沒有,估計被MDK5隱藏了。spa
以stm32f103c8t6和mdk5.24爲例,我寫了一個空的while循環做爲main函數,而後compile、debug,看反彙編。debug
空的main函數:code
int main(void) { while(1) { } }
反彙編,assembly模式:blog
__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。it
__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
如今是除夕夜,還有三分鐘就大年初一了,祝有幸能看到這篇文字的人新春快樂。