加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專(zhuān)業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長(zhǎng)期合作伙伴
立即加入
  • 正文
    • 10.5  ARM匯編程序設(shè)計(jì)舉例
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

ARM匯編程序設(shè)計(jì)之: ARM匯編程序設(shè)計(jì)舉例

2013/09/30
1
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

?

10.5??ARM匯編程序設(shè)計(jì)舉例

在本節(jié)中通過(guò)一些例子來(lái)說(shuō)明ARM中偽操作及指令的基本用法。

10.5.1??條件跳轉(zhuǎn)及循環(huán)

1.ALU狀態(tài)標(biāo)志

所有ARM指令都可以條件執(zhí)行。大部分ARM指令集和Thumb-2指令集的數(shù)據(jù)處理指令都可以選擇是否根據(jù)指令的執(zhí)行結(jié)果設(shè)置ALU的狀態(tài)標(biāo)志位。

注意

較早的ARM體系結(jié)構(gòu)中使用的Thumb指令不能選擇是否更新ALU的標(biāo)志位。當(dāng)數(shù)據(jù)處理指令執(zhí)行完后,處理器自動(dòng)根據(jù)指令的執(zhí)行結(jié)果更新?tīng)顟B(tài)標(biāo)志。

較早的Thumb-2指令只有跳轉(zhuǎn)指令可以條件執(zhí)行。新的體系結(jié)構(gòu)中的Thumb-2指令可以IT(if-then)標(biāo)識(shí)使程序條件執(zhí)行。

更詳細(xì)的介紹請(qǐng)參加本書(shū)的指令集部分。

2.ARM狀態(tài)下的條件執(zhí)行

在程序狀態(tài)寄存器CPSR中保存著以下4個(gè)ALU狀態(tài)標(biāo)志。

·??N:當(dāng)指令的執(zhí)行結(jié)果為負(fù)時(shí),該位置1。

·??Z:當(dāng)指令的執(zhí)行結(jié)果為零時(shí),該位置1。

·??C:當(dāng)指令的執(zhí)行結(jié)果有進(jìn)位時(shí),該位置1。

·??V:當(dāng)指令的執(zhí)行結(jié)果溢出時(shí),該位置1。

當(dāng)加法操作的結(jié)果大于等于232或加法操作的結(jié)果為負(fù)時(shí),進(jìn)位標(biāo)志C置位。

當(dāng)加法、減法、比較操作結(jié)果大于等于231或小于-232時(shí),溢出標(biāo)志V置位。

在ARM指令后增加條件域可以使指令條件執(zhí)行,各條件碼的含義和助記符如表10.11所示??蓷l件執(zhí)行的指令可以在其助記符的擴(kuò)展域加上條件碼助記符,從而在特定條件下執(zhí)行。

表10.11 指令的條件碼

條??件??碼

助記符后綴

標(biāo)????志

含????義

0000

EQ

Z置位

相等

0001

NE

Z清零

不相等

0010

CS

C置位

無(wú)符號(hào)數(shù)大于或等于

0011

CC

C清零

無(wú)符號(hào)數(shù)小于

0100

MI

N置位

負(fù)數(shù)

0101

PL

N清零

正數(shù)或零

0110

VS

V置位

溢出

0111

VC

V清零

未溢出

1000

HI

C置位Z清零

無(wú)符號(hào)數(shù)大于

1001

LS

C清零Z置位

無(wú)符號(hào)數(shù)小于或等于

1010

GE

N等于V

帶符號(hào)數(shù)大于或等于

1011

LT

N不等于V

帶符號(hào)數(shù)小于

1100

GT

Z清零且(N等于V)

帶符號(hào)數(shù)大于

1101

LE

Z置位或(N不等于V)

帶符號(hào)數(shù)小于或等于

1110

AL

忽略

無(wú)條件執(zhí)行

默認(rèn)情況下,ARM指令并不會(huì)更新ARM寄存器cpsr中的N、Z、C、V標(biāo)志。對(duì)大多數(shù)指令,若要更新這些標(biāo)志需要對(duì)指令助記符加后綴S。但CMP指令不需要S后綴就更新這些標(biāo)志位。

下面的一段程序,說(shuō)明了指令的S后綴和條件執(zhí)行的過(guò)程。

???ADD?????r0,?r1,?r2 ;r0?=?r1?+?r2,不更新標(biāo)志位

???ADDS????r0,?r1,?r2 ;r0?=?r1?+?r2,并且更新標(biāo)志位

???ADDSCS??r0,?r1,?r2 ;如果進(jìn)位標(biāo)志位C=1,r0?=?r1?+?r2,并且更新標(biāo)志位

???CMP?????r0,?r1 ;根據(jù)?r0-r1的結(jié)果更新標(biāo)志位

從上面的例子可以看出,無(wú)論更新標(biāo)志位標(biāo)志“S”是否設(shè)置,CMP指令自動(dòng)更新標(biāo)志位。

3.條件執(zhí)行的例子

通過(guò)組合使用條件執(zhí)行和條件標(biāo)志設(shè)置,可是簡(jiǎn)單地實(shí)現(xiàn)分支語(yǔ)句,不需要任何分支指令。這樣可以改善性能,因?yàn)榉种е噶顣?huì)占用較多的周期數(shù);同時(shí)這樣做也可以減小代碼尺寸,提高代碼密度。

下面是一段C語(yǔ)言程序,該程序?qū)崿F(xiàn)了著名的Euclid最大公約數(shù)算法。

int?gcd(int?a,?int?b)

{

??????while?(a?!=?b)

????????{

???????????if?(a?>?b)

???????????????????a?=?a?-?b;

???????????else

???????????????????b?=?b?-?a;

????????}

??????return?a;

}

用ARM匯編語(yǔ)言重寫(xiě)來(lái)重寫(xiě)這個(gè)例子,如下所示。

【程序1】

gcd?????CMP??????r0,?r1

?????????BEQ??????end

?????????BLT??????less

?????????SUB??????r0,?r0,?r1

?????????B????????gcd

less

?????????SUB??????r1,?r1,?r0

?????????B????????gcd

End

充分地利用條件執(zhí)行修改上面的例子,得到【程序2】。

【程序2】

gcd

????????CMP??????r0,?r1

????????SUBGT????r0,?r0,?r1

????????SUBLT????r1,?r1,?r0

????????BNE??????gcd

【程序1】?jī)H使用了分支指令,【程序2】充分利用了ARM指令條件執(zhí)行的特點(diǎn),僅使用了4條指令就完成了全部算法。這對(duì)提供程序的代碼密度和執(zhí)行速度十分有幫助。

事實(shí)上,分支指令十分影響處理器的速度。每次執(zhí)行分支指令,處理器都會(huì)排空流水線,重新裝載指令。

注意

新的ARM處理器如ARM10和StrongARM都有分支預(yù)測(cè)硬件。只有當(dāng)分支預(yù)測(cè)硬件失敗時(shí),處理器才排空流水線,重新裝載指令。

?

表10.12和10.13分別總結(jié)了【程序1】和【程序2】在ARM7上的執(zhí)行過(guò)程(假設(shè)r0=1、r1=2)。

表10.12 程序1執(zhí)行過(guò)程

