LDR指令解析

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

ARM中LDR使用频繁,初上手会有些理解困难的地方,本文章结合一段小代码解析LDR指令的使用。


提示:以下是本篇文章正文内容,下面案例可供参考

一、LDR指令是什么

LDR Rn, label1

LDR指令负责将label1所代表的存储器中数据搬移到内部寄存器Rn中。指令使用方式有:

LDR R0,[R1] ;R1中代表存储器地址,在存储器中将R1地址处的数据加载到寄存器R0中。

LDR R0,=0x00000040 ;将立即数装入R0中,如果立即数小,该指令等效 MOV R0,#64,如果立即数很大比如占据32bit,那么该指令将变成伪指令,见下条。

LDR R0,=0xF0000000 ;立即数很大,无法将立即数和指令合并成32bit,指令会被编译器拆分为LDR R0, [PC, #offset]; .word 0xF00000000两条指令,即先将立即数利用.word指令存储在该LDR指令附近,编译器计算立即数与当前正在执行指令PC(program counter)指针的偏差offset,注意ARM是流水线指令,采用取指令,译指令和执行指令。

LDR R0,label;将label标号所代表的寄存器地址中数据装在到R0。

二、代码分析

1.示例代码

代码如下(示例):

.text
.global _start
_start:
    LDR r0,=0x00001000  
    LDR r0,abc
abc: .word 0x00000040
    LDR r0,whs
whs: .word abc
/* no use code below*/
mov r0,r1
mov r1,r0
loop:
    b loop

 反汇编后的代码

start.elf:     文件格式 elf32-littlearm


Disassembly of section .text:

00000000 <_start>:
   0:    e3a00a01     mov    r0, #4096    ; 0x1000
   4:    e51f0004     ldr    r0, [pc, #-4]    ; 8 <abc>

00000008 <abc>:
   8:    00000040     andeq    r0, r0, r0, asr #32
   c:    e51f0004     ldr    r0, [pc, #-4]    ; 10 <whs>

00000010 <whs>:
  10:    00000008     andeq    r0, r0, r8
  14:    e1a00001     mov    r0, r1
  18:    e1a01000     mov    r1, r0

0000001c <loop>:
  1c:    eafffffe     b    1c <loop>

Disassembly of section .ARM.attributes:

00000000 <.ARM.attributes>:
   0:    00001e41     andeq    r1, r0, r1, asr #28
   4:    61656100     cmnvs    r5, r0, lsl #2
   8:    01006962     tsteq    r0, r2, ror #18
   c:    00000014     andeq    r0, r0, r4, lsl r0
  10:    412d3705             ; <UNDEFINED> instruction: 0x412d3705
  14:    070a0600     streq    r0, [sl, -r0, lsl #12]
  18:    09010841     stmdbeq    r1, {r0, r6, fp}
  1c:    地址 0x000000000000001c 越界。

 LDR r0,=0x00001000 对应0: e3a00a01 mov r0, #4096装载立即数且立即数很小,可直接对应MOV指令0:e3a00a01代表存储器地址0x00000000处存有指令e3a00a01,占用4字节。

LDR r0,abc对应4:e51f0004 ldr r0, [pc, #-4]; 8 <abc> 标号label abc编译后数值为8(0x00000008)因为ARM是取指-译指-执行指令流水线结构,当LDR r0,abc位于地址4处执行指令时,当前PC应该等于0xC处,所以PC,#-4应该等于8,正好是我们立即数0x00000040的存储地址。

LDR r0,whs 和whs: .word abc这两个指令在编译完成后变成LDR r0,whs whs和.word 0x8

立即数0x8也就是abc编译后确定的值,即abc=0x8存储在 10:  00000008处,也就是地址0x10处。


总结

LDR Rn,addr 第二个参数addr代表存储器中的地址。addr可以由[R0],R0中的值作为地址寻址。如果LDR R1,R0是不对的,应为寄存器之间搬移需要用MOV R1,R0指令。

<think>好的,我现在需要回答用户关于ARM LDR指令的用法和使用示例的问题。首先,我应该回忆一下自己对LDR指令的了解,并结合用户提供的参考资料来整理答案。 用户给出的引用中有几个关键点。引用[1]提到LDR的基本语法和用途,包括条件码、字节操作等选项。引用[2]说明了当立即数过大时,LDR会被拆分为两条指令,使用PC相对偏移来加载数据。引用[3]补充了LDRB和LDRH等不同数据宽度的操作。引用[5]则提到了LDR指令用于加载大立即数到寄存器的情况。 首先,我需要明确LDR指令的几种常见使用场景:加载内存数据到寄存器、加载立即数(尤其是大立即数)、以及不同数据宽度的加载。然后,要区分LDR作为普通指令和伪指令的不同情况。 接下来,我应该组织这些信息,分点说明,并给出示例代码。例如,基本用法中,从内存地址加载数据,可能需要使用方括号中的基址寄存器加偏移。对于大立即数的情况,使用LDR指令,这时候编译器会自动处理为合适的指令。另外,不同的数据宽度如字节、半字需要使用LDRB和LDRH。 还要注意用户提到的系统级指令,比如数学表达式要用$...$,独立公式用$$...$$,但这里可能涉及较少数学内容,但如果有的话需要正确格式化。同时要使用中文回答,生成相关问题,并在引用处添加标识。 现在需要检查是否有遗漏的点。例如,引用[4]中的SUB指令可能不相关,但用户的问题是关于LDR的,所以可以忽略这部分。另外,压栈和出栈指令在引用[3]中提到,但可能和LDR关系不大,除非涉及到栈操作时的加载,但用户的问题可能不涉及这个。 然后,用户可能需要示例代码,例如如何用LDR加载字、半字、字节,以及伪指令的使用。同时,注意事项部分需要包括立即数大小限制、地址对齐问题、不同后缀的影响等。 最后,生成相关问题,比如LDR与MOV的区别,如何加载大立即数,不同后缀的作用,地址对齐问题等。 现在需要确保回答结构清晰,分点明确,示例代码正确,并且正确引用提供的资料。例如,在伪指令部分引用[2]和[5],在数据宽度部分引用[3],在基本语法引用[1]等。</think>### ARM LDR指令用法详解 #### 一、基本功能 LDR(Load Register)指令用于将内存中的数据加载到寄存器中,支持**基址+偏移**寻址方式。基本语法为: $$ \text{LDR\{cond\}\{B|H\} Rd, [Rn{, #offset}]} $$ 其中: - `cond`:条件码(可选) - `B/H`:字节/半字操作(默认加载32位字数据) - `Rd`:目标寄存器 - `Rn`:基址寄存器 - `offset`:偏移量(12位立即数)[^1] #### 二、核心用法与示例 1. **加载内存数据** ```armasm LDR R0, [R1] @ 将R1指向的内存地址的32位数据加载到R0 LDRB R2, [R3, #4] @ 将R3+4地址的8位字节数据加载到R2 LDRH R4, [R5, R6] @ 将R5+R6地址的16位半字数据加载到R4 [^3] ``` 2. **加载大立即数(伪指令)** 当立即数超过MOV指令范围(如0x55555555),使用`LDR=立即数`伪指令: ```armasm LDR R3, =0x55555555 @ 编译器自动拆解为两条指令: @ 1. LDR R3, [PC, #offset] @ 2. 在附近存储.word 0x55555555 [^2][^5] ``` 3. **复杂寻址模式** ```armasm LDR R0, [R1, #-8]! @ 先执行R1=R1-8,再将R1地址的数据加载到R0 LDR R2, [R3], #4 @ 将R3地址数据加载到R2后,R3=R3+4 ``` #### 三、关键注意事项 1. **立即数限制**:直接使用LDR指令时偏移量须为12位,超出范围需改用伪指令或分层加载 2. **地址对齐**:字加载要求地址4字节对齐,半字要求2字节对齐 3. **后缀作用**: - `B`:零扩展8位→32位(无符号) - `SB`:符号扩展8位→32位 - `H`:零扩展16位→32位 - `SH`:符号扩展16位→32位 #### 四、典型应用场景 1. 访问外设寄存器: ```armasm LDR R0, =0x40020000 @ 加载GPIO基地址 LDR R1, [R0, #0x08] @ 读取GPIO状态寄存器 ``` 2. 结构体成员访问: ```armasm @ 假设R0指向结构体,成员offset为12 LDR R2, [R0, #12] @ 加载结构体成员值 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值