ARM Cortex-M3 SoC運行程式的詳細流程
目錄
基本概念
幾種不同型別的存盤器
startup.s vs bootloader
啟動模式
啟動流程
1、編譯鏈接
The _start Function
2、ROM的燒寫
3、系統上電復位執行
4、main函式執行
基本概念
幾種不同型別的存盤器

RAM的讀寫速度比ROM快
在過去的20年里,嵌入式系統一直使用ROM(EPROM)作為它們的存盤設備,然而近年來Flash全面代替了ROM(EPROM)在嵌入式系統中的地位,用作存盤Bootloader以及作業系統或者程式代碼或者直接當硬碟使用(U盤),
參考鏈接:
https://www.huaweicloud.com/articles/9d767b49832fd1fd5c6d23163d87b83e.html
https://blog.csdn.net/u012351051/article/details/81034661
startup.s vs bootloader
相信很多嵌入式的Developer肯定知道startup.s(匯編檔案)
它是系統的啟動檔案,程式上電復位之后第一個執行的程式,一般用來堆疊的初始化,設定中斷向量表,以及跳轉到main函式
但是學過作業系統的肯定知道bootloader,是一個系統的引導程式,同樣是上電復位之后第一個執行的程式
那么兩者到底是啥關系呢?誰先開始執行,誰后執行?哪一個執行哪一個不執行?如何執行?(可能自己之前是計算機專業的,對startup.s有困惑)
實際上:兩者是干同樣的事情的:先進行系統初始化,然后跳轉到main函式運行程式
堆疊初始化
建立向量表
跳轉到main函式
如果硬是要說區別的話,那就是bootloader要更加的復雜,能干的事情更多,通常如果要啟動作業系統的話,或者寫很復雜的程式的話就會使用到bootloader,說到這計算機背景的肯定就知道自己只接觸過bootload了,因為基本計算機都要運行作業系統的
如果是普通的嵌入式應用的話,使用startup.s就好,
那具體分析一下,到底復雜到哪里:
bootloader會有檔案驅動或者網路驅動,因為通常作業系統是放在硬碟中的,boloader如果要加載作業系統到系統RAM的話,就必須能夠讀取檔案內容,而有的作業系統是通過網路啟動
還有一個就是重映射的問題remap:
一般來說,ROM存盤器從0x0處開始編址,里面存放有例外中斷向量,但是ROM的讀寫速度是沒有RAM高的
為了提高系統的性能,bootloader會將ROM中的資料copy到RAM中,然后進行地址的重映射,即將RAM映射到0x0地址處,這樣在發生例外中斷的時候,訪問的就是RAM,而不是ROM
參考鏈接:
https://stackoverflow.com/questions/15696258/what-is-the-bootloader-and-startup-code-in-embedded-systems
https://www.cnblogs.com/no7dw/archive/2012/06/28/2567113.html
https://blog.csdn.net/weiLongElectrophile/article/details/75043746
啟動模式
從ROM啟動/boot ROM啟動
這里我所理解的是如果要使用bootloader的話,就從boot ROM啟動,這是可選的模塊,可以通過引數配置來設定啟動的模式
一般簡單的嵌入式是用不到boot ROM的,(M3默認是不啟用boot ROM)

