BIOS/UEFI基础——StdLib的编译和使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jiangwei0512/article/details/86751566

StdLib简要说明

UEFI的源代码中有一个Pacakge实现了UEFI下的标准C库,如下所示:

里面有很多C语言的基础函数,比如有stdio.h:

使用StdLib库可以方便对Linux等的代码的快速移植,也方便从其他C语言领域到UEFI开发的转移。

本文接下去介绍如何在UEFI下使用StdLib。

代码以https://gitee.com/jiangwei0512/vUDK2017中的为例。

StdLib的编译

StdLib有独立的Package,可以独立编译。

本文使用的编译器是VS2015。

编译的步骤如下:

1. 运行edksetup.bat:

D:\Codes\vUDK2017>edksetup.bat
          PATH      = D:\Codes\vUDK2017\BaseTools\Bin\Win32;C:\Program Files (x86)\Razer Chroma SDK\bin;C:\Program Files\Razer Chroma SDK\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\Git\cmd;C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit\;D:\Program Files\TortoiseGit\bin;C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin;;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Windows\system32\config\systemprofile\AppData\Local\Microsoft\WindowsApps;C:\Python37\Scripts\;C:\Python37\;C:\Users\HOME\AppData\Local\Microsoft\WindowsApps;D:\Program Files\Microsoft VS Code\bin;C:\Python27;C:\Python36;C:\Nasm;D:\Program Files\qemu;C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin;

     WORKSPACE      = D:\Codes\vUDK2017
EDK_TOOLS_PATH      = D:\Codes\vUDK2017\BaseTools
BASE_TOOLS_PATH     = D:\Codes\vUDK2017\BaseTools
 EDK_TOOLS_BIN      = D:\Codes\vUDK2017\BaseTools\Bin\Win32
     CONF_PATH      = D:\Codes\vUDK2017\Conf


!!! WARNING !!! No CYGWIN_HOME set, gcc build may not be used !!!

D:\Codes\vUDK2017>

2. 执行build命令:

D:\Codes\vUDK2017>build -a X64 -p StdLib\StdLib.dsc -t VS2015x86

但是发现执行命令时报错了:

Processing meta-data ... done!
Building ... d:\codes\vudk2017\StdLib\LibC\LibC.inf [X64]
        "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Vc\bin\x86_amd64\cl.exe" /Fod:\codes\vudk2017\Build\StdLib\DEBUG_VS2015x86\X64\StdLib\LibC\LibC\OUTPUT\Main\errno.obj /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Zi /Gm /X /Zc:wchar_t /D UEFI_C_SOURCE /Wv:11 /Id:\codes\vudk2017\StdLib\LibC\Main\X64  /Id:\codes\vudk2017\StdLib\LibC\Main  /Id:\codes\vudk2017\StdLib\LibC  /Id:\codes\vudk2017\Build\StdLib\DEBUG_VS2015x86\X64\StdLib\LibC\LibC\DEBUG  /Id:\codes\vudk2017\StdLib  /Id:\codes\vudk2017\StdLib\Include  /Id:\codes\vudk2017\StdLib\Include\X64  /Id:\codes\vudk2017\StdLibPrivateInternalFiles  /Id:\codes\vudk2017\StdLibPrivateInternalFiles\Include  /Id:\codes\vudk2017\StdLibPrivateInternalFiles\Include\X64  /Id:\codes\vudk2017\MdePkg  /Id:\codes\vudk2017\MdePkg\Include  /Id:\codes\vudk2017\MdePkg\Include\X64  /Id:\codes\vudk2017\ShellPkg  /Id:\codes\vudk2017\ShellPkg\Include d:\codes\vudk2017\StdLib\LibC\Main\errno.c
errno.c
        "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Vc\bin\x86_amd64\cl.exe" /Fod:\codes\vudk2017\Build\StdLib\DEBUG_VS2015x86\X64\StdLib\LibC\LibC\OUTPUT\Main\assert.obj /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Zi /Gm /X /Zc:wchar_t /D UEFI_C_SOURCE /Wv:11 /Id:\codes\vudk2017\StdLib\LibC\Main\X64  /Id:\codes\vudk2017\StdLib\LibC\Main  /Id:\codes\vudk2017\StdLib\LibC  /Id:\codes\vudk2017\Build\StdLib\DEBUG_VS2015x86\X64\StdLib\LibC\LibC\DEBUG  /Id:\codes\vudk2017\StdLib  /Id:\codes\vudk2017\StdLib\Include  /Id:\codes\vudk2017\StdLib\Include\X64  /Id:\codes\vudk2017\StdLibPrivateInternalFiles  /Id:\codes\vudk2017\StdLibPrivateInternalFiles\Include  /Id:\codes\vudk2017\StdLibPrivateInternalFiles\Include\X64  /Id:\codes\vudk2017\MdePkg  /Id:\codes\vudk2017\MdePkg\Include  /Id:\codes\vudk2017\MdePkg\Include\X64  /Id:\codes\vudk2017\ShellPkg  /Id:\codes\vudk2017\ShellPkg\Include d:\codes\vudk2017\StdLib\LibC\Main\assert.c
assert.c
d:\codes\vudk2017\StdLib\Include\sys/EfiCdefs.h(342): error C2220: 警告被视为错误 - 没有生成“object”文件
d:\codes\vudk2017\StdLib\Include\sys/EfiCdefs.h(342): warning C4117: 保留“__STDC_HOSTED__”宏名,忽略“#define”
NMAKE : fatal error U1077: “"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Vc\bin\x86_amd64\cl.exe"”: 返回代码“0x2”
Stop.

从说明中可以看出,报错的原因是宏重定义了,这是一个warning(编号是4117),由于EDK编译时默认设置了警告视为错误,所以这里就报错了。

