Step to UEFI (136)哪里来的的 memset

最近编写一个非常简单的代码,遇到奇怪的问题,有兴趣的朋友可以先自己猜一下,答案在后面。
代码如下:

/** @file
    A simple, basic, application showing how the Hello application could be
    built using the "Standard C Libraries" from StdLib.

    Copyright (c) 2010 - 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.

    THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
    WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Library/BaseLib.h>
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/PrintLib.h>
#include <Library/ShellCEntryLib.h>
#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>

void prt(IN UINT16 *p)
{
       UINT8   i;
        for (i=0;i<256;i++) {
           Print(L"%c",*p);
           p++;
        }
}
INTN
EFIAPI
ShellAppMain (
  IN UINTN Argc,
  IN CHAR16 **Argv
  )
{
        CHAR8   buffer[256];
        UINT16  i;
        
        for (i=0;i<256;i++) {
                buffer[i]='L';
        }
        prt((UINT16*)buffer);
        return 0;
}

 

错误信息如下:

“C:\Program Files (x86)\Microsoft Visual Studio 12.0\Vc\bin\x86_amd64\li
b.exe” /NOLOGO /LTCG /OUT:d:\udk2017\Build\AppPkg\DEBUG_VS2013x86\X64\AppPkg\App
lications\SimpleDemo\SimpleDemo\OUTPUT\wft.lib @d:\udk2017\Build\AppPkg\DEBUG_VS
2013×86\X64\AppPkg\Applications\SimpleDemo\SimpleDemo\OUTPUT\object_files.lst
“C:\Program Files (x86)\Microsoft Visual Studio 12.0\Vc\bin\x86_amd64\li
nk.exe” /OUT:d:\udk2017\Build\AppPkg\DEBUG_VS2013x86\X64\AppPkg\Applications\Sim
pleDemo\SimpleDemo\DEBUG\wft.dll /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OP
T:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /
DLL /ENTRY:_ModuleEntryPoint /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BAS
E:0 /DRIVER /DEBUG @d:\udk2017\Build\AppPkg\DEBUG_VS2013x86\X64\AppPkg\Applicat
ions\SimpleDemo\SimpleDemo\OUTPUT\static_library_files.lst
Generating code
Finished generating code
UefiApplicationEntryPoint.lib(ApplicationEntryPoint.obj) : error LNK2001: unreso
lved external symbol memset
d:\udk2017\Build\AppPkg\DEBUG_VS2013x86\X64\AppPkg\Applications\SimpleDemo\Simpl
eDemo\DEBUG\wft.dll : fatal error LNK1120: 1 unresolved externals
NMAKE : fatal error U1077: ‘”C:\Program Files (x86)\Microsoft Visual Studio 12.0
\Vc\bin\x86_amd64\link.exe”‘ : return code ‘0x460’
Stop.

build…
: error 7000: Failed to execute command
C:\Program Files (x86)\Microsoft Visual Studio 12.0\Vc\bin\nmake.exe /no
logo tbuild [d:\udk2017\Build\AppPkg\DEBUG_VS2013x86\X64\AppPkg\Applications\Sim
pleDemo\SimpleDemo]

build…
: error F002: Failed to build module
d:\udk2017\AppPkg\Applications\SimpleDemo\SimpleDemo.inf [X64, VS2013x86
, DEBUG]

– Failed –
Build end time: 11:17:59, Dec.12 2017
Build total time: 00:00:12

上面就是完整的代码和现象,有兴趣的朋友可以琢磨一下,答案在下面。

 

kenan

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

刚开始看到错误提示我还非常疑惑”为啥没有具体错误信息“。仔细观察才发现错误信息是无法Link到 memset上。但是我的代码没有调用 memset。带着疑惑,我在 Inf 中刚加入 /FAcs /Od 准备查看汇编级代码。但是加入之后错误就会消失。
[BuildOptions]
MSFT:*_*_X64_CC_FLAGS = /FAcs /Od
再仔细研究,原来是 /Od 会让错误消失,接下来就简单了,比较只有 /FAcs 和带有 /Od的汇编代码,在 Simpledemo.cod 文件中找到了答案。左边是没有加入 /Od 的,右边是加入 /Od 的。这个参数的意思是关闭优化。比较打开和关闭优化的结果:

mms

因此,问题就清楚了,因为我的赋值是对 buffer[] 全部写入 “L”,所以编译器会自作主张的用memset 来对内存直接赋值,但是恰好我们没有定义 memset,所以就会出现错误。

Step to UEFI (136)哪里来的的 memset》上有 10 条评论

  1. kaotuz

    這問題剛好之前遇到 ,之前百思不得其解
    那時最後for迴圈還改寫成 每個array值一一給予
    感謝版主 現在懂了

    回复
    1. ziv2013 文章作者

      我用的就是 vs2015 。 我记得之前看过 uefi 的编译设置,会设定“不使用编译器自带的库”,所以即使 vs 自定义了 memset 也是不会使用的。

      回复
    1. ziv2013 文章作者

      可以用C 库函数直接赋值,而不是用for 来填充。再或者将 memset 函数头文件Include进去就不会找不到了。

      回复
  2. krishna

    最近看了一些memory function的源码,有些地方是这样描述的:
    //
    // Declare the local variables that actually move the data elements as
    // volatile to prevent the optimizer from replacing this function with
    // the intrinsic memset()
    //
    volatile UINT8 *Pointer;

    变量声明volatile, 以防止这种情形的典范,有好几处都是这样子描述的,大伙可以搜一下。

    回复
  3. krishna

    这种方法只适合指针类型,如果静态数组或结构数组,可能要另想办法,除了楼主的方法,
    我还找到另外一种方法:
    1,楼主的方法:
    [BuildOptions]
    MSFT:*_*_X64_CC_FLAGS = /Od

    2,在下的方法,禁止使用intrinsic functions,改用【 /Oi-】:
    [BuildOptions]
    MSFT:*_*_X64_CC_FLAGS == /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /Oi- /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Gw

    说明1:
    上面的内容来自于”D:\edk2-vUDK2018\Conf\tools_def.txt”,作了优化,原始内容如下,
    RELEASE_VS2015_X64_CC_FLAGS = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Gw

    说明2:
    “MSFT:*_*_X64_CC_FLAGS =”这种风格追加到原来的编译选项。
    “MSFT:*_*_X64_CC_FLAGS ==”这种风格完全取代原来的编译选项。

    参考3:
    https://msdn.microsoft.com/en-us/library/aafb762y.aspx
    https://msdn.microsoft.com/en-us/library/f99tchzc.aspx
    EDK II Module Information (INF) File Specification –> 3.5 [BuildOptions] Sections

    ———————————————————————————————-
    另外说下,我几乎把所有的参数都研究了一遍,这个【/Gs32768 】影响函数stack的大小,例如:
    //CHAR8 buffer[1024*31];//ok
    CHAR8 buffer[1024*32];//error LNK2001: unresolved external symbol __chkstk
    怪不得有时候申请栈过大导致弹出这个栈检查。。。

    回复

发表评论

电子邮件地址不会被公开。 必填项已用*标注