
AREA StrCopy, CODE, READONLY
ENTRY ; mark the first instruction to call
start
LDR r1, =srcstr ; pointer to first string
LDR r0, =dststr ; pointer to second string
BL strcopy ;
call subroutine to do copy
stop
MOV r0,
#0x18
LDR r1,
=0x20026
SWI
0x123456
strcopy
LDRB r2, [r1],#1
STRB r2, [r0],#1
CMP r2, #0
BNE strcopy
MOV pc,lr ;
Return
AREA Strings, DATA, READWRITE
srcstr DCB First string - source,0
dststr DCB Second string - destination,0
END
试试,
你好,这里的回答应当与ARM相似下面我做一个简单的ARM汇编语言描述
ARM中伪指令不是真正的ARM指令或者Thumb指令,这些伪指令在汇编编译时对源程序进行汇编处理时被替换成对应的ARM或Thumb指令(序列)。ARM伪指令包括ADR、ADRL、LDR和NOP等。
1、ADR(小范围的地址读取伪指令)
该指令将基于PC的地址值或基于寄存器的地址值读取到寄存器中。
语法格式
ADR{cond} register, expr
其中,cond为可选的指令执行的条件
register为目标寄存器
expr为基于PC或者基于寄存器的地址表达式,其取值范围如下:
当地址值不是字对齐时,其取值范围为-255~255
当地址值是字对齐时,其取值范围为-1020~1020
当地址值是16字节对齐时,其取值范围将更大
在汇编编译器处理源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能。
因为ADR伪指令中的地址是基于PC或者基于寄存器的,所以ADR读取到的地址为位置无关的地址。当ADR伪指令中的地址是基于PC时,该地址与ADR伪指令必须在同一个代码段中。
示例
start MOV r0,#10 ;因为PC值为当前指令地址值加8字节
ADR r4, start ;本ADR伪指令将被编译器替换成SUB r4,pc,#0xc
2、 ADRL(中等范围的地址读取伪指令)
该指令将基于PC或基于寄存器的地址值读取到寄存器中。ADRL伪指令比ADR伪指令可以读取更大范围的地址。ADRL伪指令在汇编时被编译器替换成两条指令,即使一条指令可以完成该伪指令的功能。
语法格式
ADRL{cond} register,expr
示例
start MOV r0,#10 ;因为PC值为当前指令地址值加8字节
ADRL r4,start+60000 ;本ADRL伪指令将被编译器替换成下面两条指令
ADD r4,pc,#0xe800
ADD r4,r4,#0x254
3、LDR(大范围的地址读取伪指令)
LDR伪指令将一个32位的常数或者一个地址值读取到寄存器中
语法格式
LDR{cond} register, =[expr|label-expr]
其中,expr为32位的常量。编译器将根据expr的取值情况,如下处理LDR伪指令:
当expr表示的地址值没有超过MOV或MVN指令中地址的取值范围时,编译器用合适的MOV或MVN指令代替该LDR伪指令
当expr表示的地址值超过了MOV或者MVN指令中地址的取值范围时,编译器将该常数放在数据缓冲区中,同时用一条基于PC的LDR指令读取该常数。
label-expr为基于PC的地址表达式或者是外部表达式。当label-expr为基于PC的地址表达式时,编译器将label-expr表示的数值放在数据缓冲区(literal pool)中,然后将该LDR伪指令处理成一条基于PC到该数据缓冲区单元的LDR指令,从而将该地址值读取到寄存器中。这时,要求该数据缓冲区单元到PC的距离小于4KB。当label-expr为外部表达式,或者非当前段的表达式时,汇编编译器将在目标文件中插入一个地址重定位伪 *** 作,这样连接器将在连接时生成该地址。
LDR伪指令主要有以下两种用途:
当需要读取到寄存器中的数据超过了MOV及MVN指令可以 *** 作的范围时,可以使用LDR伪指令将该数据读取到寄存器中。
将一个基于PC的地址值或者外部的地址值读取到寄存器中。由于这种地址值是在连接时确定的,所以这种代码不是位置无关的。同时LDR伪指令的PC值到数据缓冲区中的目标数据所在的地址的偏移量要小于4KB。
示例
将0xff0读取到R1中
LDR R1,=0xFF0
汇编后将得到:
MOV R1,0xFF0
将0xfff读取到R1中
LDR R1,=0xFFF
汇编后将得到:
LDR R1,[PC,OFFSET_TO_LPOOL]
…
LPOOL DCD 0xFFF
将外部地址ADDR1读取到R1中
LDR R1,=ADDR1
汇编后将得到:
LDR R1,[PC,OFFSET_TO_LPOOL]
…
LPOOL DCD ADDR1
4、NOP空 *** 作伪指令
在汇编时将被替换成ARM中的空 *** 作,如MOV R0,R0
NOP伪指令不影响CPSR中的条件标志位
以上是对ARM汇编语言的回答描述,望采纳。谢谢
一种方法是在编译器中加上-thumb选项,在编译器中进行设置好了之后编译下,采用的指令集就是Thumb指令集了。二是可以直接在ARM汇编里实现。具体的切换是通过Branch Exchange-即BX 指令来实现的。指令格式为:Thumb状态 BX RnARM状态 BX<condition> Rn其中Rn可以是寄存器R0-R15中的任意一个。指令可以通过将寄存器Rn的内容拷贝到程序计数器PC来完成在4Gbyte地址空间中的绝对跳转,而状态切换是由寄存器Rn的最低位来指定的,如果 *** 作数寄存器的状态位Bit0=0,则进入ARM状态,如果Bit0=1,则进入Thumb状态,以下是一个用例:CODE32 //表示以下使用ARM状态下的代码,32位对齐LDR R0, =Into_Thumb+1 //将Into_Thumb地址值加1,再赋给R0//产生跳转地址并且设置最低位BX R0 //地址值位0为1,将进入THUMB状态//Branch Exchange 进入Thumb状态… CODE16 //Thumb状态下的子函数,16位对齐…LDR R3, =Back_to_ARM //将Back_to_ARM 地址值赋给R0//产生字对齐的跳转地址,最低位被清除,即bit0为0BX R3//Branch Exchange 返回到ARM状态,此时运行在ARM指令集环境里 CODE32 //ARM状态下的子函数Bach_to_ARM
mov r2,#10h
mov r0,0100h
mov r1,0200h
rool:
cmp r2,0
jz exit
mov r1,r0
inc r1
inc r2
jmp rool
exit:
ARM汇编程序特点:
l 所有运算处理都是发生通用寄存器(一般是R0~R14)的之中所有存储器空间(如C语言变量的本质就是一个存储器空间上的几个BYTE)的值的处理,都是要传送到通用寄存器来完成因此代码中大量看到LDR,STR指令来传送值
l ARM汇编语句中当前语句很多时候要隐含的使用上一句的执行结果而且上一句的执行结果,是放在CPSR寄存器里,(比如说进位,为0,为负…)
CMP R0,R1
BNE NoMatch
比如上一句,BNE隐含的使用的上一句CMP执行结果NE后缀表示使用Z标志位两句合起来的意思就是,如果R0,R1的值不相等,就跳转到NoMatch处执行
注意,PC=R15,CPSR=R16,
ARM伪指令不是必须的,但是一个完整没有伪指令几乎很难写出来
n 比如一个程序至少包含READONLY AREA和ENTRY,否则CPU都无法知道从哪里开始运行
l ARM的属于RISC,指令并不多,但是可以带后缀表示扩展出不同用法,这里与X86汇编完全不同风格
n 如BNE实际上是B指令的变种,本质还同一类指令只是多一个对CPSR的Z标志位的判断。
ARM常用指令,伪指令
ARM常用指令并不太多,因此使用阅读ARM汇编代码,并不太困难以下是使用频率最高的指令和伪指令,并不是完整的指令集的教材。详细指令参见参考资料。
l B,BL
l MOV,MVN
l LDR,STR
l ADD,SUB,ADC,SBC,MUL
l AND,ORR,XOR,TST,BIC
l CMP
l LDM/STM
l nop
1 跳转语句 B,BL
程序流程的跳转,在 ARM 程序中有两种方法可以实现程序流程的跳转指令用于实现
l 使用专门的跳转指令 B
l 直接向程序计数器PC 写入跳转地址值
n 这是几乎是任何一种CPU必备的机器,PC表示CPU当前执行语句位置,改变PC的值,相当于实现程序跳转
n 如实现类似C语言的Return 语句,就是用MOV PC,LR
n 这里可以在任意4G的空间进行跳转
B指令(Branch)表示无条件跳转
B main ;跳转到标号为main地代码处
BL指令(Branch with Link)表示带返回值的跳转
BL比B多做一步,在跳转前,BL会把当前位置保存在R14(即LR寄存器),当跳转代码结束后,用MOV PC,LR指令跳回来,这实际上就是C语言执行函数的用法,
汇编里调子程序都用BL,执行完子函数后,可以用MOV PC,LR跳回来
BL delay ;执行子函数或代码段delay ,delay可以为C函数
与MOV PC,XXX能在4G空间跳转不同,B语句只能32M空间跳转,(因为偏移量是一个有符号26bit的数值=32M)
2 传输数据指令MOV,MVN
n MOV(MOVE)指令可完成从另一个寄存器、被移位的寄存器或将一个立即数加载到目的寄存器
MOV R0,R1 ; 把R1的值传到R0
MOV R3,#3 ;把常数3传给R3,MOV中用#表示常数,这个值不能超过
n MVN( MOVE Negative)取反后再传值,比MOV多了一步取反
MVN R0, #0 ;把0取反(即-1)传给R0
MVN R1,R2 ;把R2的值取反传给R1
3 加载/存储指令,LDR,STR
n LDR,STR是用于寄存器和外部存储器交换数据指令,注意与MOV的区别,后面只在寄存器或常数交换
u LDR/STR可以采用多种寻址方式,以下只举出使用频率最高几种用法
n LDR(load)用于把一个32Bit的WORD数据从外部存储空间装入到寄存器中
LDR R0,[R1]; R1的值当成地址,再从这个地址装入数据到R0 (R0=R1)
LDR R1,=0x30008000 ; 把地址0x30008000的值装入到R1中,LDR中用常数要用=打头(注意跟MOV的区别,MOV是#)
ldr r0, =(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0)
用位与的方法赋值
n STR(Store) 用于把一个寄存器的值存入外部存储空间,是LDR的逆 *** 作
STR R0,[R1] ; 把R0的值,存入到R1对应地址空间上(R1 = R0)
STR R0,=0x30008000 ;把R0中值存入到地址0x30008000
S2C2440的中CPU内核以外的模块的控制寄存器空间也是属于外部空间,所以也得用如下指令LDR R0,=GPFDAT
4 算术运算指令,ADD/ADC,SUB/SBC ,MUL
n ADD加法指令
ADD R0,R1,R2; R0=R1+R2
ADD R0,R1,#3 ;R0=R1+3
n ADC带进位加法指令,即除了加两个数以外,还要把CPSR的C值也要带进来
u 通常用于大数(超过32Bit整数)相加,这时单用ADD不能处理,必须折成两步,其中一步用ADC
u 以下是做64Bit的加法
ADDS R0,R1,R2; R0=R1+R2,ADDS中S表示把进位结果写入CPSR
ADC R5,R3,R4 ;R5=R3+R4+C
n SUB减法指令
SUB R0,R1,R2; R0=R1-R2
SUB R0,R1,#3 ;R0=R1-3
n SBC带进位减法指令,即除了加两个数以外,还要把CPSR的C值也要带进来,类似ADC
u 以下是做64Bit的减法
SUBS R0,R1,R2; R0=R1-R2,SUBS中S表示把进位结果写入CPSR
SBC R5,R3,R4 ;R5=R3-R4-C
n MUL 乘法指令
MUL R0,R1,R2; R0=R1R2
MUL R0,R1,#3 ;R0=R13
5 位 *** 作指令 AND,ORR, TST,BIC
n AND位与指令
AND R0,R1,R2; R0=R1 & R2
AND R0,R1,#0xFF ;R0=R1 & 0xFF
n ORR位或指令
ORR R0,R1,R2; R0=R1 | R2
ORR R0,R1,#0xFF ;R0=R1 | 0xFF
n TST测试某一位是否为1,并把结果写入CPSR,供下一句使用
TST R1,#0xffe; 等同于if(R1 & 0xffe)
TST R1,#%1;测试最低位是否为1,%表示二进制
n BIC清位 *** 作
BIC R0,R0,#0xF ; 等同于 R0 &=~(0xF)
BIC R0,R0,#%1011 ; 该指令清除 R0 中的位 0 1 3,其余的位保持; %表示是二进制,0x表示十六进制
6 比较指令 CMP
n CMP比较两个 *** 作数,并把结果存入CPSR供下一句语句使用
CMP R0,R1; 比较R0,R1
7 多寄存器语句传输指令,LDM,STM
类似于一次传一个BUFFER到寄存器当中,或反过来后面一般要接一个地址改变方法
n LDM 从BUFFER传数据多个寄存器传输数据到
LDMIA R0! ,{R3-R9} ;加R0指向的地址上连续空间的数据,保存到R3-R9当中,!表示R0值更新,IA后缀表示按WORD递增
LDMFD SP!,{R0-R7,PC}^;恢复现场,异常处理返回,^表示不允许在用户模式下使用。
n STM 从寄存器列表向存储空间传值。
STMIA R1!,{R3-R9} ;将R3-R9的数据存储到R1指向的地址上,R1值更新。
STMFD SP!,{R0-R7,LR}; 现场保存,将R0~R7,LR入栈
stmfd sp!,{r8-r9} ,把SP寄存器对庆的地址的值存到R8,R9当中!表示最后的值写入SP中。Fd表示
8 ARM指令的变形
大部分指令后位可以接 与S两个特殊位来表示,对CPSR特殊的一些判断
S,表示当前指令执行后把结果改写CPSR
subs,Adds
取决于具体条件,只有CPSR满足指定条件时才指这一指令
BEQ 实际上B+ EQ的条件执行
addne 表示ADD +NE 才开始加
9 ARM指令的寻址方式
寻址方式是根据指令中给出的地址码来定位真实的地址,ARM中有9种寻址方法
l 寄存器寻址
直接用寄存器编号来寻址,最为常用
MOV R1,R2 ;R2->R1
l 立即数寻址
即指令中的地址码是 *** 作数本身,可以立即取出使用,立即数前带一个#表示,否则表示一个地址
SUBS R0,R0,#1 ;R0 -1 ->R0
注意与SUBS R0,R0,1区别
l 寄存器偏移寻址
这是ARM特有的寻址模式,当第2 *** 作数是寄存器,在执行 *** 作之前,可以做一次移位 *** 作
MOV R0,R2,LSL #3 ;R2的逻辑左移3位,结果放入R0,即R0=R28
ANDS R1,R1,R2,LSL R3;RS的值左移R3位,然后和R1相与 *** 作,结果放入R1
移位 *** 作有LSL (逻辑左移),LSR(逻辑右移) ,ASR(算术右移),ROR(循环右移)RRX带扩展的循环右移
l 寄存器间接寻址
即寄存器中值是一个地址,用[]来取出定位到地址当中
LDR R2,[R0] ;把R0的值当成地址,取出相应值,赋给R2
l 基址寻址
把寄存器的地址值加上一个偏移量
LDR R2,[R3,#0x0F]; R3中的值加上0x0F,从这个地址取出值赋给R@
l 相对寻址
基址寻址的变形,由PC寄存器提供基准地址,指令中地址段作为偏移量两者相加即是有效地址,以下是BL采用相对寻址
BL NEXT
…
NEXT
…
MOV PC,LR ;从子程序返回
10 ADS ARM的伪指令
类似于C语言的宏,由汇编程序预处理
l 符号定义指令
全局变量定义 GBLA ,GBLL,GBLS
局域变量定义 LCLA,LCLL,LCLS
变量赋值SETA,SETL,SETS
其中上述伪指令中,最后面的A表示给一个算术变量赋值,L表示用于给一个逻辑变量赋值,s表示给一个字符串赋值
GBLL codedbg; 声明一个全局的逻辑变量
Codebg SETL {TRUE} ; 设置变量为{TRUE}
LCLA bitno; 声明一个算术变量
Bitno SETA 8 ;设变量值为8
l 数据定义伪指令
n SPACE 定义一个内存空间,并用0初始化
{label } SPACE expr
DataBuf SPACE 100 ;定义100字节长空间, unsigned char DataBuf[100];
n DCB 定义一个连续字节内存空间,用伪指令的表达式expr来初始化一般可以用定义数据表格,或文字字符串(这时等同于SETS),用于初始二进制BUFFER
DCB expr{,expr …} Dest DCB -120,20,36,55 ;等同于 unsigned char Dest[]={-120,20,36,55};n DCU定义的一段字的内存空间(DCB是字节),并用后面表达式初始化 _RESET DCU Reset ; 等同于 DWORD _RESET[]={Reset};n MAP定一个结构化内存,相当于定义一个C结构n FILED 定义一个结构化内存的成员MAP 0x00,R9 ; 定义内存表,地址为R9Timer FIELD 4 ; 定义数据域Timer,长为4字Attrib FIELD 4 ; 定义数据域Attrib,长为4字String FILED 100 ; 定义数据域String ,长为100字相当于C语言的定义:struct {DWORD Timer ;DWORD Attrib ;Char String[100];} R9;11 杂项的伪指令n 字节对齐 ALIGNALIGN; 声明4字节对齐n 定义一个数字常量定义 EQUNAME EQU expr {type} PLLCON EQU 0xE01FC080;定义PLLCON,类似于C的宏或C++的常量n 包含文件 GET和INCLUDEINCLUDE lpc2106incn NOP 空指令在汇编时会被ARM的空 *** 作代替,比如MOV R0,R0,一般用于延时与占位。n 声明一个外部符符号 IMPORT,EXTERNIMPORT,EXTERN 向外部导入一个符号,一般是外部程序全局变量n 条件编译:[]。类似于C的#ifdef 之类定义。格式 :[ 条件表达式 满足条件分支 | 不满足条件分支 ]示例1: [ ENTRY_BUS_WIDTH=32 ;类似#if ENTRY_BUS_WIDTH=32 b ChangeBigEndian ;DCD 0xea000007 ] ; 类似#endif 示例2: [ CLKDIV_VAL>1 ; 类似#if CLKDIV_VAL>1bl MMU_SetAsyncBusMode |;类似#else bl MMU_SetFastBusMode ; default value]; 类似#endif 示例3 [ THUMBCODE 类似#ifdef THUMBCODE bx lr | ;类似#else mov pc,lr ] ;类似#endifn 段定义 AREAn 指令集定义 CODE16和CODE32指示是Thumb 指令集(压缩指令集,每个指令16位)。还是普通32位指令集n 汇编结束:ENDn 程序入口ENTRY你好!应该使用辗转相除法。提供一个调试成功的汇编语言例程,可自行改为ARM语言。
>
以上就是关于arm汇编小程序全部的内容,包括:arm汇编小程序、使用ARM汇编伪指令编程:分别将两个无符号数放在寄存器R0和R1中,求其中较大的那个数的阶乘、ARM/Thumb指令集的汇编程序等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!欢迎分享,转载请注明来源:内存溢出
原文地址:https://54852.com/zz/9763212.html

