第四節(jié) arm匯編語言設計2_第1頁
第四節(jié) arm匯編語言設計2_第2頁
第四節(jié) arm匯編語言設計2_第3頁
第四節(jié) arm匯編語言設計2_第4頁
第四節(jié) arm匯編語言設計2_第5頁
已閱讀5頁,還剩51頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領

文檔簡介

ARM匯編、C和C++混合編程

在C/C++程序中如果必須使用匯編指令來完成某些操作,可以采用兩種方法:1.采用內(nèi)嵌匯編:即在C/C++源程序中嵌入一塊匯編代碼;2.形成一個子程序:C/C++程序可以調(diào)用這些匯編程序來完成特定的操作。內(nèi)嵌匯編內(nèi)嵌匯編(inlineassembly)的語法如下:__asm{

指令[;指令]/*注釋*/ … [指令]}內(nèi)嵌匯編的指令用法內(nèi)嵌在C或者C++程序中的ARM匯編指令與普通(ADS)格式的ARM匯編指令有所不同。CPU的內(nèi)部寄存器資源使用有額外約束,以下講解內(nèi)嵌ARM匯編指令的用法。ARM內(nèi)嵌匯編程序的操作數(shù)內(nèi)嵌匯編指令中作為操作數(shù)的寄存器和常量可以是表達式。這些表達式可以是char,short或int類型,而且這些表達式都是作為無符號數(shù)進行操作,編譯器將會計算這些表達式的值,并為其分配寄存器。ARM內(nèi)嵌匯編程序的物理寄存器內(nèi)嵌匯編程序中使用物理寄存器有以下限制。1.不能直接向PC寄存器賦值,程序跳轉(zhuǎn)只能使用B或BL指令實現(xiàn)2.不要使用過于復雜的C表達式,因為將會需要較多的物理寄存器,這將導致與其他指令中用到的物理寄存器產(chǎn)生使用沖突。

inttmp,r1;

__asm{MOVr1,1<<3MOVtmp,r1++MRStmp,CPSR //CPSR->tempORRtmp,tmp,#0x80 //置I位

MSRCPSR_c,tmp

//temp->CPSR}MOVR2,#0x00000008;r1<->R2MOVR0,R2ADDR2,R2,#0x00000001MOVR1,R0;tmp<->R1MRSR1,CPSRORRR1,R1,#0x00000080MSRCPSR_c,R1其他內(nèi)嵌匯編程序的編寫注意點常量:在內(nèi)嵌匯編指令中,常量前面的“#”可以省略。指令展開:內(nèi)嵌匯編指令中,如果包含常量操作數(shù),該指令可能被內(nèi)嵌匯編器展開成幾條指令。標號:C程序中的標號可以被內(nèi)嵌的匯編指令使用,但是只有指令B可以使用C程序中的標號,而指令BL則不能使用。內(nèi)存單元的分配:所有的內(nèi)存分配均由C編譯器完成,分配的內(nèi)存單元通過變量供內(nèi)嵌匯編器使用。內(nèi)嵌匯編器不支持內(nèi)嵌程序中用于內(nèi)存分配的偽指令。#definea1int

main(void){chartmp;

intr1=0;__asm{MOVtmp,a*aMOVtmp,a==1 MOVtmp,a^0xffffffff MOVtmp,r1<<=3}}MOVR0,#0x00000000;初始化MOVR2,#0x00000001;MOVtmp,a*aMOVR2,#0x00000001;MOVtmp,a==1MVNR2,#0x00000001;MOVtmp,a^0xffffffff

MOVR3,R0,LSL#3;MOVtmp,r1<<=3MOVR0,R3MOVR1,R3MOVR0,R1MOVR2,R0內(nèi)嵌匯編程序中的SWI和BL指令SWI和BL指令:在兩個指令使用到內(nèi)嵌匯編中,除了正常的操作數(shù)域外,還必須增加以下3個可選的寄存器列表:

用于輸入?yún)?shù)的寄存器列表。

用于存儲返回結(jié)果的寄存器列表。

用于表示那些寄存器將有可能會被修改的寄存器列表。內(nèi)嵌匯編代碼舉例字符串復制#include<stdio.h>voidstr_cpy(constchar*src,char*dst){

int

