嵌入式Linux ARM汇编(四)——ARM汇编程序设计

2019-07-13 05:18发布

 汇编程序有顺序、循环、分支、子程序四种结构形式。

一、顺序结构

程序实例: 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      

二、分支结构

1ifelse分支结构的程序实现

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 R0R1;判断R0>R1 MOVHI R2,100;R0>R1时,R2=100 MOVLS R1,50;R0时,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汇编语言实现: R0xR2i,均为无符号整数 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汇编语言实现: xR0yR1,均为无符号整数 MOV R0,#1;初始化R0=1 MOV R1,#20;初始化R1=20 BW_2;首先要判断条件 W_1MOV R0,R0,LSL#1;循环体,R0*=2 W_2CMP R0,R1;判断R0<=R1,x<=y BLSW_1;R0<=R1,继续循环体 W_END

3、循环语句实现数据块的复制

ARM汇编语言实现: LDR R0,=DATA_DST;指向数据目标地址 LDR R1,=DATA_SRC;指向数据源地址 MOV R10,#20;复制数据个数20*N个字 ;NLDM指令操作数据个数   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-R7PC};PC值从堆栈中返回 使用堆栈来恢复处理器的状态时,STMFDLDMFD要配合使用。     一般来说,在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汇编语言实现: X EQU19;定义X的值为19 NEQU20;定义N的值为20 AREA hello,CODE32,READONLY;声明代码段 ENTRY;标识程序入口 STARTLDR R0,=X;R0R1赋初值 LDR R1,=N BL MAX;调用子程序MAX HALTBHALT;死循环 MAX;声明子程序MAX CMP R0,R1 MOVHI R2,R0;比较R0R1R2等于最大值 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 SUBLOR2R2#0x20 STRBLOR2[R0,R1] NEXT ADDR1R1#1 CMPR1#100 BNELP 2编写一简单ARM汇编程序段,实现1+2+…+100的运算 MOVR2#100 MOVR1#0 LOOP ADDR1R1R2R1中为累加和 SUBSR2R2#1R2控制循环 BNELOOP 3编写程序,比较存储器中0x4000000x400004两无符号字数据的大小,并且将比较结果存于0x400008的字中,若两数相等其结果记为0,若前者大于后者其结果记为1,若前者小于后者其结果记为-1 MOVR0#0x400000 LDRR1[R0];取第1个数 LDRR2[R0#4] ;取第2个数 CMPR1R2;两个数相比较 MOVHIR1#1R1 MOVLOR1# -1R1 MOVEQR1#0;两个数相等 STRR1[R0#8] 4编写一程序,存储器中从0x400200开始有一个64位数。(1)将取反,再存回原处;(2)求其补码,存放到0x400208  LDRR0=0x400200 LDRR2=0xFFFFFFFF LDRR1[R0];取低32位数  EORR1R1R2;取反 STRR1[R0];存低32位反码  ADDSR1R1#1;又加1为求补 STRR1[R0#8] ;存低32位补码 LDRR1[R0#4] ;取高32位数  EORR1R1R2;取反 STRR1[R0#4] ;存高32位反码  ADCR1R1#0;高32位求补 STRR1[R0#12] ;存高32位补码