2025年ldr指令和mov(ldr 指令)

ldr指令和mov(ldr 指令)svg xmlns http www w3 org 2000 svg style display none svg

大家好,我是讯享网,很高兴认识大家。



 <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path> </svg> <p>首先说明一下 ARM是RISC&#xff08;“reduced instruction set computer”&#xff0c;即“精简指令集计算机”&#xff09;结构<br /> x86是CISC&#xff08;“Complex Instruction Set Computer”&#xff0c;即“复杂指令系统计算机”&#xff09;结构<br /> 想表达个什么意思呢&#xff1f;也就是它俩不一样&#xff0c;至于怎么不一样呢&#xff0c;并非这篇博客讨论的要点。因此mov指令使用起来也不一样。</p> 

讯享网

接下来介绍一下ARM里面的mov指令
mov只能在寄存器之间移动数据,或者把立即数移动到寄存器中,这个和x86这种CISC架构的芯片区别最大的地方。
x86中没有ldr这种指令,因为x86的mov指令可以将数据从内存中移动到寄存器中。

而且ARM里面的mov指令有一些限制,有的数是不能表示出来的哦,待我道来:

MOV对于立即数是有要求的,就是下面的“8位图”数据。

只能由一个8bit连续有效位通过偶数次移(为什么是偶数次呢,因为必须乘以2(规定就是如此))位得到的数。
在这里插入图片描述
讯享网
它为什么会有这样的限制呢?


原因是,MOV本身就是一个32bit指令,除了指令码本身,它不可能再带一个可以表示32bit的数字,所以用了其中的12bit来表示

立即数,其中4bit表示移位的尾数(循环右移,且数值*2),8bit用来表示要移位的一个基数。

如果立即数超过这个范围,就没有办法用一条MOV指令给寄存器赋值

举例解释:
在这里插入图片描述
Operand2占了12位,其中bit11-bit8是移位数(rotate),bit7-0是一个8位的立即数(imm),MOV Rn, op2,(这里描述得不太准确,主要看下面例子)执行之后,Rn=op2 &gt;&gt; (rotate * 2),这里的移位是循环右移
(而且循环右移的空间范围是32位)
当我以前看到这里的时候,我总是在想,它会不会把高位数据覆盖了?如果高位数据搞了半天没用的话,全部置零,等着来循环移动覆盖,那不是多此一举吗?反而浪费了好多空间,为什么不能直接填入,还要覆盖,后来我请教了一位佬,他跟我解释是:
机器在底层是有个芯片算法的,来识别这个立即数,可以理解为机器码和芯片之间的约定(所以并不是在原始地方进行移位,这样一解释的话,那的确节省了好多空间呀)
举个例子:





以下是几个例子:

1、mov r3, #0x

虽然0x是一个32位的数,但是可以找到这么一个8位立即数,通过右移得到,看下机器码e3a03456,展开成二进制,对照下格式

1110 0011 1010 0000 0011 0100 0101 0110

cond[31:28]=1110

[27:26]=00

L[25]=1,代表op2是一个立即数

OpCode[24:21]=1101

S[20]=0

Rn[19:16]=0000

Rd[15:12]=0011,R3

Op2[11:8]=0100,右移4 * 2位

Op2[7:0]=0101 0110,8位立即数,0x56

首先要将0x56扩展成32位的无符号数,0x00000056,然后循环右移8位,就得到了0x

2、mov r3, #0x

0x是无法通过移位来得到的,这时编译器会报错,C语言编写的程序,编译器会这样来处理:

mov r3, #0x

add r3, r3, #0x14

代替mov的另外一条指令就是ldr,或许会更方便点。

MOV指令可以操作的数字举例:
0x12
0x120
0x1200
0x
MOV指令不能操作的数字举例:
0x123
0x1230
0x







mov指令到此就讲解完成。接下来是LDR和LDR伪指令:

LDR指令(有等号的ldr指令是伪汇编指令)
ldr指令既可以是大范围的地址读取伪指令,也可以内存访问指令。
当它的第二个参数前面有“=”时,表示伪指令,否则表示内存访问指令。
LDR指令:就是个单寄存器存储的ARM存储器访问指令。
(LDR补充了MOV指令不能访问内存的缺陷。)



数据从内存到CPU之间的移动只能通过L/S指令来完成,也就是ldr/str指令。比如想把数据从内存中某处读取到寄存器中,只能使用ldr。mov不能干这个活,mov只能在寄存器之间移动数据,或者把立即数移动到寄存器中,再次强调

ldr r0, 0x
就是把0x这个地址中的值存放到r0中。

ldr r0, =0x
这样,就把0x这个地址写到r0中了。所以,ldr伪指令和mov是比较相似的只不过mov指令限制了立即数的长度为8位,也就是不能超过512。而ldr伪指令没有这个限制。如果使用ldr伪指令时,后面跟的立即数没有超过8位,那么在实际汇编的时候该ldr伪指令是被转换为mov指令的。

ldr伪指令和ldr指令不是一个同东西

LDR指令的格式:

LDR{条件} 目的寄存器 &lt;存储器地址&gt;

作用:将 存储器地址 所指地址处连续的4个字节(1个字)的数据传送到目的寄存器中。

LDR R0,[R1,R2] ;将存储器地址为R1+R2的字数据读入寄存器R0。

LDR R0,[R1,#8] ;将存储器地址为R1+8的字数据读入寄存器R0。

LDR R0,[R1],R2 ;将存储器地址为R1的字数据读入寄存器R0,并将R1+R2的值存入R1。

LDR R0,[R1],#8 ;将存储器地址为R1的字数据读入寄存器R0,并将R1+8的值存入R1。

LDR R0,[R1,R2]! ;将存储器地址为R1+R2的字数据读入寄存器R0,并将R1+R2的值存入R1。

LDR R0,[R1,LSL #3] ;将存储器地址为R1*8的字数据读入寄存器R0。

LDR R0,[R1,R2,LSL #2] ;将存储器地址为R1+R2*4的字数据读入寄存器R0。

LDR R0,[R1,R2,LSL #2]! ;将存储器地址为R1+R24的字数据读入寄存器R0,并将R1+R24的值存入R1。

LDR R0,[R1],R2,LSL #2 ;将存储器地址为R1的字数据读入寄存器R0,并将R1+R2*4的值存入R1。

LDR R0,Label ;Label为程序标号,Label必须是当前指令的-4~4KB范围内。

要注意的是

LDR Rd,[Rn],#0x04 ;这里Rd不允许是R15。

另外LDRB 的指令格式与LDR相似,只不过它是将存储器地址中的8位(1个字节)读到目的寄存器中。

LDRH的指令格式也与LDR相似,它是将内存中的16位(半字)读到目的寄存器中。

LDR R0,=0xff

这里的LDR不是arm指令,而是伪指令。这个时候与MOVE很相似,只不过MOV指令后的立即数是有限制的。这个立即数必须是0X00-OXFF范围内的数经过偶数次右移得到的数,所以MOV用起来比较麻烦,因为有些数不那么容易看出来是否合法。

综上所述:ldr伪指令用于加载32位的立即数或一个地址值到指定寄存器。
在汇编编译源程序时,ldr伪指令被编译器替换成一条合适的指令。
若加载的常数未超出mov或mvn的范围,则使用mov或mvn指令代替该ldr伪指令,
否则汇编器将常量放入文字池,并使用一条程序相对偏移的ldr指令从文字池读出常量。



小讯
上一篇 2025-05-17 10:01
下一篇 2025-06-12 20:59

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/172225.html