r0:a

R1:b

指????令

執(zhí)行周期(ARM7)

1

2

CMP?r0,?r1

1

1

2

BEQ?end

1?(未執(zhí)行)

1

2

BLT?less

3

1

2

SUB?r1,?r1,?r0

1

1

2

B?gcd

3

1

1

CMP?r0,?r1

1

1

1

BEQ?end

3

Total?=?13

表10.13 程序2執(zhí)行過(guò)程

r0:a

R1:b

指????令

執(zhí)行周期(ARM7)

1

2

CMP?r0,?r1

1

1

2

SUBGT?r0,r0,r1

1?(未執(zhí)行)

1

1

SUBLT?r1,r1,r0

1

1

1

BNE?gcd

3

1

1

CMP?r0,r1

1

1

1

SUBGT?r0,r0,r1

1?(未執(zhí)行)

1

1

SUBLT?r1,r1,r0

1?(未執(zhí)行)

1

1

BNE?gcd

1?(未執(zhí)行)

Total?=?10

從上面的例子可以看出,利用條件執(zhí)行執(zhí)行可以實(shí)現(xiàn)大部分條件語(yǔ)句,比使用條件分支指令效率高很多。

10.5.2??傳送指令程序設(shè)計(jì)

1.加載立即數(shù)

通常,使用MOV和MVN指令向寄存器加載常量,但由于單條MOV或MVN指令只能包含8位立即數(shù),向寄存器加載立即數(shù)需要一些特殊的操作。

注意

在ARMv6T2體系結(jié)構(gòu)及以上版本中,可以使用MOV32偽操作將一個(gè)32位立即數(shù)加載到寄存器。

下面分別介紹加載立即數(shù)的不同方法。

(1)使用MOV和MVN指令

在ARM或Thumb-2狀態(tài)下,可以使用MOV和MVN指令將符合一定規(guī)則的常數(shù)加載到寄存器。在16位的Thumb指令下,可以將0~255的任意常數(shù)加載到寄存器。表10.14列出了在ARM狀態(tài)下可直接加載到寄存器的立即數(shù)。

表10.14 ARM狀態(tài)合法立即數(shù)

二??進(jìn)??制

十??進(jìn)??制

步驟

十六進(jìn)制

MVN指令值

注釋

000000000000000000000000abcdefgh

0~255

1

0~0xFF

-1~-256

0000000000000000000000abcdefgh00

0~1020

4

0~0x3FC

-4~-1024

00000000000000000000abcdefgh0000

0~4080

16

0~0xFF0

-16~-4096

000000000000000000abcdefgh000000

0~16320

64

0~0x3FC0

-64~-16384

...

...

...

...

abcdefgh000000000000000000000000

0~255×224

224

0~0xFF000000

1~256ד-224”

cdefgh000000000000000000000000ab

(bit?pattern)

(bit?pattern)

efgh000000000000000000000000abcd

(bit?pattern)

(bit?pattern)

gh000000000000000000000000abcdef

(bit?pattern)

(bit?pattern)

00000000000000000000abcdefghijkl

0~4095

1

0~0xFFF

注釋

①?在ARM數(shù)據(jù)操作指令中,除MVN外,其他指令不能直接操作MVN的值,即MVN列所列出的立即數(shù)在其他數(shù)據(jù)操作指令中可能為非法操作數(shù)。

②?表中所列數(shù)據(jù)為ARM狀態(tài)合法數(shù)據(jù),對(duì)Thumb-2狀態(tài)不一定適用。

③?這些值只能在ARMv6T2體系結(jié)構(gòu)及其以上版本中適用。

ARM狀態(tài)下立即數(shù)的使用要符合以下規(guī)則。

①?每個(gè)立即數(shù)由一個(gè)8位的常數(shù)循環(huán)右移偶數(shù)位得到。

注意

這樣得到的立即數(shù)對(duì)任何數(shù)據(jù)處理指令都是合法的。

②?MVN指令向寄存器加載一個(gè)合法立即數(shù)的“按位反”,即-(n+1)。其中n為MOV指令可以加載的合法立即數(shù)。

③?ARMv6T2體系結(jié)構(gòu)及其以上版本,可以加載12位的立即數(shù),但MVN指令不能加載此12位立即數(shù)的“按位反”。

?

在ARMv6T2體系結(jié)構(gòu)及其以上版本的Thumb狀態(tài)下,可以加載的合法立即數(shù)有以下規(guī)則。

①?32位的MOV指令可以加載的立即數(shù)符合以下規(guī)則。

·??任意8位立即數(shù)(范圍0x0~0xff)。

·??任意8位立即數(shù)向左移任意位。

·??任意8位立即數(shù)重復(fù)4次填充32位寄存器。

·??使用任意8位立即數(shù)填充一個(gè)32位寄存器的第0和第2字節(jié),其余兩個(gè)字節(jié)填充0。

·??使用任意8位立即數(shù)填充一個(gè)32位寄存器的第1和第3字節(jié),其余兩個(gè)字節(jié)填充0。

注意

通過(guò)上述方法得到的立即數(shù),在其他數(shù)據(jù)操作指令中同樣合法。

②?MVN指令向寄存器加載一個(gè)合法立即數(shù)的“按位反”,即-(n+1)。其中n為MOV指令可以的加載的合法立即數(shù)。

③?可以加載任意12位的立即數(shù),但MVN指令不能加載此12位立即數(shù)的“按位反”。

表10.15列出了在Thumb-2狀態(tài)下可直接加載到寄存器的立即數(shù)。

表10.15 Thumb狀態(tài)合法立即數(shù)

二??進(jìn)??制

十進(jìn)制

步驟

十?六?進(jìn)?制

MVN指令值

注釋

000000000000000000000000abcdefgh

0~255

1

0~0xFF

-1?to?-256

00000000000000000000000abcdefgh0

0~510

2

0~0x1FE

-2?to?-512

0000000000000000000000abcdefgh00

0~1020

4

0~0x3FC

-4?to?-1024

...

...

...

...

0abcdefgh00000000000000000000000

0~0x7F800000

abcdefgh000000000000000000000000

0~0xFF000000

abcdefghabcdefghabcdefghabcdefgh

(bit?pattern)

-

0xXYXYXYXY

-

00000000abcdefgh00000000abcdefgh

(bit?pattern)

-

0x00XY00XY

0xFFXYFFXY

abcdefgh00000000abcdefgh00000000

(bit?pattern)

-

0xXY00XY00

0xXYFFXYFF

00000000000000000000abcdefghijkl

0~4095

1

0~0xFFF

-

(2)使用MOV32偽操作

ARMv6T2體系結(jié)構(gòu)中,ARM和Thumb-2指令集包括下面兩條數(shù)據(jù)傳送指令。

·??MOV指令:可以加載任意8位立即數(shù)到32位寄存器。

·??MOVT指令:可以加載任意16位立即數(shù)(0x0~0xffff)到32寄存器的高16位或低16位,而不改變余下的位。

可以使用組合的MOV和MOVT指令加載任意32位立即數(shù)到寄存器,也可以使用偽操作MOV32實(shí)現(xiàn)上述兩條指令的組合功能。匯編器在掃描源代碼時(shí),自動(dòng)將偽操作MOV32編譯成MOV加MOVT指令的組合。

