? ??按照編譯器不同愧口,匯編分為兩大量:一類是ADS的匯編程序舞虱,一類是GNU匯編格式任欢际。
? ??以冒號結(jié)尾的標識符都被認為是一個標號,而不一定非要在一行的開始矾兜。
? ? GNU匯編:http://web.mit.edu/gnu/doc/html/as_toc.html#SEC127
一损趋、ARM指令? (帶點的一般都是ARM GNU偽匯編指令)
? ? ? ? 1. ".title xxx":指定匯編列表的標題。
????????????".list":用來輸出列表文件椅寺。
????????????".type xxx":指定符號的類型浑槽。
? ? ? ? 2. ".text":代碼段蒋失。已編譯程序的可執(zhí)行機器碼。
? ? ? ? ? ? ".rodata":只讀數(shù)據(jù)段括荡。const全局變量高镐。比如printf語句中的格式串和開關(guān)(switch)語句的跳轉(zhuǎn)表。
????????????".data":數(shù)據(jù)段畸冲。已初始化的非零全局變量和靜態(tài)變量嫉髓。它會在main函數(shù)之前被處理。
????????????".bss":未初始化(或初值為0)的全局變量邑闲。它在目標文件中不占實際的空間(不保存在bin文件中)算行,是一個占位符。目標文件格式區(qū)分初始化和未初始化變量是為了提高空間效率苫耸。啟動代碼完成兩方面:①未初始化變量的清0州邢。②設(shè)置已初始化變量的初值。保存了BSS段和COMMON段(存放注釋)的內(nèi)容褪子。
? ? ? ? ? ??".symtab":符號表量淌。存放被定義和引用的函數(shù)及全局變量。每個可重定位目標文件在.symtab中都有一張符號表嫌褪。與編譯器中的符號表不同呀枢,.symtab不包含局部變量的表目。不一定要通過-g編譯程序笼痛,得到符號表信息裙秋。
? ? ? ? ? ? 注釋:為了讓啟動代碼簡單,編譯鏈接器會把已初始化的變量放.data段缨伊,這個段的映像(包含了各個變量的初值)保存在“只讀數(shù)據(jù)段”摘刑。啟動代碼復(fù)制這個映像到 .data 段,初始化所有變量刻坊。初始化為0的變量保存在bss段枷恕,未初始化變量保存在common段,鏈接時再將其放入bss段紧唱。啟動代碼調(diào)用 memset 把所有未初始化變量清0活尊。
????????????".rel.text":保存著一系列在.text中的位置的列表。這些位置在鏈接時被修改漏益。這些位置通常保存著引用全局變量,或外部函數(shù)的指令深胳。在運行時并不需要它以及下面的.rel.data绰疤。生成可執(zhí)行文件ELF object時會去掉。除非使用者去顯式指示鏈接器包含這些信息舞终。
????????????".rel.data":保存全局變量的重定位信息轻庆。如果一個全局變量的初始化值癣猾,是另一個全局變量的地址,或者是外部函數(shù)的地址時余爆,它就需要被重定位纷宇。
? ??????????".debug":調(diào)試符號表。其可以是程序中定義的:局部變量蛾方、類型定義像捶、全局變量的定義和引用、C源文件桩砰。只有" -g "選項才會生成這張表拓春。
????????????".line":源程序中的行號和.text中機器指令間的映射。只有以-g選項調(diào)用編譯驅(qū)動程序時才會生成亚隅。
? ? ? ? ? ? ".strtab":字符串表硼莽。包含.symtab和.debug中的符號表,和各個section的名字煮纵。字符串表是以null結(jié)尾的字符串序列懂鸵。.debug和.symtab中,保存name的域行疏,等于保存了一個偏移值匆光。可以通過這個偏移值在字符串表里面找到相應(yīng)字符串隘擎。(https://www.veryarm.com/23019.html)
? ? ? ? 3. ".section":自定義一個段殴穴。.section section_name [, "flags"[, %type[,flag_specific_arguments]]]。每一個段以段名為開始, 以下一個段名或者文件結(jié)尾為結(jié)束货葬。這些段都有缺省的標志(flags),連接器可以識別這些標志采幌。(與armasm中的AREA相同)。
? ? ? ? 4. 注釋:代碼行中的注釋符號: ‘@’震桶。整行注釋符號: ‘#’休傍。語句分離符號: ‘ ; ’。直接操作數(shù)前綴: ‘#’ 或 ‘$’蹲姐。
? ? ? ? 5. "_start":匯編程序的缺省入口磨取。如果想更改,到相應(yīng)的鏈接腳本中去用ENTRY指明其他入口標志柴墩。標號可以直接認為是地址忙厌。
? ? ??? 6. ".globl/.global":定義一個全局符號,通常為ld使用江咳。例如 .global _start(定義 _start 為外部程序可以訪問的標簽)逢净。
? ? ? ??7. ".abort":停止匯編。
? ??????8.?".string/.asciz/.ascii"、".byte"爹土、".short"甥雕、".int"、".long"胀茵、".float"社露、".word"、".quad":定義一個類型并分配空間(字符串琼娘、字節(jié)(1 byte)峭弟、短整型(2 byte)、整型(4 byte)轨奄、長整型(4 byte)孟害、浮點數(shù)、字(與系統(tǒng)位數(shù)有關(guān)挪拟。16位系統(tǒng)中是2字節(jié))挨务、quard word(4字))。用".string/.asciz"定義時要加雙引號玉组,用".ascii"定義時還要在末尾手動添加"\0"谎柄。
? ? ? ? 9. ".align?xxx, yyy":對齊方式。xxx表示對齊方式惯雳,4, 8,16或32朝巫。 yyy?表示填充的值。一般用于定義完字符串等類型之后的代碼對齊石景。
? ? ? ? 10. ".if" ".else" ".endif":條件預(yù)編譯劈猿。if的變種如下:
? ? ? ? 11. ".include "file" ":包含指定文件〕蹦酰可以把匯編常量定義放在頭文件中揪荣。
? ? ? ? 12. ".incbin "file"[,skip[,count]]":將二進制文件編譯到當(dāng)前文件中。skip是以字節(jié)為單位往史,從文件頭部讀取的偏移量仗颈。count是讀取的字數(shù)。
? ? ? ? 13. ".macro .endm":.macro定義的宏代碼的開始, .endm宏代碼的結(jié)束,.exitm跳出宏椎例。若宏使用參數(shù)挨决,則宏體中使用該參數(shù)時添加前綴“\”。宏定義時的參數(shù)還可以使用默認值订歪。
? ? ? ? 14. ".comm symbol, length":在bss段申請一段叫symbol的命名空間脖祈,長度為length。Ld連接器連接時會為它留出空間刷晋。
? ? ? ? 15. ".rept x":重復(fù)定義x次其內(nèi)的定義撒犀。用 .endr結(jié)束福压。
? ? ? ? 16. "(.equ/.set) xxx, yyy":把符號定義成值掏秩。它不分配空間或舞,相當(dāng)于#define∶苫茫或者用“ xxx equ yyy ”映凳。
? ? ? ? 17. ".req":為寄存器定義別名。
? ? ? ? ? ? ? ".unreq":取消寄存器別名邮破。
? ? ? ? 18. ".code":.code [16|32]: 指定指令代碼產(chǎn)生的長度, 16表示Thumb指令, 32表示ARM指令诈豌。
? ? ? ? 19. ".ltorg/.pool":當(dāng)前往下的定義在歸于當(dāng)前段,并為之分配空間。即聲明數(shù)據(jù)緩沖池抒和。
? ? ? ? 20. ".space <x> {,<aaa>}":分配x字節(jié)空間矫渔,并用aaa填充。缺省填充0摧莽。
二庙洼、進制的表示
? ? ? ? 1. 二進制數(shù)以0b開頭,其中字母也可以為大寫
? ? ? ? 2. 八進制數(shù)以0開始,如:0456,0123
? ? ? ? 3. 十進制數(shù)以非0數(shù)字開頭,如:123和9876
? ? ? ? 4. 十六進制數(shù)以0x開頭,如:0xabcd,0X123f
? ? ? ? 5. 字符串常量用引號括起來,中間也可以使用轉(zhuǎn)義字符镊辕。如: “You are welcome!\n”
? ? ? ? 6. 當(dāng)前地址以" . "表示
? ? ? ? 7. 表達式:匯編程序中表達式可使用常數(shù)或數(shù)值油够。" - "取負數(shù), " ~ "取補征懈," < > "不相等石咬," +、-卖哎、*鬼悠、 /、%亏娜、<焕窝、<<、>照藻、>>袜啃、|、&幸缕、^群发、!、==发乔、>=熟妓、<=、&&栏尚、|| "跟C語言用法相似起愈。
三、操作寄存器
? ? ? ? "ldr? ? r0,? ??[ r1 ]":讀取地址 [ r1 ] 上的數(shù)據(jù),并保存到?R0 寄存器中抬虽,長度為4字節(jié)官觅。(方括號內(nèi)的表示地址)
? ? ? ? "ldr? ??r0,? ??[ r1, #4 ]":將地址為 r1+4 的內(nèi)存單元數(shù)據(jù)讀取到 r1 中。
? ??????"ldr? ??r0,? ??[ r1 ],????#4:將地址為?[ r1 ]?的內(nèi)存單元數(shù)據(jù)讀取到 r0 中阐污,然后 r1 = r1+4休涤。
? ? ? ? ★.在32位ARM指令中會用某些位表示當(dāng)前執(zhí)行的指令(LDR等)及寄存器(R0等)。剩下的位數(shù)不足以表示任意值笛辟,所以引入偽指令功氨。偽指令會被拆分成ARM指令。
????????ldr 偽指令的三種用法:
????????????????①. ldr r0, = 0x10:給 r0 賦值為0x10手幢。
? ? ? ? ? ? ? ? ②.?ldr?pc, =Label:將?Label?符號放入pc寄存器中捷凄。編譯時會替換成一條 ldr 指令和一條 dcd 偽指令。符號地址由編譯器指定围来。
? ? ? ? ? ? ? ? ③.?ldr?pc,?Label_addr:讀取存儲器中 Label_addr 符號所表示的地址中的值放入 pc 跺涤。多讀一次存儲器。
? ? ? ? "str? ? r0,? ??[ r1 ]":把 r0 寄存器上的值管钳,保存到地址 [ r1 ] 的地方钦铁,長度為4字節(jié)。
? ? ? ? "str? ??r0,? ??[ r1, #4 ]":將 r0 的數(shù)據(jù)保存到地址為 r1+4 的內(nèi)存單元中才漆。
? ? ? ? "str????r0,????[ r1 ],????#4":將 r0 的數(shù)據(jù)保存到地址為 r1 的內(nèi)存單元中牛曹,然后 r1=r1+4。
? ? ? ? "ldmia? ??r0,? ??{ r1, r2, r3, r4 }??/??stmdb? ??r0!,? ??{ r1, r2, r3, r4 }":一次設(shè)置多個寄存器醇滥。后增黎比,即先操作后增加。32位芯片的話鸳玩,增加/減少的單位是4阅虫。按寄存器編號依次操作寄存器,高編號寄存器存放在高地址不跟。(ld/st) + m + (i/d/f/e) + (a/b) = (讀取/設(shè)置)+ 多個寄存器 +(增加/減少/滿/空)+(之后/之前)颓帝。"?!?"表示此寄存器的值等于最終被修改后的值。否則最終值等于初始值窝革。ldm命令末尾的"?^?"表示將spsr寫回到cpsr购城,用于異常返回后工作狀態(tài)的恢復(fù),不允許在用戶模式和系統(tǒng)模式下運行虐译。
????????當(dāng)堆棧指針指向最后壓入的數(shù)據(jù)時為滿堆棧瘪板,當(dāng)指針指向下一個將要放入數(shù)據(jù)的空位置時為空堆棧。當(dāng)堆棧由低地址向高地址生成時稱遞增堆棧漆诽,當(dāng)堆棧由高地址向低地址生成時稱遞減堆棧侮攀。下列是入棧和出棧的指令對:
????????????????Full descending :????stmdb--ldmia? 或? stmfd--ldmfd??
????????????????Full ascending :? ????stmib--ldmda? 或? stmfa--ldmfa??
????????????????Empty descending :stmda--ldmib? 或? stmed--ldmed??
????????????????Empty ascending :? stmia--ldmdb? 或? stmea--ldmea??
? ? ? ? 注意:雖然ARM處理器核對于兩種生長方式的堆棧均支持锣枝,但ADS的C語言編譯器僅支持一種方式,即從上往下長兰英,并且必須是滿遞減堆棧撇叁。所以STMFD等指令用的最多。
? ? ? ? "adr? ??r0,? ??xxx":將基于PC相對偏移的地址值讀取到 r0箭昵。編譯時ADR偽指令會被替換税朴。通常是用ADD或SUB指令。若不能用一條指令實現(xiàn)家制,則會產(chǎn)生錯誤,編譯失敗泡一。
? ? ? ? "mrs? ??r1,? ??cpsr":讀出 cpsr 中的值到 r1 中颤殴。
? ? ? ? "msr? ??cpsr,? ??r1":將 r1 寄存器中的值恢復(fù)到 r1 中。
? ? ? ? "swi? ? xxx":執(zhí)行軟中斷鼻忠。xxx 為24位的二進制數(shù)涵但,表示處理不同軟中斷。
? ? ? ??"mov? ? R0,? ? R1":把 R1 的值賦給 R0 帖蔓。
? ? ? ? "mov? ? R0,? ? [ R1 ]":把 R1 地址的值賦給 R0 矮瘟。
????????"mov? ? R0,? ? #0x10":把立即數(shù)?0x10 賦給 R0 。立即數(shù)是小于0xff(65535)的數(shù)塑娇,如果大于65535澈侠,則用ldr指令賦值。
? ? ? ? "mvn????r0,????#0":把0取反(即-1)傳給 r0埋酬。
? ? ? ? 注意:ARM是RISC結(jié)構(gòu)哨啃,數(shù)據(jù)在內(nèi)存和CPU間的移動只能通過ldr/str指令。mov只是在寄存器間移動數(shù)據(jù)写妥,或把立即數(shù)移動到寄存器中拳球。而X86中沒有l(wèi)dr這種指令。因為X86的mov指令可以將數(shù)據(jù)從內(nèi)存中移到寄存器中珍特。
? ? ? ??"nop":空操作指令祝峻。可以用作延時扎筒。
????????"add? ? r0,? ? r1,? ? r2":r0 = r1 + r2莱找。
????????"adds????r0,????r1,????r2":r0 = r1 + r2。s表示把進位結(jié)果寫入cpsr砸琅。sub同理宋距。
????????"sub? ? r0,? ? r1,? ? r2":r0 = r1 - r2。
? ? ? ? "mul ?? r0,????r1,????r2": r0 = r1 * r2症脂。
<opcode>{<cond>}{S}?<Rd>,<Rn>{,<shifter_operand>}
????????對shifter_operand參數(shù)的位移谚赎。
? ? ? ? 左右移:http://www.eeworld.com.cn/mcu/2015/0930/article_22693.html
????????"tst????r0, ?? r1":位比較淫僻。先按位與并把結(jié)果寫入CPSR,供下一句使用壶唤。結(jié)果為1雳灵,則設(shè)置標志位zero=0,會執(zhí)行bne語句闸盔。否則不執(zhí)行bne悯辙。beq則相反。
? ? ? ? "cmp? ? xxx,? ? yyy":兩值相減迎吵,只改標志位躲撰。標志位存入CPSR供下一句語句使用。
????????(分支指令)
? ??????"b? ? xxx":簡單的跳轉(zhuǎn)击费,即調(diào)用子程序拢蛋。跳轉(zhuǎn)到到目標標號處執(zhí)行。跳轉(zhuǎn)范圍是當(dāng)前指令的前后32M蔫巩。
? ??????"bl? ? xxx":帶鏈接的程序跳轉(zhuǎn)谆棱,即要帶返回地址。跳轉(zhuǎn)前將當(dāng)前PC-4(返回地址)保存至R14(LR)圆仔。子程序返回時會執(zhí)行 MOV PC, LR垃瞧。跳轉(zhuǎn)范圍是當(dāng)前指令的前后32M。
? ??????"bx{<condition>}? <rx>":<condition>為指令執(zhí)行的條件碼坪郭,缺省時無條件執(zhí)行个从。<rx>寄存器中為跳轉(zhuǎn)的目標地址。當(dāng)<rx>寄存器bit[0]為0時截粗,目標地址處的指令為ARM指令信姓;當(dāng)bit[0]為1時,則為Thumb指令绸罗。(ARM匯編)
? ? ? ? 注意:反匯編文件里意推,用 B或BL 等跳某個值,只是方便查看珊蟀,并不是真的跳轉(zhuǎn)菊值。
????????(條件執(zhí)行指令)
? ??????"bne? ? xxx":數(shù)據(jù)跳轉(zhuǎn)指令,標志寄存器中Z標志位不等于零時育灸,跳轉(zhuǎn)到BNE后標簽處腻窒。
? ??????"beq? ? xxx":數(shù)據(jù)跳轉(zhuǎn)指令,標志寄存器中Z標志位等于零時磅崭,跳轉(zhuǎn)到BEQ后標簽處儿子。
? ??????注意:bne 1f,或beq 1b砸喻。1f:程序之后的"1"標號(forward)柔逼。1b:程序之前的"1"標號(before)蒋譬。
? ? ? ? ?bvs:? Branch if overflow(溢出) Set
? ? ? ? ?bvc:? Branch if overflow(溢出) Clear
??? ? ? ?bhi:? ?Branch if HIgher
? ? ?????bls:? ?Branch if Lower or the Same
? ? ? ???bpl:? ?Branch if Plus
? ???????bmi:? ?Branch if MInus
? ? ?????bcs:? ?Branch if Carry Set(進位設(shè)置)
? ? ? ???bcc:? ?Branch if Carry Clear(進位清除)
? ? ? ? ?bge:? ?Branch if Greater than or Equal
? ? ? ? ?bgt:? ?Branch if Greater Than
?????????ble:? ?Branch if Less than or Equal
? ???????blt:? ?Branch if Less Than
? ? ? ? ?bleq:? Branch with Link if Equal(帶返回鏈接的判斷型跳轉(zhuǎn))
? ? ? ? ?bllt:? Branch with Link if Less Than(帶返回鏈接的判斷型跳轉(zhuǎn))
? ??????"moveq? ? r1, #0":?如果上一句條件執(zhí)行碼<condition>判斷為相等,則執(zhí)行mov指令愉适。ARM匯編指令犯助。
? ??????"movgt? ??r1, #0":如果上一句條件執(zhí)行碼<condition>判斷左邊大,則執(zhí)行mov指令维咸。ARM匯編指令剂买。
? ? ? ? "and????r0,????r1":r0 &= r1。按位與癌蓖。
? ? ? ? "and????r0,????r1,????r2":r0 = r1 & r2瞬哼。
????????"orr????r0,????r1":r0 |= r1。按位或费坊。
????????"orr????r0,????r1, ?? r2":r0 = r1 | r2倒槐。
? ? ? ? "not ?? r0":r0 = ! r0。按位取反附井。指令的執(zhí)行不影響任何標志位。
? ? ? ? "bic ?? r0, ?? r1":r0 &= ~r1两残。按位清零永毅。
? ? ? ? "bic ?? r0, ?? r1, ?? #%1011":r0 = r1 & 4。%表示二進制人弓,0x表示十六進制沼死。
? ? ? ? "orn ?? r0, ?? r1":r0 = r0 | ~r1。按位或反崔赌。
? ? ? ? "eor ?? r0, ?? r1":r0 ^= r1意蛀。按位異或(不同為1,相同為0)健芭。
1县钥、注釋行以“@”代替“;”
2慈迈、偽操作符替換:INCLUDE 替換成 .INCLUDE
TCLK2 EQU PB25 替換成 .equ TCLK2, PB25
EXPORT 替換成 .global
IMPORT 替換成 .extern
DCD 替換成 .long
IF :DEF: 替換成 .IFDEF
ELSE 替換成 .ELSE
ENDIF 替換成 .ENDIF
:OR: 替換成 |
:SHL: 替換成 <<
END 替換成 .end
符號定義后要加":"號
AREA Word, CODE, READONLY --> .text
AREA Block, DATA, READWRITE --> .data
CODE32 --> .arm
CODE16 --> .thumb
LTORG --> .ltorg