汇编程序有顺序、循环、分支、子程序四种结构形式。
一、顺序结构
程序实例:
AREA Buf,DATA,READWRITE;定义数据段Buf
ArrayDCB 0x11,0x22,0x33,0x44;定义12个字的数组Array
DCB 0x55,0x66,0x77,0x88
DCB 0x00,0x00,0x00,0x00
AREA hello,CODE32,READONLY
ENTRY
LDR R0,=Array;取得数组Array的首地址
LDR R2,[R0];装载数组第1项字数据给R2
MOV R1,#4
LDR R3,[R0,R1,LSL#2];装载数组第5项字数据给R3
ADD R2,R2,R3
MOV R1,#8
STR R2,[R0,R1,LSL#2];保存结构到数组第9项
END
二、分支结构
1、ifelse分支结构的程序实现
C语言实现:
int x=76;
int y=88;
if(x>y)
z=100;
else
z=50
ARM汇编语言实现
MOV R0,#76;初始化R0的值
MOV R1,#88;初始化R1的值
CMP R0,R1;判断R0>R1?
MOVHI R2,100;R0>R1时,R2=100
MOVLS R1,50;R0<R1时,R2=50
2、B指令实现散转功能
CMPR0,#MAX_INDEX;判断索引号是否超出最大索引值
ADDLOPC,PC,R0,LSL#2;索引号若没有超出,则程序跳到相应位置
BHI ERROR;索引号若超出,则进行出错处理
BFUN1;跳到第一个程序
BFUN2;跳到第二个程序
BFUN3;跳到第三个程序
三、循环结构
1、for循环
C语言实现:
for(i = 0; i < 10; i++)
x++;
ARM汇编语言实现:
R0为x,R2为i,均为无符号整数
MOV R0,#0;初始化R0=0
MOV R2,#0;初始化R2=0
FORCMP R2,#10;判断R2<10?
BCS FOR_E;若条件失败(即R>=10),退出循环
ADD R0,R0,#1;执行循环体,R0=R0+1
ADD R2,R2,#1;R2=R2+1
BFOR
FOR_E
2、wihle循环
C语言实现:
while(x<=y)
X*=2;
ARM汇编语言实现:
x为R0,y为R1,均为无符号整数
MOV R0,#1;初始化R0=1
MOV R1,#20;初始化R1=20
BW_2;首先要判断条件
W_1MOVR0,R0,LSL#1;循环体,R0*=2
W_2CMPR0,R1;判断R0<=R1,即x<=y
BLSW_1;若R0<=R1,继续循环体
W_END
3、循环语句实现数据块的复制
ARM汇编语言实现:
LDRR0,=DATA_DST;指向数据目标地址
LDRR1,=DATA_SRC;指向数据源地址
MOVR10,#20;复制数据个数20*N个字
;N为LDM指令操作数据个数
LOOPLDMIAR1!,{R2-R9};从数据源读取8个字节到R2-R9
STMIAR0!,{R2-R9};将R2-R9的数据保存到目标地址
SUBSR10,R10,#1;R0-1,并改变程序状态寄存器
BNELOOP
4、双层for循环的实现
ARM汇编语言实现:
AREABlock,CODE; 声明代码段
ENTRY
;for(i = 0; i < 10; i++)
;for(j = i+1; j<=10; j++)
;z +=1
START
MOV R1, #0; i = 0
MOV R0, #0; Z
LOOP
CMP R1, #10; i < 10
BEQ STOP
ADD R2, R1, #1; j = i+1
LOOP1
CMP R2, #10+1; j<=10
ADDNE R0, R0, #1; z +=1
ADDNE R2, R2, #1; j++
BNE LOOP1
ADD R1, R1, #1; i++
B LOOP
STOP
MOV R0, #0x18
LDR R1, =0x20026
SWI 0x123456
END
5、数据块拷贝
ARM汇编语言实现:
;数据块拷贝,利用LDR/STR指令
num EQU10
AREABlockData,DATA; 声明数据段
srcDCD0,1,2,3,4,5,6,7,8,9; 定义十个数
dstSPACE10*4
AREABlock,CODE; 声明代码段
ENTRY
START
LDRR1, =src
LDR R2, =dst
MOV R3, #num
LOOP
LDR R0, [R1], #4
STR R0, [R2], #4
SUBS R3, R3, #1
BNE LOOP
STOP
MOV R0, #0x18
LDR R1, =0x20026
SWI 0x123456
END
四、子程序
调用程序在调用子程序时,经常需要传送一些参数给子程序,子程序运行完成后也需要回送结果给调用程序。调用程序和子程序之间的信息传送称为参数传送。参数传送的两种方法:
A、当参数比较少时,可以通过寄存器传送参数
B、当参数比较多时,可以通过内存块或堆栈传送参数
调用程序在调入子程序时必须保存正确的返回地址,即当前PC值,PC值可以保存在专用的寄存器R14中,也可以保存到堆栈中。根据这两种情况,可以在子程序采用如下的返回语句:
MOV PC,LR;恢复PC的值
STMFD SP!,{R0-R7,PC};将PC值从堆栈中返回
使用堆栈来恢复处理器的状态时,STMFD与LDMFD要配合使用。
一般来说,在ARM汇编语言程序中,子程序的调用是通过B来实现的。BL在执行时完成如下操作:
将子程序的返回地址存放在链接寄存器LR中,同时将程序计数器PC指向子程序的入口点,当子程序执行完毕需要返回调用处时,只需要将存放在LR中的返回地址重新拷贝给程序计数器PC即可。
C语言实现:
int MAX(int i, int j)
{
if(x > j)
return i;
else
return j;
}
int main(void)
{
int a, b, c;
a = 19;
b = 20;
c = MAX(a, b);
}
ARM汇编语言实现:
XEQU19;定义X的值为19
NEQU20;定义N的值为20
AREA hello,CODE32,READONLY;声明代码段
ENTRY;标识程序入口
STARTLDR R0,=X;给R0,R1赋初值
LDR R1,=N
BL MAX;调用子程序MAX
HALTBHALT;死循环
MAX;声明子程序MAX
CMP R0,R1
MOVHI R2,R0;比较R0,R1,R2等于最大值
MOVLS R2,R1
MOV PC,LR;返回语句
MAX_END
END
五、常见程序设计示例
以下是几个类似C语言编程题目的例子,用ARM汇编语言给出的程序。
1、存储器从0x400000开始的100个单元中存放着ASCII码,编写程序,将其所有的小写字母转换成大写字母,对其它的ASCII码不做变换。
MOVR0,#0x400000
MOVR1,#0
LP
LDRBR2,[R0,R1]
CMPR2,#0x61
BLONEXT
CMPR2,#0x7B;0x61---0x7A为小写字母的ASC
SUBLOR2,R2,#0x20
STRBLOR2,[R0,R1]
NEXT
ADDR1,R1,#1
CMPR1,#100
BNELP
2、编写一简单ARM汇编程序段,实现1+2+…+100的运算
MOVR2,#100
MOVR1,#0
LOOP
ADDR1,R1,R2;R1中为累加和
SUBSR2,R2,#1;R2控制循环
BNELOOP
3、编写程序,比较存储器中0x400000和0x400004两无符号字数据的大小,并且将比较结果存于0x400008的字中,若两数相等其结果记为0,若前者大于后者其结果记为1,若前者小于后者其结果记为-1
MOVR0,#0x400000
LDRR1,[R0];取第1个数
LDRR2,[R0,#4];取第2个数
CMPR1,R2;两个数相比较
MOVHIR1,#1;R1大
MOVLOR1,# -1;R1小
MOVEQR1,#0;两个数相等
STRR1,[R0,#8]
4、编写一程序,存储器中从0x400200开始有一个64位数。(1)将取反,再存回原处;(2)求其补码,存放到0x400208处
LDRR0,=0x400200
LDRR2,=0xFFFFFFFF
LDRR1,[R0];取低32位数
EORR1,R1,R2;取反
STRR1,[R0];存低32位反码
ADDSR1,R1,#1;又加1为求补
STRR1,[R0,#8];存低32位补码
LDRR1,[R0,#4];取高32位数
EORR1,R1,R2;取反
STRR1,[R0,#4];存高32位反码
ADCR1,R1,#0;高32位求补
STRR1,[R0,#12];存高32位补码