GNU風格 ARM彙編語法指南

彙編源程序通常用於系統最基本的初始化:初始化堆棧指針、設置頁表、操做 ARM的協處理器等。這些初始化工做完成後就能夠跳轉到C代碼main函數中執行。express

一、  GNU彙編語言語句格式編程

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

l         instruction爲指令函數

l         directive爲僞操做編碼

l         pseudo-instruction爲僞指令spa

l         <label>: 爲標號GNU彙編中,任何以冒號結尾的標識符都被認爲是一個標號,而不必定非要在一行的開始。指針

l         comment爲語句的註釋code

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

.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)。

二、  GNU彙編程序中的標號symbol(或label

    標號只能由a~z,A~Z,0~9,.」,_等(由點、字母、數字、下劃線等組成,除局部標號外,不能以數字開頭)字符組成。

    Symbol的本質:表明它所在的地址,所以也能夠看成變量或者函數來使用。

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

l          段外標號的地址值在鏈接時肯定。

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

<1>    基於PC的標號。基於PC的標號是位於目標指令前的標號或者程序中數據定義僞操做前的標號。這種標號在彙編時將被處理成PC值加上(或減去)一個數字常量,經常使用於表示跳轉指令」b」等的目標地址,或者代碼段中所嵌入的少許數據。

<2>    基於寄存器的標號。基於寄存器的標號經常使用MAP和FIELD來定義,也能夠用EQU來定義。這種標號在彙編時將被處理成寄存器的值加上(或減去)一個數字常量,經常使用於訪問數據段中的數據。

<3>    絕對地址。絕對地址是一個32位數據。它能夠尋址的範圍爲[0,232-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          若是F和B都沒有指定,編譯器先向前搜索,再向後搜索

l          若是A和T都沒有指定,編譯器搜索全部從當前層次到宏的最高層次,比當前層次低的層次再也不搜索。

l          若是指定了routname,編譯器向前搜索最近的ROUT僞操做,若routname與該ROUT僞操做定義的名稱不匹配,編譯器報告錯誤,彙編失敗。

三、  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段以前。

四、  GNU彙編語言定義入口點

    彙編程序的缺省入口是_start標號,用戶也能夠在鏈接腳本文件中用ENTRY標誌指明其它入口點

例:定義入口點

.section .data

         < initialized data here>

.section .bss

         < uninitialized data here>

.section .text

.globl  _start

_start:

         <instruction code goes here>

 

五、  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

六、  GNU彙編程序中的常數

<1>    十進制數以非0數字開頭,如:123和9876;

<2>    二進制數以0b開頭,其中字母也能夠爲大寫;

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

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

<5>    字符串常量須要用引號括起來,中間也可使用轉義字符,如: 「You are welcome!\n」;

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

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

 

七、  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寄存器(參數、結果或暫存寄存器,r0到r3 的同義字)以及浮點寄存器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:代表源文件的結束。

l         .include:能夠將指定的文件在使用.include 的地方展開,通常是頭文件,例如:

         .include 「myarmasm.h」

l         .incbin僞操做能夠將原封不動的一個二進制文件編譯到當前文件中,使用方法以下:

         .incbin "file"[,skip[,count]]

         skip代表是從文件開始跳過skip個字節開始讀取文件,count是讀取的字數.

<4>    ..if僞操做

    根據一個表達式的值來決定是否要編譯下面的代碼, 用.endif僞操做來表示條件判斷的結束, 中間可使用.else來決定.if的條件不知足的狀況下應該編譯哪一部分代碼。

.if有多個變種:

.ifdef symbol           @判斷symbol是否認義

.ifc string1,string2      @字符串string1和string2是否相等,字符串能夠用單引號括起來

.ifeq expression        @判斷expression的值是否爲0

.ifeqs string1,string2    @判斷string1和string2是否相等,字符 串必須用雙引號括起來

.ifge expression        @判斷expression的值是否大於等於0

.ifgt absolute expression @判斷expression的值是否大於0

.ifle expression        @判斷expression的值是否小於等於0

.iflt absolute expression    @判斷expression的值是否小於0

.ifnc string1,string2        @判斷string1和string2是否不相等, 其用法跟.ifc剛好相反。

.ifndef symbol, .ifnotdef symbol @判斷是否沒有定義symbol, 跟.ifdef剛好相反

.ifne expression          @若是expression的值不是0, 那麼編譯器將編譯下面的代碼

.ifnes string1,string2      @若是字符串string1和string2不相 等, 那麼編譯器將編譯下面的代碼.

 

<5>    .global .type .title .list

l         .global/ .globl :用來定義一個全局的符號,格式以下:

          .global symbol 或者 .globl symbol

l          .type:用來指定一個符號的類型是函數類型或者是對象類型, 對象類型通常是數據, 格式以下:

          .type 符號, 類型描述

例:

.globl a

.data

.align 4

.type a, @object

.size a, 4

a:

.long 10

例:

.section .text

.type asmfunc, @function

.globl asmfunc

asmfunc:

mov pc, lr

 

<6>    列表控制語句:

.title:用來指定彙編列表的標題,例如:

  .title 「my program」

.list:用來輸出列表文件.

 

<7>    ARM特有的僞操做

l          .reg: 用來給寄存器賦予別名,格式以下:

       別名 .req 寄存器名

l          .unreq: 用來取消一個寄存器的別名,格式以下:

   .unreq 寄存器別名

    注意被取消的別名必須事先定義過,不然編譯器就會報錯,這個僞操做也能夠用來取消系統預製的別名, 例如r0, 但若是沒有必要的話不推薦那樣作。

l          .code僞操做用來選擇ARM或者Thumb指令集,格式以下:

    .code 表達式

  若是表達式的值爲16則代表下面的指令爲Thumb指令,若是表達式的值爲32則代表下面的指令爲ARM指令.

l          .thumb僞操做等同於.code 16, 代表使用Thumb指令, 相似的.arm等同於.code 32

l          .force_thumb僞操做用來強制目標處理器選擇thumb的指令集而無論處理器是否支持

l          .thumb_func僞操做用來指明一個函數是thumb指令集的函數

l          .thumb_set僞操做的做用相似於.set, 能夠用來給一個標誌起一個別名, 比.set功能增長的一點是能夠把一個標誌標記爲thumb函數的入口, 這點功能等同於.thumb_func

l          .ltorg用於聲明一個數據緩衝池(literal pool)的開始,它能夠分配很大的空間。

l          .pool的做用等同.ltorg

l          .space <number_of_bytes> {,<fill_byte>}

     分配number_of_bytes字節的數據空間,並填充其值爲fill_byte,若未指定該值,缺省填充0。(與armasm中的SPACE功能相同)

l          .word <word1> {,<word2>} …

     插入一個32-bit的數據隊列。(與armasm中的DCD功能相同)。可使用.word把標識符做爲常量使用。

例:

Start:

valueOfStart:

      .word Start

這樣程序的開頭Start便被存入了內存變量valueOfStart中。

l          .hword <short1> {,<short2>} …

    插入一個16-bit的數據隊列。(與armasm中的DCW相同)

 

八、  GNU ARM彙編特殊字符和語法

<1>    代碼行中的註釋符號: ‘@’

<2>    整行註釋符號: ‘#’

<3>    語句分離符號: ‘;’

<4>    當即數前綴: ‘#’ 或 ‘$’

相關文章
相關標籤/搜索