日韩一区二区三区精品,欧美疯狂xxxxbbbb牲交,热99re久久免费视精品频,人妻互换 综合,欧美激情肉欲高潮视频

歷史上的今天

今天是:2024年10月21日(星期一)

正在發(fā)生

2018年10月21日 | ARM編程進(jìn)階之二 —— ATPCS與混合編程

發(fā)布者:美夢(mèng)小獅子 來(lái)源: eefocus關(guān)鍵字:ARM編程  ATPCS  混合編程 手機(jī)看文章 掃描二維碼
隨時(shí)隨地手機(jī)看文章

完全使用匯編語(yǔ)言來(lái)編寫(xiě)程序會(huì)非常的繁瑣,因此通常情況下,只是使用匯編程序來(lái)完成少量必須由匯編程序才能完成的工作,而其它工作則由C語(yǔ)言程序來(lái)完成。這樣一來(lái),我們實(shí)際上就是在進(jìn)行匯編和C的混合編程,甚至同一個(gè)程序的匯編源文件和C源文件是由不同的程序員編寫(xiě)的。在這種情況下,要想使不同程序員編寫(xiě)的匯編代碼和C代碼能耦合的很好,則必須有一個(gè)雙方都必須遵守的規(guī)則,這就是ATPCS規(guī)則。

第一部分內(nèi)容:ATPCS規(guī)則

ATPCS(ARM-Thumb Produce Call Standard)是ARM程序和Thumb程序中子程序調(diào)用的基本規(guī)則,目的是為了使單獨(dú)編譯的C語(yǔ)言程序和匯編程序之間能夠相互調(diào)用。這些基本規(guī)則包括子程序調(diào)用過(guò)程中寄存器的使用規(guī)則、數(shù)據(jù)棧的使用規(guī)則和參數(shù)的傳遞規(guī)則。

1、寄存器的使用規(guī)則:

image

a)、寄存器R0 -- R11被分為2組:a1 -- a4,v1 – v8。所以對(duì)于兼容ATPCS的編譯器而言,在編程的時(shí)候可以使用a1替換R0

b)、除了R13 -- R15有別名外,對(duì)于兼容ATPCS的編譯器而言,也可以使用其它寄存器的別名:wr, sb, sl, fp, ip,它們都有自己的一些特殊用法

c)、寄存器R0 -- R3用于傳遞子程序的參數(shù)和返回結(jié)果(詳見(jiàn)本文后部)

d)、寄存器a1 -- a4和ip是scratch寄存器(即:臨時(shí)寄存器),其值在進(jìn)行子程序調(diào)用時(shí)不需要保存和恢復(fù)。(詳見(jiàn)本文后部)

2、數(shù)據(jù)棧的使用規(guī)則

在“其它尋址模式與其它指令”一文中,我講到棧有4種類(lèi)型:

FD (Full Descending) 滿遞減

ED (Empty Descending)空遞減

FA (Full Ascending) 滿遞增

EA (Empty Ascending) 空遞增

ATPCS規(guī)定數(shù)據(jù)棧為FD(滿遞減)類(lèi)型,并且對(duì)數(shù)據(jù)棧的操作是8字節(jié)對(duì)齊的。這意味著我們?cè)诰帉?xiě)匯編子程序時(shí),如果要進(jìn)行出棧和入棧操作,則必須使用ldmfd和stmfd指令(或者ldmia和ldmdb);而兼容ATPCS的編譯器在編譯C代碼時(shí),也必須這樣做。

3、參數(shù)的傳遞規(guī)則

參數(shù)個(gè)數(shù)固定的子程序參數(shù)傳遞規(guī)則:
    前4個(gè)整數(shù)參數(shù),通過(guò)寄存器R0~R3來(lái)傳遞。其他參數(shù)通過(guò)數(shù)據(jù)棧傳遞。
子程序結(jié)果返回規(guī)則 
    結(jié)果為一個(gè)32位的整數(shù)時(shí),必須通過(guò)寄存器R0返回;結(jié)果為一個(gè)64位整數(shù)時(shí),通過(guò)寄存器R0和R1返回,依次類(lèi)推。

下面看一下編譯器對(duì)于這幾個(gè)規(guī)則的遵循(實(shí)現(xiàn))情況。