(3)使用LDR偽操作

LDR?Rd,=const偽操作可以將任意32位立即數(shù)加載到寄存器??梢允褂么藗尾僮鲗⒊鯩OV和MVN指令操作范圍的立即數(shù)加載到寄存器。LDR的效率很高,如果立即數(shù)可以由指令中的<shifter_operand>表示,則匯編器生成相應(yīng)的MOV或MVN指令;如果立即數(shù)不能由<shifter_operand>直接表示,則匯編器將該立即數(shù)放到一個(gè)緩沖池(literal?pool),并生成一條將該緩沖池內(nèi)容加載到目標(biāo)寄存器的LDR指令。例如,

LDR??????rn,?[pc,?#offset?to?literal?pool]

該指令從地址[pc,?#offset?to?literal?pool]向Rn寄存器加載一個(gè)字。因此,必須確保在該LDR指令的訪問(wèn)范圍內(nèi),存在一個(gè)可用的緩沖池。匯編器會(huì)在每個(gè)段后面添加一個(gè)緩沖池。對(duì)于ARM指令集,計(jì)數(shù)器PC的偏移量必須小于4KB,對(duì)于Thumb指令,PC的偏移量必須小于1KB。通常,匯編器會(huì)在LDR偽操作后尋找可用的緩沖池,但是,如果LDR指令與默認(rèn)緩沖池距離太遠(yuǎn),則匯編器將會(huì)報(bào)錯(cuò)。此時(shí)必須在LDR指令上下4KB(Thumb為1KB)之間用LTORG偽操作顯式地在代碼段中添加緩沖池,而且由于緩沖池在代碼段中,必須確保它不會(huì)被處理器作為指令而加以執(zhí)行。通常將其緊跟在無(wú)條件跳轉(zhuǎn)指令后面。

下面是使用LDR偽操作加載立即數(shù)的例子。

AREA?????Loadcon,?CODE,?READONLY

ENTRY ;函數(shù)入口

start BL???????func1 ;跳轉(zhuǎn)到func1

BL???????func2 ;跳轉(zhuǎn)到func2

stop MOV??????r0,?#0x18 ;angel_SWIreason_ReportException為SWI調(diào)用準(zhǔn)備參數(shù)

LDR??????r1,?=0x20026 ;調(diào)用SWI的ADP_Stopped_ApplicationExit功能

SWI??????0x123456 ;調(diào)用ARM?semihosting?SWI

func1

LDR??????r0,?=42 ;將立即數(shù)42存入

LDR??????r1,?=0x55555555

;將立即數(shù)0x55555555存入r1,該指令被編譯為L(zhǎng)DR?R1,[PC,#offset]

LDR??????r2,?=0xFFFFFFFF ;將0xFFFFFFFF存入r2

BX???????lr

LTORG ;緩存池?1?contains

;該緩存池中包含立即數(shù)Ox55555555

func2

LDR??????r3,?=0x55555555

;將立即數(shù)存入r3,該偽操作被編譯為L(zhǎng)DR?R3,[PC,#offset]

;?LDR?r4,?=0x66666666 ;將立即數(shù)0x66666666存入r4

BX???????lr

LargeTable

SPACE????4200 ;申請(qǐng)4200字節(jié)的內(nèi)存空間并初始化為零

END ;Literal?Pool?2?is?empty

(4)加載浮點(diǎn)常數(shù)

ARM體系結(jié)構(gòu)中,允許加載單精度和雙精度的浮點(diǎn)數(shù)。詳細(xì)信息請(qǐng)參見(jiàn)FLD偽操作。

?

2.加載程序地址

通常在編寫(xiě)程序時(shí)需要加載程序地址。這些地址包括變量地址、字符串地址或程序跳轉(zhuǎn)表的入口地址。這些地址通常是基于程序計(jì)數(shù)器PC或某個(gè)基址寄存器的偏移量。

下面分別介紹加載程序地址的不同方法。

(1)使用ADR和ADRL偽操作

使用ADR和ADRL偽操作可以直接向寄存器加載程序地址。ADR和ADRL偽操作的操作數(shù)可以是程序相關(guān)表達(dá)式,匯編器在編譯時(shí),將此表達(dá)式轉(zhuǎn)換成相對(duì)PC或寄存器的偏移量加載到目標(biāo)寄存器。

注意

ADR和ADRL偽操作所加載的地址是有一定限制的。加載的標(biāo)號(hào)地址必須和當(dāng)前指令在同一代碼段內(nèi)。如果加載的程序標(biāo)號(hào)和當(dāng)前指令不在同一代碼段,匯編器將報(bào)錯(cuò)并中止匯編。另外在Thumb狀態(tài)下,ADR偽操作只能產(chǎn)生字對(duì)齊的地址加載指令。

ADRL偽操作只能在ARM狀態(tài)下使用。

ADR和ADRL偽操作(ADR?rn,label或ADRL?rn,label)所能加載的地址范圍依賴使用的指令集。

下面列出了在不同指令集下,ADR偽操作所能加載的地址范圍。

·??ARM:在字節(jié)或半字節(jié)對(duì)齊的內(nèi)存使用模式下,范圍為±255字節(jié)。在字對(duì)齊的內(nèi)存使用模式下,范圍為±1020字節(jié)。

·??16位Thumb指令集:0~1020字節(jié)。Label必須是字對(duì)齊地址標(biāo)號(hào),可以和偽操作ALIGN配合使用。

·??32位Thumb-2指令集:±4095字節(jié)(無(wú)論標(biāo)號(hào)label是字、半字還是字節(jié)對(duì)齊)。

下面列出了在不同指令集下,ADRL偽操作所能加載的地址范圍。

·??ARM:在字節(jié)或半字節(jié)對(duì)齊的內(nèi)存使用模式下,范圍為±64KB。在字對(duì)齊的內(nèi)存使用模式下,范圍為:±256KB。

·??16位Thumb指令集:ADRL偽指令不可用。

·??32位Thumb-2指令集:±1M字節(jié)(無(wú)論標(biāo)號(hào)label是字、半字還是字節(jié)對(duì)齊)。

匯編過(guò)程中,匯編器將偽指令A(yù)DR編譯成一條ADD或SUB指令,如果一條指令不能完成偽操作的功能,編譯器將報(bào)錯(cuò)。ADRL偽操作被編譯器編譯成兩條數(shù)據(jù)處理指令,詳細(xì)信息參見(jiàn)ARM偽操作一節(jié)。

下面的程序使用ADR偽操作加載了跳轉(zhuǎn)表的入口地址,成功地實(shí)現(xiàn)了程序跳轉(zhuǎn)。

AREA????Jump,?CODE,?READONLY ;將該子程序命名為Name

CODE32 ;下面的代碼為ARM代碼

num?????EQU?????2 ;要查找的跳轉(zhuǎn)表入口號(hào)

ENTRY ;程序入口

start ;程序指令開(kāi)始

MOV????r0,?#0 ;為程序跳轉(zhuǎn)加載3個(gè)參數(shù)

MOV?????r1,?#3

MOV?????r2,?#2

BL??????arithfunc ;調(diào)用函數(shù)arithfunc

stop????MOV?????r0,?#0x18 ;為SWI調(diào)用準(zhǔn)備參數(shù)

LDR?????r1,?=0x20026 ;調(diào)用ADP_Stopped_ApplicationExit功能

SWI?????0x123456 ;ARM?semihosting?SWI

arithfunc ;arithfunc函數(shù)入口

CMP?????r0,?#num ;r0中數(shù)值和num做比較

integer

BXHS????lr ;如果r0≥num,函數(shù)返回

ADR?????r3,?JumpTable ;加載跳轉(zhuǎn)表地址

LDR?????pc,?[r3,r0,LSL#2] ;跳轉(zhuǎn)到相應(yīng)的函數(shù)入口

JumpTable

DCD?????DoAdd

DCD?????DoSub

DoAdd???ADD?????r0,?r1,?r2 ;r1和r2相加,結(jié)果放入r0

BX??????lr ;子函數(shù)返回

DoSub???SUB?????r0,?r1,?r2 ;r1和r2相減,結(jié)果放入r0

BX??????lr ;子函數(shù)返回

END ;程序結(jié)束

上面的程序段中,函數(shù)arithfunc帶有3個(gè)參數(shù)(使用r0、r1和r2傳參),函數(shù)的返回值通過(guò)r0返回。參數(shù)1決定該函數(shù)的功能。

·??參數(shù)1=0,結(jié)果=參數(shù)1+參數(shù)2;

·??參數(shù)1=1,結(jié)果=參數(shù)1-參數(shù)2。

程序中偽操作LDR?pc,[r3,r0,LSL#2]向PC寄存器加載了跳轉(zhuǎn)表中的正確的子函數(shù)入口地址。

(2)使用LDR?Rd,?=?label偽指令

使用LDR?Rd,?=?label可以將32位的常數(shù)加載到寄存器。詳見(jiàn)ARM偽指令一節(jié)。

ARM匯編器首先將label地址存入數(shù)據(jù)緩沖池,在使用LDR?rn?[pc,?#offset?to?literal?pool]指令將該label地址加載到寄存器。

使用LDR?Rd,?=?label可以加載本段以外的標(biāo)號(hào)label地址值(與ADR不同)。如果LDR?Rd,?=?label加載的地址標(biāo)號(hào)label和指令不在同一段,匯編器將在目標(biāo)碼中放置重定位偽操作指示連接器在連接時(shí)替換成合適地址值。

下面的例子使用LDR?Rd,?=?label加載了本段之外的標(biāo)號(hào)。

AREA????LDRlabel,?CODE,READONLY

ENTRY ;程序入口

start

BL??????func1 ;跳轉(zhuǎn)到func1

BL??????func2 ;跳轉(zhuǎn)到func2

stop????MOV?????r0,?#0x18 ;為SWI調(diào)用準(zhǔn)備參數(shù)

LDR?????r1,?=0x20026 ;準(zhǔn)備調(diào)用SWI的ADP_Stopped_ApplicationExit功能

SWI?????0x123456 ;semihosting軟中斷調(diào)用

func1

LDR?????r0,?=start ;加載標(biāo)號(hào)地址

LDR?????r1,?=Darea?+?12 ;該偽操作被編譯為指令LDR?R1,[PC,#offset?into

;Literal?Pool?1]

LDR?????r2,?=Darea?+?6000 ;該偽操作被編譯為指令LDR?R2,?[PC,?#offset?into

;Literal?Pool?1]

MOV?????pc,lr ;程序返回

LTORG ;內(nèi)存池1入口

func2

LDR?????r3,?=Darea?+?6000 ;編譯為指令LDR?r3,?[PC,?#offset?into

;Literal?Pool?1]

;(共享內(nèi)存池)

;?LDR???r4,?=Darea?+?6004 ;從內(nèi)存池2中加載新的數(shù)據(jù),因?yàn)閮?nèi)存池2超出范圍,

;所以指令失敗

BX??????lr ;返回

Darea???SPACE???8000 ;申請(qǐng)8000字節(jié)的內(nèi)存空間并初始化為0

END ;程序結(jié)束,內(nèi)存池2超出了LDR指令的數(shù)據(jù)加載范圍

?

3.使用LDM和STM指令實(shí)現(xiàn)堆棧操作

無(wú)論ARM、Thumb-2還是16位Thumb指令集,都有相同的加載多個(gè)寄存器的指令(LDM和STM指令)。多寄存器數(shù)據(jù)傳輸指令為寄存器和內(nèi)存的多數(shù)據(jù)交換提供了有效方法。這些指令通常用于塊拷貝或堆棧操作。使用多寄存器數(shù)據(jù)傳輸指令代替多條單寄存器傳輸指令的組合,有下面幾點(diǎn)優(yōu)勢(shì)。

①?產(chǎn)生的代碼量小,代碼密度高。

②?在沒(méi)有Cache的ARM處理器上使用多寄存器傳輸指令傳輸數(shù)據(jù)時(shí),除第一個(gè)被傳送的數(shù)據(jù)外,其余數(shù)據(jù)均是在連續(xù)的指令周期完成的(第一個(gè)被傳送的數(shù)據(jù)使用非連續(xù)的內(nèi)存周期),提高了指令的執(zhí)行速度。

多寄存器的LDM和STM指令會(huì)增加中斷的延時(shí),因?yàn)锳RM通常不會(huì)打斷正在執(zhí)行的指令去相應(yīng)中斷,而必須等到指令執(zhí)行完。編譯器會(huì)提供一個(gè)開(kāi)關(guān)來(lái)控制Load/Store指令可以傳送的最大寄存器數(shù)目以限制最大的中斷延遲。

更多的關(guān)于LDM和STM指令的信息請(qǐng)參加ARM指令一節(jié)。

使用ARM匯編語(yǔ)言實(shí)現(xiàn)堆棧操作時(shí),下面4條指令常被用到。

·??LDM:加載多寄存器指令;

·??STM:存儲(chǔ)多寄存器指令;

·??PUSH:將多個(gè)寄存器的值存儲(chǔ)到堆棧并更新堆棧指針;

·??POS:從堆棧中裝載多個(gè)寄存器的值并更新堆棧指針。

下面分別介紹操作這些指令時(shí)的一些限制。

對(duì)于LDM/STM指令,可操作的寄存器要滿足以下要求。

①?ARM狀態(tài)下,r0~r15中的任意寄存器或寄存器的組合。

②?在32位的Thumb-2指令集中,可以是r0~r12中的任意寄存器或寄存器的組合或有選擇性的使用r14或r15。

③?在16位的Thumb指令集中,可以使用r0~r7中的任意寄存器或寄存器的組合。

對(duì)于LDM/STM指令,內(nèi)存地址要滿足以下要求。

①?數(shù)據(jù)傳送后增長(zhǎng)。

②?數(shù)據(jù)傳送前增長(zhǎng)(僅在ARM指令集中)。

③?數(shù)據(jù)傳送后減少(僅在ARM指令集中)。

④?數(shù)據(jù)傳送前減少(僅在ARM和32位Thumb指令集中)。

任何當(dāng)前寄存器組的子集都可以使用多寄存器LDM/STM指令與寄存器進(jìn)行數(shù)據(jù)交換?;芳拇嫫鱎n決定目標(biāo)或源地址,可以通過(guò)選擇使用Rn后綴字符“!”來(lái)確定Rn的值是否隨著傳送而改變,就像使用回寫(xiě)前變址尋址的單寄存器傳送指令一樣。

對(duì)于PUSH和POS,要滿足以下要求。

①?使用堆棧指針寄存器r13作為基址寄存器,并在操作后更新該寄存器的值。

②?在每一個(gè)POP指令后,基址寄存器地址自動(dòng)增加;在每一個(gè)PUSH指令后,基址寄存器地址自動(dòng)減少。

③?對(duì)指令操作的寄存器的限制同LDM/STM指令。

在ARM的37個(gè)寄存器中,R13通常用作堆棧指針。堆棧尋址是隱含的,堆棧指針?biāo)付ǖ拇鎯?chǔ)單元就是堆棧的棧頂,堆棧尋址通常有兩種方式:向上生長(zhǎng)(ascending)和向下生長(zhǎng)(descending)。ARM處理器有ARM和Thumb兩種指令集。每種指令集都有豐富的指令可以對(duì)堆棧進(jìn)行操作。堆棧指針指向最后壓入堆棧的有效數(shù)據(jù),稱為滿堆棧(full?stack);堆棧指針指向下一個(gè)數(shù)據(jù)項(xiàng)放入的空位置,稱為空堆棧(empty?stack)。根據(jù)堆棧的生長(zhǎng)方向不同,可以生成4種類(lèi)型的堆棧,即滿遞增、空遞增、滿遞減和空遞減。

注意

這種遞增和遞減的多寄存器傳送指令不僅可以對(duì)堆棧進(jìn)行操作,而且也可以用于正向或反向訪問(wèn)數(shù)組。

為方便堆棧的操作,ARM指令增加了專(zhuān)門(mén)對(duì)堆棧操作的指令后綴。表10.16列出了對(duì)堆棧操作的數(shù)據(jù)傳輸指令。

表10.16 對(duì)堆棧操作的數(shù)據(jù)傳送指令

堆?棧?類(lèi)?型

Push

Pop

滿遞減

STMFD(STMDB,Decrement?Before)

LDMFD?(LDM?,?Icrement?Ater)?

滿遞增

STMFA?(STMIB,?Increment?Before)?

LDMFA?(LDMDA?,?Decrement?After)?

空遞減

STMED?(STMDA,?Decrement?After)?

LDMED?(LDMIB,?Increment?Before)?

空遞增

STMEA?(STM?,?increment?after)?

LDMEA?(LDMDB,?Decrement?Before)?

下面的例子顯示了數(shù)據(jù)傳送指令對(duì)堆棧的操作。

STMFD?r13!,?{r0-r5}???;r0~r5入棧,該堆棧為滿遞減堆棧

LDMFD?r13!,?{r0-r5}???;數(shù)據(jù)出棧,放入寄存器r0~r5,該堆棧為滿遞減堆棧

注意

ARM過(guò)程調(diào)用標(biāo)準(zhǔn)AAPCS定義使用滿遞減堆棧。使用PUSH和POP指令操作堆棧,堆棧類(lèi)型默認(rèn)為滿遞減堆棧,自動(dòng)使用地址回寫(xiě)。

堆棧操作經(jīng)常用于子程序調(diào)用的現(xiàn)場(chǎng)保護(hù)和子程序返回的現(xiàn)場(chǎng)恢復(fù)。另外,子程序的返回地址也常常被壓棧保護(hù)。

下面的例子顯示如何在子程序中進(jìn)行現(xiàn)場(chǎng)保護(hù)和現(xiàn)場(chǎng)恢復(fù)。

subroutine?PUSH?{r5-r7,lr} ;將工作寄存器和返回地址lr壓棧

;?code

BL?somewhere_else

;?code

POP?{r5-r7,pc} ;保存的寄存器數(shù)據(jù)和返回地址出棧

如果系統(tǒng)中存在ARM和Thumb的交互工作,以上代碼只能用于ARMv5架構(gòu)及其以上版本。在ARMv4架構(gòu)中,直接將返回地址送PC,不能引起處理器狀態(tài)的切換。

下面的例子顯示在符合AAPCS標(biāo)準(zhǔn)的滿遞減堆棧上,使用STMFD指令完成的PUSH操作(見(jiàn)圖10.1)。STMFD指令把寄存器內(nèi)容壓棧,SP指針指向棧頂。

圖10.1??滿遞減堆棧的STMFD操作

????????MOV??r1,0x01

????????MOV??r4,0x04

????????STMFD??SP!,{r1,r4}

若要檢查一個(gè)堆棧,必須關(guān)注堆棧的3個(gè)屬性:堆?;贰⒍褩V羔樇岸褩O拗?。堆?;肥嵌褩T?a class="article-link" target="_blank" href="/tag/%E5%AD%98%E5%82%A8%E5%99%A8/">存儲(chǔ)器中的起始地址;堆棧指針初始時(shí)指向堆?;穯卧S著數(shù)據(jù)壓棧,堆棧指針連續(xù)移動(dòng)并始終指向棧頂;如果堆棧指針超過(guò)了堆棧限制,就會(huì)發(fā)生堆棧溢出錯(cuò)誤。下面代碼用于檢測(cè)遞減式堆棧的溢出錯(cuò)誤。

SUB??SP,SP,#size

CPM??SP,r10

BLLO??_stack_overflow??????;條件

AAPCS把寄存器r10定義為堆棧限制或sl(stack?limit)寄存器。這是一個(gè)可選的操作,因?yàn)?,堆棧檢查只有在堆棧檢查使能的時(shí)候才可以使用。BLL0指令是一個(gè)附加了條件助記符L0的帶鏈接的分支指令。如果在執(zhí)行一個(gè)push操作后,SP的值小于r10的值,就發(fā)生了堆棧溢出錯(cuò)誤。如果堆棧指針在執(zhí)行pop操作后,超出了堆棧基址,那么就產(chǎn)生了堆棧下溢(stack?underflow)錯(cuò)誤。

?

4.使用LDM和STM指令實(shí)現(xiàn)塊復(fù)制

當(dāng)程序中有大量數(shù)據(jù)需要復(fù)制或搬移時(shí),常用到LDM和STM指令。雖然使用單寄存器數(shù)據(jù)傳送指令LDR和STR也能實(shí)現(xiàn)同樣的功能,但代碼密度和執(zhí)行效率要低于使用多寄存器傳送指令。

下面通過(guò)兩個(gè)例子說(shuō)明了使用單寄存器數(shù)據(jù)傳送指令和使用多寄存器數(shù)據(jù)傳送指令的區(qū)別。

AREA Word,?CODE,?READONLY ;給代碼段起名為Word

num EQU 20 ;num=20將要拷貝的字的個(gè)數(shù)

ENTRY ;程序入口

call

start

LDR r0,?=src ;r0?=?源操作塊起始地址

LDR r1,?=dst ;r1?=?目的操作塊起始地址

MOV r2,?#num ;r2?=?將要拷貝的字的個(gè)數(shù)

wordcopy LDR r3,?[r0],?#4 ;從源操作塊裝載一個(gè)字

STR r3,?[r1],?#4 ;存儲(chǔ)到目的操作塊

SUBS r2,?r2,?#1 ;指針移到下一個(gè)要拷貝的字單元

BNE wordcopy ;循環(huán)拷貝

stop MOV r0,?#0x18 ;angel_SWIreason_ReportException為軟中斷調(diào)用準(zhǔn)備參數(shù)

LDR r1,?=0x20026 ;調(diào)用Semihosting的ADP_Stopped_ApplicationExit功能

SWI 0x123456 ;ARM?semihosting?SWI調(diào)用

AREA BlockData,?DATA,?READWRITE

src DCD 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4

dst DCD 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

END

下面是使用多寄存器數(shù)據(jù)拷貝命令LDM和STM重寫(xiě)的代碼。

AREA Block,?CODE,?READONLY ;給代碼段起名為Block

num EQU 20 ;num=20將要拷貝的字的個(gè)數(shù)

ENTRY ;程序入口?

call

start

LDR r0,?=src ;r0?=?源操作塊起始地址

LDR r1,?=dst ;r1?=?目的操作塊起始地址

MOV r2,?#num ;r2?=?將要拷貝的字的個(gè)數(shù)

MOV sp,?#0x400 ;設(shè)置堆棧指針?(r13)

blockcopy MOVS r3,r2,?LSR?#3 ;判斷要移動(dòng)的字的個(gè)數(shù)是8的幾倍

BEQ copywords ;如果移動(dòng)的字的個(gè)數(shù)小于8則跳轉(zhuǎn)到copywords子函數(shù)

PUSH {r4-r11} ;將用到的工作寄存器壓棧保存

octcopy LDM r0!,?{r4-r11} ;從源地址拷貝8個(gè)字

STM r1!,?{r4-r11} ;存到目的地址

SUBS r3,?r3,?#1 ;計(jì)數(shù)器減1

BNE octcopy ;如果計(jì)數(shù)器不等于零,繼續(xù)拷貝

POP {r4-r11} ;如果計(jì)數(shù)器等于零,恢復(fù)工作寄存器

copywords ANDS r2,?r2,?#7 ;判斷要拷貝的剩余字個(gè)數(shù)

BEQ stop ;判斷剩余字?jǐn)?shù)是否為零

