【正文】
L D R R 2 , = $ tim e S T R R 2 , [ R 1 ]M E N D ; 宏 定 義 結 束 ... M A X 0 x 8 5 8 , 1 2 ; 調 用 宏 A D D R 3 , R 0 , R 2 ? 匯編控制偽指令( 5) 上例定義了 MAX宏,宏語句段的功能是完成將兩個參數 date和 time保存到起始地址為 0x1000的內存單元中。 調用宏的好處是不占用傳送參數的寄存器,不用保護現場,但如果多次調用宏,則無形中增加了代碼量。用宏定義中的指令序列替換程序中宏名的調用,并將實際參數的值傳遞給宏定義中的參數。調用宏是通過調用宏的名稱來實現的。 宏是一段功能完整的程序,能夠實現一個特定的功能,在使用中可以把它視為一個子程序。當宏指令被展開時將被替換成相應的值,類似于函數的形式參數。宏調用是通過調用宏的名稱來實現的。當宏定義被展開時,可被替換成相應的符號,通常為一個標號,在一個符號前使用 $表示被匯編時將使用相應的值替代 $后的符號。 在程序中就可以通過宏指令多次調用該代碼段。MACRO定義一個宏語句段的開始, MEND定義宏語句段的結束, MEXIT可以實現從宏程序段的跳出。 ■ 重復匯編: WHILE和 WEND。該類偽指令如下: ■ 宏定義: MACRO和 MEND。 MESSAGE DCB Hi, Monkey$ ;分配字節(jié)類型內存單元 ? 數據定義偽指令( 14) 圖 例 16內存分配示意圖 Hi,Monkey$…字 符 數 據 表 示M E S S A G E低 地 址 A d d r高 地 址A d d r + 9 ? 數據定義偽指令( 15) 例 17 向量中斷表(操作數還可以是程序中的標號)。 D A T A _ B D C B 1 0 , 4 , 0 x 3 3 , 3 * 2 0 ; 分 配 字 節(jié) 類 型 內 存 單 元D A T A _ W D C W 1 0 0 0 , 0 x 1 0 0 0 ; 分 配 半 字 類 型 內 存 單 元D A T A _ D D C D 0 x F F F D 0 0 ; 分 配 字 類 型 內 存 單 元 ? 數據定義偽指令( 12) 圖 例 15內存分配示意圖 …十 六 進 制數 據 表 示D A T A _ DD A T A _ WD A T A _ BF F F D 0 01 0 0 03 E 83 C3 34A A d d r + 0A d d r + 1A d d r + 2A d d r + 3A d d r + 4A d d r + 6A d d r + 8A d d r + C ? 數據定義偽指令( 13) 例 16 分配內存單元舉例(操作數也可以是字符串)。 ? 數據定義偽指令( 11) 匯編程序在匯編期間對存儲器進行內存分配,分配結果如圖 ,其中 Addr代表一個隨機分配的內存地址。 ■ DCQ分配一段雙字的內存單元,其后的每個操作數都占有 8個字節(jié)。 { la b e l} M n e m o n ic O p e r a n d , . . . , O p e r a n d ? 數據定義偽指令( 10) ■ DCW分配一段半字的內存單元,其后的每個操作數都占有兩個字節(jié),操作數是 16位二進制數,取值范圍為32768~ 65535。 Operand為操作數,即內存單元的初始化數據。唯一的區(qū)別是它們分配內存單元的大小不同。 例 14 為 Buf變量申請空間。 %與 SPACE同義。 {label} FIELD expr ? 數據定義偽指令( 7) 例 13 MAP和 FIELD偽指令的使用。 MAP偽指令定義內存表的首地址, FIELD偽指令定義內存表中的各個數據域,并可以為每個數據域指定一個標號供其他的指令引用。 偽指令格式如下: 其中 label為數據域標號, expr表示本數據域在內存表中所占的字節(jié)數。 MAP 0x00, R9 ;定義內存表的首地址為R9Timer FIELD 4 ;定義數據域Timer,長度為4字節(jié)Attrib FIELD 4 ;定義數據域Attrib,長度為4字節(jié)String FIELD 100 ;定義數據域String,長度為100字節(jié) ... ADR R9, DataStart ;設置R9的值,即設置結構化的內存表地址 LDR R0, Attrib ;相當于LDR, R0, [R9, 4] ... ? 數據定義偽指令( 6) ( 3) FIELD: FIELD偽指令用于定義一個結構化內存表中的數據域。 但 MAP、 FIELD偽指令僅僅是定義數據結構,它們并不初始化內存單元的內容。 MAP expr {, base_register} ? 數據定義偽指令( 5) 例 12 MAP指令。 偽指令格式如下: 其中, expr為程序中的標號或數字表達式。{VAR}為匯編器的內臵變量。 ? 數據定義偽指令( 4) ( 2) MAP: MAP偽指令用于定義一個結構化的內存表的首地址。 偽指令格式如下: 例 11 文字池舉例。 ■ 分配一段雙字的內存單元,并用指定的數據初始化: DCQ。 ■ 分配一段半字的內存單元,并用指定的數據初始化: DCW。 ■ 分配一塊內存空間,并用 0初始化: SPACE。 ■ 定義一個結構化的內存表的首地址: MAP。 該類偽指令有許多,這里只詳細介紹如下常用的偽指令,感興趣的可參考相關手冊。表達式的取值范圍為 0~ 31。偏移量也為一個數字表達式,若使用該字段,則當前位臵的對齊方式為: 2的表達式次方 +偏移量。 可能的取值為 2的冪,如 16等,不能為 0。 ARE Example1, CODE, READONLY, ALIGN = 2 ? 段及段屬性定義偽指令( 6) ( 2) ALIGN偽指令: ALIGN偽指令可通過添加填充字節(jié)的方式,使當前位臵滿足一定的對齊方式。 ■ 使用 AREA偽指令將程序分為多個 ELF格式的段,段名稱可以相同,這時同名的段被放在同一個 ELF段中。 ? 段及段屬性定義偽指令( 5) ■ READONLY指定本段為只讀,代碼段的默認屬性為READONLY。各源文件中同名的 COMMON段共用同樣的內存單元,鏈接器為其分配合適的尺寸。該段不包含任何用戶代碼和數據。屬性默認為 READWRITE。屬性默認為 READONLY。任何時候鏈接 section段也必須包括 sectionname段。 ■ ASSOC=section。默認的情況下,代碼段和數據段是 4字節(jié)對齊的, expr可以取 0~ 31的數值,相應的對齊方式為 2expr字節(jié)對齊。 attr為該代碼段或數據段的屬性。 偽指令格式如下: 其中 sectionname為所定義的代碼段或數據段的名稱。 ( 1) AREA偽指令: AREA偽指令用于定義一個代碼段或數據段。每一個匯編文件均要使用一個 END偽指令指示本源程序結束。要用 BX指令操作才能進行切換。其中 CODE16偽指令指示匯編編譯器后面的指令為 16位的 Thumb指令, CODE32偽指令指示匯編編譯器后面的指令為 32位的 ARM指令。 CODE32偽指令指示匯編編譯器后面的指令為 32位的 ARM指令。 ENTRY偽指令用于指定程序的入口點。 例 9 代碼段的例子。 ■ CODE16:指明本段為 16位 Thumb代碼。 ■ ALIGN:定義邊界對齊方式。該類指令介紹如下: ■ AREA:定義一個段開始。 Variable_a SETA expr_aVariable_l SETL expr_lVariable_s SETS expr_s ? 符號定義偽指令( 6) 例 8 給字符串變量賦值。 指令格式如下: 其中 Variable_a、 Variable_l、 Variable_s就是前面全局變量或局部變量所定義的變量名。 ■ SETL偽指令用于給一個全局或局部的邏輯變量賦值。 GBL codebg ;聲明一個全局邏輯變量codebgcodebg SETL {TRUE} ;設置變量為{TRUE} ..MACRO ;聲明一個宏SENDDAT $dat ;宏的原型LCLA bitno ;聲明一個局部數字變量,在此宏中使用...bitno SETA 8 ;設置變量bitno值為8...MEND ? 符號定義偽指令( 5) ( 3)變量賦值偽指令: 變量賦值偽指令用于對已定義的全局變量或局部變量賦值,共有 3條變量賦值偽指令: SETA、 SETL、 SETS。 例 6 使用全局變量。 偽指令格式如下: [GB/LC]L[A/L/S] variable ? 符號定義偽指令( 4) 其中, [GB/LC]L[A/L/S]為變量聲明偽指令,可以為6個變量聲明偽指令( GBLA、 GBLL、 GBLS、 LCLA、LCLL、 LCLS)中的任一個。 ■ GBLL、 LCLL偽指令用于聲明一個邏輯變量,并將其初始化為 {FALSE}。全局變量多用于程序體中,而局部變量用于宏定義體中。 name EQU expr {, type}T_bit EQU 0x20