之前我们在介绍 Source Level Debug 的文章中使用过 Noopt 的选项。后来找人请教了一下这个编译目标的含义:关闭一切编译优化。我猜测这样做的目的是为了让编译结果很容易实现汇编和 Source Code的一一对应。但是,很多情况下,编写EDK2代码的人都会忘记测试这个选项,于是,直接下载的代码会碰到X64 IA32 一切正常,唯独=在这个编译目标上发生问题。
比如,最近我又碰到了关于这个编译目标的问题,下面是简化之后的代码,可以帮助展示这个问题:
#include <Uefi.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 ) { UINTN *z; UINT64 x; z=(UINTN *)1024; //取内存 1024处的值,这里只是为了演示没有实际意义 //如果直接赋值常数,在编译过程中会被优化掉 x=*z; Print (L"%d",x / 1024); return EFI_SUCCESS; }
上面的代码在下面的编译命令时
Build –a IA32 –p MdeModulePkg/MdeModulePkg.dsc –b NOOPT
会出现这样的报错
"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Vc\bin\link.exe" /OUT:c:\buildbs\test\Build\MdeModule\NOOPT_VS2015x86\IA32\MdeModulePkg\Application\NooptTest\NooptTest\DEBUG\NooptTest.dll /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:_ModuleEntryPoint /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG @c:\buildbs\test\Build\MdeModule\NOOPT_VS2015x86\IA32\MdeModulePkg\Application\NooptTest\NooptTest\OUTPUT\static_library_files.lst
NooptTest.lib(NooptTest.obj) : error LNK2001: unresolved external symbol __aulldiv
c:\buildbs\test\Build\MdeModule\NOOPT_VS2015x86\IA32\MdeModulePkg\Application\NooptTest\NooptTest\DEBUG\NooptTest.dll : fatal error LNK1120: 1 unresolved externals
NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Vc\bin\link.exe"' : return code '0x460'
Stop.
build...
: error 7000: Failed to execute command
C:\Program Files (x86)\Microsoft Visual Studio 14.0\Vc\bin\nmake.exe /nologo tbuild [c:\buildbs\test\Build\MdeModule\NOOPT_VS2015x86\IA32\MdeModulePkg\Application\NooptTest\NooptTest]
具体原因我不清楚,-b Release 以及 –b Debug 都不存在问题,可以确定和 NOOPT 模式有关。
标准的解决方法是使用 BaseLib.h 中的DivU64x32函数来代替直接除法运算避免这个问题。同样的,如果针对64位变量进行左移右移也会遇到类似的问题,同样在
BaseLib.h 中可以找到替代的函数。