wordcopy LDR r3,?[r0],?#4 ;從源地址加載一個(gè)字

STR r3,?[r1],?#4 ;到目的地址

SUBS r2,?r2,?#1 ;計(jì)算器減1

BNE wordcopy ;如果計(jì)數(shù)器不等于零,繼續(xù)拷貝

stop MOV r0,?#0x18 ;為軟中斷調(diào)用準(zhǔn)備參數(shù)

LDR r1,?=0x20026 ;調(diào)用Semihosting的ADP_Stopped_ApplicationExit功能

SWI 0x123456 ;調(diào)用Semihosting軟中斷

AREA BlockData,?DATA,?READWRITE

src DCD 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4

dst DCD 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

END

為了增加數(shù)據(jù)拷貝的效率,程序中使用了“MOVS????r3,r2,?LSR?#3”指令。該指令將為下面以8個(gè)字節(jié)為單位進(jìn)行數(shù)據(jù)拷貝做準(zhǔn)備。將數(shù)據(jù)以8個(gè)字為單位拷貝,是因?yàn)锳RM體系結(jié)構(gòu)中所能使用的寄存器為8個(gè),即:r4~r11(根據(jù)AAPCS標(biāo)準(zhǔn),r0~r3在子程序調(diào)用過(guò)程中將被使用)。

