从机器码理解RIP 相对寻址
本作品采用知识共享署名 4.0 国际许可协议进行许可。转载联系作者并保留声明头部与原文链接https://luzeshu.com/blog/rip-relative-addressing
本博客同步在 http://www.cnblogs.com/papertree/p/6298763.html
1. 情景
在调试linux-3.0.0内核源码过程中,碰到一处lea指令,略有疑问。
代码如下(路径linux/arch/x86/boot/compressed/head_64.S):
249 /*
250 * Copy the compressed kernel to the end of our buffer
251 * where decompression in place becomes safe.
252 */
253 pushq %rsi
254 leaq (_bss-8)(%rip), %rsi
255 leaq (_bss-8)(%rbx), %rdi
256 movq $_bss /* - $startup_32 */, %rcx
257 shrq $3, %rcx
258 std
259 rep movsq
260 cld
261 popq %rsi
下图1-1是调试过程中的CPU上下文:

图1-1
从“mov rcx,0x243e80”中可以看到,_bss的值为0x243e80的,这是_bss这个symbol在进行汇编时,其所在的section内的偏移位置。
从“lea rdi,[rbx+0x243e78]”中可以看到,加到%rbx的值是_bss-8,这跟汇编源代码是一致的。
而从“lea rsi,[rip+0x243c30]” 中可以看到,加到%rip的偏移值并不是_bss-8 的值。
先说明一点,这个section是加载在0x1000000的内存位置,所以0x1000241这条指令,相对于所在section的起始偏移是0x241。
那么,上面的0x243c30这个值,是由(_bss-8)再减去0x248(下一条指令相对于section的起始偏移值)而得来。
那么,前后两条看起来十分相似的汇编代码为什么有这样的区别呢?
2. RIP的特殊性以及PIC(位置无关代码)
因为RIP寄存器存放着当前指令的地址,所以有它的特殊性。
比如上面的%rip + displacement,其中displacement存放的如果是_bss这个symbol与该指令的“距离值”,那么不管这段代码所在的section装载到哪个位置,都可以通过这个计算,访问到_bss实际装载的位置。
比如section装载在0x1000000,那么指令的%rip为0x1000241,_bss的值为0x1243c30。
而如果装载在0x5000000,那么指令的%rip为0x5000241,_bss的值为0x5243c30。
那么如果displacement存放的是_bss与指令之间的距离值,那么不管实际加载到哪个位置,都可以访问到实际的_bss位置。
这里解释了上面的问题 —— 这两条相似汇编代码的区别,正好利用rip的特殊性,实现了PIC的功能。
但是,还是有疑问。这里的解释仅仅是解释了displacement为什么有“距离值”和“实际值”两种情况,这里的区别似乎只是停留在汇编层面,因为gas汇编器就可以这样实现,当发现base register是%rip,那么displacement就使用_bss与当前指令的下一条指令的“距离值”,而当base register是其他寄存器时,displacement就等于_bss自身的值。
而汇编成机器码之后,displacement的值已经由汇编器计算好了,CPU在执行的时候,%rip + displacement 和 %rbx + displacement不是一样的模式吗?
在搜索资料的时候,发现RIP相对寻址这个概念,这并不是一个汇编器的概念,而是CPU的,所以,既然把%rip + displacement这种寻址模式单独拿出来,那么还是会有差别的。
此外,在维基上看到的,RIP相对寻址是在x86-64加进去的:
http://wiki.osdev.org/X86-64_Instruction_Encoding#16-bit_addressing
RIP/EIP-relative addressing
Addressing in x86-64 can be relative to the current instruction pointer value. This is indicated with the RIP (64-bit) and EIP (32-bit) instruction pointer registers, which are not otherwise exposed to the program and may not exist physically. RIP-relative addressing allows object files to be location independent.
3. RIP相对寻址
那么为了进一步从CPU层面解释%rip + displacement和%rbx + displacement这两种寻址模式的区别,需要来看一下CPU如何解释机器代码。
下面是从《Intel 64 and IA-32 Architectures Software Developer's Manual》截取的几张图:

图3-1
这张图展示了一条机器码指令的结构,下面结合实际指令解释一下。
首先,在上面图1-1的例子中,查看一下两条lea指令所在的内存数据:
gdb$ x /14xb 0x1000241
0x1000241: 0x48 0x8d 0x35 0x30 0x3c 0x24 0x00 0x48
0x1000249: 0x8d 0xbb 0x78 0x3e 0x24 0x00
这里两条指令分别7个字节。
其中0x48是Prefixs,0x8d是lea指令的opcode,0x35和0xbb分别是两条指令的ModR/M,这里面没有SIB(下面解释),剩下的0x243c80和0x243e78就是两条指令的Displacement了。
Instruction Prefixs可以有很多种,上面的wiki链接也解释得很全了。这里的0x48是一种64位长模式特有的REX Prefix。对于REX Prefix的解释见下图3-2和3-3,其中高4位0100是固定的,低四位分别作为指令其他部分的扩展位。下面再进行解释。
那么上面的0x48,即为0100 1000,即W位为1,R X B 三个位都为0。
ModR/M 可以划分成3个field,高2位mod,中间3位reg,低3位r/m。例子中的0x35即为(00 110 101),还有0xbb即为(10 111 011),图3-4给出了一份助记表,可以找到0x35的坐标位(disp32,ESI),还有0xbb的坐标为([EBX]+disp32, EDI)。
看回例子中的“lea rsi,[rip+disp]” 和“lea rdi, [rbx]+disp”,rip作为base register和其他通用寄存器的区别在这里。但是,我也不知道该说这特不特殊了,全部是0和1之间的差别。
SIB在这两条指令中没有,答案可以从图3-4的NOTES.1中看到,当ModR/M中的mod域和R/M域为某些特定组合时,才存在SIB字节。
再看会刚刚的REX Prefix的R X B三个位,如何做其他部分的扩展在上面的wiki链接中挺全面。这里截了其中一个图作为解释性说明,见图3-5,当其中的B位为0时,ModR/M的r/m域是符合图3-4的,但是当B位为1时,r/m域选择的寄存器变成了从R8、R9...这些扩展寄存器中选择了。

