我将要描述的最后一个数据目录是基址重定位目录。它是由可选头数据目录中的IMAGE_DIRECTORY_ENTRY_BASERELOC(基址重定位目录项)项来指向的。典型的,它包含在自己的节中,名字象“.reloc”这样,并且IMAGE_SCN_CNT_INITIALIZED_DATA(已初始化数据内容节)、 IMAGE_SCN_MEM_DISCARDABLE(内存可丢弃节)和IMAGE_SCN_MEM_READ(内存可读节)等标志位被置1。
如果映象文件不能被加载到可选头中提到的优先载入地址“ImageBase”(映象基址)时,重定位数据对加载器来说就是必须的。此时,链接器所提供的固定地址就不再有效,并且加载器将不得不对静态变量、字符串文字等使用的绝对地址进行修正。
所谓重定位目录就是一些连续的块,每一块都包含4K映象文件的重定位信息。块由一个“IMAGE_BASE_RELOCATION(基址重定位)”结构体开始,这个结构体包含一个32位的“VirtualAddress(虚拟地址)”项和一个32位的“SizeOfBlock(块大小)”项。跟在它们后面的就是块的实际重定位数据,每一条都是16位的。
“VirtualAddress(虚拟地址)”就是重定位所在块需要应用的基本的RVA;“SizeOfBlock(块大小)”就是整个块的字节大小;跟在后面的重定位的数目是:('SizeOfBlock'-sizeof(IMAGE_BASE_RELOCATION))/2个。当你碰到一个“VirtualAddress(虚拟地址)”值为0的“IMAGE_BASE_RELOCATION(基址重定位)”结构体时,重定位信息就结束了。
每一个16位的重定位信息由低12位的重定位位置和高4位的重定位类型组成。要得到重定位的RVA,你需要用这个12位的位置加上“IMAGE_BASE_RELOCATION(基址重定位)”中的“VirtualAddress(虚拟地址)”。类型是下面之一:
IMAGE_REL_BASED_ABSOLUTE (0)
这种不需操作;用于将块按32位边界对齐。位置应该为0。
IMAGE_REL_BASED_HIGH (1)
重定位的高16位必须被用于被偏移量所指向的那个16位的WORD单元,此WORD是一个32位的DWORD的高位WORD。
IMAGE_REL_BASED_LOW (2)
重定位的低16位必须被用于被偏移量所指向的那个16位的WORD单元,此WORD是一个32位的DWORD的低位WORD。
IMAGE_REL_BASED_HIGHLOW (3)
重定位的全部32位必须应用于上面所说的全部32位。这种(和不需操作的第“0”种)是我在二进制文件种实际发现的仅有的重定位类型。
IMAGE_REL_BASED_HIGHADJ (4)
这是一种复杂的。请自己参阅(参考文献[6]),并努力弄懂它的意思:“高调整。这种修正要求一个全32位值。高16位定位于偏移量处,低16位定位在下一个数组元素(此数组元素包括在大小的域中)的偏移量处。它们两个需要被连成一个有符号的变量。加上32位的增量。然后加上0x8000并将有符号变量的高16位存储在偏移量处的16位域中。”
IMAGE_REL_BASED_MIPS_JMPADDR (5)
不清楚
IMAGE_REL_BASED_SECTION (6)
不清楚
IMAGE_REL_BASED_REL32 (7)
不清楚
举一个例子,如果你发现重定位信息是
0x00004000 (32位, 开始的RVA)
0x00000010 (32位, 块的大小)
0x3012 (16位的重定位数据)
0x3080 (16位的重定位数据)
0x30f6 (16位的重定位数据)
0x0000 (16位的重定位数据)
0x00000000 (下一块的RVA)
0xff341234
你知道第一块描述的重定位开始于RVA 0x4000处,有16字节长。因为头用掉了8字节,并且一个重定位要用2字节,所以块中计有(16-8)/2=4个重定位。第一个重定位被应用于0x4012处的DWORD,第二个于0x4080处的DWORD,第三个于0x40f6处的DWORD。最后一个不需操作。
下一块的RVA是0,列表结束。
好,你怎么处理一个重定位呢?
你能知道映象文件“被”重定位到可选头“ImageBase(映象基址)”的优先载入地址;你也能知道你真正载入的地址。如果它们相同,你什么也不用做。如果它们不同,你需计算出实际基址-优先基址的差并加上重定位位置的值(有符号,可能为负值),此值你可通过上面讲述的方法找到。
九、致谢(Acknowledgments)
---------------------------
感谢David Binette的调试和校读。(剩下的错误全部都是我的。)
也感谢wotsit.org网站让我将此文放到他们的网站上。
十、版权(Copyright)
---------------------
本文的版权属于B. Luevelsmeyer,1999年。它是免费的,你可以任意的使用,但后果自负。它含有错误并不完整,特此警告。
十一、Bug报告(Bug reports)
----------------------------
Bug报告(或其他建议)请发送至:
[email protected]十二、版本(Versions)
----------------------
你可在文件的顶部找到当前的版本号。
1998-04-06
第一次公开发表
1998-07-29
将映象文件版本和子系统版本中错误的“byte”改为“word”
更正“栈只限于1 MB”的错误(实际上没有上限)
更正一些输入错误
1999-03-15
更正输出目录的描述,原来非常不全
调整输入目录的描述,原来讲的不清
更正输入错误并为其它节改了一些词句