bootloader的第二部分代碼主要是采用C語(yǔ)言來(lái)實(shí)現(xiàn)的,利用C語(yǔ)言實(shí)現(xiàn)串口、網(wǎng)卡等功能,并成功啟動(dòng)操作系統(tǒng)。
一、棧的初始化
1、概念解析
棧:先進(jìn)后出性質(zhì)的數(shù)據(jù)組織方式 棧底:第一個(gè)進(jìn)棧的數(shù)據(jù)所處位置 棧頂:最后一個(gè)進(jìn)棧的數(shù)據(jù)所處位置
滿棧:當(dāng)堆棧指針SP總是指向最后壓入堆棧的數(shù)據(jù) 空棧:當(dāng)堆棧指針SP指向下一個(gè)將要放入數(shù)據(jù)的空位置
升棧:隨著數(shù)據(jù)的入棧,SP指針從 低地址–》高低址 降棧:隨著數(shù)據(jù)的入棧,SP指針從 高地址–》低低址
棧幀:就是一個(gè)函數(shù)所使用的那部分棧(R11寄存器,也就是棧幀寄存器FP) 所有函數(shù)的棧幀串起來(lái)組成就是一個(gè)完整的棧,在堆棧指針SP(下邊界)與棧幀指針FP(上邊界)之間就是棧區(qū)。
ARM采用 滿降棧!!
2、手把手帶你分析
棧的作用:
2、1 保存局部變量保存
//stack1.c#include <stdio.h>int main(){ int a; a++; return a;}//在sheel里面運(yùn)行實(shí)例程序stack1.carm-linux-gcc -g stack1.c -o stack1arm-linux-objdump -D -S stack1 >dump1 //反匯編vim dump1 //進(jìn)入文件后,在:中搜索關(guān)鍵字,例如: :/main進(jìn)入dump后可以結(jié)合匯編代碼,可知a是存儲(chǔ)在棧幀指針fp和堆棧指針sp之間的。如圖: 
2、2 傳遞參數(shù)
當(dāng)函數(shù)的參數(shù)大于 4個(gè)的時(shí)候,將使用棧來(lái)傳遞參數(shù)。
//stack2.c#include <stdio.h>void func1(int a,int b,int c,int d,int e,int f){ int k; k=e+f;}int main(){ func1(1,2,3,4,5,6); return 0;}//在sheel里面運(yùn)行實(shí)例程序stack2.carm-linux-gcc -g stack2.c -o stack2arm-linux-objdump -D -S stack2 >dump2 //反匯編vim dump2

3.3 保存寄存器的值
#include <stdio.h>void func2(int a,int b){ int k; k=a+b;}void func1(int a,int b){ int c; func2(3,4); c=a+b;}int main(){ func1(1,2); return 0;}//在sheel里面運(yùn)行實(shí)例程序stack3.carm-linux-gcc -g stack3.c -o stack3arm-linux-objdump -D -S stack3 >dump3 //反匯編vim dump3

3、初始化堆棧
不管是2440還是6410還是210,將sp指針指向64M內(nèi)存(保證夠用)的地方,在使用的過(guò)程中,sp向下移(因?yàn)锳RM中采用的降棧)。 2440:0x30000000+64M = 0x34000000 6410:0x50000000+64M 210 :0x20000000+64M
//2440的堆棧初始化init_stack: ldr sp, =0x34000000 mov pc ,lr二、bss段初始化
未初始化的全局變量 分析驗(yàn)證代碼如下:
//bss.c#include <stdio.h>int year;int main(){ year = 2017; return year;}//在sheel里面輸入arm-linux-gcc -g bss.c -o bssarm-linux-readelf -a bss >dumpvi dump //然后:/year由下圖結(jié)果可知,未初始化的全局變量處于bss段之間: 
如果存在bss段的內(nèi)容沒有賦值而直接采用,則里面存儲(chǔ)的值可能是亂碼,為了確保軟件質(zhì)量,所以一般要有清零操作。
clean_bss: ldr r0, =bss_start //bss_start和bss_end是在鏈接器腳本gboot.lds中定義的 ldr r1, =bss_end cmp r0, r1 moveq pc, lr //若r0和r1相等,則直接返回,否則展開清零工作clean_loop: mov r2, #0 str r2, [r0], #4 cmp r0, r1 bne clean_loop mov pc, lr三、跳轉(zhuǎn)到C大門
采用絕對(duì)方式跳轉(zhuǎn)。 定義文件main.c
int gboot_main(){ return 0;}在start.s中加上:
ldr pc, =goot_main修改Makefile:

因?yàn)橹笆窃趨R編中點(diǎn)亮led的(起一個(gè)驗(yàn)證代碼是否正確的作用),現(xiàn)在為了驗(yàn)證程序能不能正確跳轉(zhuǎn)到main.c中,可以將點(diǎn)亮led的代碼移植到main.c中:
請(qǐng)注意:(volatile unsigned long*)的書寫方式。
//main.c#define GPBCON (volatile unsigned long*)0x56000010#define GPBDAT (volatile unsigned long*)0x56000014int gboot_main(){ *(GPBCON) = 0x400; *(GPBDAT) = 0x0; return 0; }之前匯編中的代碼如下:
bl light_led...light_led: #define GPBCON 0x56000010 #define GPBDAT 0x56000014 light_led: ldr r0, =GPBCON mov r1, #0x400 str r1, [r0] ldr r0, =GPBDAT mov r1, #0x0 str r1, [r0] mov pc, lr將上面的bl light_led備注掉,即@bl light_led。注意匯編中的注釋符號(hào)是“”@“”。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注