新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > ARM匯編編程基礎之四-ARM匯編偽操作

        ARM匯編編程基礎之四-ARM匯編偽操作

        作者: 時間:2016-11-27 來源:網絡 收藏
        掌握了基本的ARM匯編指令后,要寫出簡單的ARM匯編程序,還必須要掌握基本的ARM匯編偽操作(directive)。現在我們來看一個簡單的匯編程序,該程序調用子程序完成了加法操作。

        1 ;文件名:TEST.S
        2 ;功能:實現兩個寄存器相加
        3AREA Example,CODE,READONLY ;聲明代碼段Example
        4ENTRY ;標識程序入口
        5CODE32 ;聲明32位ARM指令
        6STARTMOV R0,#0 ;設置參數
        7MOV R1,#10
        8LOOP BL ADD_SUB ;調用子程序ADD_SUB
        9B LOOP ;跳轉到LOOP
        10 ADD_SUB
        11ADD R0,R0,R1 ;R0 = R0 + R1
        12MOV PC,LR ;子程序返回
        13END ;文件結束

        本文引用地址:http://www.104case.com/article/201611/322181.htm

        第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:對全局算術符號進行賦值,例如:testvalSETA9;testval SETA testval + 1

        DCD:在編譯時為整數分配字存儲空間,例如:DCD 0x123456ab,這條偽操作將導致編譯器在最終的二進制可執行文件中分配一個字的空間,并在該空間中存放整數0x123456ab

        DCB:在編譯時為整數分配字節存儲空間,例如:DCB ‘a’,這條偽操作將導致編譯器在最終的二進制可執行文件中分配一個字節的空間,并在該空間中存放字符a的ASCII碼

        IF,ELSE及ENDIF:相當于C語言的條件編譯,例如:

        GBLA testval
        testvalSETA 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看的。這是匯編偽操作與匯編指令最大的區別。


        上一頁 1 2 下一頁

        關鍵詞: ARM匯編編程偽操

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 康保县| 湖南省| 醴陵市| 阿合奇县| 黔东| 门头沟区| 济南市| 海伦市| 威海市| 拜城县| 布尔津县| 双牌县| 什邡市| 巴南区| 东乌| 呼玛县| 玉溪市| 岳阳县| 中宁县| 黄梅县| 项城市| 突泉县| 长武县| 漳浦县| 隆尧县| 长宁县| 平度市| 景泰县| 定安县| 丽江市| 仁化县| 贵德县| 乌兰浩特市| 阳城县| 新乡市| 工布江达县| 当涂县| 金川县| 钦州市| 双桥区| 北碚区|