參數(shù)傳遞(4個(gè)參數(shù))以及結(jié)果返回 :很顯然,主調(diào)程序在調(diào)用子程序(即:bl func1)之前,將要傳遞給子程序的4個(gè)參數(shù)準(zhǔn)備在了R0~R3中,從而使得子程序可以通過(guò)該4個(gè)寄存器獲得轉(zhuǎn)遞給它的參數(shù)(即:4個(gè)參數(shù)是通過(guò)寄存器R0~R3來(lái)傳遞的);子程序在返回之前,將返回值放在了寄存器R0中,從而使得主調(diào)函數(shù)可以通過(guò)R0來(lái)獲得子程序的返回值(即:結(jié)果為一個(gè)32位的整數(shù)時(shí),通過(guò)寄存器R0返回)

image

多于4個(gè)參數(shù),前4個(gè)參數(shù)通過(guò)寄存器R0~R3來(lái)傳遞,其他參數(shù)通過(guò)數(shù)據(jù)棧傳遞。

7個(gè)參數(shù)的情景。下面是程序

int func(int a, int b, int c, int d, int e, int f, int g)
{
    return(a+b+c+d+e+f+g);
}
int main()
{
    int a=1,b=2,c=3,d=4,e=5,f=6,g=7;
    return func(a,b,c,d,e,f,g);
}

的反匯編結(jié)果。我們通過(guò)它來(lái)分析一下當(dāng)參數(shù)超過(guò)4個(gè)的時(shí)候,所謂“通過(guò)數(shù)據(jù)棧傳遞其它參數(shù)”是什么含義。

1 int func(int a, int b, int c, int d, int e, int f, int g)
2 {
3 func [0xe92d4010] stmfd r13!,{r4,r14}
4 000080ac [0xe59d4010] ldr r4,[r13,#0x10] //r4為第7個(gè)參數(shù)的值
5 000080b0 [0xe28de008] add r14,r13,#8 //r14指向了存放傳入?yún)?shù)在棧中的位置
6 000080b4 [0xe89e5000] ldmia r14,{r12,r14} //r12為第5個(gè)參數(shù)的值,r14為第6個(gè)參數(shù)的值
7 return(a+b+c+d+e+f+g);
8 000080b8 [0xe0800001] add r0,r0,r1
9 000080bc [0xe0800002] add r0,r0,r2
10 000080c0 [0xe0800003] add r0,r0,r3
11 000080c4 [0xe080000c] add r0,r0,r12
12 000080c8 [0xe080000e] add r0,r0,r14
13 000080cc [0xe0800004] add r0,r0,r4
14 }
15 000080d0 [0xe8bd8010] ldmfd r13!,{r4,pc}
16 int main()
17 {
18 main [0xe92d401e] stmfd r13!,{r1-r4,r14}
19 int a=1,b=2,c=3,d=4,e=5,f=6,g=7;
20 000080d8 [0xe3a00001] mov r0,#1
21 000080dc [0xe3a0c002] mov r12,#2
22 000080e0 [0xe3a0e003] mov r14,#3
23 000080e4 [0xe3a04004] mov r4,#4
24 000080e8 [0xe3a01005] mov r1,#5
25 000080ec [0xe3a02006] mov r2,#6
26 000080f0 [0xe3a03007] mov r3,#7
27 return func(a,b,c,d,e,f,g);
28 000080f4 [0xe88d000e] stmia r13,{r1-r3} //main處的入棧操作,r1-r3實(shí)為占位符,是替第5、6、7個(gè)參數(shù)預(yù)先在棧內(nèi)占位置的
29 000080f8 [0xe1a03004] mov r3,r4
30 000080fc [0xe1a0200e] mov r2,r14
31 00008100 [0xe1a0100c] mov r1,r12
32 00008104 [0xebffffe7] bl func
33 }
34 00008108 [0xe8bd801e] ldmfd r13!,{r1-r4,pc}

第3行采用的是stmfd指令實(shí)施入棧,這是因?yàn)橐獫M足ATPCS中的“數(shù)據(jù)棧的使用規(guī)則”。而入棧的寄存器是r4和r14,r4入棧是因?yàn)閞4在子程序中被破壞(使用)了,因此必須在子程序的入口入棧保存,在子程序的出口處出?;謴?fù)(第28行);而r14要入棧則是因?yàn)閞14存放的是子程序的返回地址,而r14又在子程序中被破壞(使用)了,如果不保存的話,在子程序返回(第34行)的時(shí)候,將不會(huì)正確地返回到主調(diào)程序。當(dāng)然,你也許發(fā)現(xiàn)了r0,r1,r2,r3,r12同樣在子程序中被破壞了,為什么它們不需要保存和恢復(fù)呢?這是因?yàn)椤凹拇嫫鱝1 -- a4和ip是scratch寄存器(即:臨時(shí)寄存器),其值在進(jìn)行子程序調(diào)用時(shí)不需要保存和恢復(fù)?!保ㄒ?jiàn)前文)。也就是說(shuō),對(duì)于主調(diào)程序的編寫(xiě)者而言,他應(yīng)該很清楚他必須遵循ATPCS規(guī)則,所以他不會(huì)期望在子程序返回后,寄存器r0, r1, r2, r3, r12的值一定會(huì)維持原樣。因此子程序的編寫(xiě)者也就不必保存和恢復(fù)這幾個(gè)寄存器了,即使子程序破壞了它們的值。隨便說(shuō)一句,這條stmfd指令是由編譯器自動(dòng)加在子函數(shù)的第1條語(yǔ)句之前的,所以類(lèi)推一下就應(yīng)該明白,main函數(shù)運(yùn)行時(shí)的第1條指令并不是程序員書(shū)寫(xiě)main函數(shù)的第1條語(yǔ)句,而是編譯器添加的入棧指令。更進(jìn)一步,為什么編譯器要加這條入棧指令呢?因?yàn)閙ain函數(shù)本質(zhì)上也是個(gè)子函數(shù)而已,它也會(huì)被別人調(diào)用,也就是說(shuō),程序運(yùn)行起來(lái)后,main函數(shù)并不是首先運(yùn)行的。那么,是誰(shuí)首先運(yùn)行呢?當(dāng)然是調(diào)用main函數(shù)的代碼,這段代碼被稱(chēng)之為:例行啟動(dòng)程序(boot routine),或稱(chēng)啟動(dòng)例程。它是由編譯器在編譯程序時(shí)自動(dòng)加入的。

