ARM匯編語(yǔ)言(4) 指令、偽操作、偽指令學(xué)習(xí)
LDR R0,[R1]:指令,將R1指向的內(nèi)存地址存放的內(nèi)容加載到R0中;
本文引用地址:http://m.butianyuan.cn/article/201611/317563.htmLDR R0,LABEL:指令,將標(biāo)號(hào)LABEL所代表的內(nèi)存地址處存放的內(nèi)容加載到R0中;
LDR R0,=10000:偽指令,將常熟10000賦予R0,采用LDR指令+文字池的方式實(shí)現(xiàn);
LDR R0,=LABEL:偽指令,將標(biāo)號(hào)LABEL所代表的內(nèi)存地址賦予R0;
指令部分:
偽操作部分:
符號(hào)定義偽操作:定義變量,對(duì)變量進(jìn)行賦值,定義寄存器名稱(chēng)
GBLA:全局的算術(shù)變量,初始化為0;
GBLL:全局的邏輯變量,初始化為{FALSE};
GBLS:全局的串變量,初始化為“”;
LCLA:局部的算術(shù)變量,初始化為0;
LCLL:局部的邏輯變量,初始化為{FALSE};
LCLS:局部的串變量,初始化為“”;
SETA:給算術(shù)變量賦值;
SETL:給邏輯變量賦值;
SETS:給串變量賦值;
RLIST:為一個(gè)通用寄存器列表定義名稱(chēng);
CN:為一個(gè)協(xié)處理器的寄存器定義名稱(chēng);
CP:為一個(gè)協(xié)處理器定義名稱(chēng);
DN:為一個(gè)雙精度的VFP寄存器定義名稱(chēng);
SN:為一個(gè)單精度的VFP寄存器定義名稱(chēng);
FN:為一個(gè)FPA浮點(diǎn)寄存器定義名稱(chēng);
數(shù)據(jù)定義偽操作
LTORG:聲明一個(gè)數(shù)據(jù)緩沖池的開(kāi)始;
MAP:定義一個(gè)結(jié)構(gòu)化的內(nèi)存表的首地址,同義詞為^;
FIELD:定義一個(gè)結(jié)構(gòu)化內(nèi)存表中的數(shù)據(jù)域,同義詞#;
SPACE:分配一塊內(nèi)存單元,并用0初始化,同義詞%;
{label} SPACE exprexpr表示分配的內(nèi)存字節(jié)數(shù);
DCB:分配一段字節(jié)內(nèi)存單元,并用expr初始化之,同義詞=;
{label} DCB expr, {expr}...expr是-128~255的數(shù)值或字符串;
DCD,DCDU:分配一段字內(nèi)存單元,分配的內(nèi)存都是字對(duì)齊的,并用expr初始化之,同義詞&,DCDU分配的內(nèi)存單元不嚴(yán)格字對(duì)齊;
DCDO:分配一段字內(nèi)存單元,分配的內(nèi)存都是字對(duì)齊的,并將每個(gè)字單元的內(nèi)容初始化為expr標(biāo)號(hào)基于靜態(tài)基址寄存器R9的偏移量;
DCFD,DCFDU:
DCFS,DCFSU:
DCI:(ARM)分配一段字內(nèi)存單元,分配的內(nèi)存都是字對(duì)齊的,并用expr初始化;(Thumb)分配一段半字內(nèi)存單元,分配的內(nèi)存都是半字對(duì)齊的,并用expr初始化;
DCQ,DCQU:
DCW,DCWU:
匯編控制偽操作
IF,ELSE,ENDIF:根據(jù)條件將一段源代碼包括在匯編語(yǔ)言程序中或者將其排除在程序之外;
IF logical expression
instructions or directives
ELSE
instructions or directives
ENDIF
WHILE,WEND:根據(jù)條件重復(fù)匯編相同的或者幾乎相同的一段源代碼;
WHILE logical expression
instructions or directives
WEND
MACRO,MEND:定義宏定義體;
MEXIT:從宏中跳轉(zhuǎn)出去;
棧中數(shù)據(jù)幀描述偽操作;
信息報(bào)告?zhèn)尾僮鳎?/p>
其它偽操作:
CODE16,CODE32:
EQU:為數(shù)字常量,基于寄存器的值和程序中的標(biāo)號(hào)定義一個(gè)字符名稱(chēng),同義詞*;
name EQU expr {, type}
AREA:
ENTRY:
END:
ALIGN:
EXPORT:
GLOBAL:
IMPORT:
EXTERN:
GET:
INCLUDE:
INCBIN:
KEEP:
NOFP:
REQUIRE:
REQUIRE8:
PRESERVE8:
RN:
ROUT:
偽指令部分:偽指令不是真正的指令,在匯編編譯器對(duì)源程序進(jìn)行匯編處理時(shí)被替換成對(duì)應(yīng)的ARM或者Thumb指令;
ADR(小范圍的地址讀取偽指令):將基于PC的地址值或者基于寄存器的地址值讀取到寄存器中;
ADR{cond} register, expr
expr是基于PC或者基于寄存器的地址表達(dá)式,取值范圍如下:
地址值不是字對(duì)齊時(shí),取值范圍-255~255;
地址值是字對(duì)齊時(shí),取值范圍-1020~1020;
地址值是16字節(jié)對(duì)齊時(shí),取值范圍更大;
ADRL(中等范圍的地址讀取偽指令):將基于PC的地址值或者基于寄存器的地址值讀取到寄存器中;
ADRL{cond} register, expr
expr是基于PC或者基于寄存器的地址表達(dá)式,取值范圍如下:
地址不是字對(duì)齊時(shí),-64KB~64KB;
地址是字對(duì)齊時(shí),-256KB~256KB;
地址是16字節(jié)對(duì)齊時(shí),取值范圍更大;
LDR:將一個(gè)32位的常數(shù)或者一個(gè)地址值讀取到寄存器中;
LDR{cond} register, ={expr | label-expr}
expr為32位常量;
label-expr為基于PC的地址表達(dá)式或者外部表達(dá)式;
NOP:匯編時(shí)被替換成ARM中的空操作;
實(shí)例程序:
1、
AREA LDR_Code, CODE, READONLY
ENTRY
LDR r0, =src
LDR r1, =dst
MOV r2, r0
MOV r3, r1
MOV r5, #100
LDR r6, =100
LDR r7, =999999
srcDCD 0, 1;, 2, 3, 4, 5, 6, 7, 8, 9
dstDCD 0, 0;, 0, 0, 0, 0, 0, 0, 0, 0
END
反匯編代碼:
$a
LDR_Code
0x00000000: e59f0024 $... LDR r0,0x2c
0x00000004: e59f1024 $... LDR r1,0x30
0x00000008: e1a02000 . .. MOV r2,r0
0x0000000c: e1a03001 .0.. MOV r3,r1
0x00000010: e3a05064 dP.. MOV r5,#0x64
0x00000014: e3a06064 d`.. MOV r6,#0x64
0x00000018: e59f7014 .p.. LDR r7,0x34
src
$d
0x0000001c: 00000000 .... DCD 0
0x00000020: 00000001 .... DCD 1
dst
0x00000024: 00000000 .... DCD 0
0x00000028: 00000000 .... DCD 0
0x0000002c: 0000001c .... DCD 28
0x00000030: 00000024 $... DCD 36
0x00000034: 000f423f ?B.. DCD 999999
(1)為L(zhǎng)DR偽指令生成的代碼,似乎有問(wèn)題,不是基于PC的值,還是有默認(rèn)的規(guī)則?
使用GNU ARM Assembly將上面的代碼重新實(shí)現(xiàn)一次:
.section .text
.global _start
_start:
LDR r0, =src
LDR r1, =dst
LDR r2, =1000
LDR r3, =5555
MOV r4, r2
MOV r5, r3
.section .data
src: .word 0, 0
dst: .word 0, 1
編譯通過(guò)了,不確定代碼有沒(méi)有問(wèn)題,后面再檢查
將上面的代碼使用arm-none-eabi-as編譯不鏈接,然后使用arm-none-eabi-objdump反匯編:
Disassembly of section .text:
00000000 <_start>:
0: e59f0010 ldr r0, [pc, #16] ; 18 <_start+0x18>
4: e59f1010 ldr r1, [pc, #16] ; 1c <_start+0x1c>
8: e3a02ffa mov r2, #1000 ; 0x3e8
c: e59f300c ldr r3, [pc, #12] ; 20 <_start+0x20>
10: e1a04002 mov r4, r2
14: e1a05003 mov r5, r3
18: 00000000 andeq r0, r0, r0
1c: 00000008 andeq r0, r0, r8
20: 000015b3 strheq r1, [r0], -r3
誠(chéng)如文檔中對(duì)LDR的介紹:
LDR r0, =src
LDR r1, =dst
LDR r2, =1000
LDR r3, =5555
這四條命令都進(jìn)行了處理,以LDR r0, =src為例:
0: e59f0010 ldr r0, [pc, #16] ; 18 <_start+0x18>
src的值被存儲(chǔ),ldr指令將[pc, #16]地址中的值加載到寄存器r0中,
ARM處理器中,pc的值為當(dāng)前執(zhí)行的指令的地址值加上8,因此,執(zhí)行該條
指令時(shí),pc的值為8,此時(shí)pc加上16,則為十進(jìn)制的24,十六進(jìn)制的
0x18,但是此時(shí)地址單元0x18中存儲(chǔ)的卻是一條指令:
andeq r0, r0, r0
為什么?
將之前編譯生成的.o文件使用arm-none-eabi-ld進(jìn)行連接,生成可執(zhí)行文件,
然后反匯編,此時(shí)代碼變?yōu)椋?/p>
Disassembly of section .text:
00008000 <_start>:
8000: e59f0010 ldr r0, [pc, #16] ; 8018 <_start+0x18>
8004: e59f1010 ldr r1, [pc, #16] ; 801c <_start+0x1c>
8008: e3a02ffa mov r2, #1000 ; 0x3e8
800c: e59f300c ldr r3, [pc, #12] ; 8020 <_start+0x20>
8010: e1a04002 mov r4, r2
8014: e1a05003 mov r5, r3
8018: 00010024 andeq r0, r1, r4, lsr #32
801c: 0001002c andeq r0, r1, ip, lsr #32
8020: 000015b3 strheq r1, [r0], -r3
此時(shí),src的值應(yīng)該存放在0x8000 + 8 + 16,8和16都是十進(jìn)制的,因此應(yīng)該是0x8018,
但是0x8018地址單元中為:
andeq r0, r1, r4, lsr #32
lsr在上一篇尋址方式中有所介紹,此時(shí)r4中的值通過(guò)上面的指令可知為十進(jìn)制的1000,十六進(jìn)制的0x3E8,
0x3E8的二進(jìn)制:
0000 0000 0000 0000 0000 0011 1110 1000,執(zhí)行l(wèi)sr #32操作,右移32位,則變?yōu)?,
r1中此時(shí)不管是什么值,AND指令執(zhí)行按位取與操作,指令的執(zhí)行結(jié)果自然是0,存放到r0寄存器中?
此處應(yīng)該是個(gè)pool?為什么是指令?
(2)$a、$d分別表示什么意思?
摘錄自:Using asThegnuAssembler的Mapping Symbols章節(jié)
The ARM ELF specification requires that special symbols be inserted into object files to
mark certain features:
$a At the start of a region of code containing ARM instructions.
$t At the start of a region of code containing THUMB instructions.
$d At the start of a region of data.
待補(bǔ)充...
評(píng)論