1. 程式人生 > >GNU風格 ARM 彙編指令語法總結

GNU風格 ARM 彙編指令語法總結

彙編源程式一般用於系統最基本的初始化:初始化堆疊指標、設定頁表、操作 ARM的協處理器等。這些初始化工作完成後就可以跳轉到C程式碼main函式中執行。

1、 GNU組合語言語句格式

任何Linux彙編行都是如下結構:[<label>:][<instruction or directive or pseudo-instruction>} @comment

l instruction指令

l directive偽操作

l pseudo-instruction偽指令

l <label>: 標號, GNU彙編中,

任何以冒號結尾的識別符號都被認為是一個標號而不一定非要在一行的開始

l comment為語句的註釋

下面定義一個"add"的函式,最終返回兩個引數的和:

    .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

注意:

l ARM指令,偽指令,偽操作,暫存器名可以全部為大寫字母,也可全部為小寫字母,但不可大小寫混用

l 如果語句太長,可以將一條語句分幾行來書寫,在行末用“\”表示換行(即下一行與本行為同一語句)。“\”後不能有任何字元,包含空格和製表符(Tab)

2、 GNU彙編程式中的標號symbol(或label

標號只能由azAZ09._等(由點、字母、數字、下劃線等組成,除區域性標號外,不能以數字開頭)字元組成。

Symbol本質:代表它所在的地址,因此也可以當作變數或者函式來使用。

l 段內標號的地址值在彙編時確定;

l 段外標號的地址值在連線時確定。

Symbol分類:3類(依據標號的生成方式)。

        <1> 基於PC的標號。基於PC的標號是位於目標指令前的標號或者程式中資料定義偽操作前的標號。這種標號在彙編時將被處理成PC值加上(或減去)一個數字常量,常用於表示跳轉指令”b”的目標地址,或者程式碼段中所嵌入的少量資料。

        <2> 基於暫存器的標號。基於暫存器的標號常用MAPFIELD來定義,也可以用EQU來定義。這種標號在彙編時將被處理成暫存器的值加 上(或減去)一個數字常量,常用於訪問資料段中的資料。

        <3> 絕對地址。絕對地址是一個32位資料。它可以定址的範圍為[0232-1]即可以直接定址整個記憶體空間。

特別說明:區域性標號Symbol

區域性標號主要在區域性範圍內使用,而且區域性標號可以重複出現它由兩部組成:開頭是一個0-99直接的數字,後面緊接一個通常表示該區域性變數作用範圍的符號。區域性變數的作用範圍通常為當前段,也可以用ROUT來定義區域性變數的作用範圍。

區域性變數定義的語法格式:N{routname}

l N:為0~99之間的數字。

l routname:當前區域性範圍的名稱(為符號),通常為該變數作用範圍的名稱(ROUT偽操作定義的)。

區域性變數引用的語法格式:%{F|B}{A|T}N{routname}

l %:表示引用操作

l N:為區域性變數的數字號

l routname為當前作用範圍的名稱(ROUT偽操作定義的

l F:指示編譯器只向前搜尋

l B:指示編譯器只向後搜尋

l A:指示編譯器搜尋巨集的所有巢狀層次

l T:指示編譯器搜尋巨集的當前層次

例:使用區域性符號的例子,一段迴圈程式

1:

subs r0, r0, #1 @每次迴圈使r0=r0-1

bne 1F @跳轉到1標號去執行

注意:

l 如果FB都沒有指定,編譯器先向前搜尋,再向後搜尋

l 如果AT都沒有指定,編譯器搜尋所有從當前層次到巨集的最高層次,比當前層次低的層次不再搜尋。

l 如果指定了routname,編譯器向前搜尋最近的ROUT偽操作,若routname與該ROUT偽操作定義的名稱不匹配,編譯器報告錯誤,彙編失敗。

3、 GNU彙編程式中的分段

<1   .section偽操作

.section <section_name> {,”<flags>”}

Starts a new code or data section. Sections in GNU are called .text, a code section, .data, an initialized data section, and .bss, an uninitialized data section.

These sections have default flags, and the linker understands the default names(similar directive to the armasm directive AREA).The following are allowable .section flags for ELF format files:

<Flag> Meaning

a allowable section

w writable section

x executable section

中文解釋:

使用者可以通過.section偽操作來自定義一個段,格式如下:

.section section_name [, "flags"[, %type[,flag_specific_arguments]]]

每一個段以段名為開始, 以下一個段名或者檔案結尾為結束。這些段都有預設的標誌(flags聯結器可以識別這些標誌。(arm asm中的AREA相同)。下面是ELF格式允許的段標誌flags

<標誌> 含義

a 允許段

w 可寫段

x 執行段

例:定義一個“段”

.section .mysection @自定義資料段,段名為 “.mysection”

.align 2

strtemp:

.ascii "Temp string \n\0" @ 對這一句的理解,我覺得應該是:將"Temp string \n\0"這個字串儲存在以標號strtemp:

@為起始地址的一段記憶體空間裡

<2    > 彙編系統預定義的段名

l .text @程式碼段

l .data @初始化資料段 .data Read-write initialized long data.

l .bss @未初始化資料段

l .sdata @ .sdata Read-write initialized short data.

l .sbss @

注意:源程式中.bss段應該在.text段之前。

4、 GNU組合語言定義入口點

彙編程式的預設入口是_start標號,使用者也可以在連線指令碼檔案中用ENTRY標誌指明其它入口點

例:定義入口點

.section .data

< initialized data here>

.section .bss

< uninitialized data here>

.section .text

.globl _start

_start:

<instruction code goes here>

5、 GNU彙編程式中的巨集定義

格式如下:

.macro 巨集名 引數名列表 @偽指令.macro定義一個巨集

巨集體

.endm @.endm表示巨集結束

如果巨集使用引數,那麼在巨集體中使用該引數時新增字首“\”巨集定義時的引數還可以使用預設值。可以使用.exitm偽指令來退出巨集。

例:巨集定義

.macro SHIFTLEFT a, b

.if \b < 0

MOV \a, \a, ASR #-\b

.exitm

.endif

MOV \a, \a, LSL #\b

.endm

6、 GNU彙編程式中的常數

        <1> 十進位制數以非0數字開頭,:1239876

        <2> 二進位制數以0b開頭,其中字母也可以為大寫;

        <3> 八進位制數以0開始,:0456,0123

        <4> 十六進位制數以0x開頭,:0xabcd,0X123f

        <5> 字串常量需要用引號括起來,中間也可以使用轉義字元,: “You are welcome!\n”

        <6> 當前地址以.表示,GNU彙編程式中可以使用這個符號代表當前指令的地址;

        <7> 表示式:在彙編程式中的表示式可以使用常數或者數值, “-”表示取負數, “~”表示取補,“<>”表示不相等,其他的符號如:+-* /%<<<>>>|&^!==>=<=&&|| C語言中的用法相似。

7、 GNU ARM彙編的常用偽操作

在前面已經提到過了一些為操作,還有下面一些為操作:

l 資料定義偽操作: .byte.short.long.quad.float.string/.asciz/.ascii,重複定義偽操作.rept,賦值語句.equ/.set

l 函式的定義;

l 對齊方式偽操作 .align

l 原始檔結束偽操作.end

l .include偽操作;

l if偽操作;

l .global/ .globl 偽操作

l .type偽操作

l 列表控制語句

     別於GNU AS彙編的通用偽操作,下面是ARM特有的偽操作:

    .reg .unreq .code .thumb .thumb_func .thumb_set .ltorg .pool

<1    > 資料定義偽操作

l .byte:單位元組定義,如:.byte 1,2,0b01,0x34,072,'s'

l .short:定義雙位元組資料,如:.short 0x1234,60000

l .long:定義4位元組資料,如:.long 0x12345678,23876565

l .quad:定義8位元組,如:.quad 0x1234567890abcd

l .float:定義浮點數,如:.float 0f-314159265358979323846264338327\

95028841971.693993751E-40 @ - pi

l .string/.asciz/.ascii:定義多個字串,如:

.string "abcd", "efgh", "hello!"

.asciz "qwer", "sun", "world!"

.ascii "welcome\0"

注意:ascii偽操作定義的字串需要自行新增結尾字元'\0'

l .rept:重複定義偽操作, 格式如下:

.rept 重複次數

資料定義

.endr @結束重複定義

例:

.rept 3

.byte 0x23

.endr

l .equ/.set: 賦值語句, 格式如下:

.equ(.set) 變數名,表示式

例:

.equ abc, 3 @abc=3

<2    > 函式的定義偽操作

l     函式的定義,格式如下:

函式名:

函式體

返回語句

一般的,函式如果需要在其他檔案中呼叫, 需要用到.global偽操作將函式宣告為全域性函式。為了不至於在其他程式在呼叫某個C函式時發生混亂,對暫存器的使用我們需要遵循APCS準則。函式編譯器將處理函式程式碼為一段.global的彙編碼。

l 函式的編寫應當遵循如下規則:

a. a1-a4暫存器(引數、結果或暫存暫存器,r0r3 的同義字)以及浮點暫存器f0-f3(如果存在浮點協處理器)在函式中是不必儲存的;

b. 如果函式返回一個不大於一個字大小的值,則在函式結束時應該把這個值送到 r0 中;

c. 如果函式返回一個浮點數,則在函式結束時把它放入浮點暫存器f0中;

d. 如果函式的過程改動了sp(堆疊指標,r13)、fp(框架指標,r11)、sl(堆疊限制,r10)、lr(連線暫存器,r14)、v1-v8(變數暫存器,r4 r11)和 f4-f7,那麼函式結束時這些暫存器應當被恢復為包含在進入函式時它所持有的值。

<3    > .align .end .include .incbin偽操作

l .align:用來指定資料的對齊方式,格式如下:

.align [absexpr1, absexpr2]

以某種對齊方式,在未使用的儲存區域填充值. 第一個值表示對齊方式,4, 8,16 32. 第二個表示式值表示填充的值。

l .end:表明原始檔的結束。