新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > ARM匯編語言中的偽操作(一)

        ARM匯編語言中的偽操作(一)

        作者: 時間:2016-11-11 來源:網絡 收藏
        偽操作(derective)是ARM匯編語言程序里的一些特殊的指令助記符,其作用主要是為完成匯編程序做各種準備工作,在源程序運行匯編程序處理,而不是在計算機運行期間有機器執行.也就是說,這些偽操作只是匯編過程中起作用,一旦匯編結束,偽操作的使命也就隨之消失.

        符號定義( Symbol Definition )偽操作
        符號定義偽操作用于定義 ARM 匯編程序中的變量、對變量賦值以及定義寄存器的別名。
        包括以下偽操作:
        — 用于聲明全局變量 GBLA 、 GBLL 和 GBLS 。
        — 用于聲明局部變量 LCLA 、 LCLL 和 LCLS 。
        — 用于對變量賦值 SETA 、 SETL 、 SETS 。
        — 為通用寄存器列表定義名稱 RLIST 。

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

        —為協處理器的寄存器定義名稱 CN
        — 為協處理器定義名稱 CP
        — 為VFP的寄存器定義名稱 DN、SN
        — 為FPA的浮點寄存器定義名稱 FN

        1、 GBLA、GBLL 和GBLS
        語法格式:
        GBLA ( GBLL 或 GBLS ) 全局變量名
        GBLA 、 GBLL 和 GBLS 偽操作用于聲明一個 ARM 程序中的全局變量,并將其初始化。其中:
        GBLA 偽操作用于聲明一個全局的算術變量,并初始化為 0 ;
        GBLL 偽操作用于聲明一個全局的邏輯變量,并初始化為 {FALSE};
        GBLS 偽操作用于聲明一個全局的字符串變量,并初始化為空串;
        全局變量名在其作用范圍內必須唯一。 如果用這些偽操作重新聲明已經聲明過的變量,則變量的值將 被初始化成后一次聲明語句中的值。
        使用示例:
        GBLA Test1 ;聲明一個全局的算術變量,變量名為 Test1
        Test1 SETA 0xaa ;將該變量賦值為 0xaa
        SPACE Test1 ;引用該變量

        GBLL Test2 ;聲明一個全局的邏輯變量,變量名為 Test2
        Test2 SETL {TRUE} ;將該變量賦值為真
        GBLS Test3 ;聲明一個全局的字符串變量,變量名為 Test3
        Test3 SETS “ Testing ” ;將該變量賦值為 “ Testing ”

        2、 LCLA、LCLL 和LCLS
        語法格式:
        LCLA ( LCLL 或 LCLS ) 局部變量名
        LCLA 、 LCLL 和 LCLS 偽操作用于聲明一個 ARM 程序中的局部變量,并將其初始化。其中:
        LCLA 偽操作用于聲明一個局部的數字變量,并初始化為 0 ;
        LCLL 偽操作用于聲明一個局部的邏輯變量,并初始化為 {FALSE};
        LCLS 偽操作用于聲明一個局部的字符串變量,并初始化為空串;
        使用示例:
        MACRO ;聲明一個宏

        $label message $a ;宏的原型

        LCLS err ;聲明一個局部串變量err

        err SETS “error no: “ ;向該變量賦值

        $label ;代碼

        INFO 0, “err”:CC: :STR: $a ;使用該串變量

        MEND ;宏定義結束

        3、 SETA、SETL 和SETS
        語法格式:
        變量名 SETA ( SETL 或 SETS ) 表達式
        偽操作 SETA 、 SETL 、 SETS 用于給一個ARM程序中的變量賦值。
        SETA 偽操作用于給一個算術變量賦值;
        SETL 偽操作用于給一個邏輯變量賦值;
        SETS 偽操作用于給一個字符串變量賦值;
        其中,變量名為已經定義過的全局變量或局部變量,表達式為將要賦給變量的值。 在向變量賦值前,必須先聲明該變量。

        4 、 RLIST
        語法格式:
        名稱 RLIST { 寄存器列表 }
        RLIST 偽操作用于對一個通用寄存器列表定義名稱,定義的名稱可在LDM/STM指令中使用。在 LDM/STM 指令中,寄存器列表中的寄存器的訪問次序總是先訪問編號較低的寄存器,再訪問編號較高的寄存器,而不管寄存器列表中各寄存器的排列順序。

        使用示例:
        RegList RLIST {R0-R5 , R8 , R10} ;將寄存器列表名稱定義為 RegList ,可在 ARM 指令 LDM/STM中通過該名稱訪問寄存器列表。


        5 、 CN

        語法格式:

        name CN expr

        其中:name 是該寄存器的名稱

        expr為協處理器的寄存器的編號,數值范圍為0~15。

        CN偽操作用于給一個協處理器的寄存器定義名稱。方便程序員記憶該寄存器的功能

        示例

        Power CN 6 ;將協處理器的寄存器6名稱定義為Power

        注:以下的偽操作類似(可參考CN)

        數據定義( Data Definition )偽操作
        數據定義偽操作包括以下偽操作:

        LTORG 聲明一個數據緩沖池的開始;

        MAP 定義一個結構化的內存表首地址;

        FIELD 定義結構化的內存表中的一個數據域;

        SPACE 分配一塊內存單元,并用0初始化;

        DCB 分配一段字節的內存單元,并用指定的數據初始化;

        DCD及DCDU 分配一段字的內存單元,并用指定的數據初始化;

        DCDO 分配一段字的內存單元,并將每個單元的內容初始化成該單元相對于基態值的寄存器的偏移量;

        DCFD及DCFDU 分配一段雙字的內存單元,并用雙精度的浮點數據初始化;

        DCFS及DCFSU 分配一段字的內存單元, 并用單精度的浮點數據初始化;

        DCI 分配一段字節的內存單元,用指定的數據初始化,指定內存單元中存放的是代碼,而不是數據;

        DCQ及DCQU 分配一段雙字的內存單元,并用64位的整數數據初始化;

        DCW及DCWU 分配一段半字的內存單元,并用指定的數據初始化;

        DATA 在代碼段中使用數據(現在已不再使用,僅用于保持向前兼容)。

        以下主要介紹幾種常用的:
        1、 DCB (“ = ”)
        語法格式:
        標號 DCB 表達式
        用于分配一段字節內存單元并用偽操作中指定的表達式初始化。其中,表達式可以為 -128~ 255 的數值或字符串。
        使用示例:
        Str DCB “ This is a test ! ” ;分配一片連續的字節存儲單元并初始化。

        2、DCD “ &”(或DCDU)
        語法格式:
        標號 DCD (或 DCDU ) 表達式
        用于分配一段字內存單元并用偽操作中指定的表達式初始化。其中,表達式可以為程序中的標號或數字表達式。

        用DCD 分配的字存儲單元是字對齊的,而用 DCDU 分配的字存儲單元并不嚴格字對齊。
        使用示例:
        DataTest DCD 4,5,6 ;其值分別為4,5和6。
        data2 DCD memaddr+4 ;分配一個字單元,其值為程序中標號memaddr加4個字節
        3、DCQ(或DCQU)
        語法格式:
        標號 DCQ (或 DCQU ) 表達式
        用于分配一段以8個字節為單位的內存并用偽操作中指定的表達式初始化。
        用 DCQ 分配的存儲單元是字對齊的,而用 DCQU 分配的存儲單元并不嚴格字對齊。
        使用示例:
        DataTest DCQ -255,2_101 ;2_101指的是二進制的101

        4、 SPACE (“ % ”)
        語法格式:
        標號 SPACE 表達式
        用于分配一塊內存單元,并初始化為 0 。其中,表達式為要分配的字節數。
        使用示例:
        DataSpace SPACE 100 ;分配連續 100 字節的存儲單元并初始化為 0 。

        5、 MAP (“ ^ ”)
        語法格式:
        MAP 表達式 { ,基址寄存器 }
        用于定義一個結構化的內存表的首地址。
        表達式可以為程序中的標號或數字表達式,基址寄存器為可選項,當基址寄存器選項不存在時,表達式的值即為內存表的首地址,當該選項存在時,內存表的首地址為表達式的值與基址寄存器的和。
        MAP 偽操作通常與 FIELD 偽操作配合使用來定義結構化的內存表。
        使用示例:
        MAP 0x100 , R9;定義結構化內存表首地址的值為 0x100 + R9 。

        6、 FILED (“ # ” )
        語法格式:
        標號 FIELD 表達式
        用于定義一個結構化內存表中的數據域。
        表達式的值為當前數據域在內存表中所占的字節數。
        FIELD 偽操作常與 MAP 偽操作配合使用來定義結構化的內存表結構。 MAP 偽操作定義內存表的首地址, FIELD 偽操作定義內存表中的各數據域的字節長度,并可以為每個數據域指定一個標號供其他的指令引用。
        注意 MAP 和 FIELD 偽操作僅用于定義數據結構,并不實際分配存儲單元。
        示例1:
        下面的偽操作序列定義一個內存表,其首地址為固定地址4096,該內存表中包括5個數據域:consta長度為4個字節;constb長度為4個字節;x長度為8個字節;y長度為8個字節;string長度為256個字節。這種內存表稱為基于絕對地址的內存表。

        MAP 4096 ;內存表的首地址為4096(0x1000)

        consta FIELD 4 ;consta長度為4個字節,相對位置為0

        constb FIELD 4 ;constb長度為4個字節,相對位置為5000

        x FIELD 8 ;x長度為4個字節,相對位置為5004

        y FIELD 8 ;y長度為4個字節,相對位置為5012

        string FIELD 256 ;string長度為256字節,相對位置為5020

        ;在指令中可以這樣引用內存表中的數據域:

        LDR R6,consta

        上面的指令僅僅可以訪問LDR指令前面(或后面)4KB地址范圍的數據域

        示例2:

        下面的偽操作序列定義一個內存表,其首地址為0,該內存表中包括5個數據域:consta長度為4個字節;constb長度為4個字節;x長度為8個字節;y長度為8個字節;string長度為256個字節。這種內存表稱為基于相對地址的內存表。

        MAP 4096 ;內存表的首地址為0

        consta FIELD 4 ;consta長度為4個字節,相對位置為0

        constb FIELD 4 ;constb長度為4個字節,相對位置為4

        x FIELD 8 ;x長度為4個字節,相對位置為8

        y FIELD 8 ;y長度為4個字節,相對位置為16

        string FIELD 256 ;string長度為256字節,相對位置為24

        ;可以通過下面的指令方便地訪問地址范圍超過4KB的數據

        MOV R9,#4096

        LDR R5,[R9,constb] ;將內存表中數據域constb讀取到R5中

        在這里,內存表中各數據域的實際內存地址不是基于一個固定地址,而是基于LDR指令執行時R9寄存器中的內容。這樣通過上面方法定義的內存表結構可以在程序中有多個實例(通過在LDR指令中指定不同的基址寄存器值來實現)。通常用R9作為靜態基址寄存器。

        7、LTORG

        用于聲明一個數據緩沖池(literal pool)的開始

        通常ARM匯編編譯器把數據緩沖池放在代碼段的最后面,即下一個代碼段開始之前,或者END偽操作之前。

        當程序中使用LDFD之類的指令時,數據緩沖池的使用可能越界。這時可以使用LTORG偽操作定義數據緩沖池,已越界發生。通常大的代碼段可以使用多個數據緩沖池。

        LTORG偽操作通常放在無條件跳轉指令之后,或者子程序返回指令之后,這樣處理器就不會錯誤地將數據緩沖池中的數據當作指令來執行。

        匯編控制( Assembly Control )偽操作
        匯編控制偽操作用于控制匯編程序的執行流程,常用的匯編控制偽操作包括以下幾條:
        — IF 、 ELSE 、 ENDIF
        — WHILE 、 WEND
        — MACRO 、 MEND
        — MEXIT
        1、 IF、ELSE、ENDIF
        語法格式:
        IF 邏輯表達式
        指令序列 1
        ELSE
        指令序列 2
        ENDIF
        IF 、 ELSE 、 ENDIF 偽操作能根據條件把一段源代碼包括在匯編程序內或者將其排除在程序之外。[是IF偽操作的同義詞,|是ELSE偽操作的同義詞,]是ENDIF偽操作的同義詞。
        IF 、 ELSE 、 ENDIF 偽指令可以嵌套使用。
        使用示例:
        MACRO
        MOV_PC_LR
        [ THUMBCODE
        bx lr
        |
        mov pc,lr
        ]
        MEND
        2、 WHILE、WEND
        語法格式:
        WHILE 邏輯表達式
        指令序列
        WEND
        WHILE 、 WEND 偽操作能根據條件重復匯編相同的或者幾乎相同的一段源代碼。 WHILE 、 WEND 偽操作可以嵌套使用。
        使用示例:
        GBLA Counter ;聲明一個全局的算術變量,變量名為 counter
        counter SETA 3 ;設置循環計數變量counter初始值為3
        WHILE counter <=10 ;由counter控制循環執行的次數
        counter SETA counter+1 ;將循環計數變量加1
        ;代碼 ;代碼
        WEND

        3、 MACRO、MEND
        語法格式:
        MACRO
        [$ label] macroname{ $ parameter1, $ parameter,…… }
        指令序列
        MEND
        MACRO偽操作標識宏定義的開始,MEND標識宏定義的結束。用MACRO及MEND定義一段代碼,稱為宏定義體,這樣在程序中就可以通過宏指令多次調用該代碼段。
        其中, $ label在宏指令被展開時,label會被替換成相應的符號,通常是一個標號。在一個符號前使用$表示程序被匯編時將使用相應的值來替代$后的符號。
        macroname為所定義的宏的名稱。
        $parameter為宏指令的參數。當宏指令被展開時將被替換成相應的值,類似于函數中的形式參數,可以在宏定義時為參數指定相應的默認值。
        宏指令的使用方式和功能與子程序有些相似,子程序可以提供模塊化的程序設計、節省存儲空間并提高運行速度。但在使用子程序結構時需要保護現場,從而增加了系統的開銷,因此,在代碼較短且需要傳遞的參數較多時,可以使用宏匯編技術。
        首先使用MACRO和MEND等偽操作定義宏。包含在 MACRO 和 MEND 之間的代碼段稱為宏定義體,在MACRO偽操作之后的一行聲明宏的原型(包含宏名、所需的參數),然后就可以在匯編程序中通過宏名來調用它。在源程序被匯編時,匯編器將宏調用展開,用宏定義體代替源程序中的宏定義的名稱,并用實際參數值代替宏定義時的形式參數。
        宏定義中的$label是一個可選參數。當宏定義體中用到多個標號時,可以使用類似$label.$internallabel的標號命名規則使程序易讀。
        MACRO 、 MEND 偽操作可以嵌套使用。
        使用示例:
        MACRO
        $HandlerLabel HANDLER $HandleLabel ;宏的名稱為HANDLER,有1個參數$HandleLabel

        $HandlerLabel
        sub sp,sp,#4 ;decrement sp(to store jump address)
        stmfd sp!,{r0} ;PUSH the work register to stack(lr does not push because it return to original address)
        ldr r0,=$HandleLabel;load the address of HandleXXX to r0
        ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX
        str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
        ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
        MEND
        ;在程序中調用該宏
        HandlerFIQ HANDLER HandleFIQ ;通過宏的名稱HANDLER調用宏,其中宏的標號為HandlerFIQ,參數為HandleFIQ
        HandlerIRQ HANDLER HandleIRQ
        HandlerUndef HANDLER HandleUndef
        HandlerSWI HANDLER HandleSWI
        HandlerDabort HANDLER HandleDabort
        HandlerPabort HANDLER HandlePabort
        ;程序被匯編后,宏展開的結果
        HandlerFIQ
        sub sp,sp,#4 ;decrement sp(to store jump address)
        stmfd sp!,{r0} ;PUSH the work register to stack(lr does not push because it return to original address)
        ldr r0,=HandleFIQ;load the address of HandleXXX to r0
        ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX
        str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
        ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)

        b HandlerUndef ;handler for Undefined mode
        b HandlerSWI ;handler for SWI interrupt
        b HandlerPabort ;handler for PAbort
        b HandlerDabort ;handler for DAbort
        b . ;reserved
        b HandlerIRQ ;handler for IRQ interrupt
        b HandlerFIQ ;handler for FIQ interrupt

        4、 MEXIT
        語法格式:
        MEXIT
        MEXIT 用于從宏定義中跳轉出去。
        信息報告偽操作
        ASSERT 斷言錯誤偽操作;
        INFO 匯編診斷信息顯示偽操作;
        OPT 設置列表選項偽操作;
        TTL及SUBT 用于在列表文件每一項的開頭插入一個標題和子標題



        關鍵詞: ARM匯編語言偽操

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 腾冲县| 嘉祥县| 泗洪县| 长兴县| 苍溪县| 托里县| 永德县| 和顺县| 镇江市| 湖州市| 瓦房店市| 龙川县| 琼海市| 兴仁县| 邻水| 宁津县| 金湖县| 肥东县| 饶阳县| 云龙县| 安福县| 东光县| 山东| 潢川县| 永宁县| 周宁县| 明星| 郯城县| 新源县| 东乡县| 青川县| 嘉义县| 利津县| 宣恩县| 达孜县| 三原县| 佛坪县| 德钦县| 天祝| 阿克陶县| 车致|