先来了解一下ldr指令:

LDR 是ARM中的指令,也是伪指令。
当用 LDR r0, =num
编译时,编译器会根据num是否能表示为立即数,决定用 ldr 指令或者是mov或mvn指令。
当num能表示为立即数,就将它翻译成一条mov或mvn指令。不能,编译器会将num存在一个内存单元中,然后再用一条ldr指令加载这个内存单元的的值到r0中。
LDR r0, label  和 LDR r0, =label的区别:
LDR r0, =label 会把label表示的值加载到r0中,相当于直接赋值。
LDR r0, label  会把label当做地址,把label指向的地址中的值加载到r0中,相当于指针操作.
譬如 label的值是 0x8000, LDR r0, =label会将 0x8000加载到r0中,而LDR r0, label则会将内存0x8000处的值加载到r0中。
ADR 和 ADRL 伪指令:用于将一个地址加载到寄存器中。
ADR为小范围的地址读取伪指令。ADR指令将基于PC相对偏移的地址值读取到寄存器中。
在汇编编译源程序时,ADR伪指令被编译器替换在一条合适的指令,通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,
若不能使用一条指令实现,则产生错误。其能加载的地址范围,当为字节对齐时,是-1020~1020,当为非字对齐时在-255~255之间。
ADRL是中等范围的地址读取指令。会被编译器翻译成两条指令。如果不能用两条指令表示,则产生错误。
ADRL能加载的地址范围当为非字节对齐时是-64K~64K之间;当为字节对齐时是-256K~256K之间。

在学习ARM裸机实时,对于程序的链接地址和程序的运行地址是很重要的,通常在程序的前几k的代码中使用的都是相对跳转指令b,bl,前面几k的代码的主要任务就是将整个程序复制到对应的链接地址上去的。这个过程就是代码的重定位,在重定位之前的代码与位置无关(是位置无关码);重定位完成以后就可以跳转到新的地址中去运行了,通常使用 ldr pc, xxx,来实现跳转。这里先来看看三段汇编代码,来理解uboot中重定位后,跳转的实现。und_addr,do_und都是标记,也就是地址。

  • ldr pc, und_addr(这是uboot中的用法)
  • ldr pc, do_und
  • ldr pc, =do_und(这是一条伪指令)
.text
.global _start_start:b resetldr pc, und_addr        //1//ldr pc, do_und        //2//ldr pc, =do_und       //3und_addr:.word do_unddo_und://设置未定义指令异常是的栈ldr sp, =0x34000000//保存现场stmdb sp!, {r0-r12, lr}//0x600000DBmrs r0, cpsrldr r1, =und_stringbl printException//输出sprs 0x600000D3mrs r0, spsrbl putHexldmia sp!, {r0-r12, pc}^

分别编译这三种情况,然后反汇编查看汇编代码。

ldr pc, und_addr(这是uboot中的用法)