這部分的內容也看了相關的文章,感覺有一些地方不是很通順,我還是把鏈接放過來
參考鏈接:
https://stackoverflow.com/questions/15665052/what-is-the-difference-between-a-bootrom-vs-bootloader-on-arm-systems
https://www.huaweicloud.com/articles/e7597769b186ee314625969ffa806654.html
啟動流程
從上面的分析可以知道M3 SoC是從room啟動,使用的是startup.s
1、編譯鏈接
C語言程式 + startup.s + libc庫檔案
ps:這里使用的編譯工具是arm-none-eabi-gcc,arm的gcc工具鏈有好幾種,都有不同的應用場景,不要弄混了
gcc工具在編譯之后,會使用鏈接程式linker將它們鏈接到一起,至于為什么還有會用到libc庫檔案,這和startup.s有關
The
_startFunctionFor most C and C++ programs, the true entry point is not
main, it’s the_startfunction. This function initializes the program runtime and invokes the program’smainfunction.The use of
_startis merely a general convention. The entry function can vary depending on the system, compiler, and standard libraries. For example, OS X only has dynamically linked applications; the loader takes care of setup, and the entry point to the program is actuallymain.The linker controls the program’s entry point. The default entry point can be overridden by clang and GCC linkers using the
-eflag, although this is rarely done for most programs.The implementation of the
_startfunction is usually supplied bylibc. The_startfunction is often written in assembly. Many implementations store the_startfunction in a file calledcrt0.s. Compilers typically ship with pre-compiledcrt0.oobject files for each supported architecture.
大概的意思是:
- C程式的入口點通常并不是main,而是start,
- 是在start中跳轉到main函式執行用戶程式,這是通常的一種做法
- start的實作依賴作業系統,編譯器以及標準庫等等
最后在編譯之后,將這三部分鏈接形成一個完整的程式(通常這并不是直接能夠運行在裸機上的檔案,還需要轉換成hex檔案)
ps:這里分析一波startup.s檔案干了什么事情
通常linker會將startup.s的相關內容放在這個完整的程式的開頭
那么它干了什么事呢?
看圖



解釋一波:
首先就是堆疊的初始化(記住:裸機上要執行程式,首先就是要初始化一個堆疊,建立一個程式執行的環境)
然后是設定中斷向量表(中斷向量表第一個字是MSP,第二個字是reset handler的入口地址,后面解釋)
最后是跳轉到start函式,然后再跳轉到main函式
2、ROM的燒寫
有了可執行的程式了,接下來就是通過燒寫工具將其燒寫到ROM中,(不需要關心,知道ROM的資料是如何來的就好)
3、系統上電復位執行
由上面的分析可以知道:
0x0:存放的是MSP(主堆疊指標)
0x4:存放的是PC(reset handler的入口地址)
系統上電復位之后,PC指標指向0x0出
處理器自動讀取0x0的MSP指標存放到處理器的內部狀態暫存器,PC指向0x4地址處(一個字32位)
然后跳轉到reset handler執行
那么reset handler干了什么事情呢?


- 就是將一些程式運行程序中的臨時變數等需要改變的資料copy到RAM中(因為ROM在燒錄之后是不能在寫資料的),通常是.data段以及.bass段;而指令還是存放在ROM中的,因為指令只是讀取,ROM允許讀
- systemInit系統的初始化,
- 跳轉到start函式
4、main函式執行
從start跳到main函式,這樣就執行用戶程式了~~
OK,OK(OK怪上線,哈哈哈),明白了吧~~哈哈
ps:start通常會干啥事?
Program startup code behavior is not specified by the C and C++ standards. Instead, the standards describe the conditions that must be true when the
mainfunction is called. However, there are many steps that are commonly performed across the majority of_startimplementations.At a high level, the
_startfunction handles:
- Early low-level initialization, such as:
- Configuring processor registers
- Initializing external memory
- Enabling caches
- Configuring the MMU
- Stack initialization, making sure that the stack is properly aligned per the ABI requirements
- Frame pointer initialization
- C/C++ runtime setup
- Initializing other scaffolding required by the system
- Jumping to
main- Exiting the program with the return code from
mainWhile the
_startroutine typically encompasses these activities, the specific order and implementation varies from system to system. For example, early low-level initialization code is commonly found with bare-metal embedded systems, but rarely on host machines with an OS. Your Linux or OS X program startup code will have multiple scaffolding functions which you will not find in embedded startup code.
(這里我就不說了,感興趣的自己去了解~)
下面貼了鏈接~~~
最后最后,上面都是自己個人的總結和見解,希望能夠幫到大家
另外這里的誰太深了,還有很多東西我沒有分析,這里就不在多少了,夠用就好~~~,感興趣的自己去看吧~,就在下面最后的鏈接 investigating what it takes to get to main,
謝謝大家,能夠看到這里,希望能夠幫到你們~~~哈哈
參考鏈接:
https://www.jianshu.com/p/fd0103d59d8e
https://blog.csdn.net/kagaobin/article/details/84198141
investigating what it takes to get to main
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/275536.html
標籤:其他
上一篇:嵌入式系統開發小白學習筆記22
下一篇:模電——半導體基礎知識