ch; __asm { loop://普通ARM匯編代碼中的標號后面不能跟冒號。C程序中

//的標號可以被內(nèi)嵌的匯編指令使用。ARM內(nèi)嵌匯編代碼中

//只有B指令可以使用C的標號,而BL指令不能夠使用C代碼

//的標號。C程序的標號后面跟冒號,由Goto語句轉(zhuǎn)向標號處。

LDRB ch,[src],#1 STRB ch,[dst],#1 CMPch,#0 BNE loop }}LDRBr2,[r0],#1STRBr2,[r1],#1CMPr2,#0BNE{pc}-0xc;0x0MOVpc,r14內(nèi)嵌匯編代碼舉例字符串復制int

main(void){ constchar*a="Helloworld!\n"; charb[20]; __asm { MOVR0,a//將串a(chǎn)的串首地址送到R0寄存器

MOVR1,b//將串b的串首地址送到R1寄存器

BLstr_cpy,{R0,R1}//調(diào)用C函數(shù)str_cpy() }

printf("Originalstring:%s\n",a);

printf("Copiedstring:%s\n",b);//半主機方式顯示復制前后的兩個串

return(0);}STMFDr13!,{r4,r14}SUBr13,r13,#0x18ADDr4,pc,#0x2c;#0x50MOVr0,r4ADDr1,r13,#4BLstr_cpy;0x0MOVr1,r4ADDr0,pc,#0x28;#0x60BL_printfADDr1,r13,#4ADDr0,pc,#0x34;#0x78BL_printfMOVr0,#0ADDr13,r13,#0x18LDMFDr13!,{r4,pc}內(nèi)嵌匯編器與armasm匯編器差異

內(nèi)嵌匯編器不支持通過“.”指示符或PC值來獲取當前指令的地址。不支持“LDRLRn,=expr”偽指令,而使用“MOVRn,expr”指令向寄存器賦值。

不支持標號表達式。

不支持ADR和ADRL偽指令。不支持BX指令。不能向PC直接賦值。當使用8位移位常數(shù)導致CPSR的ALU標志更新時,N、Z、C和V標志中的C不具有真實意義。

C/C++程序與ARM匯編語言程序的相互調(diào)用

C/C++程序與匯編程序相互調(diào)用時,應遵守相應的ATPCS,主要有五種調(diào)用。ARM匯編子程序調(diào)用C語言子程序ARM匯編子程序調(diào)用C++語言子程序C語言程序調(diào)用ARM匯編語言子程序C++語言程序調(diào)用ARM匯編語言子程序C語言程序調(diào)用C++語言子程序ATPCSATPCS(ARM-ThumbProcedureCallStandard)規(guī)定了一些子程序間調(diào)用的基本規(guī)則。使用ADS的C語言編譯器編譯的C語言子程序滿足用戶指定的ATPCS類型。而對于匯編語言來說,則需要用戶來保證各個子程序滿足ATPCS的要求。AAPCS2007年ARM公司正式推出了AAPCS標準ARMArchtectureProcedureCallStandardAAPCS是ATPCS的改進版目前,AAPCS和ATPCS都是可用的標準寄存器的使用規(guī)則子程序間通過寄存器R0~R3來傳遞參數(shù)。這時,寄存器R0~R3可記作a0~a3。在子程序中,使用寄存器R4~R11來保存局部變量。這時,寄存器R4~R11可以記作v1~v8。寄存器R12用作過程調(diào)用中間臨時寄存器,記作IP。在子程序之間的連接代碼段中常常有這種使用規(guī)則。寄存器的使用規(guī)則(續(xù))寄存器R13用作堆棧指針,記作SP。寄存器SP在進入子程序時的值和退出子程序時的值必須相等。寄存器R14稱為連接寄存器,記作LR。它用于保存子程序的返回地址。如果在子程序中保存了返回地址,寄存器R14則可以用作其他用途。寄存器R15是程序計數(shù)器,記作PC。它不能用作其它用途。堆棧使用規(guī)則ATPCS規(guī)定堆棧為FD類型,即滿遞減堆棧,并且對堆棧的操作是8字節(jié)對齊。對于匯編程序來說,如果目標文件中包含了外部調(diào)用,則必須滿足下列條件:(1)外部接口的堆棧必須是8字節(jié)對齊的。(2)在匯編程序中使用PRESERVE8偽指令告訴連接器,本匯編程序數(shù)據(jù)是8字節(jié)對齊的。參數(shù)個數(shù)可變子程序參數(shù)傳遞規(guī)則

在傳遞參數(shù)時,依次將各字數(shù)據(jù)傳遞到寄存器R0,R1,R2和R3中。如果參數(shù)多于4個,則將剩余的字數(shù)據(jù)傳遞到堆棧中。入棧的順序與參數(shù)傳遞順序相反,即最后一個字數(shù)據(jù)先入棧。子程序結(jié)果返回規(guī)則結(jié)果為一個32位整數(shù)時,可以通過寄存器R0返回;結(jié)果為一個64位整數(shù)時,可以通過寄存器R0和Rl返回;結(jié)果為一個浮點數(shù)時,可以通過浮點運算部件的寄存器f0、d0或s0來返回;對于位數(shù)更多的結(jié)果,需要通過內(nèi)存來傳遞。C/C++程序調(diào)用ARM匯編子程序要點設計匯編程序必須遵守ATPCS,保證程序調(diào)用時參數(shù)的正確傳遞。在匯編程序中使用EXPORT指示符聲明本程序可以被別的程序調(diào)用。在C語言程序中使用extern關鍵詞聲明該匯編程序可以被調(diào)用,C++語言程序使用extern“C”來聲明該匯編程序可以被調(diào)用。例1C程序調(diào)用ARM匯編子程序/*main_0522.csemihostingoutputmode*/#include<stdio.h>externint

asmfile(intarg1,intarg2,intarg3);int

main(void){inta1=1,a2=2,a3=4;printf("ExampleofCProgramcallingAssemblyprogram!\n");printf("(%d+%d+%d)*600=%d\n",a1,a2,a3,asmfile(a1,a2,a3));return(0);}C程序調(diào)用ARM匯編子程序(續(xù));ASM_0522.sEXPORTasmfileAREAMy_pro,CODE,READONLYasmfile

STMFDSP!,{R4-R6,R8,R7} addr0,r0,r1 addr0,r0,r2

mov r4,#600

mulr3,r0,r4

mov r0,r3 LDMFDSP!,{R4-R6,R8,R7}

movpc,lr END例2ARM匯編程序調(diào)用C語言子程序本案例程序比較兩個IP地址的大小,a1~a4存放IP地址1的值(按照ATPCS傳遞參數(shù)),b1~b4存放IP地址2的值(通過棧傳遞參數(shù)),如果IP地址1的值大于IP地址2的值則返回1,如果IP地址1的值小于IP地址2的值則返回-1,如果兩者相等則返回零。IP地址1取值:192.168.1.152IP地址2取值:

172.0.0.151

例2ARM匯編程序調(diào)用C子程序/*C代碼部分*/#include<stdio.h>externint

function(void);/*聲明function是外部函數(shù)*/int

compare_ip(inta1,inta2,inta3,inta4,intb1,intb2,intb3,intb4){ if(a1!=b1) returna1>b1?1:-1; if(a2!=b2) returna2>b2?1:-1; if(a3!=b3) returna3>b3?1:-1; if(a4!=b4) returna4>b4?1:-1; return0;}intmain(){

printf("Thisisaexampleofsemihosting\n");

printf("resultis%d\n",function());}例2ARM匯編調(diào)用C子程序 AREAFUNCTION,CODE,READONLY;ARM匯編子程序 IMPORTcompare_ip EXPORTfunctionfunction STMFD r13!,{r0-r3,r14};保存寄存器到棧區(qū) MOV r3,#0x97;存入IP地址2的4個數(shù),0x97=151 MOV r2,#0 ;存入0 MOV r1,#0 ;存入0 MOV r0,#0xac ;存入0xac=172 STMIA r13,{r0-r3} ;R0-R3覆蓋存入棧區(qū)的R0-R3位置 MOV r3,#0x98 ;存入IP地址1的4個數(shù),0x98=152 MOV r2,#1 ;存入1 MOV r1,#0xa8;存入0xa8=168 MOV r0,#0xc0 ;存入0xc0=192 BL compare_ip;調(diào)用C語言函數(shù)進行IP值比較 ADD r13,r13,#0x10 ;棧指針上移4個字(元素) LDR pc,[r13],#4 ;將保存的r14值加載到PC,而后r13加4 END

例2ARM匯編調(diào)用C子程序ARM匯編語言子程序Function的棧區(qū)操作圖解ARM匯編(子)程序的相互調(diào)用基本要點:如果一個ARM匯編語言程序文件含有調(diào)用外部匯編語言程序文件中子程序(函數(shù))的指令,則需要用IMPORT指示符來指明將要調(diào)用的子程序名稱。如果本匯編語言程序文件中的某個子程序(函數(shù)),需要被外部的ARM匯編語言程序文件中的語句調(diào)用,則需要用EXPORT指示符來指明將要被調(diào)用的子程序(函數(shù))名稱。被執(zhí)行的匯編子程序在運行前,要注意將寄存器組壓入棧區(qū),返回時要注意將棧區(qū)保存的工作現(xiàn)場恢復到處理器的寄存器組。例3ARM匯編子程序嵌套調(diào)用這里給出的ARM匯編程序嵌套調(diào)用范例程序做如下計算:求自然數(shù)1到n的階乘的總和例3ARM匯編子程序嵌套調(diào)用#include<stdio.h>externint

asmFac(intn);struct

factorial_sum{int

cal_fn;int

sum_fn;intfn[9];};externstruct

factorial_sum*summing(struct

factorial_sum*arg1);例3ARM匯編子程序嵌套調(diào)用int

main(void){

intj;

struct

factorial_sum

fac={9,0,{1,1,1,1,1,1,1,1,1} };//設置參數(shù)

struct

factorial_sum*result; //申請變量作為返回值

printf("ExampleofamultiAssemblyprogramcalling!\n"); result=summing(&fac); //調(diào)用求和函數(shù)R0存放的是FAC變量的首地址

printf("Thetotalsumis%d\n",result->sum_fn);//輸出結(jié)果

for(j=0;j<9;j++){

printf("%d\t",(result->fn)[j]); } }例3ARM匯編子程序嵌套調(diào)用EXPORTsummingIMPORTasmFac ;說明用到了其他文件中的子匯編程序

AREASUMMING,CODE,READONLYsumming

stmfd sp!,{r4-r5}

ldr r1,[r0] ;r1=cal_fn

mov r2,#1 ;將r2設置為當前需要計算的階乘數(shù), ;它從1變化到cal_fn add r3,r0,#8 ;將r3指向fn數(shù)組

mov r5,#0 ;r5為總和,初始值置為0loop

cmp r1,r2 ;將cal_fn與當前所需計算的階乘值比較

blt back ;如果小于,則返回例3ARM匯編子程序嵌套調(diào)用

STMFDsp!,{r0-r3,lr};保存r0~r3,lr ;因為調(diào)用了外部文件的匯編子程序

mov r0,r2 ;將r0設置為當前所需計算的階乘值

bl

asmFac ;調(diào)用階乘函數(shù)

mov r4,r0 ;將返回值(階乘)存在r4中

ldmfd SP!,{R0-R3,lr};恢復先前保存的寄存器值

str r4,[r3] ;將計算所得的階乘值存入數(shù)組中

add r3,r3,#4 ;將r3指向數(shù)組的下一個

add r5,r5,r4 ;將階乘值加入總和

add r2,r2,#1 ;計算下一個階乘

bloop ;循環(huán)back

str r5,[r0,#4] ;將計算所得的總和存入結(jié)構(gòu)體中

ldmfd SP!,{R4-R5} ;恢復寄存器值

mov pc,lr ;summing子程序返回

END ;匯編代碼結(jié)束例3ARM匯編子程序嵌套調(diào)用;這個ARM匯編函數(shù)也可以被C函數(shù)調(diào)用,符合ATPCS規(guī)范;int

asmFac(intn)EXPORTasmFacAREAASMFILE,CODE,READONLYasmFac

mov r1,r0 ;r1=nloop subs r1,r1,#1;將r1減1

mulgt r0,r1,r0;如果大于0,則乘上r1(相當與n*(n-1))

bgt loop ;如果大于0,繼續(xù)

movpc,lr ;asmFac子程序返回

END ;匯編代碼結(jié)束例4ARM匯編子程序嵌套調(diào)用#include<stdio.h>intmain(){

printf("Helloworld\n"); return0;};Example7_asm.sAREAAsm_C,CODE,READONLYENTRY LDR SP,=0x4000 IMPORT __main BL __main B . END系統(tǒng)的初始化過程

初始化代碼:在用戶的應用程序運行之前完成系統(tǒng)初始化工作的代碼初始化代碼直接對ARM微處理器內(nèi)核及硬件控制器編程,多采用匯編語言編程,初始化代碼一般應包含如下典型任務:定義程序入口點設置異常向量初始化存儲器系統(tǒng)初始化堆棧指針寄存器初始化臨界I/O設備初始化C代碼的運行環(huán)境改變處理器的運行模式和狀態(tài)使能中斷進入C代碼運行系統(tǒng)的初始化過程

ARM微處理器在復位或上電狀態(tài)下的默認模式為管理模式(SupervisorMode),而在初始化代碼中可能需要切換到其他模式進行必要的操作,如初始化各個模式下的堆棧指針寄存器,因此,在系統(tǒng)的初始化過程中處理器模式一般會經(jīng)歷如下變化:(1)初始化存儲設備(2)初始化堆棧空間(3)初始化必要的硬件設備(1)匯編程序入口(2)系統(tǒng)初始化,設置中斷向量(3)關看門狗及中斷IMPORT__mainLDRlr,=__mainMOVpc,lr__main__scatterload(1)把RW/RO段從裝載域復制到相應的RAM中(即運行域)(2)初始化ZI段__rt_entry(1)初始化庫函數(shù)(2)建立堆棧(3)調(diào)用main()(4)退出應用(5)用main()函數(shù)的返回值做為exit()參數(shù)

main()系統(tǒng)的初始化過程進入C代碼運行 最簡單的情況:

IMPORT C_Entry

;定義一個外部標號,一般不使用main

B C_Entry

;跳轉(zhuǎn)到該處執(zhí)行

在ARM的ADS編譯環(huán)境中,還另外提供了一種進入C代碼的機制:

IMPORT __main B __main

__main()是編譯器提供的一個函數(shù),負責完成庫函數(shù)的初始化和對C代碼運行環(huán)境的初始化,最后自動跳轉(zhuǎn)到main()函數(shù)執(zhí)行,此時應用程序的主函數(shù)名必須是main()。 用戶可以根據(jù)需要選擇是否使用__main()函數(shù),如果想讓系統(tǒng)自動完成初始化過程,可以使用__main()函數(shù);如果所有的初始化過程都由用戶自己完成,則不使用__main()函數(shù)。系統(tǒng)的初始化過程定義程序入口點 初始化代碼必須定義整個程序的入口點(EntryPoint)

偽操作Entry

鏈接器的設置 確定整個程序的入口點系統(tǒng)的初始化過程設置異常向量

AREA Init,CODE,READONLY ENTRY B Reset_Handler

B Undef_Handler B SWI_Handler B PreAbort_Handler B DataAbort_Handler B . B IRQ_Handler B FIQ_HandlerReset_Handler

系統(tǒng)的初始化過程初始化存儲器系統(tǒng)

初始化存儲器系統(tǒng)主要包含對系統(tǒng)存儲器控制器的初始化,如果系統(tǒng)具有存儲器管理單元(MMU),也必須對其進行初始化。 基于ARM微處理器的系統(tǒng)一般都需要外擴大容量的存儲器,這些存儲器需要專門的存儲器控制器控制其讀、寫操作。系統(tǒng)的初始化過程存儲器的地址分配與地址重映射(Remap)

存儲器的地址分配也就是將物理存儲器定位在4GB地址空間的具體位置

ARM微處理器常采用兩種方式來完成地址分配:固定的存儲器地址分配存儲器地址重映射(Remap)

系統(tǒng)的初始化過程FLASH中斷向量表程序(RO)RAM堆棧數(shù)據(jù)數(shù)據(jù)(RO)FLASH中斷向量表程序(RO)內(nèi)部RAM數(shù)據(jù)(RW)內(nèi)部RAM中斷向量表FLASH堆棧程序數(shù)據(jù)外部SRAMSDRAM外部SRAMSDRAM4G存儲空間4G存儲空間4G存儲空間固定的存儲器地址分配存儲器地址重映射(Remap)系統(tǒng)的初始化過程初始化堆棧指針寄存器

SP_svc

SP_irq

SP_fiq

SP_abt

SP_und

SP_usr系統(tǒng)的初始化過程初始化堆棧的示例代碼,共初始化了三種模式下的堆棧指針寄存器:

MODEMASK EQU 0x1F FIQMODE EQU 0x11 IRQMODE EQU 0x12 SVCMODE EQU 0x13

SVCStack

EQ

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論