![嵌入式系統(tǒng)原理與應用 第3版 課件 第4章 微處理器ARM程序設計_第1頁](http://file4.renrendoc.com/view2/M03/14/10/wKhkFmYDvNCAI1-kAAJh2wHFxOc912.jpg)
![嵌入式系統(tǒng)原理與應用 第3版 課件 第4章 微處理器ARM程序設計_第2頁](http://file4.renrendoc.com/view2/M03/14/10/wKhkFmYDvNCAI1-kAAJh2wHFxOc9122.jpg)
![嵌入式系統(tǒng)原理與應用 第3版 課件 第4章 微處理器ARM程序設計_第3頁](http://file4.renrendoc.com/view2/M03/14/10/wKhkFmYDvNCAI1-kAAJh2wHFxOc9123.jpg)
![嵌入式系統(tǒng)原理與應用 第3版 課件 第4章 微處理器ARM程序設計_第4頁](http://file4.renrendoc.com/view2/M03/14/10/wKhkFmYDvNCAI1-kAAJh2wHFxOc9124.jpg)
![嵌入式系統(tǒng)原理與應用 第3版 課件 第4章 微處理器ARM程序設計_第5頁](http://file4.renrendoc.com/view2/M03/14/10/wKhkFmYDvNCAI1-kAAJh2wHFxOc9125.jpg)
版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
第4章微處理器ARM編程程序設計不但要掌握處理器的指令功能與使用,還必須借助ARM的集成開發(fā)環(huán)境進行程序的代碼編輯、編譯、和調試運行。為了提高編程效率,縮短開發(fā)周期,還必須學會使用C/C++語言進行程序設計。這就要求我們掌握ARM9匯編語言偽指令、匯編語言程序的語法結構、ARM處理器的C語言編程、匯編語言與C語言混合編程的ATPCS規(guī)則等。本章主要講述ARM偽指令、ARM匯編語言程序設計、ARM匯編語言與C語言的混合編程以及子程序或函數之間的相互調用。最后通過實例講述ARM匯編語言與C語言之間的參數傳遞方法、程序之間的相互調用等。124.1ARM匯編偽指令ARM匯編語言源程序是由偽指令、ARM指令和宏指令組成。偽指令完成的操作稱為偽操作。偽指令的定義:在ARM匯編語言程序里,有一些特殊指令助記符,這些特殊的助記符與指令系統(tǒng)的助記符不同,沒有相對應的操作碼,也就是不會生成機器碼,僅僅是在編譯軟件中起著格式化的作用,通常稱這些特殊指令助記符為偽指令。偽指令的作用:是為完成匯編程序作各種準備工作的,這些偽指令僅在匯編過程中起作用,一旦匯編結束,偽指令的使命就結束了。宏指令:實際上是一段獨立的程序代碼,在匯編程序中通過宏名來調用,而在程序被匯編時,調用的宏將被展開,用宏的定義體代替宏名。因此宏可以使程序代碼更加簡潔直觀,是用指令占用的空間換取執(zhí)行的時間。ARM匯編可以在Windows操作系統(tǒng)下的ADS1.2集成開發(fā)環(huán)境中進行,也可以在Linux操作系統(tǒng)下的GUN開發(fā)環(huán)境中進行。以下介紹ADS1.2開發(fā)環(huán)境中ARM匯編器中使用的偽指令。34.1.1數據常量定義偽指令數據常量定義偽指令EQU用于為程序中的常量、標號等定義一個等效的字符名稱,類似于C語言中的#define。EQU語法格式如下:
常量名稱EQU表達式{,類型}
其中:名稱為EQU偽指令定義的字符名稱,當表達式為32位的常量時,可以指定表達式的數據類型,可以使用以下三種類型:CODE16、CODE32和DATA
。EQU可用符號“*”代替。應用示例:Data_inEQU200;定義標號Data_in的值為200
,AddrEQU0xff,CODE32;
定義標號Addr的值為0xff,且該處為32位的ARM指令地址
注意:EQU可以定義字節(jié)、半字、字長度的數據值,也可以認為是常數,主要在于應用的場合;也可以定義32位的地址值等。44.1.2數據變量定義偽指令數據變量定義偽指令用于定義ARM匯編程序中的變量、對變量賦值以及定義寄存器的別名等操作。全局變量偽指令GBLA、GBLL和GBLS全局變量一般是指在這個匯編程序中定義,需要在另外一個匯編程序中應用的變量。GBLA(GBLL或GBLS)全局變量名GBLA用于定義一個全局的數字變量,并初始化為0。GBLL用于定義一個全局的邏輯變量,并初始化F。GBLS用于定義一個全局的字符串變量,并初始化為空。應用示例:(說明全局變量名必須唯一)GBLAVariable1;定義全局的數字變量,變量名為Variable1GBLLVariable2;定義全局的邏輯變量,變量名為Variable2GBLSVariable3;定義全局的字符串變量,變量名為Variable352.局部變量偽指令LCLA、LCLL和LCLS
局部變量是指在某個匯編程序中定義并使用的變量,在其它匯編程序中不能使用。語法格式如下:
LCLA(LCLL或LCLS)局部變量名
LCLA偽指令用于定義一個局部的數字變量,并初始化為0。LCLL偽指令用于定義一個局部的邏輯變量,并初始化為F(假)。LCLS偽指令用于定義一個局部的字符串變量,并初始化為空。應用示例:(局部必須唯一)LCLAVariable4;定義局部的數字變量,變量名為Variable463.變量賦值偽指令SETA、SETL和SETS
變量賦值偽指令既可以給全局變量賦值,也可以給局部變量賦值。偽指令SETA、SETL、SETS用于給一個已經定義的全局變量或局部變量賦值。偽指令的格式如下:
變量名SETA(SETL或SETS)表達式
SETA偽指令用于給一個數字變量賦值。SETL偽指令用于給一個邏輯變量賦值。SETS偽指令用于給一個字符串變量賦值。應用示例:Variable1SETA0xbb;將該變量賦值為數字值0xbbVariable2SETL{TRUE};將該變量賦值為邏輯“真”Variable3SETS“Testing”;將該變量賦值為字符串Testing74.寄存器列表定義偽指令RLIST
RLIST偽指令可用于對一個通用寄存器列表定義名稱,使用該偽指令定義的名稱可在ARM指令LDM/STM中使用。在LDM/STM指令中,列表中的寄存器訪問次序根據寄存器的編號由低到高,列表中的寄存器排列次序必須從小到大。偽指令格式如下:
寄存器列表名稱RLIST{寄存器列表}
應用示例:
Reglist1RLIST{R0-R6,R8,R10};將寄存器列表名稱定義為Reglist1,以后可直接指令中使用84.1.3內存分配偽指令內存分配偽指令一般用于為特定的數據分配存儲單元,同時可完成已分配存儲單元的初始化。以下介紹常見的內存分配數據定義偽指令。1.字節(jié)分配偽指令DCB
該偽指令用于分配一片連續(xù)的字節(jié)(8bit)存儲單元,并用偽指令中指定的表達式初始化。其中表達式的值可以為0~255或字符串。DCB偽指令也可以用符號“=”代替。指令格式如下:
標號DCB表達式應用示例:Str1DCB“Thisisastring”;分配一片連續(xù)的字節(jié)存儲單元并初始化。Str2DCB0x0,0x02,0x03,0x04,0x05
;分配一片連續(xù)的字節(jié)存儲單元并初始化的另一種方式。92.半字分配偽指令DCW(或DCWU)
該偽指令用于分配一片連續(xù)的半字(16bit)存儲單元,并用偽指令中指定的表達式初始化。其中表達式可以為程序標號或表達式。DCW要求半字對齊,而DCWU不要求半字對齊。指令格式如下:
標號DCW(或DCWU)
表達式
應用示例:DataTestDCW1,2,3;分配連續(xù)的半字存儲單元并初始化注意:每一個數字均占2字節(jié)存儲單元,即半字。3.字分配偽指令DCD(或DCDU)
該偽指令用于分配一片連續(xù)的字存儲(32bit)單元,并用偽指令中指定的表達式初始化??梢允褂梅枴?”代替。指令格式如下:
標號DCD(或DCDU)表達式
應用示例:WordDataDCD1,2,3;分配連續(xù)的字存儲單元并初始化,每個數字占4字節(jié)內存單元即字單元104.DCFS(或DCFSU)偽指令
該指令用于為單精度的浮點數分配一片連續(xù)的存儲單元,每個雙精度數占1個字單元,并用偽指令中指定的表達式初始化。偽指令格式如下
標號DCFS(或DCFSU)表達式應用示例:SFloatDataDCFS–5E7,2E-8
;分配連續(xù)的字存儲單元并初始化為指定的單精度數。5.DCFD(或DCFDU)偽指令
該偽指令用于為雙精度的浮點數分配一片連續(xù)的存儲單元,每個雙精度數占2個字單元,并用偽指令中指定的表達式初始化。偽指令格式如下:
標號DCFD(或DCFDU)
表達式應用示例:FloatDataDCFD–5E7,2E-8
;分配連續(xù)的字存儲單元并初始化為指定的雙精度數。116.DCQ(或DCQU)偽指令
該指令用于分配一片以8字節(jié)為單位連續(xù)的存儲區(qū)域,并用偽指令中指定的表達式初始化。偽指令格式如下:
標號DCQ(或DCQU)表達式應用示例:
B8DataDCFD100,200;分配2個連續(xù)的8字節(jié)存儲單元并初始化。7.SPACE
偽指令
該指令用于分配一片連續(xù)的字節(jié)存儲單元并初始化為0。其中表達式是要分配的字節(jié)數。SPACE也可以用符號“%”來代替。偽指令格式如下:
標號SPACE表達式
應用示例:
SpaceDataSPACE100;分配連續(xù)100個字節(jié)單元并用0初始化。128.MAP偽指令
該指令用于定義一個結構化的內存表首地址。MAP也可以用符號“^”來代替。表達式可以是程序中的標號或數學表達式?;芳拇嫫骺蛇x,當它不存在時,表達式的值為內存表的首地址;當該項存在時,內存表的首地址即為表達式的值與寄存器的值之和。MAP偽指令常與FIELD偽指令配合使用來定義一個內存表。
MAP表達式{,基址寄存器}應用示例:MAP0x0100,R0;定義結構化首地址值為0x0100+R09.FIELD偽指令
該指令用于定義一個結構化內存表的數據域,也可用符號“#”代替,表達式的值為當前數據域在內存中所占的字節(jié)數。FIELD偽指令常與MAP偽指令配合使用來定義結構化的內存表。MAP偽指令定義內存表的首地址,FIELD偽指令定義內存表中的各個數據域字節(jié)個數,并可以為每個數據域指定一個標號供其他的指令引用。它們與C語言中的struct結構體雷同。FIELD偽指令的格式如下:
標號FIELD表達式13應用示例:1)在內存中定義異常模式程序入口地址的結構化存儲空間,即每個字單元中的內容是相對應的異常模式程序入口地址。由它們組成的表稱為異常向量表2)在內存中定義ARM的32個中斷程序或中斷函數入口地址的結構化存儲空間,即每個字單元中的內容是相應的中斷程序或中斷函數入口地址。由它們組成的表稱為中斷向量表。;異常向量表定義如下:^_ISR_STARTADDRESS;指定結構體地址的開始位置HandleReset#4;占用第1個字單元(4字節(jié))HandleUndef #4;占用第2個字單元(4字節(jié))HandleSWI #4;占用第3個字單元(4字節(jié))HandlePabort #4;占用第4個字單元(4字節(jié))HandleDabort #4;占用第5個字單元(4字節(jié))HandleReserved#4;(預留)占用第6個字單元(4字節(jié))HandleIRQ #4;占用第7個字單元(4字節(jié))HandleFIQ #4;占用第8個字單元(4字節(jié));以上的字單元內容通過程序將它們各自的異常程序入口地址寫入到相應的內存空間中。;起到由固定的異常向量地址轉向到存儲器的虛擬異常向量地址。以下是內存中斷向量表定義:HandleEINT0 #4;占用第9個字單元(4字節(jié))HandleEINT1 #4;占用第10個字單元(4字節(jié))
…HandleADC #4;占用第40個字單元(4字節(jié));以上4行實際使用時應該有32行,分別為32個ARM中斷源定義存儲它們入口程序的地址值;通過將匯編中斷服務程序入口標號或C語言中斷函數名賦值到定義的存儲單元中,就可以執(zhí)行相應的中斷程序或調用中斷函數了。關于它們具體操作在ARM中斷程序設計8.2節(jié)中講述。1410.LTORG偽指令
文字池偽指令LTORG,用于聲明一個數據緩沖池(文字池)的開始。通常ARM匯編器把文字池放在代碼段的最后面,但必須在END偽指令之前。LTORG偽指令經常放在無條件跳轉指令之后,或子程序返回指令之后,這樣處理器不會錯誤地將字緩沖池中的數據當作指令來執(zhí)行。使用時只需要用偽指令LTORG聲明,文字池中的內容是由匯編器自動生成的。應用示例:
startBLfunc1;調用子程序
…
func1LDRR1,=0x33333334;子程序入口,LDR是偽指令,立即數不可用前述的12bit來表示…;0x33333334將會自動寫入到文字池預留的3000個字節(jié)單元中
MOVPC,RL;子程序返回
LTORG;聲明文字池DataSPACE3000;預留3000字節(jié)存儲空間
END;匯編結束偽指令154.1.4匯編控制偽指令匯編控制偽指令用于控制匯編程序的執(zhí)行流程,主要有條件匯編偽指令、宏定義偽指令和重復匯編控制偽指令等,該類偽指令如下:1)條件匯編控制:IF,ELSE,ENDIF2)宏定義:MACRO和MEND3)重復匯編:WHILE和WEND161.IF、ELSE、ENDIF
偽指令IF、ELSE、ENDIF偽指令能夠根據條件把一段程序代碼包括在匯編程內或將其排除在匯編程序之外?!癧”可代替IF,“|”可代替ELSE,“]”可代替ENDIF。偽指令的格式如下:IF邏輯表達式
指令序列1
ELSE
指令序列2
ENDIF
在格式中,如果邏輯表達式為真,則指令序列1被匯編;
否則,指令序列2被匯編。ELSE可有可無。應用示例:GBLLTHUMBCODE;定義全局邏輯變量[{CONFIG}=16;如果變量CONFIG==16,即目前處于16位Thumb模式,;則條件為真。這里花括號{}是指取變量的值THUMBCODESETL{TRUE};Thumb狀態(tài)模式變量賦值為真CODE32;轉入ARM模式,以下是32位ARM指令代碼|;ELSETHUMBCODESETL{FALSE};Thumb狀態(tài)模式變量賦值為假]2.MACRO和MEND偽指令MACRO用于標識宏定義的開始,MEND用于標識宏定義的結束。用MACRO和MEND定義的代碼,稱為宏定義,這樣在程序中就可以通過宏指令多次調用該代碼段。宏指令的格式如下:MACRO$標號
宏名$參數1,$參數2,……
指令序列
MEND
其中,$表示其后的標號或參數是宏變量,使用時可以進行宏替換。例如:$標號在宏指令被展開時,標號會被替換為用戶定義的符號,宏指令的參數可以使用一個或多個,$參數n在宏指令被展開時,這些參數被相應的數值所替換。1718應用示例:MACRO;定義異常向量轉移宏匯編,主要用于中斷模式$HandlerLabelHANDLER$HandleLabel$HandlerLabelSUBSP,SP,#4;①修改堆棧指針,用于保存跳轉地址STMFDSP!,{R0};②壓棧保護R0寄存器內容LDRR0,=$HandleLabel;③將轉移的地址存入R0LDRR0,[R0];④將$HandleLabel的內容送R0STRR0,[SP,#4];⑤將R0的內容壓棧到①的單元中LDMFDSP!,{R0,PC};⑥彈?;貜蚏0,PC指向$HandleLabelMEND該宏主要實現由異常向量地址處的程序計數器PC值(HandlerXxx)向內存儲器中的定義的異常模式程序入口地址(HandleXxx的內容)處跳轉。即從固定的異常向量指針處跳轉到內存儲器中程序可控的入口地址處。對于普通中斷調用執(zhí)行時的語法是:HandlerIRQHANDLERHandleIRQ實現PC指針從HandlerIRQ跳轉到HandleIRQ的功能。193.MEXIT
偽指令
MEXIT偽指令用于從宏定義中跳轉出去。偽指令格式如下:MEXIT
若需要從MACRO和MEND定義的宏體中跳出來時可以使用該偽指令。4.WHILE和WEND偽指令
WHILE用于標識條件循環(huán)偽指令的開始,WEND用于標識循環(huán)體的結束。偽指令格式如下:
WHILE邏輯表達式
指令序列WEND如果條件為真,幾乎重復匯編相同的或幾乎相同的一段程序代碼。該偽指令可以嵌套使用。204.1.5匯編程序中常用偽指令偽指令名稱功能描述AREA定義代碼段或數據段CODE16、CODE32告訴匯編器其后是Thumb程序、ARM程序ENTRY指定程序的入口點ALIGN指定程序或數據的對齊方式,如半字對齊,字對齊等END匯編程序結束EXPORT/GLOBAL在本匯編程序中聲明標號可以在其他源文件使用IMPORT/EXTURN在其他文件中用上一欄方法聲明,在本文件中聲明使用GET/INCLUDE將一個其他源文件包含到本文件中使用INCBIN將一個二進制的文件包含在本文件中使用RN給特定的寄存器重新命名ROUT標記局部標號使用范圍的界限KEEP保留符號表中的局部符號表4-1常用匯編程序偽指令表211.AREA偽指令
用于定義一個代碼段或數據段,它是每個匯編程序不可缺少的部分。語法如下:
AREA段名,屬性1,屬性2,……
其中,段名若以數字開頭,則該段名需用“|”括起來,如|1_test|。屬性字段表示該代碼段(或數據段)的相關屬性,多個屬性用逗號分隔。屬性段如表4-2所示。屬性偽指令功能描述CODE聲明定義的是一個代碼段DATA聲明定義的是一個數據段READONLY指定本段為只讀,是代碼段的默認屬性READWRITE指定本段為可讀可寫,是數據段的默認屬性ALIGN={exp}指定段的對齊方式為2exp,exp取值在0~31。默認為字對齊COMMON指定一個通用段,該段不包含任何用戶代碼和數據NOINIT指定此數據段僅保留內存單元,而沒有將初值寫入到內存單元應用示例:
AREAStart,CODE,READONLY
這里定義一個代碼段,段名:Start,屬性為只讀。注意:一個大的匯編程序可以包含多個代碼段和數據段,一個匯編程序至少包含一個代碼段。222.CODE16和CODE32偽指令CODE16偽指令的功能是告訴匯編器后面的指令序列為16位的Thumb指令。CODE32偽指令的功能是告訴匯編器后面的指令序列為32位的ARM指令。注意:CODE16和CODE32只告訴其后指令的類型,該偽操作本身不進行ARM工作狀態(tài)的切換。3.ENTRY偽指令
該指令指定程序的入口點。偽指令格式是:ENTRY應用示例:AREAStartUp,CODE,READONLY;指定一個代碼段StartUp,屬性為只讀ENTRY;指定代碼段程序入口點CODE32;指定其后為32位ARM指令LDRR0,=start+1;使用ARM偽指令LDR給R0賦值,并使R0[0]=1BXR0;R0[0]=1將跳轉到Thumb指令程序處執(zhí)行
…CODE16;指定其后為16位Thumb指令程序startMOVR1,#20
…END;匯編結束注意:一個程序(可以包含多個源文件)中至少要有一個ENTRY,但一個源文件中最多只有一個ENTRY(可以沒有ENTRY)。234.END偽指令END偽指令告訴匯編器源文件已經結束,也就是說其后的指令將不起作用,一個源文件只能使用一次END偽指令。偽指令格式如下:END5.EXPORT/GLOBAL偽指令
該兩條偽指令用于在程序中聲明一個全局標號,可以在其它文件中使用。該偽指令語法格式如下:
EXPORT標號{[WEAK]}GLOBAL標號{[WEAK]}其中:[WEAK]選項聲明其它的同標號優(yōu)先于該標號被應用。EXPORT/GLOBAL同功能。應用示例:AREAExample,CODE,READONLYEXPORTDoAddDoAddADDR0,R1,R2246.IMPORT偽指令IMPORT偽指令是用于通知編譯器聲明的標號是在其它匯編語言文件中已經聲明,在本文件中使用的標號。而且無論當前源文件是否引用該標號,該標號均會被加入到當前源文件的符號表中。偽指令語法格式如下:IMPORT標號{[WEAK]}
其中:[WEAK]
選項聲明在其它文件中沒有定義時,編譯器也不給出錯誤信息。在多數情況下將該標號置為0,若該標號為B或BL指令引用,則將B或BL指令置為NOP操作。7.EXTERN偽指令EXTERN偽指令用于通知編譯器要使用的標號在其他的源文件中定義,但要在當前源文件中引用。如果當前源文件實際并未引用該標號,該標號就不會被加入到當前源文件的符號表中。偽指令語法格式如下:
EXTERN標號{[WEAK]}標號在程序中區(qū)分大小寫,[WEAK]選項表示當所有的源文件都沒有定義這樣一個標號時,編譯器也不給出錯誤信息。在多數情況下將該標號置為0,若該標號為B或BL指令引用,則將B或BL指令置為NOP操作。258.GET/INCLUDE偽指令
這兩條偽指令是將一個源文件包含到當前的源文件中,并將包含的文件在當前文件中進行匯編處理。指令格式如下:
GET文件名或
INCLUDE文件名應用舉例:GETd:\arm\filename.s;文件名使用全文件名,即包含文件的路徑9.INCBIN偽指令INCBIN偽指令是將一個已經編譯好的二進制文件包含到當前源程序中,匯編器不再進行匯編處理。指令格式如下:
INCBIN文件名應用示例:INCBINd:\arm\binfile.bin注意:與GET/INCLUDE偽指令的區(qū)別。INCBIN偽指令是將一個已經編譯好的二進制文件或數據文件包含到當前源文件中使用;而GET/INCLUDE偽指令是將一個匯編源文件(未編譯的)包含到當前文件中使用。2610.RN偽指令RN偽指令是給一個通用寄存器重新命名一個別名,在特定環(huán)境下使用。指令的格式如下:
別名RN通用寄存器應用示例:COUNTRNR6;定義R6為計數器COUNT,定義后直接使用COUNT11.KEEP偽指令KEEP偽指令指示編譯器保留符號表中的局部符號。偽指令的格式如下:KEEP{symbol}其中:symbol是要保留的局部符號;如果沒有此項,則除了基于寄存器的所有符號都將保含在目標文件的符號表中。12.ROUTROUT偽指令用于定義局部標號的有效范圍。偽指令的格式如下:{name}ROUT其中:name是定義作用范圍的名稱。當沒有使用ROUT偽指令時,局部標號的作用范圍為其所在段。ROUT的作用范圍是在本ROUT偽指令和下一條ROUT偽指令之間(指同一段中的偽指令)。274.1.6匯編語言中的運算符與表達式在匯編語言設計中,也經常使用各種表達式。表達式一般由變量、常量、運算符和括號組成。常用的表達式有算術表達式、邏輯表達式、關系表達式和字符串表達式,其運算遵循以下優(yōu)先級:
括號運算符的優(yōu)先級最高。一般在搞不清優(yōu)先級的情況下,可以增加括號來提高表達式的優(yōu)先級別;
單目運算符的優(yōu)先級高于其他運算符;
優(yōu)先級相同的雙目運算符運算順序是從左到右;
優(yōu)先級相同的單目運算符運算順序是從右到左。281.數字運算符與表達式數字表達式一般由算術常量、算術變量、算術運算符和括號組成。與數字運算符和表達式有關的內容如下:⑴算術運算符與表達式主要有:“+”、“-”、“×”、“/”、“MOD”運算符。以下是由X和Y以及運算符所構成的算術表達式和含義:X+Y表示X與Y之和;X-Y表示X與Y之差;X×Y表示X與Y之乘積;X/Y表示X除以Y之商;X:MOD:Y表示X除以Y的余數。⑵移位運算符與表達式主要有:“ROL”、“ROR”、“SHL”、“SHR”運算符。以下是由X和Y以及其運算符所構成的移位表達式和含義:X:ROL
:Y表示X循環(huán)左移Y位;
X
:ROR
:Y表示X循環(huán)右移Y位;X:SHL
:Y表示X左移Y位;
X:SHR
:Y表示X右移Y位。292.邏輯運算符與表達式邏輯表達式一般由邏輯常量、邏輯變量、邏輯運算符和括號組成。與邏輯運算符和表達式有關的內容如下:⑴位邏輯運算符與表達式主要有:“AND”、“OR”、“NOT”、“EOR”運算符。以下是由X和Y以及其運算符所構成的位邏輯運算表達式和含義:X:AND
:Y表示將X與Y按位進行邏輯“與”運算;X
:OR
:Y表示將X與Y按位進行邏輯“或”運算;:NOT
:Y表示將Y按位進行邏輯“非”運算;X:EOR
:Y表示將X與Y按位進行邏輯“異或”運算。⑵邏輯運算符與表達式主要有:“LAND”、“LOR”、“LNOT”、“LEOR”運算符。以下是由X和Y以及其運算符所構成的邏輯運算表達式和含義:X:LAND
:Y表示將X與Y進行邏輯“與”運算;X
:LOR
:Y表示將X與Y進行邏輯“或”運算;:LNOT
:Y表示將Y進行邏輯“非”運算;X:LEOR
:Y表示將X與Y進行邏輯“異或”運算。303.關系運算符與表達式關系表達式一般由常量、變量、關系運算符和括號組成。如果比較的兩個變量關系滿足,則輸出為“真”,否則,輸出為“假”。關系運算符主要有:“=”、“>”、“<”、“>=”“<=”、“/=”、“<>”,以下是由變量X、Y所構成的關系表達式及含義:X=Y表示X等于Y;X
>Y表示X大于Y;X<Y表示X小于Y;X>=Y表示X大于等于Y;X<=Y表示X小于等于Y;
X/=Y表示X不等于Y;X<>Y表示X不等于Y;314.字符串運算符與表達式字符串表達式一般由字符串常量、字符串變量、字符串運算符和括號組成。編譯器所支持的最大字符串長度是512字節(jié)。注意:下面的表達式也可以是變量或常量。⑴LEN運算符LEN運算符返回的是字符串變量中的字符串長度,語法格式是:
:LEN:字符表達式⑵CHR運算符CHR運算符是將0~255中的整數轉換為一個字符,語法格式是:
:CHR:整數表達式⑶STR運算符STR運算符是將一個數字表達式或一個邏輯表達式轉換成一個字符串。對于數字表達式將其轉換為一個由16進制數組成的字符串;對于一個邏輯表達式將其轉換成字符T或F。語法格式是::STR:表達式324.字符串運算符與表達式(續(xù))⑷LEFT運算符LEFT運算符返回的是左端字符串X,從左邊取出Y個字符組成的子串。語法格式是:X:LEFT:Y
其中X是源字符串;Y是一個整數,表示從左側取出字符的個數。⑸RIGHT運算符RIGHT運算符返回的是左端字符串X,從右邊取出Y個字符組成的子串。語法格式是:X:RIGHT:Y
其中X是源字符串;Y是一個整數,表示從右側取出字符的個數。⑹CC運算符CC運算符是將其左端和右端的2個字符連接為一個長的字符串,X在前,Y在后。其語法格式是:X:CC:Y
其中X、Y均為字符串表達式。335.其他運算符和表達式⑴?運算符
?運算符返回代碼行所生成的可執(zhí)行代碼的字節(jié)長度。
語法格式如下:?行標號⑵DEF運算符
DEF運算符判斷是否定義了其后的符號。
語法格式如下::DEF
:X如果符號X已經定義,其值為真,否則為假。注意:目前在集成開發(fā)環(huán)境ADS1.2中,也支持對C語言環(huán)境下的部分操作符和表達式的應用,或者說與GNU開發(fā)環(huán)境下使用基本相同的操作符與表達式。344.1.7Linux操作系統(tǒng)中GNU開發(fā)環(huán)境下的偽指令在上面介紹的偽指令都是在Windows操作系統(tǒng)中,ADS集成開發(fā)環(huán)境里使用的偽指令,它們也被稱為標準的ARM偽指令。在Linux操作系統(tǒng)中,GNU開發(fā)環(huán)境下的偽指令與ADS中具有相同的作用,但是它們的書寫格式是有區(qū)別的。目前在ARM的產品開發(fā)中,引入Linux操作系統(tǒng)的產品較多,因此本節(jié)以比較的方法介紹GNU環(huán)境下的偽指令,加快讀者對其偽指令的理解和掌握。351.內存分配偽指令
GNU開發(fā)環(huán)境下有更多的內存分配偽指令,下表列出了最常用到的大部分偽指令,要知道更多的內容請參見有關GNU環(huán)境下的偽指令。ADS偽指令GNU偽指令GNU偽指令語法格式功能簡述EQU/SETX.equ/.set.equsymbol,expr定義symbol的值是exprDCB.byte/.ascii.byteexpr{,expr}…定義字節(jié)數據單元DCW.hword/.short.shortexpr{,expr}…定義半字數據單元DCD.word/.long/.int.longexpr{,expr}…定義字數據單元DCQ.quad.quadexpr{,expr}…定義8字節(jié)數據單元DCFS.float/.single.floatexpr{,expr}…定義單精度數單元DCFD.double.doubleexpr{,expr}…定義雙精度數單元SPACE.zero.zerosize分配size字節(jié)單元,初始化為0LTORG.ltorg/.pool.ltorg聲明緩沖池SPACE.space/.skip.spacesize{,value}與zero基本相同,填充值是value注意:表里的SETX代表ADS下的SETA、SETL、SETS偽指令。362.匯編控制偽指令匯編控制偽指令主要有條件編譯控制偽指令和宏定義偽指令。與ADS環(huán)境下的偽指令區(qū)別請仔細觀察注釋字段。⑴條件編譯控制偽指令.ifGNU環(huán)境下的.if偽指令也是根據表達式值的真與假,決定是否要編譯它下面的代碼,用.endif偽指令作為條件控制偽指令的結束,中間可以使用.else偽指令進行分支選擇。它的指令格式豐富,形式是多種多樣的。以下進行簡要介紹:.ifdefsymbol/*與ADS偽指令IF:DEF:symbol功能相同*/
指令序列1
@如果symbol以定義,則匯編指令序列1.else
/*與ADS偽指令ELSE功能相同*/
指令序列2.endif
/*與ADS偽指令ENDIF功能相同*/注意:在GNU環(huán)境下的匯編語句注釋使用符號“@”開頭到本行結束,或與C語言使用相同的注釋符:
/*語句說明*/。37⑵.macro、.exitm與.endm偽指令宏定義體的作用在前面已經講述,以下是在GNU環(huán)境下的宏體定義語法格式。.macro/*與ADS偽指令MACRO功能相同*/\標號:宏體名\參數1,\參數2…
指令序列1
.exitm@需要跳出宏體時使用這條偽指令。對應ADS下的偽指令MEXIT
指令序列2.endm/*與ADS偽指令MEND功能相同*/
關于宏的調用與前述相同。在ADS集成開發(fā)環(huán)境中使用符號“$”表示宏變量,在GNU環(huán)境下使用符號“\”表示宏變量。383.匯編程序控制偽指令
GNU環(huán)境下的匯編程序控制偽指令同樣也很豐富,以下也是通過比較的方法將它們列于下表中。ADS偽指令GNU偽指令語法格式功能簡述包含在段定義中.section.sectionsection_name定義域中包含的段無.type.typesymbol,description指定符號類型(對象或函數)定義碼段的字串.text.text{subsection}聲明一個代碼段定義數據段的字串.data.data{subsection}聲明一個初始化數據段無.bss.bss{subsection}聲明一個未初始化數據段CODE16.code16/.thumb.code16/.thumb聲明以下代碼是Thumb指令CODE32.code32/.arm.code32/.arm聲明以下代碼是ARM指令ALIGN.align/.balign.align{expt}聲明對齊方式INCLUDE.include.includefilename在當前文件中引用filenameEXPORT.global/.globl.globalsymbol聲明標號,在其它文件中使用IMPORT.extern.externsymbol聲明外部標號在當前文件使用END.end.end匯編結束RN.reg.regalias,Rn定義通用寄存器別名有特用394.2ARM匯編語言程序設計程序是由指令組成的,要編寫好程序其一就是要掌握指令的功能與使用方法,其二就是要熟悉匯編語言的程序結構等。在此基礎上,熟悉程序實現中使用的算法、控制過程與步驟,復雜時畫好程序的流程圖,然后進行程序的編寫。評價一個程序的好壞,就是在實現預先規(guī)定的運算或控制過程功能的前提下,一是程序占用的存儲空間最小,即使用的指令條數最少;二是代碼的運行速度最快。但這兩者又是很難同時滿足,往往取一個折中的實現方案。本節(jié)主要介紹與之相關的主要內容。404.2.1ARM匯編中的源文件類型
在ARM的程序設計中,必不可少的部分使用匯編語言編寫,大部分程序使用C/C++語言開發(fā),常用的源文件如下表所列。源程序文件文件類型后綴說明匯編程序文件*.s或*.S用匯編語言編寫的ARM程序或Thumb程序匯編頭文件*.a或*.A使用偽指令定義的端口地址、內存分配等內容C程序文件*.c或*.C使用C語言編寫的程序代碼C程序頭文件*.h或*.H使用預處理命令定義的常量、宏體,函數的聲明等414.2.2ARM匯編語言的語句格式1.基本語句格式ARM(Thumb)匯編語言的語句格式為:{標號} {指令或偽指令} {;注釋}規(guī)則:如果一條語句太長,可將其分為若干行來書寫,在行的尾部用續(xù)行符“\”來標識下一行與本行為同一條語句。
每一條指令助記符可以全部用大寫、或全部用小寫,但不能在一條指令中大、小寫混用。注意:在使用ADS1.2編輯ARM程序時,書寫標號一定要頂格,在指令前如果沒有標號時指令一定要退格書寫。由于ADS環(huán)境下標號后沒有冒號“:”,ADS是通過頂格來區(qū)分標號和ARM指令的。422.匯編語言程序中常用的符號
在匯編語言程序設計中,可以使用各種符號代替地址、變量和常量等,以增加程序的可讀性。以下為符號命名的約定:
符號名不應與指令或偽指令同名。
符號在其作用范圍內必須唯一。
符號區(qū)分大小寫,同名的大、小寫符號被視為兩個不同的符號。
自定義的符號名不能與系統(tǒng)保留字相同。3.程序中的常量
程序中的常量是指其值在程序的運行過程中不能被改變的量。ARM(Thumb)匯編程序所支持的常量有邏輯常量、數字常量和字符串常量。
數字常量一般為32位的整數,無符號常量取值范圍為0~232-1,有符號常量取值范圍為-231~231-1。
邏輯常量只有兩種取值:真(True)或假(False)。
字符串常量為一個固定的字符串,一般用來提示程序運行時的信息。435.程序中的變量代換
程序中的變量可通過代換操作取得一個常量。代換操作符為“$”。如果“$”在數字變量前面,編譯器會將該數字變量的值轉換為十六進制的字符串,并將該十六進制的字符串代換“$”后的數字變量。ARM中的常量使用EQU定義,ARM中使用GBLA、GBLL、GBLS定義全局變量,使用LCLA、LCLL、LCLS定義局部變量,使用SETA、SETL、SETS為它們賦值。例如:
GBLSSTR1
GBLSSTR2
STR1
SETS
”pen”
STR2SETS“Thisisa$STR1"編譯后的結果是STR2的值為Thisisapen.444.2.3ARM匯編語言的程序結構ARM匯編語言程序是以段(Sectoin)為單位組織源文件的。段是相對獨立的、具有特定名字的、不可分割的指令序列或數字序列。段可以分為代碼段和數據段,代碼段的內容為執(zhí)行代碼,數據段存放代碼段運行時需要用到的數據。一個匯編程序至少應該有一個代碼段,也可以分割為多個代碼段和數據段,多個段在程序編譯鏈接時最終形成一個可執(zhí)行的映象文件(*.elf)。可執(zhí)行映象文件通常由以下幾部分構成:
一個或多個代碼段,代碼段的屬性為只讀。
零個或多個包含初始化數據的數據段,數據段的屬性為可讀寫。
零個或多個不包含初始化數據的數據段,數據段的屬性為可讀寫。匯編連接器根據系統(tǒng)默認或用戶設定的規(guī)則,將各個段安排在存儲器中的相對位置,因此源程序中段之間的相對位置與可執(zhí)行的映像文件中段的相對位置一般不會相同。ARM匯編程序結構分為基于Windows環(huán)境下ADS匯編語言程序設計結構和Linux環(huán)境下GNU匯編語言程序設計結構,以下分別介紹。451.基于Windows環(huán)境下ADS的匯編語言程序結構
ADS環(huán)境下的ARM匯編語言程序結構與GNU環(huán)境下的匯編語言程序結構大體相同,整個程序也是以段為單元來組織代碼。其語法規(guī)則總結如下:
所有標號必須在一行的頂格書寫,其后不要添加“:”號。
所有的指令均不能頂格寫。
大小寫敏感(可以全部大寫或全部小寫,但不能大小寫混合使用)。
注釋使用分號“;”。應用示例:AREAInit,CODE,READONLYENTRYstartLDRR0,=0x3FF5000;使用偽指令LDR將立即數0x3FF5000→R0
LDRR1,[R0]
;讀R0地址單元內容→R1
LDRR0,=0x3FF5004;使用偽指令LDR將立即數0x3FF5004→R0
LDRR2,[R0]
ADDR3,R2,R1;R3←R2+R1
LDRR0,=0x3FF5008;使用偽指令LDR將立即數0x3FF5008→R0STRR3,[R0]
;R3的內容寫入R0內容作為字地址的存儲單元中
END
;標識匯編源程序結束,其后如果還有內容將會被忽略。在ADS環(huán)境中,使用偽指令AREA定義一個段,并說明定義段的屬性。本例定義了一個段名為Init的代碼段CODE,屬性為只讀READONLY;ENTRY偽指令標識程序的入口點;start為程序標號,必須頂格書寫;462.基于Linux環(huán)境下GNU的匯編語言程序結構Linux環(huán)境下GNU的匯編語言規(guī)則總結如下:
所有標號必須在一行的頂格書寫,并且其后必須添加“:”號;
所有的指令均不能頂格寫;
大小寫敏感(可以全部大寫或全部小寫,但不能大小寫混合使用);
注釋使用符號“@”或使用C語言的/*注釋內容*/注釋符。(注釋的內容由“@”號起到此行結束,注釋可以在一行的頂格書寫)。應用示例:.text@表示為只讀代碼段_start:.globalstart@_start作為連接器使用。在GNU環(huán)境下,必須在這使用此標號.globalmain@聲明全局標號main,在其它程序中調用,在C中就是調用的main函數
bmain@跳轉到main函數main:
movr0,#0/*使用mov指令將立即數0送r0*/
ldrr1,=0x01/*使用ldr偽指令將立即數0x01送r1*/addop:addr2,r1,r0@r2=r1+r0
movpc,lr@返回pc處
.end/*.end匯編結束偽指令*/473.ADS與GNU環(huán)境下程序代碼的比較與移植
在ADS環(huán)境下的匯編代碼與GNU環(huán)境下的匯編代碼有較多的不同點,主要是符號與偽指令的不同,ARM指令的格式是基本相同的。掌握了它們之間的不同點,將會更好地進行它們之間的代碼移植。下表列出了在兩個環(huán)境下常用的偽指令的對應關系。ADS偽指令GNU偽指令ADS偽指令GNU偽指令INCLUDE.includeALIGN.alignTCLK2EQU30.equTCLK2,30MACRO.macroEXPORT.globalMEND.endmIMPORT.externEND.endDCD.long/.intAREAx,CODE,READONLY.textIF:DEF:.ifdefAREAy,DATA,READWRITE.dataELSE.elseCODE32.armENDIF.endifCODE16.thumb:AND:<ORG.ltorg:SHL:<<SPACE.zeroRN.regENTRY.entryGLBA.globalldrpc,[pc,#&10]ldrpc,[pc,#0x10]BUSWIDTHSETA16.equBUSWIDTH,16ldrpc,[pc,#&-10]ldrpc,[pc,#-0x10]483.ADS與GNU環(huán)境下程序代碼的比較與移植(續(xù))注意:ADS環(huán)境下的操作符與表達式在4.1.6節(jié)已經介紹;GNU環(huán)境下的操作符有:“~”表示取數的補碼,“-”表示取負,只有“<>”表示不等于,其它的符號如+、-、*、/、%、<、<<、>、>>、|、&、^、!、==、>=、<=、&&、||,與C語言中的用法相似。實際上,目前GNU環(huán)境下的許多操作符和表達式在ADS環(huán)境下也可以使用,以后將會看到。494.3ARM匯編語言與C語言混合編程在ARM的應用系統(tǒng)中,匯編語言編程主要用于系統(tǒng)的啟動與初始化,之后通過調用C語言main()函數后基本進入C語言的編程模式,關鍵涉及到的是它們在各自環(huán)境中定義的標號(在C語言中可以是一個函數)、變量、函數之間的相互使用問題。匯編語言和C/C++的混合編程通常有以下幾種方式:①在匯編語言程序中調用C程序。②在C語言程序中調用匯編程序。③在C語言程序中內嵌匯編語句。④在匯編語言程序中訪問C語言程序變量。504.3.1基本的ATPCS基本的ATPCS(ARMThumbProcedureCallStandard)規(guī)定了在混合編程時子程序調用的一些基本規(guī)則,主要有:寄存器的使用;堆棧的使用;參數傳遞;子程序結果的返回等方面的規(guī)則。511.寄存器的使用規(guī)則①程序通過寄存器R0~R3來傳遞參數,此時這些寄存器可以記作A0~A3,被調用的子程序在返回前無需恢復寄存器R0~R3的內容。②在子程序中使用R4~R11來保存局部變量,此時這些寄存器可以記作V1~V8。③寄存器R12用作子程序間scratch寄存器,記作ip,在子程序的連接代碼段中經常會有這種使用規(guī)則。Scratch寄存器用于保存SP寄存器,在函數返回時使用該寄存器出棧。④寄存器R13用作數據棧指針,記做SP,在子程序中寄存器R13不能用做其他用途。⑤寄存器R14用作連接寄存器,記作LR,它用于保存子程序的返回地址。⑥寄存器R15是程序計數器,記作PC,它不能用作其他用途。⑦ATPCS中的各寄存器在ARM編譯器和匯編器中都是預定義的。522.堆棧的使用規(guī)則堆對棧指針通??梢灾赶虿煌奈恢茫绻斍岸褩V羔樦付ǖ膯卧写嬖谟行祿r,稱為FULL棧(滿棧)。如果當前堆棧指針指定的單元中不存在有效數據時,稱為Empty棧(空棧)。堆棧的增長方向也可以不同,當堆棧向內存減小的地址方向增長時,稱為Descending棧(遞減棧);反之稱為Ascending棧(遞增棧)。注意:ATPCS規(guī)定堆棧使用FD(滿棧遞減型)類型,并要求堆棧的操作是8字節(jié)對齊的。也就是說在應用系統(tǒng)的程序設計中,均使用的是該種類型的堆棧。533.參數的傳遞規(guī)則根據參數個數是否固定,可以將子程序分為參數個數固定的子程序和參數個數可變的子程序,這兩種子程序的參數傳遞規(guī)則是不同的。
第一,參數個數可變的子程序參數傳遞規(guī)則。對于參數個數可變的子程序,當參數不超過4個時,可以使用寄存器R0~R3來傳遞參數;當參數個數超過4個時,可以使用堆棧來傳遞參數。
第二,參數個數固定的子程序參數傳遞規(guī)則。對于參數個數固定的子程序,參數傳遞與參數個數可變的子程序參數傳遞規(guī)則不同。如果系統(tǒng)包含浮點運算的硬件部件,浮點參數將按照下面的規(guī)則傳遞:各個浮點參數按順序處理;為每個浮點參數分配FP寄存器;分配的方法是,滿足該浮點參數需要的且編號最小的一組連續(xù)的FP寄存器。第1個整數參數通過寄存器R0~R3來傳遞,其他參數通過堆棧來傳遞.544.子程序結果返回規(guī)則結果為一個32位的整數時,可通過寄存器R0返回。結果為一個64位整數時,可以通R0和R1返回,依此類推。結果為一個浮點數時,可以通過浮點運算部件的寄存器f0,d0或者s0來返回。結果為一個復合的浮點數時,可以通過寄存器f0-fN或者d0~dN來返回。對于位數更多的結果,則需要通過調用內存來傳遞。554.3.2匯編語言程序調用C語言程序在匯編語言中調用C語言,需要使用IMPORT對C函數進行說明;然后將C的代碼放在一個獨立的C文件中進行編譯,剩下的工作由連接器完成。應用示例:該項目由1個匯編語言文件和1個C語言文件組成,以下是它們的代碼內容。1.匯編語言文件:
AREAasmfile,CODE,READONLY
IMPORTcFun;聲明在C語言中定義的函數
ENTRY
;匯編程序入口
MOVR0,#0;傳遞函數cFun第1參數
MOVR1,#1;傳遞函數cFun第2參數
MOVR2,#2;傳遞函數cFun第3參數
blcFun;調用C語言函數
MOVR3,R0;將調用C語言函數的結果保存在R3中
END
;匯編結束偽指令562.C語言文件/*Cfile,calledbyasmfile*/intcFun(inta,intb,intc)/*C語言函數定義,形參分別對應R0、R1、R2寄存器*/{returna+b+c;}注意:在匯編語言程序中聲明C語言函數時只使用函數名,C語言中的函數名是一個常量地址;由于C語言中函數使用的形參是整型變量,所以在匯編語言傳遞參數時使用的是寄存器,即對應于寄存器尋址;這里的參數傳遞是利用寄存器R0~R2。需要指出的是當函數的參數個數大于4時就要借助于堆棧。57
4.3.3C語言程序中調用匯編語言程序在匯編程序中使用EXPORT偽指令聲明程序(是一個標號),使得本程序可以被其他的程序調用;在C語言中使用EXTERN關鍵詞聲明該匯編程序,這樣就可以在C中使用該函數了。從C的角度,并不知道該函數的實現是用C語言還是匯編語言。應用示例:該項目由1個C語言文件和1個匯編語言文件組成,以下是它們的代碼內容。581.C語言文件#include<stdio.h>
externvoidasm_strcpy(constchar*src,char*dest);/*將匯編語言中的子程序聲明為C語言函數*/intmain(){constchar*s=“hello,world!”;chard[32];asm_strcpy(s,d);/*調用聲明的函數*/printf(“source,%s”,s);printf(“destination:%d”,d);return0;}2.匯編語言文件AREAasmfile,CODE,READONLY;定義一個名為asmfile的代碼段EXPORTasm_strcpy;聲明匯編程序標號,在C語言中可以調用并且將作為一個函數名asm_strcpy;匯編程序入口標號,C語言中的程序名loopldrbr4,[r0],#1;r0在C函數中作為第1個參數。r4←[r0],r0←r0+1cmpr4,#0beqover;如果是字符串結尾,eq=1,程序跳轉到標號over處strbr4,[r1],#1;r1在C函數中作為第2個參數。[r0]←r4,r1←r1+1bloopovermovpc,lr;pc←lr,子程序返回END594.3.4C語言程序中內嵌匯編語言程序在C程序中內嵌的匯編指令支持大部分的ARM和Thumb指令,不過其使用與匯編文件中的指令有些不同,存在一些限制,主要有下面幾個方面:①不能直接向PC賦值,程序跳轉要使用B或者BL指令;②在使用物理寄存器時,不要使用過于復雜的C表達式,避免物理寄存器沖突;③R12和R13可能被編譯器用來存放中間編譯結果;④一般不要直接指定物理寄存器,而讓編譯器進行分配;601.內嵌匯編語言標記內嵌匯編語言標記是__asm或者asm關鍵字,用法如下:__asm{
指令1[;注釋]……
指令n}
或:在關鍵字asm后使用圓括號“()”將關鍵字為__asm中的花括號“{}”代換也可。2.應用示例#include<stdio.h>voidmy_strcpy(constchar*src,char*dest)/*定義字符串拷貝函數*/{charch;/*定義字符串變量,在匯編中有系統(tǒng)指定寄存器替換*/__asm/*使用內嵌匯編關鍵字*/{loopldrbch,[src],#1;src寄存器間接尋址,編譯時系統(tǒng)指定R0。ch←[src],src←src+1
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 經營酒吧合同
- 股份制改革流程文書模板與指導
- 汽車美容店合作協議書年
- 委托培訓協議書
- 質量管理體系培訓指導書
- 2025年青海貨運從業(yè)資證孝試模似題庫
- 小學三年級數學加減乘除混合口算
- 2025年黔東南道路貨運駕駛員從業(yè)資格證考試題庫
- 2025年上海貨車叢業(yè)資格證考試題
- 2025年汕頭貨運從業(yè)資格證怎么考試
- (一模)寧波市2024學年第一學期高考模擬考試 數學試卷(含答案)
- 攝影入門課程-攝影基礎與技巧全面解析
- 冀少版小學二年級下冊音樂教案
- 【龍集鎮(zhèn)稻蝦綜合種養(yǎng)面臨的問題及優(yōu)化建議探析(論文)13000字】
- 父母贈與子女農村土地協議書范本
- 《師范硬筆書法教程(第2版)》全套教學課件
- 中國聯通H248技術規(guī)范
- 集團母子公司協議書
- 孫權勸學省公共課一等獎全國賽課獲獎課件
- DL-T-692-2018電力行業(yè)緊急救護技術規(guī)范
- 2024年杭州錢塘新區(qū)建設投資集團有限公司招聘筆試沖刺題(帶答案解析)
評論
0/150
提交評論