GNU ARM 彙編基礎
ARM GNU彙編基礎
0 前言
全文補充提醒:
筆者在閱讀ARM官方文檔及查閱實際的u-boot源碼中的彙編代碼後,發現了一些不同於ARM官方文檔中的彙編語法,查閱相關資料後,才發現主要由於彙編器的不同,有兩種不同的彙編語法:
ARM標準彙編
- 彙編程序:armasm
GNU ARM彙編
- 彙編程序:as
兩者在語法上主要的區別在於偽操作的不同,其他相關的指令基本上是一致的,所以這一區別並不會對我們下文的學習造成太大的影響,為了方便,筆者通篇的示例均以GNU ARM彙編語法為標準,使用的彙編程序為arm-linux-gnueabihf-as.讀者如需學習ARM標準彙編相關知識,需自行參考ARM官方文檔 ARM Software Development Toolkit User Guide。
第二次補充提醒:
全文沒有過多的去關注和介紹所有的ARM指令,更多的關注點均在基礎語法和相關知識
全文內容大部分參考ARM官方文檔 ARM Software Development Toolkit User Guide第五章以及GNU文檔Using as,主要介紹了編寫ARM和Thumb彙編程序的通用準則。主要包含了以下章節:
- ARM架構概述
- 彙編語言的模塊結構
- 數據處理指令
- 內存訪問指令
- 條件執行
- 宏的使用
在開始之前,希望讀者能夠搭建好相應的開發環境(編譯工具鏈和運行環境),在此,筆者使用的是arm-linux-gnueabihf-交叉編譯工具鏈,為了能夠運行ARM程序,筆者使用的是QEMU,相關工具的下載和安裝在此不再詳述。
由於計算機最終只能識別機器碼,也就是二進制序列,所以彙編語言同其他語言一樣,需要相應的工具將其轉換成機器語言,這就需要前面提的編譯工具鏈,由於筆者的平台是X86架構,而編寫的是ARM架構上的程序,因此需要一個能夠執行ARM指令的設備,在這裡筆者使用的即前文提及的QEMU工具,由於筆者編譯的平台是X86架構,而目標機器是ARM架構,所以需要的是交叉編譯工具鏈,不清楚這一知識的讀者可自行補充交叉編譯相關知識。
當你有一個寫好的彙編代碼文件( .s 後綴)後,你需要使用as工具進行彙編,生成機器語言,再使用ld工具進行鏈接。
$ arm-linux-gnueabihf-as sum10.s -o sum10.o -g
$ arm-linux-gnueabihf-ld sum10.o -o sum10
/*
-g:帶有debug信息
-o:指定輸出文件名
*/
Note:
c語言編譯過程中,中途會先進行編譯生成彙編代碼,然後再進行彙編和鏈接,最終生成可執行文件
1 ARM架構概述
本章主要簡單介紹下後文中所需要的一些ARM架構相關知識,讀者如遇見不清楚的地方,可自行去閱讀ARM Architectural Reference Manual。
ARM是一個典型的RISC(精簡指令集)處理器,只有加載和存儲指令可以訪問內存,數據操作相關指令只能操作寄存器。這也就意味着程序更新一次內存中數據,至少需要三步:
- 從內存中將數據讀取到寄存器中
- 對寄存器中的數據進行更新
- 將更新後的數據放回內存中
1.1 ARM 架構版本
ARM family | ARM架構版本 |
---|---|
ARM7 | ARM v4 |
ARM9 | ARM v5 |
ARM11 | ARM v6 |
Cortex-A | ARM v7-A |
Cortex-R | ARM v7-R |
Cortex-M | ARM v7-M |
1.2 ARM & Thumb state
在ARM v4T和v4TxM架構中,定義了一種長度為16bits的指令集,並稱之為Thumb指令集,這一指令集是ARM指令集的一個子集。這一指令集同ARM指令集主要有以下區別:
- 在寄存器的訪問上受一定的限制
- 只能通過分支指令實現條件執行
- 不允許訪問桶式移位器(barrel shifter)
ARM處理器執行ARM指令時被稱為處於ARM狀態,執行Thumb指令時,被稱為Thumb狀態。
Note:後面會詳細急介紹以上三點區別,讀者不清楚,不用着急
ARM處理器最開始總是處於ARM狀態,可通過BX指令轉換至Thumb狀態。
1.3 地址空間
在ARM v3架構之後,所有的的處理器均有32bit的尋址範圍
1.4 處理器模式
ARM擁有以下7種基本操作模式:
- User
- FIQ
- IRQ
- Supervisor(svc)
- Abort
- Undefined
- System
以上其中模式中,大部分的程序都運行與User模式下,其他的六種均為特權模式
1.5 寄存器
ARM處理器一共提供了37個寄存器。寄存器排布在部分重疊的存儲區域。每種模式下均有不同的寄存器組。
User mode | IRQ | FIQ | Undef | Abort | SVC |
---|---|---|---|---|---|
r0-r7 | |||||
r8 | r8 | ||||
r9 | r9 | ||||
r10 | r10 | ||||
r11 | r11 | ||||
r12 | r12 | ||||
r13 (sp) | r13 (sp) | r13 (sp) | r13 (sp) | r13 (sp) | r13 (sp) |
r14 (lr) | r14 (lr) | r14 (lr) | r14 (lr) | r14 (lr) | r14 (lr) |
r15 (pc) | |||||
cpsr | |||||
spsr | spsr | spsr | spsr | spsr |
30個32位通用寄存器,根據當前處理器的模式,可以隨時看到其中的15個寄存器,分別是:r0,r1…r14。
通常情況下,r13會被用作棧指針(stack pointer),r14會被用作鏈接寄存器(link register),用於存儲調用子程序時存儲返回地址。r15是程序計數器,用於存放下一條需要執行的指令的位置,所以可以通過將程序需要跳轉的地址放入PC來實現程序跳轉。
CPSR寄存器(Current Program Status Register)主要持有了以下信息:
- ALU的狀態標誌信息(C/V/N/Z)
- 當前處理器的模式
- 中斷Disable標誌
- ARM State or Thumb State (如果該處理器支持Thumb)
SPSR寄存器(Saved Program Status Register)用於異常發生時存儲CPSR。
CPSR寄存器:
N | Z | C | V | J | GE | E | A | I | F | T | M | |||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
31 | 30 | 29 | 28 | 24 | 19-16 | 9 | 8 | 7 | 6 | 5 | 4-0 |
M:處理器模式
T:ARM || Thumb 狀態
N:負數標誌
Z:結果為0
C:進位標誌
V:溢出標誌
1.6 ARM指令集概述
所有的ARM指令長度均為32bits。因為指令在內存中按字對齊存儲,故地址最低2個bits應該為0。因此除了分支交換BX指令外,所有具有地址操作數的ARM指令都將忽略這兩個bit,而BX正是通過這個bit來確定進入Thumb狀態還是ARM狀態。
ARM指令可大致分為以下積累幾類:
- 分支指令
- 數據處理指令
- 狀態寄存器訪問指令
- 單一寄存器加載/存儲指令
- 多寄存器加載/存儲指令
- 信號量指令
- 協處理器指令
指令功能:
- 條件執行
- 寄存器訪問
- 訪問桶式移位器
1.7 Thumb指令集概述
所有的Thumb指令長度為16bits,且存儲為半字對齊,故地址最低bit應該為0。因此除了分支交換BX指令外,所有具有地址操作數的指令都將忽略這個bit,而BX正是通過這個bit來確定進入Thumb狀態還是ARM狀態。
下面是Thumb指令與ARM指令的不同之處:
-
分支指令
- 相對於ARM指令,在範圍上擁有更多的限制,而且僅支持無條件跳轉
-
數據處理指令
- 受一定限制訪的問r8-r15
- 一直會更新CPSR中的CVNZ位(ARM指令需添加S後綴),除了訪問r8-r15
-
狀態寄存器訪問指令
- 沒有相關的訪問指令
-
單一寄存器加載/存儲指令
- 不可訪問r8-r15
-
多寄存器加載/存儲指令
- 內存到寄存器的訪問範圍被限制在了r0-r7
- 此外,PUSH 和 POP可以分別使用r13和r14
-
信號量指令(無)
-
協處理器指令(無)
Thumb指令的功能
- 條件執行
- 只能通過分支指令來實現條件執行
- 訪問寄存器
- 大部分情況下只能呢個訪問r0-r7
- r8-r15訪問受限,但也可以使用,比如作為快速臨時存儲
- 訪問桶式移位器
- 只能通過特定的指令去訪問,LSL、LSR、ASR、ROR
2 彙編語言結構
彙編語言在這裡指的是允許通過ARM彙編程序分析和彙編生成目標代碼的語言,它們可以是:
- ARM彙編語言
- Thumb彙編語言
- 以上兩者的混合
2.1 彙編語言源文件的布局
彙編源文件中的的代碼行的通常的形式如下:
GNU ARM 彙編格式:
{label:}{instruction | directive | pseudo-instruction} {@comment}
ARM 標準彙編格式:
{label} {instruction | directive | pseudo-instruction} {;comment}
{標籤} {指令|偽操作|偽指令} {注釋}
在這裡需要注意的是,instruction | directive | pseudo-instruction 前面必須要有空格或者TAB
以上的三個部分均是可選的,也就是你完全可以用空行去分割你的代碼,使其更具可讀性
-
大小寫規則
- 所有的指令助記符可以是大寫或者小寫,但是不能混合
- Directive必須大寫
- 寄存器符號可以大寫或者小寫,但是不能混合
-
單行代碼長度
- 為了使代碼具有可讀性,可允許使用『\』字符來分割換行
-
label 標籤
- 在彙編語言中,標籤是代表地址的一個符號,這個地址將在彙編期間被計算出來
- 在GNU彙編中,任何一個以冒號結尾的標識符都會被認為是一個標籤,而不一定要在行首
-
局部標籤 local labels
-
注釋
- ARM 標準彙編的注釋以 ; 開始
- GNU標準彙編的注釋以@ 開始,同時也可以使用C語言中的 /* */
-
常量
- 數字
- 字符串
- 字符串常量用雙引號「 」括起來
- 布爾型
- {TRUE}
- {FALSE}
- 字符
- 使用單引號『 』
-
布爾型
2.2 ARM彙編的示例
2.2.1 example的彙編和鏈接
AREA ARMexample, CODE, READONLE
ENTRY
start mov r0, #10
mov r1, #3
add r0, r0, r1
stop mov r0, #0x18
ldr r1, =0x20026
swi 0x123456
end
;ARM 標準彙編語法,不做詳細解釋,讀者可自行參考相關資料
GNU 彙編語法
.section .text
.global _start
_start:
MOV r0, #10
MOV r1, #3
ADD r0, r0, r1
stop:
MOV r0, #0x18
LDR r1, =0x20026
SWI 0x123456
將該文件保存為gnuAssembly.S,並使用as進行彙編,然後用ld進行鏈接生成可執行文件
arm-linux-gnueabihf-as -g gnuAsExample.S -o gnuAsExample.o
arm-linux-gnueabihf-ld gnuAsExample.o -o gnuAsExample
說明:
-g: 帶有debug信息
-o:指定輸出文件名
2.2.2 GDB和QEMU 調試
彙編鏈接生成gnuAsExample可執行文件之後,我們可以使用qemu-arm仿真工具執行該文件。
/*首先使用qemu-arm 加載並執行該可執行文件*/
qemu-arm -g 1234 gnuAsExample
/*另外開一個shell窗口,使用GDB工具進行聯調*/
arm-linux-gnueabihf-gdb ./gnuAsExample
/*進入GDB模式後,執行如下命令*/
(gdb) target remote 127.0.0.1:1234
/*成功後,可看見如下信息*/
(gdb) target remote 127.0.0.1:1234
Remote debugging using 127.0.0.1:1234
_start () at gnuAsExample.S:5
5 MOV r0, #10
說明:GDB工具連接的端口號需和使用qemu-arm中設置的端口號一致,在這裡均為1234。詳細的GDB命令在此不再詳述,讀者可自行查閱相關資料
2.2.3 示例詳解
.section .text @聲明text段
.global _start @聲明全局變量
_start: @定義_start標籤
MOV r0, #10 @立即數10賦值給r0
MOV r1, #3 @將立即數3賦值給r0
ADD r0, r0, r1 @將r0寄存器和r1寄存器的值相加,並將結果存放至r0
stop:
MOV r0, #0x18 @將0x18放入r0
LDR r1, =0x20026 @將0x20026放入r1
SWI 0x123456 @執行軟中斷命令
說明:stop標籤後的三條指令是一個退出程序的指令序列,首先是設置r0和r1的值,然後再觸發軟件中斷,這裏面會用到者兩個寄存器的值,具體這些值的含義讀者可自行查閱相關資料,在此不進行說明,讀者在這裡也可以完全忽略具體的值,只需要對彙編的寫法有個整體上的認知
在GNU ARM彙編中_start標籤是默認的程序起始地址,且由於程序是通過加載器來加載的,因此必須將 _start符號聲明為全局的,這樣加載器才能找到。
2.3 Thumb 彙編示例
.section .text
.global _start
_start:
.code 32
adr r2, thumb+1
/*在前面我們有說到,由於ARM指令按字對齊,而Thumb指令按半字對齊,
因此有最低的一個bit或兩個bit為0,而在這裡我們通過加1,使其不為0,
下一條bx指令正是通過這一位判斷是否需要進行ARM到Thumb狀態的轉換*/
bx r2
thumb:
.code 16
mov r0, #10
mov r1, #3
add r0, r0, r1
bkpt
下面是彙編鏈接調試過程,共讀者參考
窗口 1
log@log:~$ arm-linux-gnueabihf-as -g gnuAsThumbEx.S -o gnuAsThumbEx.o
log@log:~$ arm-linux-gnueabihf-ld gnuAsThumbEx.o -o gnuAsThumbEx
log@log:~$ qemu-arm -g 1234 gnuAsThumbEx
窗口 2
log@log:~$ arm-linux-gnueabihf-gdb gnuAsThumbEx
GNU gdb (Linaro_GDB-2017.08) 8.0.0.20170823-git
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <//gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-unknown-linux-gnu --target=arm-linux-gnueabihf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<//www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<//www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from gnuAsThumbEx...done.
(gdb) target remote 127.0.0.1:1234
Remote debugging using 127.0.0.1:1234
_start () at gnuAsThumbEx.S:7
7 adr r2, thumb+1
(gdb) info registers r2
r2 0x0 0
(gdb) n
8 bx r2
(gdb) info registers r2
r2 0x1005d 65629
(gdb) l
3 .global _start
4
5 _start:
6 .code 32
7 adr r2, thumb+1
8 bx r2
9
10 thumb:
11 .code 16
12 mov r0, #10
(gdb) n
thumb () at gnuAsThumbEx.S:12
12 mov r0, #10
(gdb) n
13 mov r1, #3
(gdb) info registers r2
r2 0x1005d 65629
(gdb) info registers r0
r0 0xa 10
(gdb) info registers r1
r1 0xf6fff66b -150997397
(gdb) n
14 add r0, r0, r1
(gdb) info registers r0 r1
r0 0xa 10
r1 0x3 3
(gdb) n
15 bkpt
(gdb) info registers r0 r1
r0 0xd 13
r1 0x3 3
(gdb) n
3 數據處理指令
ARM指令通常有一個或兩個操作數,形如:
助記符{s}{條件} {rd} , 操作數1,操作數2
說明:
- {s}:指令加了s後綴後,意味着將會更新CPSR中的CVZN標誌
- {條件}:可以決定該指令是否執行
- {rd}: 通常用於存儲結果
- 操作數1:第一個操作數,可以是寄存器或立即數
- 操作數2:第二個操作數,可以是立即數或者是一個對寄存器進行移位操作
常見的表達式:
-
1 立即數
-
rx 寄存器x,r1、r2…
-
rx, asr n 算術右移n位
-
rx,lsl n 邏輯左移n位
-
rx,lsr n 邏輯右移n位
-
rx,ror n 循環右移n位
-
rx,rrx 循環右移1位
3.1 數據傳輸指令
-
mov:用於兩個寄存器之間或者立即數和寄存器之間傳遞數據
-
mvn:和mov用法一致,區別在於會將第二個操作數進行按位取反後再進行傳遞
說明:
在這裡特別需要說明的是使用mov和mvn在寄存器中和立即數中傳遞數據,這裡的立即數是範圍是有一定的限制的。
因為ARM指令編碼格式長度微32位,拋去條件碼、操作碼、目標寄存器等,留給立即數的位數只剩下12位,因此它是沒有辦法去表示所有的32位的數的,如果按常規操作,它只能表示0x000-0xfff,但是在ARM中,並沒有按常規操作去表示這些數據,而是將其中的低8位作為基數,高4位作為右移位數(x2):
例如:0x101代表的是:0x01 循環右移1×2位,變成:0x40000000
通過這種方法,使得12位的數可以表示比較大的數據,但是它依舊不肯呢個表示所有的數據,因此立即數是有一定的限制的,在編程時,如使用了非法立即數,彙編過程中會報告一個錯誤。
3.2 算數運算指令
- add:加法運算
- sub:減法運算
- rsb:反減運算
- adc:帶進位的加法
- sbc:帶進位的減法
- rsc:帶進位的反減
3.3 邏輯運算指令
- and:與
- orr:或
- eor:異或
- bic:位清除操作
3.4 比較指令
- cmp:比較大小
- cmn:取反運算
- tst:按位與運算
- teq:按位異或運算
3.5 乘法指令
mvl、mla、umull、umlal、smull、smlal
3.6 CPSR訪問指令
用於訪問CPSR寄存器
- mrc:用於讀出cpsr和spsr寄存器
- msr:用於寫入cpsr和spsr寄存器
說明:CPSR是程序狀態寄存器,只有一個,而SPSR寄存器在五種異常模式下各有一個,用於保存普通模式下的CPSR寄存器的值
4 內存訪問指令
在ARM指令集中,只有特定的加載和存儲指令允許訪問內存,所以在對一個數據進行操作之前,都必須將該數加載到寄存器當中去,然後進行操作,操作完成後,再更新回內存中。
4.1 單一寄存器加載和存儲
- ldr:可用於加載一個地址中的內容到寄存器中,也可以加載一個32bit長度的常量存儲在寄存器中
- str:主要用與將寄存器中的值寫入內存中
ldr是ARM中的一個指令,也同時是一個偽指令,其主要有兩種用法:
-
加載一個常量到寄存器中
例如:ldr r1,=42
在這裡,ldr是一個偽指令,彙編程序會根據需加載常量的不同,而翻譯成不同的指令,具體規則是:
如果該常量能夠使用mvn或mov指令進行操作,則直接將該指令翻譯成mvn或mov
如果該常量並不能夠直接被mvn或mov指令進行操作,則彙編器首先會在附近的文字池(literal pool)中存放這麼一個常量,然後在使用ldr指令進行讀取
literal pool: a portion of memory embedded in the code to hold constant value
在這裡需要注意的是,編程者必須確保在LDR能夠訪問的範圍內存在文字池,如果不存在,在進行彙編的過程中,會報告一個錯誤,這時編程者可通過 LTORG 指令放置一個文字池,詳細信息見下文
放置文字池
通常來說,彙編程序會在每個area的末尾放置一個文字池,但是如果該area過大的話,可能會超出部分LDR指令能夠訪問的範圍。
在ARM狀態,從PC到常量的偏移量不能超過4KB
在Thumb狀態,該偏移量不能超過1KB
.section .text .global _start _start: ldr r0, =3 ldr r1, =0x55555555 largeTable: .space 4200 .end
arm-linux-gnueabihf-as -g gnuAsLiteralPool.S -o gnuAsLiteralPool.o gnuAsLiteralPool.S: Assembler messages: gnuAsLiteralPool.S:6: 錯誤: invalid literal constant: pool needs to be closer
如上代碼,在用as彙編時,會產生一個error,因為在ldr r1 , =0x55555555語句中,不能直接用mov或mvn加載,只能通過在文字池中存放該常量,然後使用ldr指令進行加載,然而在該示例中,因為後買你有一個4200位元組的空間,使得文字池的範圍超出了ldr指令可以訪問的範圍,因此需要我們手動在適合的位置放置一個文字池。如下:
.section .text .global _start _start: ldr r0, =3 ldr r1, =0x55555555 .ltorg largeTable: .space 4200 .end
在這裡我們對彙編生成後的文件進行反彙編,結果如下:
log@log:~$ arm-linux-gnueabihf-objdump gnuAsLiteralPool.o -S gnuAsLiteralPool.o: 文件格式 elf32-littlearm Disassembly of section .text: 00000000 <_start>: .section .text .global _start _start: ldr r0, =3 0: e3a00003 mov r0, #3 ldr r1, =0x55555555 4: e51f1004 ldr r1, [pc, #-4] ; 8 <_start+0x8> 8: 55555555 .word 0x55555555 0000000c <largeTable>: ...
在這裡可以看見,ldr r0,=3指令被翻譯成了mov r0, #3;而ldr r1, =0x55555555,則被翻譯成了兩條指令,一個是在.word 0x55555555,一個是ldr r1, [pc, #-4] ; 8 <_start+0x8>。
-
加載一個地址
除了上一種用法,ldr更多的功能則是將某個特定地址中的內容加載進寄存器中,主要有以下用法
ldr r0,[r1] @將地址r1中的字數據加載進r0中 ldr r0,[r1,r2] @將存儲器地址為r1+r2的字數據加載進r0中 ldr r0,[r1,#8] @將地址為r1+8的字數據加載進r0中 ldr r0,[r1],r2 @將r1地址中的字數據加載進r0中,並把r1+r2的值賦值給r1 ldr r0,[r1],#8 @將r1地址中的字數據加載進r0中,並把r1+8的值賦值給r1 ldr r0,[r1,r2]! @將存儲器地址為r1+r2的字數據加載進r0中,同時把r1+r2賦值給r1 ldr r0,label @將label作為地址加載 ldr r0,=label @將label作為一個常量數進行加載
說明
除了上述ldr指令能夠加載一個地址,同樣也可以使用adr偽指令進行地址加載,這一偽指令是小範圍的地址地址加載,主要通過相對於寄存器或當前PC的偏移量進行加載,且偏移量的範圍是255位元組(如果沒有按字對齊)或者1020位元組(如果地址按字對齊)
4.2 多寄存器加載和存儲
ldm:用於從內存中讀取連續的多個字存放進寄存器中
stm:用於將多個寄存器中的值存儲到內存中去
ldm r0,{r4-r5} @將r0地址中的兩個字內容分別加載到r4,r5
stm r1,{r4-r5} @將r4-r5兩個寄存器的值寫入r1地址中
後綴說明:
ia:每次傳送後地址加4,其中的寄存器從左到右執行
ib:每次傳送前地址加4,同上
da:每次傳送後地址減4,其中的寄存器從右到左執行
db:每次傳動前地址減4,同上
!:用最後的地址更新基地址
5 條件執行
在ARM狀態,每個數據操作指令都可以通過添加『s』後綴,根據操作結果去設置CPSR的ALU狀態標誌,也就是CPSR的N、C、V、Z位
在Thumb狀態,沒有s後綴,因為所有的指令都會自動去設置這一標誌,除了通過mov和mvn指令去操作高位寄存器(r8-r15)
注意:在Thumb狀態下,只能通過分支指令實現條件執行,所以下述通過添加指令後綴實現條件執行,都是處於ARM狀態
5.1 ALU狀態標誌
CPSR寄存器包含了ALU以下狀態標誌:
- N:當操作結果為負數時,被置1
- Z:當操作結果為0時,被置1
- C:當操作結果出現進完位時,被置1
- V:當操作導致溢出時,被置1
當加減結果大於或等於2的32次方,或者由於一定而導致僅為,則C置1
當加減結果大於或等於2的31次方,或者少於-2的31次方,則發生溢出
不要將s後綴與cmp\cmn\tst\teq一起使用,因為這些指令默認都是會去更新這一標誌的。
5.2 執行條件
後綴 | 標誌 | 意義 |
---|---|---|
eq | Z = 1 | 相等 |
ne | Z = 0 | 不想等 |
cs/hs | C = 1 | unsigned >= |
cc/lo | C = 0 | unsigned < |
mi | N = 1 | 負數 |
pl | N = 0 | 0 或 正數 |
vs | V = 1 | 溢出 |
vc | V = 0 | 沒有溢出 |
hi | c=1&&z=0 | unsigned > |
ls | c =0&&z=1 | unsigned <= |
ge | n = v | signed >= |
lt | n != v | signed < |
gt | z=0,n=v | signed > |
le | z=1,n!=v | signed <= |
6 宏的使用
在GNU彙編中的宏定義格式如下:
.macro 宏名 參數列表
宏體
.endm
example:
.macro FUN_ADD a,b
add \a, \a, \b
.endm
7 GNU ARM彙編常見偽操作
7.1 .section 偽操作
.section 偽操作格式如下:
.section section_name [,”flags” [, %type [, flag_specific_arguments]]]
在彙編中預置的一些段:
.text @代碼段
.data@初始化數據段
.bss@未初始化數據段
.sdata
.sbss
.bss段應該在.text段之前
8 參考鏈接
ARM彙編基數://azeria-labs.com/writing-arm-assembly-part-1/
ARM官方文檔://infocenter.arm.com/help/index.jsp