第20、21、22、23、29、30、31行顯然是在準(zhǔn)備(傳遞)前4個(gè)參數(shù);第18、24、25、26、28行的執(zhí)行,顯然將后3個(gè)參數(shù)放到了棧中,而第4、5、6行完成后,子程序則將棧中的3個(gè)參數(shù)取出了。這樣就完成了“多于4個(gè)的參數(shù)通過(guò)數(shù)據(jù)棧來(lái)傳遞”這個(gè)操作。

ATPCS

由此我們可以得到關(guān)于程序優(yōu)化的一個(gè)結(jié)論:開(kāi)始四個(gè)字大小的參數(shù)直接使用寄存器的R0-R3來(lái)傳遞(快速且高效的);如果需要更多的參數(shù),將使用堆棧。(需要額外的指令和慢速的存儲(chǔ)器操作) ;所以通常限制參數(shù)的個(gè)數(shù),使它為4或更少,如果不可避免,把常用的參數(shù)前4個(gè)放在R0-R3中。

第二部分內(nèi)容:C和ARM匯編程序間相互調(diào)用(點(diǎn)擊下載示例代碼)

在C和ARM匯編程序之間相互調(diào)用必須遵守ATPCS規(guī)則。C和匯編之間的相互調(diào)用可以從以下這四方面來(lái)說(shuō)明:

在C語(yǔ)言程序中調(diào)用匯編程序
在匯編程序中調(diào)用C語(yǔ)言程序
匯編程序?qū)全局變量的訪問(wèn)
C程序?qū)R編全局變量的訪問(wèn)

C程序中內(nèi)嵌匯編

1、在C語(yǔ)言程序中調(diào)用匯編子程序

為了保證程序調(diào)用時(shí)參數(shù)的正確傳遞,匯編程序的設(shè)計(jì)要遵守ATPCS。在匯編程序中需要使用EXPORT偽操作來(lái)聲明,使得本程序可以被其它程序調(diào)用。同時(shí),在C程序調(diào)用該匯編程序之前需要在C語(yǔ)言程序中使用extern關(guān)鍵詞來(lái)聲明該匯編程序。

參閱示例代碼中xmain函數(shù)(在ledtest.c中)對(duì)delay函數(shù)(在delay.s中)的調(diào)用

extern int delay(int time);

EXPORT delay

2、在匯編程序中調(diào)用C語(yǔ)言子程序

為了保證程序調(diào)用時(shí)參數(shù)的正確傳遞,匯編程序的設(shè)計(jì)要遵守ATPCS。在C程序中不需要使用任何關(guān)鍵字來(lái)聲明將被匯編語(yǔ)言調(diào)用的C程序(只要該程序的聲明前不要加static關(guān)鍵字),但是在匯編程序調(diào)用該C程序之前需要在匯編語(yǔ)言程序中使用IMPORT偽操作來(lái)聲明該C程序。在匯編程序中通過(guò)BL指令來(lái)調(diào)用子程序。

參閱示例代碼中init.s文件中的代碼對(duì)xmain函數(shù)的調(diào)用

