天天看點

Linux下ARM彙編文法

第一部分 Linux下ARM彙編文法

      盡管在Linux下使用C或C++編寫程式很友善,但彙編源程式用于系統最基本的初始化,如初始化堆棧指針、設定頁表、操作 ARM的協處理器等。初始化完成後就可以跳轉到C代碼執行。需要注意的是,GNU的彙編器遵循AT&T的彙編文法,可以從GNU的站點 (www.gnu.org)上下載下傳有關規範。

一. Linux彙編行結構

任何彙編行都是如下結構:

[:] [} @ comment

[:] [} @ 注釋

Linux ARM 彙編中,任何以冒号結尾的辨別符都被認為是一個标号,而不一定非要在一行的開始。

【例1】定義一個"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

二. Linux 彙程式設計式中的标号

    标号隻能由a~z,A~Z,0~9,“.”,_等字元組成。當标号為0~9的數字時為局部标号,局部标号可以重複出現,使用方法如下:

? 标号f: 在引用的地方向前的标号

? 标号b: 在引用的地方向後的标号

【例2】使用局部符号的例子,一段循環程式

1:

   subs r0,r0,#1        @每次循環使r0=r0-1

   bne 1f       @跳轉到1标号去執行

局部标号代表它所在的位址,是以也可以當作變量或者函數來使用。

三. Linux彙程式設計式中的分段

(1).section僞操作

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

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

      每一個段以段名為開始, 以下一個段名或者檔案結尾為結束。這些段都有預設的标志(flags),連接配接器可以識别這些标志。(與armasm中的AREA相同)。

下面是ELF格式允許的段标志

含義

a 允許段

w 可寫段

x 執行段

【例3】定義段

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

.align   2

strtemp:

.ascii   "Temp string /n/0"

(2)彙編系統預定義的段名

.text   @代碼段

.data   @初始化資料段

.bss   @未初始化資料段

.sdata @

.sbss   @

需要注意的是,源程式中.bss段應該在.text之前。

四. 定義入口點

    彙程式設計式的預設入口是 start标号,使用者也可以在連接配接腳本檔案中用ENTRY标志指明其它入口點。

【例4】定義入口點

.section.data

.section .bss

.section .text

.globl _start

_start:

五. Linux彙程式設計式中的宏定義

格式如下:

.macro 宏名 參數名清單 @僞指令.macro定義一個宏

    宏體

.endm   @.endm表示宏結束

    如果宏使用參數,那麼在宏體中使用該參數時添加字首“/”。宏定義時的參數還可以使用預設值。

可以使用.exitm僞指令來退出宏。

【例5】宏定義

.macro SHIFTLEFT a, b

.if /b ”表示不相等,其他的符号如:+、-、*、/、%、、>>、|、&、^、!、==、>=、 {,}

配置設定number_of_bytes位元組的資料空間,并填充其值為fill_byte,若未指定該值,預設填充0。(與armasm中的SPACE功能相同)

六.word   {,} …

插入一個32-bit的資料隊列。(與armasm中的DCD功能相同)

可以使用.word把辨別符作為常量使用

例如:

Start:

valueOfStart:

    .word Start

這樣程式的開頭Start便被存入了記憶體變量valueOfStart中。

七.hword   {,} …

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

八. GNU ARM彙編特殊字元和文法

代碼行中的注釋符号: ‘@’

整行注釋符号: ‘#’

語句分離符号: ‘;’

直接操作數字首: ‘#’ 或 ‘$’

第二部分 GNU的編譯器和調試工具

一. 編譯工具

1.編輯工具介紹

    GNU 提供的編譯工具包括彙編器as、C編譯器gcc、C++編譯器g++、連接配接器ld和二進制轉換工具objcopy。基于ARM平台的工具分别為arm- linux-as、arm-linux-gcc、arm-linux-g++、arm-linux-ld和arm-linux- objcopy。GNU的編譯器功能非常強大,共有上百個操作選項,這也是這類工具讓初學者頭痛的原因。不過,實際開發中隻需要用到有限的幾個,大部分可 以采用預設選項。GNU工具的開發流程如下:編寫C、C++語言或彙編源程式,用gcc或g++生成目标檔案,編寫連接配接腳本檔案,用連接配接器生成最終目标檔案(elf格式),用二進制轉換工具生成可下載下傳的二進制代碼。

(1)編寫C、C++語言或彙編源程式

      通常彙編源程式用于系統最基本的初始化,如初始化堆棧指針、設定頁表、操作ARM的協處理器等。初始化完成後就可以跳轉到C代碼執行。需要注意的是,GNU的彙編器遵循AT&T的彙編文法,讀者可以從GNU的站點(www.gnu.org)上下載下傳有關規範。彙程式設計式的預設入口是 start标号,使用者也可以在連接配接腳本檔案中用ENTRY标志指明其它入口點(見下文關于連接配接腳本的說明)。

