前面展示了在一个程序中调用另外一个程序的方法,还有加载过程中获取被加载程序的一些基本信息。其中的一个是ImageBase。这里做一个实验来验证上面显示的ImageBase是否正确。
上次的HelloWorld.c代码中我们还加入一条显示UefiMain在内存中的位置。
#include <Uefi.h> #include <Library/PcdLib.h> #include <Library/UefiLib.h> #include <Library/UefiApplicationEntryPoint.h> /** The user Entry Point for Application. The user code starts with this function as the real entry point for the application. @param[in] ImageHandle The firmware allocated handle for the EFI image. @param[in] SystemTable A pointer to the EFI System Table. @retval EFI_SUCCESS The entry point is executed successfully. @retval other Some error occurs when executing this entry point. **/ EFI_STATUS EFIAPI UefiMain ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { Print(L"Hello,World! \r\n"); Print(L"www.lab-z.com \r\n"); Print(L"UefiMain [%X]",(UINTN)UefiMain); return EFI_SUCCESS; }
可以看到,UefiMain被加载到了0x033E 36C5 的位置。运用之前的知识,我们在
\Build\AppPkg\RELEASE_MYTOOLS\IA32\AppPkg\Applications\HelloWorld\HelloWorld\OUTPUT\
能看到编译过程中生成的HelloWorld.map文件(特别注意:我是用build –a IA32 –p AppPkg\AppPkg.dsc –b RELEASE 来生成Release版本的,其他版本会出现在不同的目录中)。
Address Publics by Value Rva+Base Lib:Object 0001:00000490 ??_C@_02PCIJFNDE@?$AN?6?$AA@ 00000690 BasePrintLib:PrintLibInternal.obj 0001:00000494 ??_C@_01LIIJDEN@?$AN?$AA@ 00000694 BasePrintLib:PrintLibInternal.obj 0001:00000496 __ModuleEntryPoint 00000696 f UefiApplicationEntryPoint:ApplicationEntryPoint.obj 0001:000004c5 _UefiMain 000006c5 f HelloWorld:HelloWorld.obj 0001:000004fa _DebugAssert 000006fa f BaseDebugLibNull:DebugLib.obj 0001:000004fb _DebugAssertEnabled 000006fb f BaseDebugLibNull:DebugLib.obj
实际加载的偏移是 6C5 ( Rva+Base ,具体解释请看【参考1 2 3】)
再使用我们的exec2来加载这个EFI可执行程序
因此从结果上看,我们用EFI_LOADED_IMAGE_PROTOCOL 获得的ImageBase是准确的。
参考:
1. http://blog.csdn.net/fantcy/article/details/4474604 PE格式深入浅出之RAV,AV,ImageBase之间的关系
2. http://www.cnblogs.com/lzjsky/archive/2011/09/22/2184942.html PE格式全分析
3. http://blog.sina.com.cn/s/blog_6cc1c52d0100t4wa.html PE文件格式学习笔记