本文根據上一篇TQ2440開發板學習紀實(1)—最簡單的獨立運行組譯工具進化而來。 0 ARM堆棧(Stack)基礎知識
ARM支援滿減類型的堆棧,滿的意思是說堆棧指標SP(即R13)總是指向剛剛入棧的資料單元。與滿相對應的就是不滿,這種類型的棧指標SP指向棧頂的下一個空白單元。減的意思是說,棧底的記憶體位址大,棧頂地址小,壓入資料時,棧向地址小的方向擴充。
目前我們只有4KB的記憶體可用,範圍為:0x00000000-0x00000FFF,如下圖:
為了充分利用這4KB的記憶體,我們把堆棧
指標SP初始指向0x00001000。這樣設定有如下考慮: 必須4位元組對齊,這是ARM的要求。也就是最後兩位二進位位必須為0. 雖然最大可用記憶體地址為0x00000FFF,但是這裡仍然可以設定SP=0x00001000。因為ARM堆棧是”滿減”,所以後續使用時並不會使用0x00001000這個記憶體單元。
C語言的函數的實現,嚴重依賴於堆棧,雖然參數較少時,直接使用寄存器傳參,但是調用函數前其返回地址必須存放到堆棧上供被調用函數返回使用。 1 項目源碼
從本文開始,項目源碼不再在文中完整列出,有需要的朋友,請自行去CSDN的git庫中下載。本次源碼的tag為v0.1。
設定堆棧代碼就一行:
/* set statck, must be aligned by 4 bytes */ ldr sp, =0x00001000
調用C函數也非常簡單
b Main
注意這裡沒有使用bl,也就意味著,永遠不會執行後面的代碼。
需要說明的是,s3c2440有好幾個運行模式,不同的模式下有各自獨立的堆棧指標寄存器,需要分別設定。目前我們只工作在預設的SVC模式下,也只是設定了該模式下的堆棧而已。
有了堆棧,C語言的函數就可以順利執行,有了C語言,誰還會用彙編呢。所以後面是用C語言寫的一個LED流水燈程式。
void Main(void){ led_init(); while(1){ int i=0; for(i=1; i<=4; i++) { led_off( i-1 < 1 ? 4 : i-1); led_on(i); delay(10000); } }}
2 編譯說明
詳見Makefile檔案。 3 運行說明
參加TQ2440開發板學習紀實(1)—最簡單的獨立運行組譯工具中的說明。