@[TOC]

为什么要有相对跳转和绝对跳转?

顺序执行:指令一条一条按照顺序往下执行,比如变量的定义和赋值都是按照顺序执行的。跳转执行:当指令执行到当前位置后跳转到其他位置执行。比如,在主函数中调用其他函数就是典型的跳转执行。其中跳转又分为绝对跳转和相对跳转。绝对跳转:直接跳转到一个固定的,实实在在的地址。相对跳转:相对于当前pc值的一个跳转,跳转到pc+offset的地址。

  我们清楚了上面几个概念,就知道了为什么要有相对跳转和绝对跳转。各种指令相互配合才能使得cpu有更高的处理效率。正是因为有了顺序和跳转指令,我们的cpu才可以处理各种复杂的计算。

在程序中只有相对跳转/绝对跳转是否可以?

  答案肯定是不可以的。我们以一个例子具体分析。指令编号 | 指令功能-------- | -----| -----指令1 | 顺序执行指令2 | 顺序执行指令3 |相对跳转到指令5指令4 | 顺序执行指令5 | 顺序执行指令6 | 绝对跳转到指令8指令7 | 顺序执行指令8 | 顺序执行

  假设程序被放在0x00000000位置开始执行,编译链接后的结果为:

指令地址 | 指令编号 | 指令功能 | 下条指令地址-------- | -----| -----| -----| -----0x00000000 | 顺序执行| 顺序执行| 当前地址+40x00000004 | 顺序执行| 顺序执行| 当前地址+40x00000008 |跳转到指令5|跳转到指令5|当前地址+80x0000000C | 顺序执行 | 顺序执行 | 当前地址+40x00000010 | 顺序执行 | 顺序执行 | 当前地址+40x00000014 | 跳转到指令8| 跳转到指令8| 0xC000001C0x00000018 | 顺序执行| 顺序执行|当前地址+40x0000001C | 顺序执行 | 顺序执行 | 当前地址+4

  当这段程序被放在0xC000000空间时,开始执行指令1,然后采用相对寻址的方法就可以运行到指令6,在指令6执行时也可以使用绝对寻址的方法从0xC0000014正确跳转到指令8所在的0xC00001C位置,这段代码运行正常。

  当这段代码被放在0x00000000空间时,开始执行指令1,然后采用相对寻址的方法就可以运行到指令6,但在指令6执行时使用绝对寻址的方法从0x0000014跳转到了0xC000001C,但0xC000001C空间没有代码,这样程序就跑飞了。

  因此,当编译地址(加载地址)和运行地址相同时,绝对跳转和相对跳转都可以正确执行。比如,程序在NORFLASH存储时。但是,当编译地址(加载地址)和运行地址不相同时,相对跳转都就会出现问题。比如,代码存储在NANDFLASH,由于NANDFLASH并不能运行代码,所以需要重定位代码到内部的SRAM。关于NANDFLASH和NORFLASH可以看这篇文章S3C2440从NAND Flash启动和NOR FLASH启动的问题。

B(BL)和LDR指令具体怎么执行的?

  我们以下图中的这句跳转代码分析下指令具体的执行过程。

#ifndef CONFIG_SKIP_LOWLEVEL_INIT    bl    cpu_init_crit#endif

  上述代码对应的反汇编代码如下:

33f000ac:    eb000017     bl    33f00110 
33f00110 :33f00110:    e3a00000     mov    r0, #0    ; 0x033f00114:    ee070f17     mcr    15, 0, r0, cr7, cr7, {0}

  当指令执行到33f000ac时,对应的机器码为eb000017(1110 1011 0000 0000 0000 0000 0001 0111‬),其中[31,28]高四位为条件码,1110表示无条件执行。[25,27]位保留区域,24位表示是否带有返回值,1表示带有返回值,也就是BL指令。[23,0]为指令的操作数,0000 0000 0000 0000 0001 0111。按照如下计算方式:

  1、将指令中24位带符号的补码立即数扩展为32位(扩展其符号位)原数变成 0000 0000 0000 0000 0000 0000 0001 0111。

  2、将此数左移两位0000 0000 0000 0000 0000 0010 1000 0000 变成 0000 0000 0000 0000 0000 0000 0101 1100 = 0x0000005c

   3、将得到的值加到PC寄存器中得到目标地址,由于ARM为3级流水线,此时的 pc = 33f000ac+8 = 33F000B4,pc = 33F000B4 + 0x0000005c = 33F00110‬与图中的cpu_init_crit的地址相等。

   在算的过程中我们使用的始终是PC的值,假设程序在 0 地址处执行,那么计算方法一样,pc 的值变了计算出来的结果也随之改变。所以 BL 的跳转时与位置无关的。

  下图为B(BL)指令的格式  28~31bts(cond)是条件码,就是表明这条语句里是否有大于、等于、非零等的条件判断,这4bts共有16种状态,分别为:  下图为LDR指令的格式  我们以下图中的第一句话作为例子分析下

ldr pc,=call_board_init_f

对应的反汇编代码如下:

33f000d0:    e59ff324     ldr    pc, [pc, #804]    ; 33f003fc 
33f003fc:    33f000d4     .word    0x33f000d4........33f000d4 :33f000d4:    e3a00000     mov    r0, #0    ; 0x0

   ldr pc, [pc, #804]这条指令为伪指令,编译的时候会将call_board_init_f的链接地址存入一个固定的地址(链接时确定的),对于本条指令这个地址就是33f000d4 。上面的反汇编出来的 ldr pc,=call_board_init_f就变成了ldr pc, [pc, #804],由于ARM使用了流水线的原因,所以在执行 ldr pc. [ pc, #4 ]的时候 pc 不在这句代码这里了,而是跑到了 pc+8的地方,这句代码相当于 pc = *(pc+804+8)=33f000d0+32C=33f003fc ,所以会跳转到33f003fc 地址取33f000d4 ,而33f000d4 是存在代码段中的一个常量,并不是计算出来的,不会随程序的位置而改变,所以无论代码和pc怎么变 *(pc+804) 的值时不会变的。

  这样,绝对跳转中的固定地址就很好理解了,要跳转地址的值在链接时就已经确定了,存在了一块内存中。而相对跳转时,反汇编bl 33f00110中的33f00110是根据pc计算出来的,当pc改变时,结果也会改变,所以,称为相对跳转,与当前位置无关。

B(BL)和LDR跳转范围是如何规定的?

  下图为B(BL)指令的格式  BL指令的[23,0]bits存放的是要跳转的相对地址,由于指令所在地址必须是4字节对齐的,因此跳转的地址最低bits必然是0,因此BL指令[23,0]bits保存的是省略这最低2bts的地址,如果补全了这2bits,BL指令就可以表示26bits的跳转地址。在这26bits中需要使用1bit表示向前跳还是向后跳,那么剩下的25bits就可以表示32 MBts的范围了,225=32M因此,B(BL)指令的跳转范围为-32MBytes~+32MBytes。

  下图为LDR指令的格式  图中的LDR的跳转范围计算方式和B指令的类似,其中Rn和Address_mode共同构成第二个操作数的内存地址,由Address_mode的9种格式可以直到,Address_mode表示的就是偏移地址的范围大小,为212=4K。(不理解的可以对比下ldr pc, [pc, #804]和Address_mode的九种格式,很明显可以看出Address_mode就是当前地址的偏移范围)

  大家的鼓励是我继续创作的动力,如果觉得写的不错,欢迎关注,点赞,收藏,转发,谢谢!

armv8 汇编 绝对地址赋值_详解汇编语言B和LDR指令与相对跳转和绝对跳转的关系...相关推荐

  1. python中有那几种赋值_详解Python列表赋值复制深拷贝及5种浅拷贝

    概述 在列表复制这个问题,看似简单的复制却有着许多的学问,尤其是对新手来说,理所当然的事情却并不如意,比如列表的赋值.复制.浅拷贝.深拷贝等绕口的名词到底有什么区别和作用呢? 列表赋值 # 定义一个新 ...

  2. armv8 汇编 绝对地址赋值_GNU风格 ARM汇编语法指南(非常详细)

    GNU风格 ARM汇编语法指南(非常详细) 汇编源程序一般用于系统最基本的初始化:初始化堆栈指针.设置页表.操作ARM的协处理器等.这些初始化工作完成后就可以跳转到C代码main函数中执行. 1.GN ...

  3. armv8 汇编 绝对地址赋值_ARMv8带来的变化

    前面的系列文章在讲解ARM汇编语言的时候,穿插了一些对ARMv8相较于前代处理器变化的描述,但还有一些改动和演进未曾提及,本文将继续展现这部分内容. [任我行的PC] 在x86架构中,直接修改IP(I ...

  4. java内部类赋值_详解 Java 内部类

    内部类在 Java 里面算是非常常见的一个功能了,在日常开发中我们肯定多多少少都用过,这里总结一下关于 Java 中内部类的相关知识点和一些使用内部类时需要注意的点. 从种类上说,内部类可以分为四类: ...

  5. linux traceroute命令详解_详解Linux系统路由跟踪指令traceroute语法、工作原理和实例说明...

    概述 traceroute我们可以知道信息从你的计算机到互联网另一端的主机是走的什么路径.当然每次数据包由某一同样的出发点(source)到达某一同样的目的地(destination)走的路径可能会不 ...

  6. java 静态对象赋值_基于Java class对象说明、Java 静态变量声明和赋值说明(详解)...

    先看下JDK中的说明: java.lang.Object java.lang.Class Instances of the class Class represent classes and inte ...

  7. python类的命名空间_Python之关于类变量的两种赋值区别详解

    我就废话不多说了,还是直接看代码吧! # -*- coding:utf-8 -*- #面试题,写一个方法,将一行字符串中所有的单词数量统计出来 class Person(object): TAG = ...

  8. 大脑构造图与功能解析_大脑的结构和功能分区_详解人脑构造与功能

    大脑的结构和功能分区 _ 详解人脑构造与功能 学习,可以开阔人的大脑 ; 学习,可以使人的大脑拥有更多的知识,人的大脑和肢 体一样,多用则灵,不用则废.那么下面学习啦小编给大家分享一些大脑的结构和功 ...

  9. 实现对绝对地址赋值详解实现绝对地址开始执行程序详解

    一.如何实现对绝对地址赋值? int *ptr; ptr = (int *)0x67a9;//指针变量初始化,给指针变量赋予一个地址 *ptr = 55; //通过*ptr来改变prt所指向地址的变量 ...

最新文章

  1. Apache Spark 技术团队开源机器学习平台 MLflow
  2. 定时器--STM32f4--HAL
  3. android:configchanges的作用,将uiMode附加到android:configChanges实际做什么?
  4. java获取网页的内容_java获取网页内容
  5. 仅需6道题轻松掌握Python异常捕获 | Python技能树征题
  6. Android 第三方应用接入微信平台(2)
  7. iPad 隐藏按钮获取函数
  8. word公式快捷键使用
  9. 大数据在高校中的应用
  10. 数据挖掘——决策树和K近邻
  11. Android设备的电池续航时间优化(Optimizing Battery Life)——(一)监听电池电量和电池的充电状态
  12. c语言解一元二次方程代码,一元二次方程求解程序完整代码
  13. ADM打不开/data,或打开后无法导出里面的文件
  14. 创芯科技-CAN收发器使用
  15. Aspose.Slides使用教程:使用 C++ 在 PowerPoint 演示文稿中添加幻灯片切换
  16. 内存管理中的 RSS 和 VSZ意思
  17. 计算机网络里面ap是什么,无线AP是什么
  18. java创建对象的五种方式
  19. windows xp下载python3.5.8_Python3.5中文版下载
  20. leetcode 974. 和可被 K 整除的子数组 详解

热门文章

  1. uni-app第三方登陆-微信
  2. mongoose日期 时间 范围查询
  3. java map集合 事务控制_对象回收过程?线程池执行过程? map原理?集合类关系?synchronized 和 volatile ? 同一个类的方法事务传播控制还有作用吗?java 锁...
  4. kubernetes mysql pxc_K8S使用operator部署和管理Percona - PXC集群
  5. html块左右排列,html – 如何均匀地排列多个内嵌块元素?
  6. 高级数据库,建库,建表,建约束
  7. 计算机组装与维护配置清单作业,计算机组装与维护 作业汇.doc
  8. php jquery模板替换图片,仿jquery插件官网头像更换(原创)
  9. MySql DDL语言(数据库和数据表的管理)
  10. ASP.NET MVC中的模型装配 封装方法 非常好用