我们可以查看出错代码:

  // Keep compiler quiet about casting from smaller to larger types
  #pragma warning ( disable : 4306 )

  #define __STDC__            1
  #define __STDC_VERSION__    199409L
  #define __STDC_HOSTED__     1

所以意思是这里的__STDC_HOSTED__有重定义,所以这里可以做如下的修改:

  // Keep compiler quiet about casting from smaller to larger types
  #pragma warning ( disable : 4306 )

  #define __STDC__            1
  #define __STDC_VERSION__    199409L
#ifndef __STDC_HOSTED__
  #define __STDC_HOSTED__     1
#endif

这样的话编译就OK了。

这种方法理论上是OK的,但是有一个疑问,即默认情况下__STDC_HOSTED__的值是1吗?如果不是1的话,显然跟我们需要定义的值不一致。

这边没有找到这个宏到底是在哪个文件,不过可以在网上搜到相关的说明(https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2015):


Standard predefined macros

The compiler supports these predefined macros specified by the ISO C99 and ISO C++17 standards.

  • __cplusplus Defined as an integer literal value when the translation unit is compiled as C++. Otherwise, undefined.

  • __DATE__ The compilation date of the current source file. The date is a constant length string literal of the form Mmm dd yyyy. The month name Mmm is the same as the abbreviated month name in dates generated by the C Runtime Library asctime function. The first character of date dd is a space if the value is less than 10. This macro is always defined.

  • __FILE__ The name of the current source file. __FILE__ expands to a character string literal. To ensure that the full path to the file is displayed, use /FC (Full Path of Source Code File in Diagnostics). This macro is always defined.

  • __LINE__ Defined as the integer line number in the current source file. The value of the __LINE__ macro can be changed by using a #line directive. This macro is always defined.

  • __STDC__ Defined as 1 only when compiled as C and if the /Za compiler option is specified. Otherwise, undefined.

  • __STDC_HOSTED__ Defined as 1 if the implementation is a hosted implementation, one that supports the entire required standard library. Otherwise, defined as 0.

  • __STDCPP_THREADS__ Defined as 1 if and only if a program can have more than one thread of execution, and compiled as C++. Otherwise, undefined.

  • __TIME__ The time of translation of the preprocessed translation unit. The time is a character string literal of the form hh:mm:ss, the same as the time returned by the C Runtime Library asctime function. This macro is always defined.


可见这个宏的值不是0,就是1,所以上述的代码修改是没有问题的。

我们也可以在VS2015下实际编写一个程序来确定:

#include "stdafx.h"


int main()
{
	printf("hello world %d\n", __STDC_HOSTED__);
	while (1);
    return 0;
}

执行的结果如下:

当然上述的问题还有其它的解决方法:

1. 在代码中使用#pragma来屏蔽这个警告:

  // Keep compiler quiet about casting from smaller to larger types
  #pragma warning ( disable : 4306 )
  #pragma warning ( disable : 4117 )

  #define __STDC__            1
  #define __STDC_VERSION__    199409L
  #define __STDC_HOSTED__     1

2. 在DSC中添加宏控制来屏蔽这个警告:

[Defines]
  PLATFORM_NAME                  = StdLib
  PLATFORM_GUID                  = 6135e67b-d813-4e4a-93c3-945d6af41858
  PLATFORM_VERSION               = 0.01
  DSC_SPECIFICATION              = 0x00010006
  OUTPUT_DIRECTORY               = Build/StdLib
  SUPPORTED_ARCHITECTURES        = IA32|X64|ARM|AARCH64
  BUILD_TARGETS                  = DEBUG|RELEASE|NOOPT
  SKUID_IDENTIFIER               = DEFAULT

[BuildOptions]
  MSFT:*_*_*_CC_FLAGS            = /wd4117

新加了宏之后,可以看到编译时有体现:

        "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Vc\bin\x86_amd64\cl.exe" /Fod:\codes\vudk2017\Build\StdLib\DEBUG_VS2015x86\X64\StdLib\SocketDxe\SocketDxe\OUTPUT\.\AutoGen.obj /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Zi /Gm /wd4117 /X /Zc:wchar_t /D UEFI_C_SOURCE /Wv:11 /Id:\codes\vudk2017\StdLib\SocketDxe  /Id:\codes\vudk2017\Build\StdLib\DEBUG_VS2015x86\X64\StdLib\SocketDxe\SocketDxe\DEBUG  /Id:\codes\vudk2017\MdePkg  /Id:\codes\vudk2017\MdePkg\Include  /Id:\codes\vudk2017\MdePkg\Include\X64  /Id:\codes\vudk2017\MdeModulePkg  /Id:\codes\vudk2017\MdeModulePkg\Include  /Id:\codes\vudk2017\StdLib  /Id:\codes\vudk2017\StdLib\Include  /Id:\codes\vudk2017\StdLib\Include\X64 d:\codes\vudk2017\Build\StdLib\DEBUG_VS2015x86\X64\StdLib\SocketDxe\SocketDxe\DEBUG\AutoGen.c
AutoGen.c

以上的三种方式都能够解决编译的问题。

StdLib的使用

一般StdLib单独编译没有多大的意义,重要的是将它编译到其它的实用模块中。

比如有AppPkg:

在AppPkg.dsc中可以看到对StdLib的包含:

##############################################################################
#
#  Include Boilerplate text required for building with the Standard Libraries.
#
##############################################################################
!include StdLib/StdLib.inc

对于StdLib的使用似乎也没有什么好多讲的,就是包含头文件之类的。

后续如果使用到再深入。

以上。

猜你喜欢

转载自blog.csdn.net/jiangwei0512/article/details/86751566