30000000 <_start>:
30000000:   ea00000e    b   30000040 <reset>
30000004:   e51ff004    ldr pc, [pc, #-4]   ; 30000008 <und_addr>30000008 <und_addr>:
30000008:   3000000c    .word   0x3000000c3000000c <do_und>:
3000000c:   e3a0d30d    mov sp, #872415232  ; 0x34000000
30000010:   e92d5fff    push    {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, lr}
30000014:   e10f0000    mrs r0, CPSR
30000018:   e59f109c    ldr r1, [pc, #156]  ; 300000bc <halt+0x4>
3000001c:   eb0000dd    bl  30000398 <printException>

ldr pc, do_und

30000000 <_start>:
30000000:   ea00000e    b   30000040 <reset>
30000004:   e59ff000    ldr pc, [pc, #0]    ; 3000000c <do_und>30000008 <und_addr>:
30000008:   3000000c    .word   0x3000000c3000000c <do_und>:
3000000c:   e3a0d30d    mov sp, #872415232  ; 0x34000000
30000010:   e92d5fff    push    {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, lr}
30000014:   e10f0000    mrs r0, CPSR
30000018:   e59f109c    ldr r1, [pc, #156]  ; 300000bc <halt+0x4>

ldr pc, =do_und(这是一条伪指令)

30000000 <_start>:
30000000:   ea00000e    b   30000040 <reset>
30000004:   e59ff0b0    ldr pc, [pc, #176]  ; 300000bc <halt+0x4>30000008 <und_addr>:
30000008:   3000000c    .word   0x3000000c3000000c <do_und>:
3000000c:   e3a0d30d    mov sp, #872415232  ; 0x34000000
30000010:   e92d5fff    push    {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, lr}
30000014:   e10f0000    mrs r0, CPSR
30000018:   e59f10a0    ldr r1, [pc, #160]  ; 300000c0 <halt+0x8>
3000001c:   eb0000dd    bl  30000398 <printException>
30000020:   e14f0000    mrs r0, SPSR
...
...
...
300000b8 <halt>:
300000b8:   eafffffe    b   300000b8 <halt>
300000bc:   3000000c    .word   0x3000000c
300000c0:   3000002c    .word   0x3000002c
300000c4:   4c000014    .word   0x4c000014
300000c8:   4c000004    .word   0x4c000004

代码中为什么要在定义下面这段

und_addr:
    .word do_und

主要是为了占领一个位置,不让这个地址放大CPU的片内srom以外了,不然就找不到他了。

在ldr pc, und_addr中可以将pc=3000000c,实现跳转

ldr pc, do_und,实现的是pc=e3a0d30d,是错误的。

ldr pc, =do_und,可能可以实现pc=3000000c,这还要取决于代码是超过了片内srom的大小ldr    pc, [pc, #176]    ; 300000bc <halt+0x4>,不可靠,也无法预测。

ARM中通过ldr pc, xxx地址,来跳转到对应的绝对地址去执行相关推荐

  1. ARM中的ldr指令与adr、ldr伪指令之间的区别

    ARM汇编语言中有ldr指令和ldr.adr伪指令,他们都可以将标号表达式作为操作数.区别如下: ldr指令和adr.ldr伪指令的区别:ldr指令属于load-store指令,用于读取标号地址中的值 ...

  2. uboot源码中start.S里中断向量表中不直接LDR   PC ,异常地址,而是使用一个标号

    LDR指令只能是跳到当前PC 4kB范围内,而B指令能跳转到32MB范围,而现在这样在  LDR  PC    ,"xxxx"这条指令不远处用"xxxx"  D ...

  3. ARM中LDR伪指令与LDR加载指令

    ARM指令集中,LDR通常都是作加载指令的,但是它也可以作伪指令. LDR伪指令的形式是"LDR Rn,=expr".下面举一个例子来说明它的用法. COUNT EQU       ...

  4. ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析

    ARM汇编有ldr指令以及ldr.adr伪指令,它们都可以将标号表达式作为操作数,下面通过分析一段代码以及对应的反汇编结果来说明它们的区别. ldr r0, _start adr r0, _start ...

  5. arm中SP,LR,PC寄存器以及其它所有寄存器以及处理器运行模式介绍

    ARM中所有寄存器都是32位的.这里以cortex-a7内核的MX6ULL处理器为例,按照功能可以分为两类:运行需要寄存器(程序正常运行所需要的,比如变量暂存,pc制作等,总共43个),系统管理控制寄 ...

  6. ARM的流水线与PC值的关系

    一.两种结构: 冯 · 诺依曼结构 和 哈佛结构: 1.冯·诺依曼结构 冯·诺依曼结构又称作普林斯顿体系结构(Princetionarchitecture). 1945年,冯·诺依曼首先提出了&quo ...

  7. ARM MOV和 LDR指令关系

    ARM是RISC结构,数据从内存到CPU之间的移动只能通过L/S指令来完成,也就是ldr/str指令. 比如想把数据从内存中某处读取到寄存器中,只能使用ldr 比如: ldr r0, 0x123456 ...

  8. ARM中的---汇编指令

    ARM中的---汇编指令 一. 带点的(一般都是ARM GNU伪汇编指令) 1. ".text".".data".".bss" 依次表示的是 ...

  9. ARM中C语言和汇编语言互相调用以及实例

    1.内联汇编 在C语言中内嵌汇编注意事项: 不能直接向PC寄存器赋值,程序跳转要使用B或者BL指令 在使用物理寄存器时,不要使用过于复杂的C表达式(比如ADD y,R0 ,x/y(无形中就是c语言表达 ...

最新文章

  1. BZOJ2215[Poi2011]Conspiracy——2-SAT+tarjan缩点
  2. 数据结构-简单实现二叉树的先序、中序、后序遍历(java)
  3. spyder中绘图无法显示负号_matlibplot+seaborn绘图风格交叉使用
  4. python3 isinstance用法_对python中assert、isinstance的用法详解
  5. centos 桥接配置 设置网络代理 lnmp搭建
  6. 分享:几款代码混淆器(DotFuscator, .NET Reactor, xenocode)
  7. C++以字符串形式返回第N个斐波那契的算法(附完整源码)
  8. 推荐一个包含大量PDF编程电子书的github仓库
  9. jolokia_Hawtio和Jolokia的Hibernate统计
  10. Python机器学习:多项式回归与模型泛化008模型泛化与岭回归
  11. python3x程序设计基础周元哲_Python 3 x程序设计基础
  12. excel 制作dashboard_【实例分享】勤哲Excel服务器做影视制作企业管理系统
  13. 小知识--oppo R9sk手机刷机
  14. 芝诺数解|「十一」千里姻缘一“线”牵—重庆网络婚恋分析报告
  15. VoIP技术的基本原理与应用
  16. 如何利用新浪博客做外链
  17. 机器学习理论: PAC学习
  18. Flash/Flex学习笔记(38):动量守恒与能量守恒
  19. unity 灯光烘焙对比
  20. 大数据中间件跨系统整合数据,打通数据鸿沟

热门文章

  1. elementUI自定义主题配色
  2. Linux下提示命令找不到:bash:command not found
  3. 会计是怎样用计算机的,一种会计用计算机的制作方法
  4. c语言工程文文件作用是什么,ccs工程文件类型和作用
  5. 游戏平台在游戏运营中具有什么优势?
  6. 透明背景怎么在线抠出来?聪明的朋友都用这个
  7. linux下安装mysql my.cnf配置文件发生错误
  8. 明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤1000),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的
  9. 选股器用计算机测试利润,净利润断层和口袋支点一键选股 原创: 田间棋子 像欧奈尔一样思索 今天 一。很多朋友询问净利润断层和口袋支点如何选取,其实我是阅读业绩报告对超预期进行... - 雪球...
  10. 微信小程序在线考试管理系统+后台管理系统