2011_08_31____关于重定位表

在看罗文斌的win32汇编语言程序设计..顺便记下看了重定位表一章的感受...方便以后查看...

为什么要有重定位表?

看了下书..重定位表一般只在dll文件才需要...当然只是一般情况下...因为当windows装载器在装载exe文件时...他单独开个进程给exe文件...所以exe文件每次都能得到他所需的IMAGE_BASE(IMAGE_BASE的意思是建议装入地址..建议装载器从哪个地址开始装入这个exe)...但是dll就不同了...因为dll文件是寄宿在exe文件之下的..而且一个exe文件中可能调用了很多dll的函数...windows下每个程序都会调用到kernel32.dll和user32.dll这些dll文件...这样问题就来了...你后调入的dll和先调入的dll他们的IMAGE_BASE是一样的...那么后一个dll就不知道放哪里了...这样就要用到重定位表了...重定位表的用处就是告诉windows的装载器..哪些地方的代码中的绝对虚拟地址需要改变..


在编译连接阶段...在代码中的全局变量必需有一个对应的绝对虚拟地址..为什么不能是RVA呢?因为是RVA那么装载器必须每次装入都要修正代码的地址...但是事先给一个个绝对虚拟地址..如果装入的是建议地址的话那么装载器就不要修正代码了...那个绝对虚拟地址其实就是IMAGE_BASE加上每个全局变量或者是其他东西的RVA..


下面讲讲重定位表的结构..其实这些看罗云彬的书也够了....

首先你从PE结构中的DATA_DIRECTORY找到重定位表..好像叫什么IMAGE_DIRECTORY_ENTRY_RELOC吧...其中的结构包括VirtualAdress和Size...其中VirtualAdress就指向.reloc这个节...这个节是专门用来存放重定位表的...这里关键要记住重定位表中的表项其实是和代码节是一一对应的..

其中重定位表里包括重定位块...结构式RVA(相对虚拟地址)和SizeOfBlock...接下来的每16位就是一个表项了...每个表项对应一个需要修正的地方..比如jmp   10003000...

每个重定位的小块里面有需要重定位的指令的相对地址....


下面是抄罗大师书上的内容:

假定模块被装入00400000h处

重定位表偏移                                   数据                                                       说明

000h                                                 00001000h                                           第一块:页面起始地址10001000(10000000 + RVA)

0004h                                               00000010h                                           重定位块长度10h...千万记住是16进制

0008h                                               3012h                                                    16位重定位项...重定位位置:10001012h

000ah                                               3040h                                                    16位重定位项,重定位位置:10001040h

000ch                                               306fh                                                      16位重定位项,重定位位置:1000106fh

000eh                                               0000h                                                     用于对其的空白区域

0010h                                               00002000h                                           第二块:页面起始地址10002000h

0014h                                               0000000ch                                           重定位块长度0ch

0018h                                               3080h                                                    16位重定位项,重定位位置:10002080h

001ah                                               30f0h                                                      16位重定位项,重定位位置:100020f0h

001ch                                               00000000h                                            重定位块的结束标志


首先说说为什么RVA要从1000h开始....很简单...因为这个给重定位结束标记给占了...所以就不能出现重定位块的RVA是000h的情况...

那么上面的图是什么意思呢?

首先看第一个块他的RVA是1000h是不是发现和代码节的第一条指令地址是一致的...

还有为什么要用RVA + Size + 表项的形式来表现重定位表呢?这个因为可以节省空间....其实操作系统中很多时候感觉都用到这种二级或者多级目录结构...什么页目录表..页表的...

先做个假设...如果你不用表的形式...而是将所有的重定位项放在一个线性的地址中...假设有n个需要重定位的项...那么他的大小肯定是4n...

而采用这种块的形式保存...则每个表项只要用到16字节就可以表示了...那你...其中高4位表示其属性....低12位才是偏移....这样做的目得除了节省空间....更有一点组织性的感觉...

它每一个重定位块对应一个4K的代码段...所以你代码段长度是多少4K的倍数...那么就有多少个重定位块....

那么我们就打个比方...假若拿出第一块的3012h出来...

3是高四位...表示双字32位都要被修正....你一开始在编译dll的时候编译器给的IMAGE_BASE是10000000h..那么凡是关于涉及到访问绝对虚拟地址的全部回事10000000h + RVA

那么在这里的第一块...3012h...10001012h...表示当你的IMAGE_BASE建议地址给别人占了的话...那么他就把(IMAGE_BASE + 重定位块RVA + 重定位表低14位)...的这个地址进行重定位....其实就是加上本次装入的地址 - IMAGE_BASE的差值...比如IMAGE_BASE是10000000h但是被装入的是20000000h...那么其实就是(差值 + IMAGE_BASE + 重定位块RVA + 重定位表低14位)...这样就得到了新的地址...当然这都是装载器干的活...


他重定位表是要在代码段载入之前载入的...载入之后就不用映射到内存了...因为映射了也是浪费...



之所以要有重定位表是因为在许多的地方他的地址用到了绝对地址...打个比方....

在PE文件的格式中的optional中...其中IMAGE_BASE是建议装载地址...dll文件建议地址一般是10000000...当然你也可以通过设置link的选项来控制...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值