




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第八章
ARMC語言的使用DMATEKCO.,LTD深圳市長高科技有限公司本章節將介紹ARMC語言程式設計概念,透過對本文的閱讀,希望讀者能瞭解ARM微處理器支援的C語言的使用方法,我們會搭配反組譯的功能,讓讀者更瞭解ARM是如何來支援高階語言的運作。本章的主要內容有:- 抽象化概念- 運算子- 區域變數/全域變數- 指標運算- 迴圈/條件判斷- 傳址呼叫和傳值呼叫8-1抽象化概念:當讀者熟讀前面幾章後,應該對ARM有深刻的印象,在指令集您會感覺到ARM的強大功能,單一指令可以同時完成許多動作,然而使用組合語言來撰寫程式,您一定倍感辛苦,而特別是靈活運用條件執行﹝ConditionalExecution﹞,把每一道指令添增了16種變化,相信您必須具備孫悟空72變化能力才能順利駕馭。本章將說明如何使用高階語言來撰寫ARM應用程式。在這之前先讓我們來看看組合語言及C語言抽象化的概念。組合語言層次的抽象化
程式設計師直接以指令來撰寫組合語言的程式,您必須熟悉指令格式、定址方式、暫存器及記憶體空間等觀念。通常組合言的指令和機器指令是採1對1的關係,在指令格式中要特別注意條件執行,若能妥善運用不但能增強管線的效能而且程式也變得更加精簡,程式長度有可能比高階語言還要短。ARM指令集可分成ARM及THUMB兩種,前者為32位元而後者則為16位元。通常對於要求效能可以使用32位元,但對於空間及節能等需求時則可以考慮將部份程式用THUMB指令撰寫。高階語言層次的抽象化高階語言允許程式設計師以跳脫機械層級的思考來撰寫程式。高階語言和機器語言間已不是1對1的關係,對高階語言的程式設計師而言,不見得要熟悉ARM指令或暫存器等配置。所以有很多高階語言程式設計師並不見得對ARM機器有很深的瞭解。然而建議讀者要清楚瞭解ARM的硬體結構,在撰寫C語言程式時,能多考慮到ARM機器的特質,如此才能事半功倍。例如:過長的迴圈將會使快取記憶體(Cache)無法發揮它的長才。8-2.1算術運算子算術運算子可分成:加法、減法、乘法、除法、及取餘數,分別用+、-、*、/、及%來表示。詳如下表:運算子
意思
範例
+
加
X+1
-
減
X-1
*
乘
X*Y
/
除
X/5
%
取餘數
X%4
以下為運算子的範例:
intmain()
{
inta,b,c;
a=1;
b=2;
c=a+b;
return0;
}其反組譯程式如下:
1 intmain()
2 {
3 inta,b,c;
4 a=1;
main [0xe3a01001]*movr1,#1
5 b=2;
000080ac [0xe3a02002]movr2,#2
6 c=a+b;
000080b0 [0xe0813002]addr3,r1,r2
7 return0;
000080b4 [0xe3a00000]movr0,#0
8 }
000080b8 [0xe1a0f00e]movpc,r14接下來我們來觀察,ARM對於除法的支援情形,以下是除法範例的反組譯程式列表:
3 inta,b,c;
4 a=6;
000080ac [0xe3a04006]movr4,#6
5 b=2;
000080b0 [0xe3a05002]movr5,#2
6 c=a/b;
000080b4 [0xe1a01004]movr1,r4
000080b8 [0xe1a00005]movr0,r5
000080bc [0xeb000004]bl__rt_sdiv
000080c0 [0xe1a06000]movr6,r0您應該可以發現ARM並未提供除法指令而由呼叫__rt_sdiv副程式取代,我們再來看看取餘數的反組譯程式列表:
3 inta,b,c;
4 a=6;
000080ac [0xe3a04006]movr4,#6
5 b=2;
000080b0 [0xe3a05002]movr5,#2
6 c=a%b;
000080b4 [0xe1a01004]movr1,r4
000080b8 [0xe1a00005]movr0,r5
000080bc [0xeb000004]bl__rt_sdiv
000080c0 [0xe1a06001]movr6,r18-2.2關係運算子 關係運算子有小於、小於等於、大於、大於等於、等於、及不等於,用<、<=、>、>=、==、及!=來表示。詳如下表:運算子
意思
範例
<
小於
X<1
<=
小於等於
X<=1
>
大於
X>Y
>=
大於等於
X>=Y
==
等於
X==1
!=
不等於
X!=1
小於關係運算子的範例如下:3 inta,b,c;4 a=6;main [0xe3a01006]*movr1,#65 b=2;000080ac [0xe3a02002]movr2,#2c=a<b;000080b0 [0xe1510002]cmpr1,r2000080b4 [0xaa000001]bge0x80c0;(main+0x18)000080b8 [0xe3a00001]movr0,#1000080bc [0xea000000]b0x80c4;(main+0x1c)000080c0 [0xe3a00000]movr0,#0000080c4 [0xe1a03000]movr3,r0
由上面範例可知小於關係運算子是利用cmp指令來設計,並利用分支指令b及其條件執行參數命令ge配合來達到將運算結果真﹝1﹞或假﹝0﹞利用將r0暫存再指定到c變數﹝r3﹞來儲存。8-2.3邏輯運算子 邏輯運算子有且、或、及非分用&&、||、及!來表示。詳如下表:運算子
意思
範例
&&
邏輯“且”AND
X&&Y
||
邏輯“或”OR
X||Y
!
邏輯“非”NOT
!X
“且”邏輯運算子的範例如下:3 inta,b,c;4 a=6;main [0xe3a01006]*movr1,#65 b=2;000080ac [0xe3a02002]movr2,#26 c=a&&b;000080b0 [0xe3510000]cmpr1,#0000080b4 [0x0a000003]beq0x80c8;(main+0x20)000080b8 [0xe3520000]cmpr2,#0000080bc [0x0a000001]beq0x80c8;(main+0x20)000080c0 [0xe3a00001]movr0,#1000080c4 [0xea000000]b0x80cc;(main+0x24)000080c8 [0xe3a00000]movr0,#0000080cc [0xe1a03000]movr3,r0在上面範例您有發現“且”具備捷徑﹝Shortcut﹞的功能,當變數a為假時則可以不需要考慮到變數b,此一作用我們稱為捷徑,若變數a為真時才需要測試變數b是否為真,當變數a及b都為真時,“且”關係運算子才會傳回真﹝0﹞,否則傳回假﹝0﹞。8-2.4指定運算子 指定運算子是用等號﹝=﹞來表示,要特別注意它具備指定的功能而非等於,它會把等號右側的常數值或變數值指定到等號左手邊的變數上。指定即為拷貝因此當指定運算子執行後,左側變數會等於右側計算後的結果,由於前面已使用過,在此不詳述。8-2.5增減運算子增減運算子就是加1或減1分別使用++和—來表示。運算子
意思
範例
++
加一
X++或++X
--
減一
X--或--X
其範例反組譯程式列表如下:3 inta,b;4 b=a++;main [0xe1a02001]*movr2,r1000080ac [0xe2811001]addr1,r1,#15 b=++a;000080b0 [0xe2810001]addr0,r1,#1000080b4 [0xe1a01000]movr1,r0000080b8 [0xe1a02000]movr2,r06 b=a--;000080bc [0xe1a02001]movr2,r1000080c0 [0xe2411001]subr1,r1,#17 b=--a;000080c4 [0xe2410001]subr0,r1,#1000080c8 [0xe1a01000]movr1,r0000080cc [0xe1a02000]movr2,r08-2.6條件運算子條件運算子是一個三元運算子,它以?和:來組成,其語法如下:
exp1?exp2:exp3當exp1條件運算為真時,則傳回exp2運算值否則傳exp3運算值,其範例如下:
a=10;
b=15;
x=(a>b)?a:b在上面範例當變數a大於b時,則將變數x內容指定成a否則指定成b。其反組譯程式碼列表如下:3 inta,b,c;4 a=1;main [0xe3a01001]*movr1,#15 b=2;000080ac
[0xe3a02002]movr2,#26 c=(a>b)?a:b;000080b0 [0xe1510002]cmpr1,r2000080b4 [0xda000001]ble0x80c0;(main+0x18)000080b8 [0xe1a00001]movr0,r1000080bc [0xea000000]b0x80c4;(main+0x1c)000080c0 [0xe1a00002]movr0,r2000080c4 [0xe1a03000]movr3,r08-2.7位元運算子位元運算子即為位元運算指令,有且、或、互斥、非、向右位移、及向左位移,用&、|、^、~、>>、及<<來表示。詳如下表:運算子
意思
範例
&
位元邏輯“且”AND
XANDY
|
位元邏輯“或”OR
XORY
^
位元邏輯“互斥”XOR
X^Y
~
位元邏輯“非”NOT
~X>>
向右位移
X>>2
<<
向左位移
X<<1
圖8-1顯示且位元運算子的運算結果,在圖中您可以發現且位元運算子﹝&﹞,使用and指令來組譯。當變數a和b分別指定為3和2時,再執行且位元運算式c=a&b後,變數c的結果為2,有興趣的讀者不妨把這些數值用二進位來表示,然後再執行且位元運算子﹝&﹞後,就可以得知為何是2。圖8-1且位元運算子執行結果8-2.8
特殊運算子最後我們來看特殊運算子,分列如下:逗號運算子(commaoperator)
value=(x=10,y=5,x+y);變數大小運算子(sizeofoperator)sizeof
m=sizeof(sum);指標運算子(pointeroperators)(&and*)成員選取運算子(memberselectionoperators)(.and->)8-3全域變數和區域變數:
變數主要是用來讓程式設計者暫時存放數值的地方,當您有需要時可以將它取出或修改它。在C語言中變數可分成兩大類:全域變數宣告在程式開頭處即為函式外面,其範圍涵蓋所有函式。通常使用記憶體空間來存放。區域變數宣告在函式內部,都以是暫存器或堆疊來存放,其使用範圍僅限於函式內部。以下為全域變數和區域變數的程式範例://採用全域變數inta,b,c;intmain(){a=1;b=1;c=a+b;return0;}//採用區域變數intmain(){inta,b,c;a=1;b=1;c=a+b;return0;}上面範例看起來程式長度一樣,但我們利用反組譯功能,您會發現多使用區域變數會提高程式的效能,其程式列表如下圖:圖8-2全域變數及區域變數效能比較8-4指標變數:
指標變數簡單來說是一種指位器,該變數儲存不是數值內容而是位址,我們可以使用*來宣告,使用如下:
int*p;在計算指標的大小時,可分成編譯階段得知或執行階段得知,編譯階段得知範例如下:
int*p;
p=p+1;我們得知每次增加4位元組,因為指標的資料型態為整數佔四個位元組。但有些情形不易得知,例如:
int*p;
inti=4;
p=p+i;在此情形則需要執行階段才能獲知,則編譯器會使用ADD指令來處理。C語言最迷人地方在於它擁有指標功能,但也是它可怕的地方。圖8-3展示其可怕之處,從圖中您會得知指標居然指到位址0,而且我們把它改成1。從此您可以得知指標能修改記憶體的內容,但必須要非常小心,否則您會把重要的程式或資料給修改,造成不可預測的結果。圖8-3危險指標圖8-4指標一定要指向變數圖8-4說明將變數指向變數,您會發現我們可以安全地變更p指標所指變數的內容,在圖中a變數為0xc000而p變數則為0xc004。8-5
條件敍述:
C語言條件敍述有if和switch兩種,if又可搭配else使用。if範例如下:
if(a>b)c=a;elsec=b;上述程式說明當a>b條件成立時c變數指定為變數a的內容否則指定為變數b。當上面範例組譯成組合語言時,可以反組譯成下面:
CMP r0,r1 ;if(a>b)…
MOVGT r2,r0 ;..c=a..
MOVLE r2,r1 ;…elsec=b..以下程式碼是C與組合語言混合寫法,詳細語法請參照8-8節。首先使用AXD模擬針對if….else的C語言程式碼如下,並進行C的反組譯如下圖8-5灰色字所示,執行結果,由於A小於B所以執行A加B的動作,結果在GlobalVariable的值A等於9,B等於5。inta=4,b=5;intMain(void){ if(a>b)La=a-b;elsea=a+b;return0; 圖8-5if….else範例程式示意圖
接下來我們來看另一個敍述switch,其語法如下:
switch(條件表示式){
case常數1:敍述區塊1;break;
case常數2:敍述區塊2;break;
…
case常數N:敍述區塊N;break;
default:敍述區塊d;break;}
ARM在支援switch指令採用,有時會採取跳躍表格方式處理,利用一表格來儲存各常數值的目的地,其指令樣板如下:;r0包含條件表示式的數值
ADR r1,JUMPTABLE ;取得跳躍表格的基值
CMP r0,#TABLEMAX ;表格最大值
LDRLS pc,[r1,r0,LSL#2] ;改變PC值來進行跳躍
B Exit L1: .. B Exit ..LN ..Exit ..以下程式碼是C與組合語言混合寫法,詳細語法請參照8-8節。首先使用AXD模擬針對switch…case的C語言程式碼如下,並進行C的反組譯如下圖8-6灰色字所示,執行結果,由於B減A等於2,所以會執行case2這段程式碼,B減A的動作,結果如下圖8-6在GlobalVariable的值A等於2,B等於5。inta=3,b=5; intMain(void){*9* switch(b-a) {case1:a=a+b;break;
case2:a=b-a;break;}return0; }圖8-6switch….case範例程式示意圖8-6迴圈敍述:
C語言支援三種迴圈敍述有for、while、do..while。for範例如下:
for(i=0;i<10;i++)
{
a[i]=0;
}
由於上面範例僅將陣列10個元素全數設定為零,因此在組譯成組合語言時,可以利用在迴圈外增加指令MOVr0,#0,來加速指令的執行,其反組譯為:
MOV r1,#0
ADR r2,#a[0]
MOV r0,#0 ;i=0
LOOP CMP r0,#10
BGE Exit
STR r1,[r2,r0,LSL#2]
ADD r0,r0,#1
B LOOP
Exit以下程式碼是C與組合語言混合寫法,詳細語法請參照8-8節。首先使用AXD模擬針對for…next的C語言程式碼如下,並進行C的反組譯如下圖8-7灰色字所示,執行結果,由於I小5,所以會執行A=A+I這段程式碼5次,執行過程0+1+2+3+4,所以A會一直累加I的值,結果如下圖8-7在GlobalVariable的值A等於10,I等於5。inti,a; intMain(void){a=0; for(i=0;i<5;i++) {a=a+i;}return0; }圖8-7for…next範例程式示意圖對於while迴圈則較簡單,可以使用下列組合語言程式來表示:
LOOP ;插入條件判斷的指定
BEQ exit
迴圈本體
B
LOOPExit以下程式碼是C與組合語言混合寫法,詳細語法請參照8-8節。首先使用AXD模擬針對while的C語言程式碼如下並進行C的反組譯如下圖8-8灰色字所示,執行結果,由於I小5,所以會執行while這段程式碼會詢問6次,執行結果為1+2+3+4+5,而詢問第六次時,就會跳開while迴圈,而A會一直累加I的值,所以結果如下圖在GlobalVariable的值A等於15,I等於5。inti,a;intMain(void){a=0,i=0; while(i<5) { i=i+1;a=a+i;}return0; }圖8-8while…範例程式示意圖對於do..while迴圈則較簡單,可以使用下列組合語言程式來表示:LOOP ;插入迴圈本體程式;插入條件判斷的指定
BNE LOOP以下程式碼是C與組合語言混合寫法,詳細語法請參照8-8節。首先使用AXD模擬針對do….while的C語言程式碼如下,並進行C的反組譯如下圖8-9灰色字所示,執行結果,由於I小5,所以會執行do…while這段程式碼只會執行5次,執行結果為1+2+3+4+5,而詢問第5次時,就會直接跳開do...while迴圈,而A會一直累加I的值,所以結果如下圖8-9在GlobalVariable的值A等於15,I等於5。inti,a;intMain(void){a=0,i=0; do { i=i+1;a=a+i;}while(i<5);return0; }圖8-9do….while範例程式示意圖8-7程式呼叫標準:ARM支援一套程式呼叫的標準(ARMProcedureCallStandard),簡稱為APCS。APCS定義下列內容:一般暫存器的特殊使用堆疊指標的使用堆疊的資料格式函式參數傳遞和傳值格式支援ARM共用函式庫其參數使用暫存器如下表所示:圖8-10
傳值呼叫範例執行結果在使用函式時,經常會利用參數來傳遞數值,最常見的就是傳值呼叫(CallbyVakue)及傳址呼叫(CallbyAddress),其範例如圖8-10和8-11所示。讀者請特別注意兩者在使用上的差異,它們之間的差別在於是否使用指標。圖8-11
傳址呼叫範例執行結果上面兩個範例,相信您已發現在Console的視窗,其執行結果不同,傳值呼叫不會改變主程式的變數值然而傳址呼叫會。接下來我們來看看函式指標如圖8-7所示,原來指標不是只用來指向資料變數,也可以用來指向函數本體。您可經過下列三步驟,即可輕輕鬆鬆地使用函式指標,我們以指向swap函式當成範例。步驟一、宣告函式指標。
void*(pFn)(inta,intb);步驟二、指定函式。
pFn=&swap;步驟三、使用函式指標來呼叫函式。
*(pFn)(&a,&b);圖8-12
函式指標範例執行結果上面函式的反組譯程式列表如下:intmain() {main [0xe92d400e]*stmfdr13!,{r1-r3,r14} inta=1,b=2;000080c0 [0xe3a01001]movr1,#1000080c4 [0xe58d1008]strr1,[r13,#8]000080c8 [0xe3a02002]movr2,#2000080cc [0xe58d2004]strr2,[r13,#4] void(*pFn)(int*a,int*b); pFn=&swap; printf("a=%d,b=%d\n",a,b);000080d0 [0xe28f0024]addr0,pc,#0x24;#0x80fc000080d4 [0xeb00000d]bl_printf (*pFn)(&a,&b);000080d8 [0xe28d1004]addr1,r13,#4000080dc [0xe28d0008]addr0,r13,#8000080e0 [0xebfffff0]blswap
printf("a=%d,b=%d\n",a,b);000080e4 [0xe28f0010]addr0,pc,#0x10;#0x80fc000080e8 [0xe59d1008]ldrr1,[r13,#8]000080ec [0xe59d2004]ldrr2,[r13,#4]000080f0 [0xeb000006]bl_printf return0;000080f4 [0xe3a00000]movr0,#0 }000080f8 [0xe8bd800e]ldmfdr13!,{r1-r3,pc}000080fc [0x64253d61]dcd0x64253d61a=%d00008100 [0x3d62202c]dcd0x3d62202c,b=[0x000a6425]dcd
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 高中实验仪器课件
- 员工劳动争议调解办法
- 高一课文《劝学》课件
- 高一政治备课经验课件
- 离婚协议必知:赡养费支付方式及调整标准解读
- 高端服务业人才派遣与劳动权益双重保障合同
- 住宅小区物业合同到期延期及绿化养护协议
- 知识产权密集型厂房租赁及研发成果转化合同
- 广告效果归因分析代理合同
- 骨髓细胞进修汇报课件
- 部编版六年级语文上册重点难点解析
- 电力监理劳务合同范本
- 2025河北工勤人员技师考试消毒员训练题及答案
- 重庆市南开中学高2026届高三第一次质量检测+化学答案
- 2025年供水管网改造工程可行性研究报告
- 肖婷民法总则教学课件
- 教育培训课程开发与实施指南模板
- 2025保密协议范本:物流行业货物信息保密
- 砂石料物资供应服务保障方案
- 2025卫星互联网承载网技术白皮书-未来网络发展大会
- 顺丰转正考试题库及答案
评论
0/150
提交评论