(2)用gcc或g++生成目标檔案

      如果應用程式包括多個檔案,就需要進行分别編譯,最後用連接配接器連接配接起來。如筆者的引導程式包括3個檔案:init.s(彙編代碼、初始化硬體)xmrecever.c(通信子產品,采用Xmode協定)和flash.c(Flash擦寫子產品)。分别用如下指令生成目标檔案: arm-linux-gcc-c-O2-oinit.oinit.s arm-linux-gcc-c-O2-oxmrecever.oxmrecever.c arm-linux-gcc-c-O2-oflash.oflash.c 其中-c指令表示隻生成目标代碼,不進行連接配接;-o指令指明目标檔案的名稱;-O2表示采用二級優化,采用優化後可使生成的代碼更短,運作速度更快。如果項目包含很多檔案,則需要編寫makefile檔案。關于makefile的内容,請感興趣的讀者參考相關資料。

(3)編寫連接配接腳本檔案

      gcc 等編譯器内置有預設的連接配接腳本。如果采用預設腳本,則生成的目标代碼需要作業系統才能加載運作。為了能在嵌入式系統上直接運作,需要編寫自己的連接配接腳本檔案。編寫連接配接腳本,首先要對目标檔案的格式有一定了解。GNU編譯器生成的目标檔案預設為elf格式。elf檔案由若幹段(section)組成,如不特殊指明,由C源程式生成的目标代碼中包含如下段:.text(正文段)包含程式的指令代碼;.data(資料段)包含固定的資料,如常量、字元 串;.bss(未初始化資料段)包含未初始化的變量、數組等。C++源程式生成的目标代碼中還包括.fini(析構函數代碼)和. init(構造函數代碼)等。連接配接器的任務就是将多個目标檔案的.text、.data和.bss等段連接配接在一起,而連接配接腳本檔案是告訴連接配接器從什麼位址 開始放置這些段。例如連接配接檔案link.lds為:

ENTRY(begin)

SECTION

{

.=0x30000000;

.text:{*(.text)}

.data:{*(.data)}

.bss:{*(.bss)}

}

    其中,ENTRY(begin)指明程式的入口點為begin标号;.=0x00300000指明目标代碼的起始位址為0x30000000,這一段位址為 MX1的片内RAM;.text:{*(.text)}表示從0x30000000開始放置所有目标檔案的代碼段,随後的.data:{* (.data)}表示資料段從代碼段的末尾開始,再後是.bss段。

(4)用連接配接器生成最終目标檔案

       有了連接配接腳本檔案,如下指令可生成最終的目标檔案:arm-linux-ld –no stadlib –o bootstrap.elf -Tlink.lds init.o xmrecever.o flash.o

其中,ostadlib表示不連接配接系統的運作庫,而是直接從begin入口;-o指明目标檔案的名稱;-T指明采用的連接配接腳本檔案(也可以使用-Ttext address,address表示執行區位址);最後是需要連接配接的目标檔案清單。

(5)生成二進制代碼

    連接配接生成的elf檔案還不能直接下載下傳執行,通過objcopy工具可生成最終的二進制檔案:

arm-linux-objcopy –O binary bootstrap.elf bootstrap.bin

其中-O binary指定生成為二進制格式檔案。Objcopy還可以生成S格式的檔案,隻需将參數換成-O srec。還可以使用-S選項,移除所有的符号資訊及重定位資訊。如果想将生成的目标代碼反彙編,還可以用objdump工具:

arm-linux-objdump -D bootstrap.elf

至此,所生成的目标檔案就可以直接寫入Flash中運作了。

2.Makefile執行個體

example: head.s   main.c

arm-linux-gcc -c -o head.o head.s

arm-linux-gcc -c -o main.o main.c

arm-linux-ld -Tlink.lds head.o ain.o -o example.elf

arm-linux-objcopy -O binary -S example_tmp.o example

arm-linux-objdump -D -b binary -m arm   example >ttt.s

二. 調試工具

Linux 下的GNU調試工具主要是gdb、gdbserver和kgdb。其中gdb和gdbserver可完成對目标闆上Linux下應用程式的遠端調試。 gdbserver是一個很小的應用程式,運作于目标闆上,可監控被調試程序的運作,并通過序列槽與上位機上的gdb通信。開發者可以通過上位機的gdb輸入指令,控制目标闆上程序的運作,檢視記憶體和寄存器的内容。gdb5.1.1以後的版本加入了對ARM處理器的支援,在初始化時加入- target==arm參數可直接生成基于ARM平台的gdbserver。gdb工具可以從ftp: //ftp.gnu.org/pub/gnu/gdb/上下載下傳。

對于Linux核心的調試,可以采用kgdb工具,同樣需要通過序列槽與上位機上的gdb通信,對目标闆的Linux核心進行調試。可以從http://oss.sgi.com/projects/kgdb/上了解具體的使用方法。

參考資料:

1. Richard Blum,Professional Assembly Language

2. GNU ARM 彙編快速入門,http://blog.chinaunix.net/u/31996/showart.php?id=326146

3. ARM GNU 彙編僞指令簡介,http://www.cppblog.com/jb8164/archive/2008/01/22/41661.aspx

4. GNU彙編使用經驗,http://blog.chinaunix.net/u1/37614/showart_390095.html

5. GNU的編譯器和開發工具,http://blog.ccidnet.com/blog-htm-do-showone-uid-34335-itemid-81387-type-blog.html

6. 用GNU工具開發基于ARM的嵌入式系統,http://blog.163.com/[email protected]/blog/static/32897598200821211144696/

7. objcopy指令介紹,http://blog.csdn.net/junhua198310/archive/2007/06/27/1669545.aspx

繼續閱讀