之前的一篇文章《Step to UEFI (9)----使用RDTSC计算当前CPU 频率》【参考1】给出了一个计算当前CPU频率的方法。不过 Tim 给我留言,他说这篇文章的程序无法在 x64下正常编译:
我猜测原因是因为我的程序使用的内嵌汇编,内嵌汇编无法被X64的编译器正常编译的。关于这个说法可以看【参考2】。
动手在 UDK2014 下面实验,不过在看到描述的问题之前还是要走一段路的。
使用编译命令 build -a X64 -p AppPkg\AppPkg.dsc 得到下面的错误信息
c:\edk\AppPkg\AppPkg.dsc(94): error 000E: File/directory not found in workspace c:\edk\PerformancePkg\Library\DxeTscTimerLib\DxeTscTimerLib.inf
检查 AppPkg.dsc
修改
[LibraryClasses.X64] TimerLib|PerformancePkg/Library/DxeTscTimerLib/DxeTscTimerLib.inf
修改为
[LibraryClasses.X64] TimerLib|PerformancePkg/Library/TscTimerLib/DxeTscTimerLib.inf
再次编译,有下面的错误信息
Processing meta-data .. done! Building ... c:\edk\MdePkg\Library\BaseLib\BaseLib.inf [X64] "C:\Program Files\Microsoft Visual Studio 9.0\Vc\bin\x86_amd64\cl.exe" /Foc:\edk\Build\AppPkg\DEBUG_MYTOOLS\X64\MdePkg\Library\BaseLib\BaseLib\OUTPUT\.\CheckSum.obj /nologo /c /WX /GS- /W4 /Gs32768 /Gy /D UNICODE /O1ib2 /GL /FIAutoG en.h /EHs-c- /GR- /GF /Zi /Gm /X /Zc:wchar_t /X /Zc:wchar_t /GL- /Ic:\edk\MdePkg\Library\BaseLib\X64 /Ic:\edk\MdePkg\Library\BaseLib /Ic:\edk\Build\AppPkg\DEBUG_MYTOOLS\X64\MdePkg\Library\BaseLib\BaseLib\DEBUG /Ic:\edk\MdePkg /Ic:\edk\M dePkg\Include /Ic:\edk\MdePkg\Include\X64 c:\edk\MdePkg\Library\BaseLib\CheckSum.c 'C:\Program' 不是内部或外部命令,也不是可运行的程序或批处理文件。 NMAKE : fatal error U1077: '"C:\Program Files\Microsoft Visual Studio 9.0\Vc\bin\x86_amd64\cl.exe' : return code '0x1' Stop. build... : error 7000: Failed to execute command C:\Program Files\Microsoft Visual Studio 9.0\Vc\bin\nmake.exe /nologo tbuild build... : error 7000: Failed to execute command C:\Program Files\Microsoft Visual Studio 9.0\Vc\bin\nmake.exe /nologo tbuild build... : error F002: Failed to build module c:\edk\MdePkg\Library\BaseLib\BaseLib.inf [X64, MYTOOLS, DEBUG] - Failed - Build end time: 11:22:09, Mar.09 2015 Build total time: 00:00:03
尝试在命令行窗口直接运行"C:\Program Files\Microsoft Visual Studio 9.0\Vc\bin\x86_amd64\cl.exe" 错误提示是:
C:\EDK>"C:\Program Files\Microsoft Visual Studio 9.0\Vc\bin\x86_amd64\cl.exe" 系统找不到指定的路径。
这是因为目前的编译环境缺少 64位编译器。我使用的是 vs2008 express 版本,默认是没有 64位的cl.exe的。
找到 'x86_amd64' 拷贝到 "C:\Program Files\Microsoft Visual Studio 9.0\VC\bin"
需要的朋友可以在这里下载到 x86_amd64
再次编译,然后就能看到 Tim 说的问题啦
C:\Program Files\Microsoft Visual Studio 9.0\VC\bin Building ... c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.inf [X64] "C:\Program Files\Microsoft Visual Studio 9.0\Vc\bin\x86_amd64\cl.exe" /Foc:\edk\Build\AppPkg\DEBUG_MYTOOLS\X64\AppPkg\Applications\FreqCalc\FreqCalc\OUTPUT\.\FreqCalc.obj /nologo /c /WX /GS- /W4 /Gs32768 /Gy /D UNICODE /O1ib2 /GL / FIAutoGen.h /EHs-c- /GR- /GF /Zi /Gm /X /Zc:wchar_t /Ic:\edk\AppPkg\Applications\FreqCalc /Ic:\edk\Build\AppPkg\DEBUG_MYTOOLS\X64\AppPkg\Applications\FreqCalc\FreqCalc\DEBUG /Ic:\edk\MdePkg /Ic:\edk\MdePkg\Include /Ic:\edk\MdePkg\Includ e\X64 /Ic:\edk\ShellPkg /Ic:\edk\ShellPkg\Include /Ic:\edk\MdeModulePkg /Ic:\edk\MdeModulePkg\Include c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c FreqCalc.c c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(15) : error C4235: nonstandard extension used : '__asm' keyword not supported on this architecture c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(18) : error C2146: syntax error : missing ';' before identifier 'mov' c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(18) : warning C4550: expression evaluates to a function which is missing an argument list c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(18) : error C2065: 'mov' : undeclared identifier c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(18) : error C2146: syntax error : missing ';' before identifier 'dword' c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(18) : error C2065: 'dword' : undeclared identifier c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(18) : error C2146: syntax error : missing ';' before identifier 'ptr' c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(18) : error C2065: 'ptr' : undeclared identifier c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(18) : error C2146: syntax error : missing ';' before identifier 'value' c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(19) : error C2065: 'eax' : undeclared identifier c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(19) : error C2146: syntax error : missing ';' before identifier 'mov' c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(19) : error C2065: 'mov' : undeclared identifier c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(19) : error C2146: syntax error : missing ';' before identifier 'dword' c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(19) : error C2065: 'dword' : undeclared identifier c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(19) : error C2146: syntax error : missing ';' before identifier 'ptr' c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(19) : error C2065: 'ptr' : undeclared identifier c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(19) : error C2109: subscript requires array or pointer type c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(20) : error C2065: 'edx' : undeclared identifier c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.c(20) : error C2143: syntax error : missing ';' before '}' NMAKE : fatal error U1077: '"C:\Program Files\Microsoft Visual Studio 9.0\Vc\bin\x86_amd64\cl.exe"' : return code '0x2' Stop. build... : error 7000: Failed to execute command C:\Program Files\Microsoft Visual Studio 9.0\Vc\bin\nmake.exe /nologo tbuild build... : error F002: Failed to build module c:\edk\AppPkg\Applications\FreqCalc\FreqCalc.inf [X64, MYTOOLS, DEBUG] - Failed - Build end time: 11:26:31, Mar.09 2015 Build total time: 00:01:16
然后就考虑如何解决,网上搜索了一下,有人遇到同样的问题【参考3】,具体的解决方法在【参考4】
简单的说,就是单独写一个 asm 然后在对应的 Inf中声明一下即可。
针对我遇到的问题,程序如下
FreqCalc.inf
## @file # Sample UEFI Application Reference EDKII Module # # This is a sample shell application that will print "UEFI Hello World!" to the # UEFI Console based on PCD setting. # # It demos how to use EDKII PCD mechanism to make code more flexible. # # Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.<BR> # # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at # http://opensource.org/licenses/bsd-license.php # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. # # ## [Defines] INF_VERSION = 0x00010005 BASE_NAME = FreqCalc FILE_GUID = 6987936E-ED34-44db-AE97-2FA5E4ED2216 MODULE_TYPE = UEFI_APPLICATION VERSION_STRING = 1.0 ENTRY_POINT = UefiMain # # The following information is for reference only and not required by the build tools. # # VALID_ARCHITECTURES = IA32 X64 IPF EBC # [Sources] FreqCalc.c ReadTsc1.asm [Packages] MdePkg/MdePkg.dec ShellPkg/ShellPkg.dec MdeModulePkg/MdeModulePkg.dec [LibraryClasses] UefiApplicationEntryPoint UefiLib PcdLib ShellCEntryLib ShellLib [FeaturePcd] [Pcd]
然后在FreqCalc.c 写成下面这样,特别注意要声明一下你用的那个汇编语言中的函数名
// // FreqCalc.C // #include <Uefi.h> #include <Library/UefiLib.h> #include <Library/ShellLib.h> EFI_SYSTEM_TABLE *gST; EFI_BOOT_SERVICES *gBS; UINT64 EFIAPI zReadTsc ( VOID ); // // Entry point function - ShowVersion // EFI_STATUS EFIAPI UefiMain ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { UINT64 elsp; gST = SystemTable; gBS = SystemTable->BootServices; elsp=zReadTsc(); gBS -> Stall(1000000); Print(L"CPU Frequency: %ld \n",zReadTsc() - elsp); return EFI_SUCCESS; }
然后还有一个ReadTsc1.asm (其实 uefi 里面提供了一个 x64的 ReadTsc.asm,可以直接使用,这里是为了让读者看的更清楚,取了一个不会重复的名称)
.code ;------------------------------------------------------------------------------ ; UINT64 ; EFIAPI ; zReadTsc ( ; VOID ; ); ;------------------------------------------------------------------------------ zReadTsc PROC rdtsc shl rdx, 20h or rax, rdx ret zReadTsc ENDP END
接下来就可以正常编译了,生成的 efi 文件会比 x64的大一些。然后我在实体机的 x64 shell下面运行成功。就是说上面的方法是没问题的。
参考:
1.http://www.lab-z.com/rdtsc/ Step to UEFI (9)----使用RDTSC计算当前CPU 频率
2.http://stackoverflow.com/questions/1295452/why-does-msvc-not-support-inline-assembly-for-amd64-and-itanium-targets 简单解释,说x64下无法支持 _ASM汇编
3.http://biosren.com/viewthread.php?tid=6822&highlight=%C4%DA%C7%B6%2B%BB%E3%B1%E0 請問如何在EDK2的AppPkg裡面使用asm (有人问同样的问题)
4.http://www.biosren.com/thread-6632-1-1.html 給個UEFI 內嵌彙編的小程序吧? 本文的主要参考,其中介绍了如何写单独写一个ASM文件