IMPORT xmain
bl xmain

int xmain(int val)

3、匯編程序訪問(wèn)全局C變量

匯編程序可以通過(guò)C全局變量的地址間接訪問(wèn)在C語(yǔ)言程序中聲明的全局變量。在匯編程序中,通過(guò)使用IMPORT關(guān)鍵詞引人C全局變量,該C全局變量的名稱(chēng)在匯編程序中被認(rèn)為是一個(gè)標(biāo)號(hào),從而匯編程序可以利用LDR和STR指令訪問(wèn)該標(biāo)號(hào)所代表的地址處存放的內(nèi)容(即:C全局變量的值)。

參閱示例代碼中init.s文件中的如下幾行:

IMPORT i
ldr r0, i
sub r0, r0, #1
str r0, i

對(duì)于不同類(lèi)型的變量,需要采用不同選項(xiàng)的LDR和STR指令,如下所示:

unsigned char LDRB/STRB
unsigned short LDRH/STRH
unsigned int LDR/STR
char LDRSB/STRB
short LDRSH/STRH

4、C程序?qū)R編全局變量的訪問(wèn)

匯編程序中用DCD為全局變量分配空間并賦初值,并定義一個(gè)標(biāo)號(hào)代表該存儲(chǔ)位置,用EXPORT導(dǎo)出該標(biāo)號(hào)。C程序?qū)?huì)將該標(biāo)號(hào)視為全局變量的名稱(chēng),在C程序中用extern聲明該全局變量,之后就可以按正常的方式訪問(wèn)該全局變量了。

參閱示例代碼中delay.s文件中的代碼和xmain函數(shù)的代碼:

    EXPORT DELAYVAL
DELAYVAL
    DCD 0xffff

extern int DELAYVAL;

5、C程序中內(nèi)嵌匯編

有些操作C語(yǔ)言程序是做不了的,例如:改變cpsr寄存器的值、初始化堆棧指針寄存器sp,等等,它們只能由匯編程序完成。但出于編程簡(jiǎn)潔以及其它一些因素的考慮,有時(shí)我們需要在C源代碼中實(shí)現(xiàn)上述的操作,此時(shí)我們就必須采用在C源代碼中嵌入少量匯編代碼的方法來(lái)實(shí)現(xiàn),這就是C程序中的內(nèi)嵌匯編。

內(nèi)嵌的匯編指令包括大部分的ARM指令和Thumb指令,但是不能直接引用C的變量定義,數(shù)據(jù)交換必須通過(guò)ATPCS進(jìn)行,不支持諸如直接修改PC實(shí)現(xiàn)跳轉(zhuǎn)等底層功能。嵌入式匯編語(yǔ)句在形式上是獨(dú)立定義的函數(shù)體,其語(yǔ)法格式為:
__asm
{
指令[;指令]
……
[指令]
}

其中“__asm”為內(nèi)嵌匯編語(yǔ)句的關(guān)鍵字,需要特別注意的是前面有兩個(gè)下劃線。同一行如有多條指令,則指令之間用分號(hào)分隔,如果一條指令占據(jù)多行,除最后一行外都要使用連字符“\”

例如,如果我們需要在C程序中禁用中斷,那么內(nèi)嵌的匯編代碼如下:

__asm
{
    MRS    R0 CPSR
    ORR    R0, R0,#0x80
    MSR    CPSR_c,R0
}

出于完整性的考慮,最后將內(nèi)嵌匯編相對(duì)于一般匯編的一些不同的特點(diǎn)羅列如下:

操作數(shù)可以是寄存器、常量或C表達(dá)式。它們可以是char、short或者int類(lèi)型,而且是作為無(wú)符號(hào)數(shù)進(jìn)行操作 。
內(nèi)嵌的匯編指令中使用物理寄存器有一些限制。
常量前的符號(hào)“#”可以省略
只有指令B可以使用C程序中的標(biāo)號(hào),指令BL不能使用C程序中的標(biāo)號(hào)。 
不支持匯編語(yǔ)言中用于內(nèi)存分配的偽操作。
指令中如果包含常量操作數(shù),該指令可能會(huì)被匯編器展開(kāi)成幾條指令。 
內(nèi)嵌匯編器不支持通過(guò)“·”指示符或PC獲取當(dāng)前指令地址;
不支持LDR Rn,= expression偽指令,而使用MOV Rn, expression指令向寄存器賦值;
不支持標(biāo)號(hào)表達(dá)式;
不支持ADR和ADRL偽指令;
不支持BX和BLX指令;
不可以向PC賦值;
使用0x前綴替代“&”表示十六進(jìn)制數(shù)。
必須小心使用物理寄存器,如R0~R3,LR和PC。
不要使用寄存器尋址變量。
使用內(nèi)嵌匯編時(shí),編譯器自己會(huì)保存和恢復(fù)它可能用到的寄存器,用戶(hù)無(wú)須保存和恢復(fù)寄存器。
LDM和STM指令的寄存器列表只允許物理寄存器。