10.5.3??宏的使用

使用偽操作MACRO和MEND可以將一段代碼定義為宏。程序運(yùn)行時(shí),使用宏名調(diào)用宏。程序中使用宏的優(yōu)勢(shì)在于。

①?提高代碼的可讀性,使用更能代表程序功能的名稱代替特定的代碼段。

②?避免同一代碼段在程序中重復(fù)多次。

1.宏在分支程序中的應(yīng)用

在ARMv6T2之前的ARM體系結(jié)構(gòu)中,一個(gè)“測(cè)試-分支”操作需要至少兩條ARM指令完成??梢允褂煤甓x這種“分支-測(cè)試”結(jié)構(gòu)。

?????????MACRO

$label??TestAndBranch??$dest,?$reg,?$cc

$label??CMP??????$reg,?#0

??????????B$cc????$dest

??????????MEND

上面的程序段定義了一個(gè)叫做TestAndBranch的宏,并且為該宏定義了4個(gè)參數(shù)($label、$dest、$reg和$cc),在程序中使用該宏時(shí),必須為參數(shù)賦值。下面的程序段顯示了如何調(diào)用TestAndBranch宏。

test????TestAndBranch????NonZero,?r0,?NE

???????????...

???????????...

NonZero

After?substitution?this?becomes:

test????CMP?????r0,?#0

??????????BNE?????NonZero

???????????...

???????????...

NonZero

2.宏在除法中的應(yīng)用

下面的例子程序定義的宏實(shí)現(xiàn)了無(wú)符號(hào)整數(shù)的除法,調(diào)用該宏需要為以下4個(gè)參數(shù)賦值。

·??$Bot:保存除法除數(shù)的寄存器。

·??$Top:指令執(zhí)行前保存被除數(shù),指令執(zhí)行后保存除數(shù)。

·??$Div:保存除法運(yùn)算的商,如果除法只要求余數(shù),該寄存器的值為0。

·??$Temp:臨時(shí)寄存器。

MACRO

$Lab DivMod??$Div,$Top,$Bot,$Temp

ASSERT??$Top?<>?$Bot ;如果使用的寄存器不全相等,產(chǎn)生錯(cuò)誤信息

ASSERT??$Top?<>?$Temp

ASSERT??$Bot?<>?$Temp

IF??????"$Div"?<>?""

????????????ASSERT??$Div?<>?$Top ;如果$Div不為空,產(chǎn)生三個(gè)提示信息

????????????ASSERT??$Div?<>?$Bot

????????????ASSERT??$Div?<>?$Temp

ENDIF

$Lab

MOV?????$Temp,?$Bot ;將除數(shù)放入$Temp

CMP?????$Temp,?$Top,?LSR?#1 ;$Temp乘以2,直到2*$Temp>$Top

90 MOVLS???$Temp,?$Temp,?LSL?#1

CMP?????$Temp,?$Top,?LSR?#1

BLS?????%b90 ;b表示向后搜索

IF??????"$Div"?<>?"" ;如果$Div為空,忽略下一條指令

????????????MOV?????$Div,?#0 ;將$Div初始化

ENDIF

91 CMP?????$Top,?$Temp ;Can?we?subtract?$Temp?$Top大于$Temp?

SUBCS???$Top,?$Top,$Temp ;如果大于,$Top減去$Temp,結(jié)果放入$Top

IF??????"$Div"?<>?"" ;如果$Div為空,忽略下一條指令

????????????ADC?????$Div,?$Div,?$Div ;將$Div乘以2

ENDIF

MOV?????$Temp,?$Temp,?LSR?#1 ;將$Temp除2

