VirtualAlloc申请连续地址需要注意的问题
1、写作缘由:最近在编写PE加载器,PE文件一般由两部分组成:PE头和节,附加数据。附加数据可以为0,当它的大小为0时,那么根据PE头计算得到的字节数和PE文件的大小是相同的,当大小大于0时,二者之差便是附加数据的大小。加载器的主要思路是分两步加载PE文件,首先根据PE文件指定的基址(一般是0x00400000)调用VirtualAlloc申请指定基址+PE头和节大小的地址空间,然后判断程序有无附加数据,如有则在所申请的地址后申请附加数据大小的地址空间。
2、出现的问题:
1) 变量:peBase=0x00400000, peSize=0x3000, additionalBase=peBase+peSize, additionalSize = 0x1000
2) 调用过程:第一次调用VirtualAlloc(peBase, peSize, MEM_RESERVE, PAGE_READWRITE);返回地址 0x00400000第二次调用 VirtualAlloc(additionalBase, additionalSize, MEM_RESERVE, PAGE_READWRITE);发生错误,返回NULL
3、问题分析:
1) 百度百科 VirtualAlloc,关于第一个参数的指定有如下描述:"LPVOID lpAddress, 分配内存区域的地址。当你使用VirtualAlloc来提交一块以前保留的内存块的时候,lpAddress参数可以用来识别以前保留的内存块。如果这个参数是NULL,系统将会决定分配内存区域的位置,并且按64-KB向上取整(roundup)。"
2) 64KB的十六进制表示为0x10000, 4KB的十六进制表示是0x1000。
3)第一次调用VirtualAlloc提供的地址 0x00400000是0x10000对齐的,因此能正确申请。第二次调用时按照0x10000对齐的地址为0x00400000。VirtualAlloc不能重复申请同一个地址,因此发生错误。
4、问题验证:
1) 调用VirtualAlloc(0x00403000, 0x1000, MEM_RESERVE, PAGE_READWRITE);返回的地址为 0x00400000,可见VirtualAlloc申请的地址确实是按照0x10000对齐的。
5、收获:VirtualAlloc在0x10000粒度内不能连续申请地址空间,因此在申请地址的时候需要注意将申请的地址和大小进行0x10000对齐。