版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
ADS/SDTIDE開發(fā)環(huán)境:它由ARM公司開發(fā),使用了CodeWarrior公司的編譯器;集成了GNU開發(fā)工具的IDE開發(fā)環(huán)境:它由GNU的匯編器as、交叉編譯器gcc、和鏈接器ld等組成。匯編語言都具有一些相同的基本特征。①一條指令一行。②使用標(biāo)號(label)給內(nèi)存單元提供名稱,從第1列開始書寫。③指令必須從第2列或能區(qū)分標(biāo)號的地方開始書寫。④注釋跟在指定的注釋字符后面(ARM使用的是“;”/”@”),一直書寫到行尾。ARM匯編語言基本的的語句格式如下:
{symbol}{instruction|directive|pseudo-instruction}{;comment}符號
指令、偽指令或偽操作
[;/@注釋]①符號由大小寫字母、數(shù)字及下畫線組成,符號不能用數(shù)字開頭。②符號區(qū)分大小寫,同名的大、小寫符號會被編譯器認(rèn)為是兩個不同的符號。③符號在其作用范圍內(nèi)必須唯一。④自定義的符號名不能與系統(tǒng)的保留字相同。⑤符號名不應(yīng)與指令或偽指令同名。偽操作(Directive)是ARM匯編語言程序里的一些特殊的指令助記符,其作用主要是為完成匯編程序做各種準(zhǔn)備工作,對源程序運行匯編程序處理,而不是在計算機(jī)運行期間由處理器執(zhí)行。不同的編譯程序所使用的偽操作有所不同。常量編譯控制偽操作程序代碼控制偽操作宏及條件編譯偽指令其他偽指令GNUARM匯編偽操作Linux匯編行結(jié)構(gòu)
任何匯編行都是如下結(jié)構(gòu):[:]
[}
@
comment
[:]
[}
@注釋
Linux
ARM
匯編中,任何以冒號結(jié)尾的標(biāo)識符都被認(rèn)為是一個標(biāo)號,而不一定非要在一行的開始。
【例1】定義一個"add”的函數(shù),返回兩個參數(shù)的和。
.section
.text,
“x”
.global
add
@
give
the
symbol
add
external
linkage
add:
ADD
r0,
r0,
r1
@
add
input
arguments
MOV
pc,
lr
@
return
from
subroutine
@
end
of
program
Linux
匯編程序中的標(biāo)號
Linux匯編程序中的標(biāo)號標(biāo)號只能由a~z,A~Z,0~9,“.”,”_”等字符組成。當(dāng)標(biāo)號為0~9的數(shù)字時為局部標(biāo)號,局部標(biāo)號可以重復(fù)出現(xiàn),使用方法如下:標(biāo)號f:在引用的地方向前的標(biāo)號標(biāo)號b:在引用的地方向后的標(biāo)號【例2】使用局部符號的例子,一段循環(huán)程序1:subsr0,r0,#1@每次循環(huán)使r0=r0-1bne1f@跳轉(zhuǎn)到1標(biāo)號去執(zhí)行局部標(biāo)號代表它所在的地址,因此也可以當(dāng)作變量或者函數(shù)來使用。Linux匯編程序中的分段(1).section偽操作
用戶可以通過.section偽操作來自定義一個段,格式如下:
.section
section_name
[,
"flags"[,
%type[,flag_specific_arguments]]]
每一個段以段名為開始,
以下一個段名或者文件結(jié)尾為結(jié)束。這些段都有缺省的標(biāo)志(flags),連接器可以識別這些標(biāo)志。(與armasm中的AREA相同)。
下面是ELF格式允許的段標(biāo)志
a
允許段,
w
可寫段x:執(zhí)行段例子:.section.mysection
@自定義數(shù)據(jù)段,段名為“.mysection”預(yù)定義段.text、.data、.bss語法格式.text{subsection}.data{subsection}
@初始化數(shù)據(jù).bss{subsection}作用.text、.data和.bss將匯編系統(tǒng)預(yù)定義的段名編譯到相應(yīng)的代碼段、數(shù)據(jù)段和bss段。注意:源程序中.bss段應(yīng)該在.text之前。說明bss段通常是指用來存放程序中未初始化的全局變量的一塊內(nèi)存區(qū)域數(shù)據(jù)段通常是指用來存放程序中已初始化的全局變量的一塊內(nèi)存區(qū)域
舉例
.section.data
<initializedatahere>
.section.bss
<uninitializeddatahere>
.section.text.global_start
_start:<instructioncodegoeshere>.end語法格式
.end作用表明源文件的結(jié)束,如果該標(biāo)號之后還有代碼,不會被編譯到執(zhí)行文件中.include語法格式 .include"filename"作用
可以將指定的文件在使用位置處展開,一般是頭文件.incbin語法格式 .incbin"file"[,skip[,count]]作用
可以將原封不動的一個二進(jìn)制文件編譯到當(dāng)前文件中。其中,skip表明是從文件開始跳過skip個字節(jié)開始讀取文件,count是讀取的字?jǐn)?shù).if、.else/.endif
語法格式
.if條件表達(dá)式
代碼段1.else
代碼段2.endif.macro、.exitm和.endm語法格式
.macro宏名參數(shù)名列表@偽操作.macro定義一個宏宏體.endm
@.endm表示宏結(jié)束說明如果宏使用參數(shù),那么在宏體中使用該參數(shù)時添加前綴“\”。宏定義時的參數(shù)還可以使用默認(rèn)值,可以使用.exitm偽指令來退出宏舉例
.macroSHIFTLEFTa,b.if\b<0MOV\a,\a,ASR#-\b.exitm.endifMOV\a,\a,LSL#\b.endm.string/.asciz/.ascii語法格式 .string/.asciz/.ascii表達(dá)式{,表達(dá)式}...作用.string/.asciz/.ascii定義多個字符串。注意:ascii偽操作定義的字符串需要自動添加結(jié)尾字符'\0'舉例
.string"abcd","hello".equ、.set語法格式.equ(.set)常量名,表達(dá)式作用
.equ和.set用于為程序中標(biāo)號定義名稱舉例
.equabc3
@讓abc=3.global/.globl語法格式.global/.globlsymbol作用
.global和.globl用來定義一個全局的符號.extern語法格式
.externlabel作用
.extern用于聲明一個外部標(biāo)號.ltorg、.pool語法格式.ltorg/.pool作用
.ltorg和.pool用于聲明一個數(shù)據(jù)緩沖池的開始,它可以分配很大的空間偽指令是ARM處理器支持的匯編語言程序里的特殊助記符,它不在處理器運行期間由機(jī)器執(zhí)行,只是在匯編時將被合適的機(jī)器指令代替成ARM或Thumb指令,從而實現(xiàn)真正的指令操作。ARM匯編語言偽指令如表3-2所示。在匯編編譯器編譯源程序時,ADR偽指令被編譯器替換成一條合適的指令。通常,編譯器用一條ADD指令或SUB指令來實現(xiàn)該ADR偽指令的功能,若不能用一條指令實現(xiàn),則產(chǎn)生錯誤,編譯失敗。ADR偽指令中的地址是基于PC或寄存器的,當(dāng)ADR偽指令中的地址是基于PC時,該地址與ADR偽指令必須在同一個代碼段中。地址表達(dá)式expr的取值范圍如下:當(dāng)?shù)刂分凳亲止?jié)對齊時,其取指范圍為?255B~255B;當(dāng)?shù)刂分凳亲謱R時,其取指范圍為?1020B~1020B。ARM偽指令——小范圍的地址讀取
ADR偽指令將基于PC相對偏移的地址值或基于寄存器相對偏移的地址值讀取到寄存器中。在匯編編譯器編譯源程序時,ADR偽指令被編譯器替換成一條合適的指令。通常,編譯器用一條ADD指令或SUB指令來實現(xiàn)該ADR偽指令的功能,若不能用一條指令實現(xiàn),則產(chǎn)生錯誤,編譯失敗。...ADRR0,Delay...DelayMOVR0,r14...應(yīng)用示例(源程序):使用偽指令將程序標(biāo)號Delay的地址存入R0...0x20ADDr1,pc,#0x3c......0x64MOVr0,r14...ARM偽指令——小范圍的地址讀取
ADR偽指令將基于PC相對偏移的地址值或基于寄存器相對偏移的地址值讀取到寄存器中。在匯編編譯器編譯源程序時,ADR偽指令被編譯器替換成一條合適的指令。通常,編譯器用一條ADD指令或SUB指令來實現(xiàn)該ADR偽指令的功能,若不能用一條指令實現(xiàn),則產(chǎn)生錯誤,編譯失敗。...ADRR1,Delay...DelayMOVR0,r14...應(yīng)用示例(源程序):編譯后的反匯編代碼:使用偽指令將程序標(biāo)號Delay的地址存入R0地址程序代碼ARM偽指令——小范圍的地址讀取
ADR偽指令將基于PC相對偏移的地址值或基于寄存器相對偏移的地址值讀取到寄存器中。在匯編編譯器編譯源程序時,ADR偽指令被編譯器替換成一條合適的指令。通常,編譯器用一條ADD指令或SUB指令來實現(xiàn)該ADR偽指令的功能,若不能用一條指令實現(xiàn),則產(chǎn)生錯誤,編譯失敗。...ADRR0,Delay...DelayMOVR0,r14...應(yīng)用示例(源程序):...0x20ADDr0,pc,#0x3c......0x64MOVr0,r14...編譯后的反匯編代碼:使用偽指令將程序標(biāo)號Delay的地址存入R0ADR偽指令被匯編成一條指令A(yù)RM偽指令——小范圍的地址讀取
ADR偽指令將基于PC相對偏移的地址值或基于寄存器相對偏移的地址值讀取到寄存器中。在匯編編譯器編譯源程序時,ADR偽指令被編譯器替換成一條合適的指令。通常,編譯器用一條ADD指令或SUB指令來實現(xiàn)該ADR偽指令的功能,若不能用一條指令實現(xiàn),則產(chǎn)生錯誤,編譯失敗。
應(yīng)用示例2(查表):
ADRR0,DISP_TAB ;加載轉(zhuǎn)換表地址
LDRBR1,[R0,R2] ;使用R2作為參數(shù),進(jìn)行查表
…DISP_TAB:.word0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8在匯編編譯源程序時,LDR偽指令被編譯器替換成一條合適的指令。若加載的常數(shù)未超出MOV或MVN的范圍,則使用MOV或MVN指令代替該LDR偽指令,否則匯編器將常量放入文字池,并使用一條程序相對偏移的LDR指令從文字池讀出常量。示例:
LDRr1,=0xff ;將0xff讀取到r1中 ;編譯后得到MOVr1,0xff示例:
LDRr1,=ADDR ;將外部地址ADDR讀取到R1中
匯編后將得到:;LDRr1,[PC,OFFSET_TO_LPOOL];…;LPOOL.wordADDR.text.global_start_start: mov r0,#9 mov r1,#15loop: cmp r0,r1 //比較r0r1 sublt r1,r1,r0 //若r0<r1則r1=r1–r0 subgt r0,r0,r1 //若r1<r0則r0=r0–r1 bne loop //若r0r1不相等則繼續(xù)循環(huán)stop: b stop.end用預(yù)先設(shè)定的行標(biāo)與B、BL結(jié)合可以設(shè)計各種循環(huán)結(jié)構(gòu)。例如:LOOPADDR0,R0,R1 ;R0=R0+R1CMPR0,#3 ;比較R0和#3BLSLOOP ;ifR0<3then跳轉(zhuǎn)到LOOP循環(huán).end在ARM匯編語言程序中,子程序的調(diào)用一般是通過BL指令來實現(xiàn)的。在程序中,使用指令:BL子程序名
即可完成子程序的調(diào)用。該指令在執(zhí)行時完成如下操作:將子程序的返回地址存放在連接寄存器LR中,同時將程序計數(shù)器PC指向子程序的入口點,當(dāng)子程序執(zhí)行完畢需要返回調(diào)用處時,只需要將存放在LR中的返回地址重新復(fù)制給程序計數(shù)器PC即可。在調(diào)用子程序的同時,也可以完成參數(shù)的傳遞和從子程序返回運算的結(jié)果,通??梢允褂眉拇嫫鱎0~R3完成。以下是使用BL指令調(diào)用子程序的匯編語言源程序的基本結(jié)構(gòu):
……BLPRINT_TEXT ;跳轉(zhuǎn)到子程序PRINT_TEXT,并保存PC至LR……PRINT_TEXT ;子程序入口……MOVPC,LR ;子程序運行完畢將PC置為LR,準(zhǔn)備返回.end【例3-3】給出一個輸出HelloWorld的程序。
.sectionHelloWorld, ;聲明代碼段.equSWI_WriteC&0 ;輸出R0中的字符,&0為預(yù)定義的
輸出代碼段入口.equSWI_Exit&11 ;程序結(jié)束&11為預(yù)定義程序結(jié)束代碼入口.text.global_start_start:
;代碼的入口ADRR1,TEXT ;R1→"HelloWorld"LOOP:LDRBR0,[R1],#1 ;讀取下一個字節(jié)CMPR0,#0 ;檢查文本終點SWINESWI_WriteC ;若非終點,則打印BNELOOP ;并返回LOOPSWISWI_Exit ;執(zhí)行結(jié)束TEXT:.string
"HelloWorld",&0a,&0d,0.end ;程序源代碼結(jié)束堆棧指令初始化INITSTACK: MOVR0,LR;保存返回地址;設(shè)置管理模式堆棧
MSRCPSR_C,#0xD3 LDRSP,StackSvc;設(shè)置中斷模式堆棧
MSRCPSR_C,#0xD2 LDRSP,StackIrqC語言的優(yōu)點是運行速度快、編譯效率高、移植性好和可讀性強。C語言支持模塊化程序設(shè)計,支持自頂向下的結(jié)構(gòu)化程序設(shè)計方法。因此,在嵌入式程序設(shè)計中經(jīng)常會用到C語言程序設(shè)計。嵌入式C語言程序設(shè)計是利用基本的C語言知識,面向嵌入式工程實際應(yīng)用進(jìn)行程序設(shè)計。也就是說它首先是C語言程序設(shè)計,因此必須符合C語言基本語法,只是它是面向嵌入式的應(yīng)用而設(shè)計的程序。為了使單獨編譯的C語言程序和匯編程序之間能夠相互調(diào)用,必須為子程序之間的調(diào)用規(guī)定一定的規(guī)則。ATPCS就是ARM程序和Thumb程序中子程序調(diào)用的基本規(guī)則。PCS即ProcedureCallStandard(過程調(diào)用規(guī)范),ATPCS即ARM-ThumbProcedureCallStandard。ATPCS規(guī)定了一些子程序之間調(diào)用的基本規(guī)則,這些基本規(guī)則包括子程序調(diào)用過程中寄存器的使用規(guī)則,數(shù)據(jù)棧的使用規(guī)則,參數(shù)的傳遞規(guī)則?;続TPCS規(guī)定了在子程序調(diào)用時的一些基本規(guī)則,包括以下3個方面的內(nèi)容:各寄存器的使用規(guī)則及其相應(yīng)的名字,數(shù)據(jù)棧的使用規(guī)則,參數(shù)傳遞的規(guī)則。相對于其他類型的ATPCS,滿足基本ATPCS的程序的執(zhí)行速度更快,所占用的內(nèi)存更少。但是它不能提供以下的支持:ARM程序和Thumb程序相互調(diào)用,數(shù)據(jù)以及代碼的位置無關(guān)的支持,子程序的可重入性,數(shù)據(jù)棧檢查的支持。1.寄存器的使用規(guī)則ATPCS中定義的寄存器如表3-3所示。表3-3
ATPCS中定義的寄存器其中:R0~R3:用于傳參,r0用于返回值。R4~R11:通用變量寄存器。
R12:用作過程調(diào)用中間臨時過渡寄存器IP。R13:堆棧指針。R14:連接寄存器。R15:PC。另外,R9、R10和R11還有一個特殊作用,分別記為:靜態(tài)基址寄存器SB,數(shù)據(jù)棧限制指針SL和楨指針FP。①子程序通過寄存器R0~R3來傳遞參數(shù),這時寄存器可以記作A0~A3,被調(diào)用的子程序在返回前無須恢復(fù)寄存器R0~R3的內(nèi)容。②在子程序中,使用R4~R11來保存局部變量,這時寄存器R4~R11可以記作V1~V8。如果在子程序中使用到V1~V8的某些寄存器,子程序進(jìn)入時必須保存這些寄存器的值,在返回前必須恢復(fù)這些寄存器的值,對于子程序中沒有用到的寄存器則不必執(zhí)行這些操作。在Thumb程序中,通常只能使用寄存器R4~R7來保存局部變量。③寄存器R12用作子程序間臨時過渡寄存器,記作IP,在子程序的連接代碼段中經(jīng)常會有這種使用規(guī)則。④寄存器R13用作數(shù)據(jù)棧指針,記做SP,在子程序中寄存器R13不能用作其他用途。寄存器SP在進(jìn)入子程序時的值和退出子程序時的值必須相等。⑤寄存器R14用作連接寄存器,記作LR。它用于保存子程序的返回地址,如果在子程序中保存了返回地址,則R14可用作其他的用途。⑥寄存器R15是程序計數(shù)器,記作PC,它不能用作其他用途。⑦ATPCS中的各寄存器在ARM編譯器和匯編器中都是預(yù)定義的。棧指針通??梢灾赶虿煌奈恢谩.?dāng)棧指針指向棧頂元素(即最后一個入棧的數(shù)據(jù)元素)時,稱為FULL棧。當(dāng)棧指針指向與棧頂元素相鄰的一個元素時,稱為Empty棧。數(shù)據(jù)棧的增長方向也可以不同,當(dāng)數(shù)據(jù)棧向內(nèi)存減小的地址方向增長時,稱為Descending棧;當(dāng)數(shù)據(jù)棧向著內(nèi)存地址增加的方向增長時,稱為Ascending棧。綜合這兩種特點可以有以下4種數(shù)據(jù)棧,即FD、ED、FA、EA。ATPCS規(guī)定數(shù)據(jù)棧為FD類型,并對數(shù)據(jù)棧的操作是8字節(jié)對齊的,下面是一個數(shù)據(jù)棧的示例及相關(guān)的名詞。①數(shù)據(jù)棧棧指針(stackpointer):指向最后一個寫入棧的數(shù)據(jù)的內(nèi)存地址。②數(shù)據(jù)棧的基地址(stackbase):指數(shù)據(jù)棧的最高地址。由于ATPCS中的數(shù)據(jù)棧是FD類型的,實際上數(shù)據(jù)棧中最早入棧數(shù)據(jù)占據(jù)的內(nèi)存單元是基地址的下一個內(nèi)存單元。③數(shù)據(jù)棧界限(stacklimit):數(shù)據(jù)棧中可以使用的最低的內(nèi)存單元地址。④已占用的數(shù)據(jù)棧(usedstack):數(shù)據(jù)棧的基地址和數(shù)據(jù)棧棧指針之間的區(qū)域,其中包括數(shù)據(jù)棧棧指針對應(yīng)的內(nèi)存單元。⑤數(shù)據(jù)棧中的數(shù)據(jù)幀(stackframes):在數(shù)據(jù)棧中,為子程序分配的用來保存寄存器和局部變量的區(qū)域。(1)參數(shù)個數(shù)可變的子程序參數(shù)傳遞規(guī)則對于參數(shù)個數(shù)可變的子程序,當(dāng)參數(shù)不超過4個時,可以使用寄存器R0~R3來進(jìn)行參數(shù)傳遞;當(dāng)參數(shù)超過4個時,還可以使用數(shù)據(jù)棧來傳遞參數(shù)。在參數(shù)傳遞時,將所有參數(shù)看做是存放在連續(xù)的內(nèi)存單元中的字?jǐn)?shù)據(jù)。然后,依次將各名字?jǐn)?shù)據(jù)傳送到寄存器R0,R1,R2,R3;如果參數(shù)多于4個,將剩余的字?jǐn)?shù)據(jù)傳送到數(shù)據(jù)棧中,入棧的順序與參數(shù)順序相反,即最后一個字?jǐn)?shù)據(jù)先入棧。按照上面的規(guī)則,一個浮點數(shù)參數(shù)可以通過寄存器傳遞,也可以通過數(shù)據(jù)棧傳遞,也可能一半通過寄存器傳遞,另一半通過數(shù)據(jù)棧傳遞。(2)參數(shù)個數(shù)固定的子程序參數(shù)傳遞規(guī)則對于參數(shù)個數(shù)固定的子程序,參數(shù)傳遞與參數(shù)個數(shù)可變的子程序參數(shù)傳遞規(guī)則不同,如果系統(tǒng)包含浮點運算的硬件部件,浮點參數(shù)將按照下面的規(guī)則傳遞:各個浮點參數(shù)按順序處理;為每個浮點參數(shù)分配FP寄存器;分配的方法是,滿足該浮點參數(shù)需要的且編號最小的一組連續(xù)的FP寄存器。第1個整數(shù)參數(shù)通過寄存器R0~R3來傳遞,其他參數(shù)通過數(shù)據(jù)棧傳遞。(3)子程序結(jié)果返回規(guī)則①結(jié)果為一個32位的整數(shù)時,可以通過寄存器R0返回。②結(jié)果為一個64位整數(shù)時,可以通過R0和R1返回,依此類推。③結(jié)果為一個浮點數(shù)時,可以通過浮點運算部件的寄存器f0、d0或者s0來返回。④結(jié)果為一個復(fù)合的浮點數(shù)時,可以通過寄存器f0~fN或者d0~dN來返回。⑤對于位數(shù)更多的結(jié)果,需要通過調(diào)用內(nèi)存來傳遞。在編譯或匯編時,使用/intework告訴編譯器或匯編器生成的目標(biāo)代碼遵守支持ARM程序和Thumb程序混合使用的ATPCS,它用在以下場合:程序中存在ARM程序調(diào)用Thumb程序的情況;程序中存在THUMB程序調(diào)用ARM程序的情況;需要連接器來進(jìn)行ARM狀態(tài)和Thumb狀態(tài)切換的情況;在下述情況下使用選項nointerwork:程序中不包含Thumb程序;用戶自己進(jìn)行ARM程序和Thumb程序切換。需要注意的是:在同一個C/C++程序中不能同時有ARM指令和Thumb指令。在嵌入式系統(tǒng)開發(fā)中,目前使用的主要編程語言是C和匯編,C++已經(jīng)有相應(yīng)的編譯器,但是現(xiàn)在使用還是比較少的。在稍大規(guī)模的嵌入式軟件中,如含有OS,大部分的代碼都是用C語言編寫的,主要是因為C語言的結(jié)構(gòu)比較好,便于人的理解,而且有大量的支持庫。盡管如此,很多地方還是要用到匯編語言,如開機(jī)時硬件系統(tǒng)的初始化,包括CPU狀態(tài)的設(shè)定,中斷的使能,主頻的設(shè)定,以及RAM的控制參數(shù)及初始化,一些中斷處理方面也可能涉及匯編。另外一個使用匯編的地方就是一些對性能非常敏感的代碼塊,這是不能依靠C編譯器的生成代碼,而要手工編寫匯編,達(dá)到優(yōu)化的目的。而且,匯編語言是和CPU的指令集緊密相連的,作為涉及底層的嵌入式系統(tǒng)開發(fā),熟練對應(yīng)匯編語言的使用也是必須的。在C語言中內(nèi)嵌的匯編指令包含大部分的ARM和Thumb指令,不過其使用與匯編文件中的指令有些不同,存在一些限制,主要有下面幾個方面。①不能直接向PC寄存器賦值,程序跳轉(zhuǎn)要使用B或者BL指令。②在使用物理寄存器時,不要使用過于復(fù)雜的C表達(dá)式,避免物理寄存器沖突。③R12和R13可能被編譯器用來存放中間編譯結(jié)果,計算表達(dá)式值時可能將R0到R3、R12及R14用于子程序調(diào)用,因此,要避免直接使用這些物理寄存器。④一般不要直接指定物理寄存器,而讓編譯器進(jìn)行分配。GCC內(nèi)嵌匯編內(nèi)嵌匯編語法如下:
__asm__(匯編語句模板:輸出部分:輸入部分:破壞描述部分)
共四個部分:匯編語句模板,輸出部分,輸入部分,破壞描述部分,各部分使用“:”格開,匯編語句模板必不可少,其他三部分可選,如果使用了后面的部分,而前面部分為空,也需要用“:”格開,相應(yīng)部分內(nèi)容為空。
例如:移位操作asm("mov%[result],%[value],ror#1" :[result]“=r”(y)/*移位結(jié)果*/ :[value]“r”(x)/*移位值*/:/*無破壞描述*/);asm("mov%0,%1,ror#1":"=r"(result):"r"(value));GCC內(nèi)嵌匯編匯編語句模板
匯編語句模板由匯編語句序列組成,語句之間使用“;”、“\n”或“\n\t”分開。指令中的操作數(shù)可以使用占位符引用C語言變量,操作數(shù)占位符最多10個,名稱如下:%0,%1,…,%9。指令中使用占位符表示的操作數(shù),總被視為long型(4個字節(jié)),為了增加擴(kuò)展性,占位符可使用%[symbol]代替。
"mov%[result],%[value],ror#1"輸出部分
輸出部分描述輸出操作數(shù),不同的操作數(shù)描述符之間用逗號格開,每個操作數(shù)描述符由限定字符串和C語言變量組成。每個輸出操作數(shù)的限定字符串必須包含“=”表示他是一個輸出操作數(shù)。
[result]"=r"(y)GCC內(nèi)嵌匯編輸入部分
輸入部分描述輸入操作數(shù),不同的操作數(shù)描述符之間使用逗號格開,每個操作數(shù)描述符由限定字符串和C語言表達(dá)式或者C語言變量組成。
[value]"r"(x)破壞描述部分
破壞描述符用于通知編譯器我們使用了哪些寄存器或內(nèi)存,由逗號格開的字符串組成,每個字符串描述一種情況,一般是寄存器名;除寄存器外還有“memory”int
value_convert(int
x)
{
int
y;
asm
volatile
(
"mov
%[result],
%[value],
ror
#1"
:
[result]
"=r"
(y)
:
[value]
"r"
(x)
:
);
return
y;
}
int
main()
{
printf("GCC
ARM
Inline
Assembler
CookBook
Demo!\n");
int
x
=
4;
printf("call
func
value_convert
with
input
x:%d,output
y:%d\n",x,value_convert(x));
return
0;
}
程序編譯運行后的輸出:
內(nèi)嵌匯編不用單獨編輯匯編語言文件,比較簡潔,但是有諸多限制,當(dāng)匯編的代碼較多時一般放在單獨的匯編文件中,這時就需要在匯編和C之間進(jìn)行一些數(shù)據(jù)的傳遞,最簡便的辦法就是使用全局變量。匯編中使用C定義的全局變量。在C中調(diào)用匯編文件中的函數(shù),要做的主要工作有兩個,一是在C中聲明函數(shù)原型,并加extern關(guān)鍵字;二是在匯編中用EXPORT導(dǎo)出函數(shù)名,并用該函數(shù)名作為匯編代碼段的標(biāo)識,最后用movpc,lr返回。然后,就可以在C中使用該函數(shù)了。從C的角度,并不知道該函數(shù)的實現(xiàn)是用C還是匯編。更深的原因是因為C的函數(shù)名起到表明函數(shù)代碼起始地址的作用,這個和匯編的label是一致的?!纠?-6】在C中調(diào)用匯編的函數(shù)(函數(shù)不多于4個參數(shù))。
#include<stdio.h>
externvoidstrcopy(char*d,constchar*s);
intmain()
{
constchar*srcstr="Firststring-source";
chardststr[]="Secondstring-destination";
/*下面將dststr作為數(shù)組進(jìn)行操作*/
printf("Beforecopying:\n");
printf("%s\n%s\n",srcstr,dststr);
strcopy(dststr,srcstr);
printf("Aftercopying:\n");
printf("%s\n%s\n",srcstr,dststr);
return(0);
}.globalstrcopystrcopy:;R0指向目的字符串;R1指向源字符串LDRBR2,[R1],#1;加載字節(jié)并更新源字符串指針地址STRBR2,[R0],#1;存儲字節(jié)并更新目的字符串指針地址CMPR2,#0;判斷是否為字符串結(jié)尾BNEstrcopy;如果不是,程序跳轉(zhuǎn)到strcopy繼續(xù)復(fù)制MOVpc,lr;程序返回【例3-8】在匯編語言中調(diào)用C語言的函數(shù)(參數(shù)不多于4個)。
;prog1_asm.asm.externprog1_c ;聲明prog1_c函數(shù).text_start:.globalprog1_asmprog1_asm:STRlr,[sp,#-4]! ;保存當(dāng)前l(fā)rldrr0,=0x1 ;參數(shù)1ldrr1,=0x2 ;參數(shù)2ldrr2,=0x3 ;參數(shù)3blprog1_c ;調(diào)用C函數(shù)LDRpc,[sp],#4 ;將lr裝進(jìn)pc(返回main函數(shù)).end//prog1_c.cvoidprog1_c(intp1,intp2,intp3){printk("%0x%0x%0x\r\n",p1,p2,p3); //輸出參數(shù)值}//main.cintmain(){prog1_asm();while(1);}【例3-9】在匯編語言中調(diào)用C語言的函數(shù)(參數(shù)多于4個)。
;prog2_asm.asm.externprog2_c ;聲明prog2_c函數(shù).section.text_start:.globalprog2_asmprog2_asm:STRlr,[sp,#-4]! ;保存當(dāng)前l(fā)rldrr0,=0x1 ;參數(shù)1ldrr1,=0x2 ;參數(shù)2ldrr2,=0x3 ;參數(shù)3ldrr3,=0x4 ;參數(shù)4ldrr4,=0x6strr4,[sp,#-4]! ;參數(shù)6入棧ldrr4,=0x5strr4,[sp,#-4]! ;參數(shù)5入棧blprog2_cADDsp,sp,#4 ;清除棧中參數(shù)5,本語句執(zhí)行完后sp指向參數(shù)6ADDsp,sp,#4 ;清除棧中參數(shù)6,本語句執(zhí)行完后sp指向lrLDRpc,[sp],#4 ;將lr裝進(jìn)pc(返回main函數(shù)).end//prog2_c.c
voidprog2_c(intp1,intp2,intp3,intp4,intp5,intp6){printk("%0x%0x%0x%0x%0x%0x\r\n",p1,p2,p3,p4,p5,p6); //輸出參數(shù)值}//main.c
intmain(){prog2_asm();while(1);}1.用匯編語言設(shè)計程序?qū)崿F(xiàn)10!(10的階乘)。2.實現(xiàn)字符串的逆序復(fù)制
TEXT1="HELLO"=〉TEXT2="OLLEH"。3.用調(diào)用子程序的方法實現(xiàn)1!+2!+3!+…+10!。4.什么是內(nèi)嵌匯編?使用內(nèi)嵌匯編時需要注意什么?5.C語言與匯編語言混合編程時的參數(shù)傳遞規(guī)則有哪些?
啟動程序設(shè)計
啟動代碼啟動代碼內(nèi)容啟動代碼工作流程啟動代碼內(nèi)容(1)啟動代碼簡介
廣州致遠(yuǎn)電子有限公司為LPC2000系列芯片編寫的啟動代碼由3個文件組成。(1)startup.s-異常向量表定義、各模式堆棧初始化、跳轉(zhuǎn)到C程序main入口等。
(2)target.c-目標(biāo)板初始化,如時鐘分頻、PLL設(shè)置、VIC設(shè)置等。
(3)irq.s-用于管理中斷嵌套。(1)startup.s.text.global_start.globalirq_handler;中斷向量表_start:bresetldrpc,_undefined_instructionldrPC,_software_interruptLDRPC,_prefetch_abortldrPC,_data_abortLDRPC,_no_usedldrPC,_irqLDRPC,_fiq_undefined_instruction:.word_undefined_instruction_software_interrupt:.word_software_interrupt_prefetch_abort:.word_prefetch_abort_data_abort:.word_data_abort_no_used:.word_no_used_irq:.word_irq_fiq:.word_fiq匯編入口異常向量表地址跳轉(zhuǎn)表(1)startup.sreset:
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024版設(shè)備購買協(xié)議
- 2025年度疫情防控應(yīng)急物資儲備中心n95口罩采購合同范本3篇
- 二零二五年度貨運司機(jī)勞務(wù)派遣合同3篇
- 2025年度大豆綠色種植推廣合作合同范本3篇
- 2025年度綠色有機(jī)西瓜產(chǎn)地直銷合作合同范本3篇
- 2025年度不銹鋼板材國際貿(mào)易結(jié)算及風(fēng)險管理合同3篇
- 2024行政合同爭議調(diào)解程序:如何有效運用行政優(yōu)先權(quán)3篇
- 2025年度WPS合同管理平臺定制開發(fā)與實施合同3篇
- 二零二五年甘肅離崗創(chuàng)業(yè)人員社保接續(xù)與待遇保障合同3篇
- 2025年物流配送與快遞快遞行業(yè)風(fēng)險管理合同范本3篇
- 課題申報書:GenAI賦能新質(zhì)人才培養(yǎng)的生成式學(xué)習(xí)設(shè)計研究
- 外配處方章管理制度
- 2025年四川長寧縣城投公司招聘筆試參考題庫含答案解析
- 駱駝祥子-(一)-劇本
- 《工程勘察設(shè)計收費標(biāo)準(zhǔn)》(2002年修訂本)
- 全國醫(yī)院數(shù)量統(tǒng)計
- 【MOOC】PLC技術(shù)及應(yīng)用(三菱FX系列)-職教MOOC建設(shè)委員會 中國大學(xué)慕課MOOC答案
- 2023七年級英語下冊 Unit 3 How do you get to school Section A 第1課時(1a-2e)教案 (新版)人教新目標(biāo)版
- 泌尿科主任述職報告
- 2024年醫(yī)美行業(yè)社媒平臺人群趨勢洞察報告-醫(yī)美行業(yè)觀察星秀傳媒
- 第六次全國幽門螺桿菌感染處理共識報告-
評論
0/150
提交評論