關(guān)鍵字:ARM編程  ATPCS  混合編程 引用地址:ARM編程進(jìn)階之二 —— ATPCS與混合編程

上一篇:ARM編程進(jìn)階之三 —— 裸機(jī)硬件的控制方法與例程
下一篇:ARM指令狀態(tài)切換到Thumb指令狀態(tài)

推薦閱讀

ASML公司日前發(fā)布2018年Q3季度財(cái)報(bào),當(dāng)季營(yíng)收27.8億歐元,凈利潤(rùn)6.8億歐元,出貨了5臺(tái)EUV光刻機(jī),全年預(yù)計(jì)出貨18臺(tái),明年將增長(zhǎng)到30臺(tái),而且明年下半年會(huì)推出新一代的NXE:3400C型光刻機(jī),生產(chǎn)能力從現(xiàn)在的每小時(shí)125晶圓提升到155片晶圓以上,意味著產(chǎn)能提升24%。?臺(tái)積電前不久試產(chǎn)了7nm EUV工藝,預(yù)計(jì)明年大規(guī)模量產(chǎn),三星今天宣布量產(chǎn)7nm EUV工藝,這...
2019年初,國(guó)家電網(wǎng)有限公司黨組以習(xí)近平新時(shí)代中國(guó)特色社會(huì)主義思想為指導(dǎo),深入貫徹落實(shí)“四個(gè)革命、一個(gè)合作”能源安全新戰(zhàn)略,順應(yīng)能源革命和數(shù)字革命融合發(fā)展趨勢(shì),創(chuàng)造性提出了“三型兩網(wǎng)、世界一流”的戰(zhàn)略目標(biāo),其中,“三型”是指樞紐型、平臺(tái)型、共享型企業(yè),圍繞產(chǎn)業(yè)屬性、網(wǎng)絡(luò)屬性、社會(huì)屬性明確了發(fā)展方向;“兩網(wǎng)”是指堅(jiān)強(qiáng)智能電網(wǎng)和泛在...
10月19日,中興終端有限公司成立,注冊(cè)資本1億人民幣,法定代表人為倪飛。圖片來(lái)源:企查查企查查顯示,該公司經(jīng)營(yíng)范圍含信設(shè)備制造;軟件開(kāi)發(fā);移動(dòng)通信設(shè)備銷(xiāo)售;通訊設(shè)備銷(xiāo)售;電子產(chǎn)品銷(xiāo)售;移動(dòng)通信設(shè)備制造;互聯(lián)網(wǎng)銷(xiāo)售(除銷(xiāo)售需要許可的商品);信息技術(shù)咨詢(xún)服務(wù);國(guó)內(nèi)貿(mào)易代理;移動(dòng)終端設(shè)備銷(xiāo)售;移動(dòng)終端設(shè)備制造;軟件銷(xiāo)售;貨物進(jìn)出口;物聯(lián)...
M to M編程過(guò)程在Flash中定義好要傳輸?shù)臄?shù)據(jù),在SRAM中定義好用來(lái)接收數(shù)據(jù)的變量;初始化DMA,主要是配置DMA結(jié)構(gòu)體;編寫(xiě)比較函數(shù);編寫(xiě)main函數(shù);1 定義數(shù)據(jù)/* Step1 定義數(shù)據(jù)目標(biāo)源和數(shù)據(jù)接收源 *********************************************/ /* 定義aSRC_Const_Buffer數(shù)組作為DMA傳輸數(shù)據(jù)源 * const關(guān)鍵字將aSRC_Const_Buffer數(shù)組變量定義為...

史海拾趣

小廣播
設(shè)計(jì)資源 培訓(xùn) 開(kāi)發(fā)板 精華推薦

最新單片機(jī)文章

 
EEWorld訂閱號(hào)

 
EEWorld服務(wù)號(hào)

 
汽車(chē)開(kāi)發(fā)圈

 
機(jī)器人開(kāi)發(fā)圈

電子工程世界版權(quán)所有 京ICP證060456號(hào) 京ICP備10001474號(hào)-1 電信業(yè)務(wù)審批[2006]字第258號(hào)函 京公網(wǎng)安備 11010802033920號(hào) Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved