相对跳转指令和绝对跳转指令的特殊用法
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
可以看到它最后的 4 位所存储的就是 Rm 寄存器的编号, 共有 2^4=16 种, 对应 R0~R15。 R 寄存器可以存放 32bits 的数据,可以表示全空间地址范围,因此 BX 指令是一种绝对跳转 指令,并且可以跳转到 32 位机的全部地址空间。 BL 是相对跳转指令, BX 是绝对跳转指令,它们虽然都是跳转指令,实现跳转功能, 除了可跳转的距离不一样之外,在某些场合还是有限制的。比如 linux 内核程序编译的基址 是 0xC0000000 ,内核程序认为它们都是在 0xC0000000 以上空间运行的,而内核在进入页 机制之前都是运行在以 0x00000000 为基址的内存空间,编译空间与运行空间不一致这样不 会有问题么?答案当然是不会有问题,否则 linux 怎么会跑起来,这其中就涉及到程序运行 的相对寻址和绝对寻址的问题了。 我们知道程序分为顺序执行和跳转执行, 顺序执行就是一条指令执行完再去执行它下面 的一条指令,而跳转又分为相对跳转和绝对跳转,正如上述的 BL 和 BX 。顺序执行和相对 跳转执行都是在当前指令的基础上加上相对的偏移量找到下条指令的, 而绝对跳转则是需要 找到实实在在的地址。 我们先来看一个例子,然后再说明上述情况是怎么实现的。 比如说我坐火车从沈阳到大连,我在 2 号车厢,餐车在 7 号车厢, � � � 如果火车停在沈阳站还没开的时候,我要去餐车,我只要走过 5 节车厢就可以到了。 如果火车已经到达大连了,那么我还是只要经过 5 节车厢就可以到餐车了。 如果火车已经到达大连了,但你告诉我说火车还停在沈阳,那么我还是只需要经过 5 节车厢就可以到餐车了。 上面这 3 种情况都是使用了相对地址,无需知道火车所处的绝对地址。 其中第 3 种情况就可以解释编译地址与运行地址不一致的问题。 火车已经到达大连——代码实际运行在 0x00000000 地址。 你告诉我说火车还停在沈阳,我就认为火车停在沈阳 ——代码被编译到 0xC0000000,
� �
�
代码认为它们运行在 0xC0000000。 从我所在位置经过 5 节车厢到达餐车——从当前指令位置经过相对偏移量找到下条指 令。 只要将被编译到 0xC0000000 地址的代码放到 0x00000000 地址开始执行,如果它们只
使用顺序执行或者相对跳转执行方式就可以正常运行, 但如果使用了绝对寻址, 那么程序就 跑飞了。 我们参照下面这段伪代码来说明这个情况。 指令编号 指令 1: 指令 2: 指令 3: 指令 4: 指令 5: 指令 6: 指令 7: 指令 8: 指令功能 顺序执行 顺序执行 相对跳转到指令 5 顺序执行 顺序执行 绝对跳转到指令 8 顺序执行 顺序执行
0xC000001C 0xC0000018 0xC0000014 0xC0000010 0xC000000C 0xC0000008 0xC0000004 0xC0000000
没有指令
0xC000001C 0xC0000018 0xC0000014 0xC0000010 0xC000000C 0xC0000008 0xC0000004 0xC0000000
在编译、链接的时候,这段程序被告知放在 0xC0000000 地址空间,编译结果为(每条 指令以 4 字节计算) : 指令地址 0x00000000 0x00000004 0x00000008 0x0000000C 0x00000010 0x00000014 0x00000018 0x0000001C 指令编号 指令 1: 指令 2: 指令 3: 指令 4: 指令 5: 指令 6: 指令 7: 指令 8: 指令功能 顺序执行 顺序执行 相对跳转到指令 5 顺序执行 顺序执行 绝对跳转到指令 8 顺序执行 顺序执行 下条指令地址 当前地址+4 当前地址+4 当前地址+8 当前地址+4 当前地址+4 0xC000001C 当前地址+4 当前地址+4
指令 8 指令 7 指令 6 指令 5 指令 4 指令 3 指令 2 指令 1
…… …… ……
…… …… ……
0x0000001C 0x00000018 0x00000014 0x00000010 0x0000000C 0x00000008 0x00000004 0x00000000
指令 8 指令 7 指令 6 指令 5 指令 4 指令 3 指令 2 指令 1
更多内容请访问blog.sina.com.cn/ifreecoding
接上一篇“从 ARM 汇编指令机器码解释一些问题” 当程序的编译地址与运行地址不一致时,使用相对跳转指令和绝对跳转指令就需要注 意了,本文档将讲述其中原因。 另有一种 B 指令是 BX,它的用法是 BX Rm 其中 Rm 是通用寄存器,例如 BX R0,它的作用是跳转到 R0 中所存储的地址,它的指 令格式如下
0x0000001C 0x00000018 0x00000014 0x00000010 0x0000000C 0x00000008 0x00000004 0x00000000 编译地址等于运行地 址, 使用绝对跳转指令 正确的情况
编译地址不等于运行 地址, 使用绝对跳转指 令出错的情况
ቤተ መጻሕፍቲ ባይዱ
因此我们在看 linux 内核启动这部分的代码时只能看到顺序执行指令和相对跳转指令, 不会存在绝对跳转指令,就是这个原因。如果需要使用全局变量或者函数指针时,则需要将 这个地址减去 0xC0000000 的偏移量才可以获取到此时运行的地址,因为全局变量和函数指 针在编译时都是按照 0xC0000000 基址编译出的绝对地址,运行时既然将程序段和数据段都 偏移了 0xC0000000 的距离,那么使用时只要减去这个值就可以找到正确的位置了。 当 linux 内 核 完 成 初 始 化 时 , 就 会 开 启 页 机 制 , 0x00000000 地 址 空 间 就 会 转 换 为 0xC0000000,再使用一个绝对跳转指令跳转到 0xC0000000 去执行,在此之后程序就运行在 了编译时指定的 0xC0000000 地址空间, 无论是采用相对寻址还是绝对寻址都不会有问题了。
当这段程序被放在 0xC0000000 空间时,开始执行指令 1,然后采用相对寻址的方法就 可以运行到指令 6,在指令 6 执行时也可以使用绝对寻址的方法从 0xC0000014 正确跳转到 指令 8 所在的 0xC000001C 位置,这段代码运行正常。 当这段代码被放在 0x00000000 空间时,开始执行指令 1,然后采用相对寻址的方法就 可 以 运 行 到 指 令 6 , 但 在 指 令 6 执 行 时 使 用 绝 对 寻 址 的 方 法 从 0x00000014 跳 转 到 了 0xC000001C,但 0xC000001C 空间没有代码,这样程序就跑飞了。