CMP?????$Temp,?$Bot ;循環(huán),直到$Temp小于除數(shù)

BHS?????%b91

MEND

下面是該除法宏被引用時(shí)的結(jié)果。

ASSERT r5?<>?r4 ;如果寄存器全不相等,顯示提示信息

ASSERT r5?<>?r2

ASSERT r4?<>?r2

ASSERT r0?<>?r5 ;如果$Div不為空,產(chǎn)生三個(gè)提示信息

ASSERT r0?<>?r4

ASSERT r0?<>?r2

ratio

MOV r2,?r4 ;將除數(shù)放在r2中

CMP r2,?r5,?LSR?#1 ;r2乘以2,直到2*r2>r5

90 MOVLS r2,?r2,?LSL?#1

CMP r2,?r5,?LSR?#1

BLS %b90 ;b表示向后搜索

MOV r0,?#0 ;初始化r0

91 CMP r5,?r2 ;判斷r5是否大于r2

SUBCS r5,?r5,?r2 ;如果大于,r5減去r2,結(jié)果放入r5

ADC r0,?r0,?r0 ;r0乘以2

MOV r2,?r2,?LSR?#1 ;r2除以2

CMP r2,?r4 ;循環(huán),直到r2<r4

BHS %b91

?

10.5.4??使用MAP和FIELD命令描述數(shù)據(jù)結(jié)構(gòu)

可以使用MAP和FIELD偽操作來(lái)描述數(shù)據(jù)結(jié)構(gòu)。這兩個(gè)偽操作一般是一起使用的。

使用MAP和FIELD偽操作定義數(shù)據(jù)結(jié)構(gòu)有以下好處。

·??容易維護(hù)。

·??可以方便地實(shí)現(xiàn)相同數(shù)據(jù)結(jié)構(gòu)的重復(fù)定義。

·??可以更高效地存取數(shù)據(jù)。

MAP偽操作指定數(shù)據(jù)結(jié)構(gòu)的基址。

FIELD偽操作指定一個(gè)數(shù)據(jù)項(xiàng)所需的存儲(chǔ)器數(shù)量,并為該數(shù)據(jù)項(xiàng)指定一個(gè)標(biāo)號(hào)。對(duì)結(jié)構(gòu)中的每個(gè)數(shù)據(jù)項(xiàng)重復(fù)該命令。

注意

使用MAP和FIELD偽操作當(dāng)定義一個(gè)數(shù)據(jù)結(jié)構(gòu)時(shí),不分配存儲(chǔ)器空間。使用定義常數(shù)的命令(如?DCD)來(lái)分配存儲(chǔ)器空間。

?

1.相對(duì)映射

MAP/FIELD偽操作和使用寄存器相對(duì)尋址的LOAD/STORE指令配合使用,訪問(wèn)事先定義好的結(jié)構(gòu)體是MAP/FIELD偽操作的基本用法。

下面是一個(gè)使用寄存器相對(duì)尋址的LOAD指令訪問(wèn)結(jié)構(gòu)體的例子。

MAP?0

consta?FIELD?4 ;consta占用4字節(jié),偏移量為0

constb?FIELD?4 ;constb占用4字節(jié),偏移量為4

x?FIELD?8 ;x占用8字節(jié),偏移量為8

y?FIELD?8 ;y占用8字節(jié),偏移量為16

string?FIELD?256 ;string占用256,偏移量為24

上面定義的數(shù)據(jù)結(jié)構(gòu),可以使用下列指令來(lái)訪問(wèn):

MOV?r9,#4096

LDR?r4,[r9,#constb]

標(biāo)號(hào)是相對(duì)于數(shù)據(jù)結(jié)構(gòu)的開(kāi)始位置的。用于存放映射的起始地址的寄存器(此例中為?r9)稱為基址寄存器。

數(shù)據(jù)結(jié)構(gòu)的位置是由運(yùn)行時(shí)裝載到基址寄存器的值確定的。MAP/FIELD偽操作不實(shí)際分配內(nèi)存地址。

同一映射可以用于描述數(shù)據(jù)結(jié)構(gòu)的多個(gè)實(shí)例。它們可以位于存儲(chǔ)器中的任何位置。

備注

r9是“ARM-Thumb?程序調(diào)用標(biāo)準(zhǔn)”中的靜態(tài)基址寄存器?(sb)。詳細(xì)信息請(qǐng)參閱本書(shū)附錄。

2.基于寄存器的映射

一般情況下,每次訪問(wèn)一個(gè)數(shù)據(jù)結(jié)構(gòu)時(shí)可以使用相同的寄存器作為基址寄存器??梢栽谑褂肕AP定義映射的基址時(shí)指定該寄存器的名稱。

下面的例子顯示了一個(gè)基于寄存器的映射。

MAP?0,r9

consta?FIELD?4 ;consta變量占用4個(gè)字節(jié),地址偏移量為0(相對(duì)于r9中的地址)

constb?FIELD?4 ;constb變量占用4個(gè)字節(jié),地址偏移量為4

x?FIELD?8 ;x占用8個(gè)字節(jié),地址偏移量為8

y?FIELD?8 ;y占用8個(gè)字節(jié),地址偏移量為16

string?FIELD?256 ;字符串占用256字節(jié),起始地址偏移量為24

利用示例中的映射,可以訪問(wèn)數(shù)據(jù)結(jié)構(gòu)(不管它在內(nèi)存中什么位置):

ADR?r9,datastart

LDR?r4,constb?;?=>?LDR?r4,[r9,#4]????????;該偽操作被編譯為L(zhǎng)DR?r4,[r9,#4]

constb包含從數(shù)據(jù)結(jié)構(gòu)開(kāi)始位置算起的數(shù)據(jù)項(xiàng)的偏移量,也包含基址寄存器。在此例中,基址寄存器是在MAP命令中定義的r9。

3.相對(duì)于程序的映射

可以使用程序計(jì)數(shù)器?(r15)?作為一個(gè)映射的基址寄存器。當(dāng)使用r15做為基址寄存器時(shí),被使用LOAD/STORE指令尋址的數(shù)據(jù)結(jié)構(gòu)偏移量不能超出4KB范圍。這是因?yàn)槭褂肞C寄存器為基址的LOAD/STORE指令,最大尋址能力為4KB。

下面的例子顯示了使用r15作為基址寄存器的程序段。其中包含一個(gè)為數(shù)據(jù)結(jié)構(gòu)分配存儲(chǔ)器空間的SPACE偽操作。

datastruc?SPACE?280??????;保留280個(gè)字節(jié)來(lái)定義數(shù)據(jù)結(jié)構(gòu)

MAP?datastruc

consta?FIELD?4

constb?FIELD?4

x?FIELD?8

y?FIELD?8

string?FIELD?256

使用下面的指令讀取constb域所包含的內(nèi)容。

LDR?r2,constb?????;?=>?LDR?r2,[pc,offset]?????該偽操作被編譯為L(zhǎng)DR?r2,[pc,offset]

在此例中,不需要在裝載數(shù)據(jù)之前裝載基址寄存器,此時(shí)使用程序計(jì)數(shù)器PC作為默認(rèn)寄存器。

注意

由于處理器里面的流水線,r15寄存器值和?LDR?指令的實(shí)際地址并不相同。但是,匯編器將修正此問(wèn)題。

?

4.定義結(jié)構(gòu)體的結(jié)束

可以使用帶有0操作數(shù)的FIELD偽操作來(lái)標(biāo)記結(jié)構(gòu)內(nèi)的一個(gè)位置。標(biāo)記位置后位置計(jì)數(shù)器并未增加(即偏移量offset不增加)。

下面的例子使用事先定義好的常量MaxStrLen和ArrayLen定義了字符串和數(shù)組的大小。為了防止MaxStrLen和ArrayLen值過(guò)大,使結(jié)構(gòu)體超出所能使用的內(nèi)存范圍,使用了“FIELD?0”偽操作來(lái)標(biāo)識(shí)結(jié)構(gòu)體的結(jié)束。

StartOfData?EQU?0x1000

EndOfData?EQU?0x2000

MAP?StartOfData

Integer?FIELD?4

Integer2?FIELD?4

String?FIELD?MaxStrLen

Array?FIELD?ArrayLen*8

BitMask?FIELD?4

EndOfUsedData?FIELD?0

ASSERT?EndOfUsedData?<=?EndOfData

該例中使用了:

·??一個(gè)EQU命令定義可使用的最大內(nèi)存空間;

·??一個(gè)帶有0操作數(shù)的FIELD偽操作來(lái)標(biāo)記數(shù)據(jù)結(jié)構(gòu)的結(jié)束位置;

·??一個(gè)ASSERT偽操作確認(rèn)數(shù)據(jù)結(jié)構(gòu)的結(jié)束位置并未超出可用內(nèi)存。

5.強(qiáng)制內(nèi)存對(duì)齊

如果在定義數(shù)據(jù)結(jié)構(gòu)時(shí),使用了一些字符變量(或其他非4字節(jié)的變量),就可能造成內(nèi)存訪問(wèn)的對(duì)齊問(wèn)題。

下面例子中顯示了一個(gè)數(shù)據(jù)結(jié)構(gòu)的定義。該定義方式使整數(shù)訪問(wèn)不能保證在字邊界對(duì)齊。

StartOfData?EQU?0x1000

EndOfData?EQU?0x2000

MAP?StartOfData

Char?FIELD?1

Char2?FIELD?1

Char3?FIELD?1

Integer?FIELD?4?????;?非字邊界對(duì)齊

Integer2?FIELD?4

String?FIELD?MaxStrLen

Array?FIELD?ArrayLen*8

BitMask?FIELD?4

EndOfUsedData?FIELD?0

ASSERT?EndOfUsedData?<=?EndOfData

這里,不能使用ALIGN偽操作來(lái)修正該邊界對(duì)齊問(wèn)題,因?yàn)锳LIGN偽操作只對(duì)齊存儲(chǔ)器內(nèi)的當(dāng)前位置。而MAP和FIELD偽操作不為其定義的結(jié)構(gòu)分配任何存儲(chǔ)空間。

