掌握了基本的arm彙編指令後,要寫出簡單的arm匯程式設計序,還必須要掌握基本的arm彙編偽操作(directive)。現在我們來看乙個簡單的匯程式設計序,該程式呼叫子程式完成了加法操作。
1 ;檔名:test.s
2 ;功能:實現兩個暫存器相加
3 area example,code,readonly ;宣告**段example
4 entry ;標識程式入口
5 code32 ;宣告32位arm指令
6 start mov r0,#0 ;設定引數
7 mov r1,#10
8 loop bl add_sub ;呼叫子程式add_sub
9 b loop ;跳轉到loop
10 add_sub
11 add r0,r0,r1 ;r0 = r0 + r1
12 mov pc,lr ;子程式返回
13 end ;檔案結束
第6、7行將傳遞給子程式的引數存放在r0和r1中,第8行呼叫子程式。第11、12行是子程式的**,完成了2個引數相加,並將結果放在r0後返回主程式。第6、8、10行的start、loop、add_sub是標號,最經常用於跳轉指令b和bl,由於彙編語法要求的緣故,標號必須頂格寫(即:不能在行首有空格),否則編譯器會報錯。與之對應的是,彙編指令一定不能頂格寫。
很明顯分號(;)在匯程式設計序中是注釋符號,相當於c語言的//號。除此之外,當然大家注意到了第3、4、5、13行是我們沒學習過的符號,其實它們就是本文的重點——arm彙編偽操作。首先我先來解釋這幾個偽操作,第3行定義了乙個**段,其段名為example,屬性為唯讀,從而表示第6——12行是程式**(而不是程式資料)。第4行表示整個程式的入口點(即:程式執行的第一條指令)是第6行的mov指令(注1)。第5行表示第6——12行的程式**是arm指令,而不是thumb指令。第13行表示源**檔案結束,其背後的含義就是:如果程式設計師在第13行後還寫有彙編指令,編譯器也根本不會理會這些**,更不會去編譯它們,當然這些**也就不可能出現在最後的可執行檔案中。哈哈,所以請務必記住,在end偽操作的後面再寫**,那是無用功,寫了也白寫。不要不以為然喲,根據經驗,初學者總是會犯這樣的錯誤。
特別說明:第9行的含義是要讓程式在執行結束後,在第9行進行死迴圈,從而讓整個程式定格在第9行。這一點也許你很困惑:在寫應用程式時,程式結束就結束了,源**根本不需要再去寫個死迴圈。但你現在要弄清楚:你寫應用程式時,有os為你處理程式結束後的若干事情。可是,你現在已經得不到os服務。如果你不自己寫第9行的**,那麼當你認為程式已經執行結束(第8行執行完成)的時候,cpu不會聰明地停下來,它會繼續任勞任怨地去取指第11行,繼續執行,這不是你所希望的。其實這還不是最糟糕的,最糟糕的是,如果你的程式沒有11-13行,那麼cpu任勞任怨取出的指令其實是記憶體中的隨機數,但cpu卻會把它當作指令來執行,那麼,你認為此時會出現什麼情況呢?哈哈,只有天知道。
當然,偽操作遠不止這幾條,下面我們再來介紹經常使用的若干偽操作。
gbla:定義全域性算術變數(準確說,應該是全域性符號),例如:gbla testval
seta:對全域性算術符號進行賦值,例如:testval
seta
9;testval seta testval + 1
dcd:在編譯時為整數分配字儲存空間,例如:dcd 0x123456ab,這條偽操作將導致編譯器在最終的二進位制可執行檔案中分配乙個字的空間,並在該空間中存放整數0x123456ab
dcb:在編譯時為整數分配位元組儲存空間,例如:dcb 『a』,這條偽操作將導致編譯器在最終的二進位制可執行檔案中分配乙個位元組的空間,並在該空間中存放字元a的ascii碼
if,else及endif:相當於c語言的條件編譯,例如:
gbla testval
testval
seta 9
if testval < 5
mov r0, #testval
else
mov r1, #testval
endif
if :def:testval
mov r2, #testval
else
info 4, "you should define testval"
endif
編譯器編譯該段**的結果是:
mov r1, #9
mov r2, #9
while及wend:例如
gbla testval
testval seta 1
while testval <= 3
testval seta testval + 1
mov r0, #testval
wend
編譯器編譯該段**的結果是:
mov r0, #2
mov r0, #3
mov r0, #4
macro 、mend及mexit:相當於c語言的巨集替換,例如:
macro
$label xmac $p1,$p2
; code1
$label.loop1
;code2
bge $label.loop1
$label.loop2
;code3
bl $p1
bgt $label.loop2
; code4
adr r0, $p2
;code5
mend
;主程式
abc xmac subr1,de
編譯器編譯該段**的結果是:
;code1
abc.loop1
;code2
bge abc.loop1
abc.loop2
;code3
bl subr1
bgt abc.loop2
;code4
adr r0, de
;code5
equ:相當於c語言的巨集定義,例如:testval equ 4
export: 見「atpcs與混合程式設計」一文
import:見「atpcs與混合程式設計」一文
非常重要的一點是:必須深刻理解彙編偽操作是給編譯器提供某些必要的資訊,以幫助編譯器正確完成程式的編譯。當編譯完成後,彙編偽操作就完成了它的歷史使命,它不可能在最終的可執行程式的二進位制**中留下哪怕是一點點痕跡,當然也就不可能在程式執行時受到cpu的「青睞」。總之記住一句話,彙編偽操作是給編譯器看的,而不是給cpu看的。這是彙編偽操作與彙編指令最大的區別。
為了保持內容的完整,下面給出較為完整的彙編偽操作列表。如需完整的列表,請自行查閱ads自帶的「online books」相關章節。
符號定義(symbol definition)偽操作:
資料定義(data definition)偽操作:
彙編控制(assembly control)偽操作:
資訊報告(reporting)偽操作:
其他(miscellaneous)偽操作:
注1:entry的本意並非如此,此處的含義僅是entry的***而以。關於其本意,後續文章將予以解釋。
ARM彙編程式設計基礎之四 ARM彙編偽操作
掌握了基本的arm彙編指令後,要寫出簡單的arm匯程式設計序,還必須要掌握基本的arm彙編偽操作 directive 現在我們來看乙個簡單的匯程式設計序,該程式呼叫子程式完成了加法操作。1 檔名 test.s 2 功能 實現兩個暫存器相加 3 area example,code,readonly 宣...
ARM彙編程式設計
arm彙編分類 目前常用的arm彙編指令有兩種 1 arm標準彙編 適用於arm公司的彙編器,適合在windows平台下使用,如ads中使用。2 gnu彙編 適用於gnu交叉編譯工具鏈中的彙編器,適合於linux開發平台。匯程式設計序的框架 section data 初始化的資料 section b...
ARM學習之ARM匯程式設計序
在arm thumb 組合語言程式中以程式段為單位組織 段可以分為 段 code section 和資料段 data section 乙個匯程式設計序至少應該有乙個 段,當程式較長時,可以分割為多個 段和資料段,多個段在程式編譯鏈結時最終形成乙個可執行的映像檔案。可執行映像檔案的構成 鏈結器根據系統...