图3-2

图3-3

图3-4

图3-5
从机器码理解RIP 相对寻址的更多相关文章
- RIP 相对寻址
知识共享许可协议本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/rip-relative-addressing 本博客 ...
- 第四次实验报告:使用Packet Tracer理解RIP路由协议
目录 1 实验目的 2 实验内容 3. 实验报告 3.1 建立网络拓扑结构 3.2 配置参数 3.3 测试网络连通性 3.4 理解RIP路由表建立和更新 4. 理解RIP消息传得慢 5. 拓展 1 实 ...
- 第四次作业:使用Packet Tracer理解RIP路由协议及ICMP协议
0 个人信息 张樱姿 201821121038 计算1812 1 实验目的 理解RIP路由表的建立与更新 感受RIP坏消息传得慢 2 实验内容 使用Packet Tracer,正确配置网络参数,使用命 ...
- X86/X64处理器体系结构及寻址模式
由8086/8088.x86.Pentium发展到core系列短短40多年间,处理器的时钟频率差点儿已接近极限.尽管如此,自从86年Intel推出386至今除了添加一些有关流媒体的指令如mmx/sse ...
- (转)示例化讲解RIP路由更新机制
目录(?)[+] 以下内容摘自最新上市的“四大金刚”图书之一<Cisco路由器配置与管理完全手册>(第二版)(其它三本分别为<Cisco交换机配置与管理完全手册>(第二 ...
- 有限等距性质RIP
参考博客:http://blog.csdn.net/jbb0523/article/details/44565647 压缩感知测量矩阵之有限等距性质(Restricted Isometry Prope ...
- RIP 实验
一.环境准备 1. 软件:GNS3 2. 路由:c7200 二.实验操作 实验要求: 1. 理解 RIP 协议的工作原理 2. 理解 RIPv1.RIPv2 的特性 3. 掌握 RIP 协议的基本配置 ...
- RIP实验
实验要求 1. 理解 RIP 协议的工作原理2. 理解 RIPv1.RIPv2 的特性3. 掌握 RIP 协议的基本配置方法4. 掌握 RIP 自动汇总和手动汇总的方法5. 掌握 RIP 配 ...
- 面试必问的 volatile,你了解多少?
前言 Java中volatile这个热门的关键字,在面试中经常会被提及,在各种技术交流群中也经常被讨论,但似乎讨论不出一个完美的结果,带着种种疑惑,准备从JVM.C++.汇编的角度重新梳理一遍. vo ...
随机推荐
- perl学习二:简单变量
字符串变量:${}1.单引号:不进行变量替换,不进行转义,字符串可以跨行.2.双引号:变量替换(贪婪匹配原则).支持转义字符(转义字符可以另外看)3.反引号 字符串的特殊表示方法:qq(...) q( ...
- perl学习一:探索Perl世界
1.perl4种变量 scalar: $ 纯变量,标量array: @hash: %file: 大写 2.变量组成 1.命名规则 大小写敏感 . 字母数字下划线...2.无关键字,$+其他,但不可以与 ...
- Python9-模块2-包的进阶-day21
包是一种通过使用‘.模块名’来组织python模块名称空间的方式. 1. 无论是import形式还是from...import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉: ...
- (转))iOS App上架AppStore 会遇到的坑
iOS App上架AppStore 会遇到的坑 前言:非原创 文章摘自:http://zhuanlan.zhihu.com/100000PM/20010725 相信大家一定非常「深恶痛疾」AppS ...
- 链式链表的C风格实现
头文件: #ifndef _LINKLIST_H_ #define _LINKLIST_H_ typedef void LinkList; //将数据的类型分离,相当于句柄 //只是一个小节点 包含着 ...
- swift final关键字、?、!可选与非可选符
?符号: 可选型 在初始化时可以赋值为nil !符号: 隐形可选型 类型值不能为nil,如果解包后的可选类型为nil会报运行时错误,主要用在一个变量/常量在定义瞬间完成之后值一定会存在的情况.这主要 ...
- Tinkoff Challenge - Elimination Round 开始补题
A. Oleg and shares time limit per test 1 second memory limit per test 256 megabytes input standard i ...
- TOJ 假题之 Cow Brainiacs
1570: Cow Brainiacs Time Limit(Common/Java):1000MS/10000MS Memory Limit:65536KByteTotal Submit: ...
- BZOJ 1875 [SDOI2009]HH去散步 ——动态规划 矩阵乘法
发现t非常大,所以大概就是快速幂一类的问题了, 然后根据k^3logn算了算,发现k大约是边数的时候复杂度比较合适. 发现比较麻烦的就是前驱的记录,所以直接把边看做点,不能走反向边,但是可以走重边,然 ...
- [BZOJ1592] [Usaco2008 Feb]Making the Grade 路面修整(DP)
传送门 有个结论,每一个位置修改高度后的数,一定是原来在这个数列中出现过的数 因为最终结果要么不递增要么不递减, 不递增的话, 如果x1 >= x2那么不用动,如果x1 < x2,把x1变 ...