解決的方法是,在Char3?FIELD?1后插入一個(gè)虛擬的FIELD?1。但是,如果改變了字符變量的數(shù)目,就會(huì)造成維護(hù)困難。每次必須重新計(jì)算正確的填充數(shù)。

下面的例子說(shuō)明了一個(gè)更好的調(diào)整填充的方法。該示例使用一個(gè)帶有0操作數(shù)的FIELD偽操作來(lái)標(biāo)記字符數(shù)據(jù)的結(jié)束位置。第二個(gè)FIELD命令根據(jù)標(biāo)號(hào)的值插入正確的填充數(shù)。使用“:AND:”運(yùn)算符來(lái)計(jì)算正確的值。

StartOfData?EQU?0x1000

EndOfData?EQU?0x2000

MAP?StartOfData

Char?FIELD?1

Char2?FIELD?1

Char3?FIELD?1

EndOfChars?FIELD?0

Padding?FIELD?(-EndOfChars):AND:3

Integer?FIELD?4

Integer2?FIELD?4

String?FIELD?MaxStrLen

Array?FIELD?ArrayLen*8

BitMask?FIELD?4

EndOfUsedData?FIELD?0

ASSERT?EndOfUsedData?<=?EndOfData

“(-EndOfChars):AND:3”表達(dá)式計(jì)算正確的填充數(shù):

·??如果EndOfChars是0?mod?4,則填充數(shù)是0;

·??如果EndOfChars是1?mod?4,則填充數(shù)是3;

·??如果EndOfChars是2?mod?4,則填充數(shù)是2;

·??如果EndOfChars是3?mod?4,則填充數(shù)是1。

無(wú)論何時(shí)添加或刪除字符變量,它會(huì)自動(dòng)調(diào)整填充數(shù)。

Arm

Arm

ARM公司是一家知識(shí)產(chǎn)權(quán)(IP)供應(yīng)商,主要為國(guó)際上其他的電子公司提供高性能RISC處理器、外設(shè)和系統(tǒng)芯片技術(shù)授權(quán)。目前,ARM公司的處理器內(nèi)核已經(jīng)成為便攜通訊、手持計(jì)算設(shè)備、多媒體數(shù)字消費(fèi)品等方案的RISC標(biāo)準(zhǔn)。公司1990年11月由Acorn、Apple和VLSI合并而成。

ARM公司是一家知識(shí)產(chǎn)權(quán)(IP)供應(yīng)商,主要為國(guó)際上其他的電子公司提供高性能RISC處理器、外設(shè)和系統(tǒng)芯片技術(shù)授權(quán)。目前,ARM公司的處理器內(nèi)核已經(jīng)成為便攜通訊、手持計(jì)算設(shè)備、多媒體數(shù)字消費(fèi)品等方案的RISC標(biāo)準(zhǔn)。公司1990年11月由Acorn、Apple和VLSI合并而成。收起

查看更多

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

華清遠(yuǎn)見(jiàn)(www.farsight.com.cn)是國(guó)內(nèi)領(lǐng)先嵌入師培訓(xùn)機(jī)構(gòu),2004年注冊(cè)于中國(guó)北京海淀高科技園區(qū),除北京總部外,上海、深圳、成都、南京、武漢、西安、廣州均有直營(yíng)分公司。華清遠(yuǎn)見(jiàn)除提供嵌入式相關(guān)的長(zhǎng)期就業(yè)培訓(xùn)、短期高端培訓(xùn)、師資培訓(xùn)及企業(yè)員工內(nèi)訓(xùn)等業(yè)務(wù)外,其下屬研發(fā)中心還負(fù)責(zé)嵌入式、Android及物聯(lián)網(wǎng)方向的教學(xué)實(shí)驗(yàn)平臺(tái)的研發(fā)及培訓(xùn)教材的出版,截止目前為止已公開(kāi)出版70余本嵌入式/移動(dòng)開(kāi)發(fā)/物聯(lián)網(wǎng)相關(guān)圖書(shū)。企業(yè)理念:專(zhuān)業(yè)始于專(zhuān)注 卓識(shí)源于遠(yuǎn)見(jiàn)。企業(yè)價(jià)值觀:做良心教育、做專(zhuān)業(yè)教育,更要做受人尊敬的職業(yè)教育。