Step to UEFI Tips

最近写程序遇到了一个非常奇怪的问题,化简问题如下:
1. 定义 CHAR8 大小的 Buffer[4]
2. 其中赋值为 128 82 0 0
3. 将他们通过下面的公式合成为一个 INT32
Buffer[0]+(Buffer[1]<<8) +(Buffer[2]<<16)+ (Buffer[3]<<24); 4. 我们期望得到 0x5280=21120, 但是给出来的结果却是 20864 编写程序如下,我们从命令行接收参数,然后转换为数值。

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
	CHAR8	Buffer[4];
	UINTN	FileSize=0;

	Print(L"Argv [%s %s %s %s]\n",
			Argv[1],Argv[2],Argv[3],Argv[4]);	
			
	#pragma warning(disable:4244)
	Buffer[0]=StrDecimalToUintn(Argv[1]);
	Buffer[1]=StrDecimalToUintn(Argv[2]);
	Buffer[2]=StrDecimalToUintn(Argv[3]);
	Buffer[3]=StrDecimalToUintn(Argv[4]);

	Print(L"Buffer [%x %x %x %x]\n",
			Buffer[0],Buffer[1],Buffer[2],Buffer[3]);		
			
	FileSize=Buffer[0]+
		(Buffer[1]<<8)+
		(Buffer[2]<<16)+
		(Buffer[3]<<24);	

	Print(L"File Size = [%d]\n",FileSize);		
				
  return EFI_SUCCESS;
}

 

运行结果:

tipsa

为了Debug,需要打开生成汇编代码的功能,方法是在工程的 inf 文件 [BuildOptions] 下面加入如下语句:

[BuildOptions]
  MSFT:*_*_IA32_CC_FLAGS  = /FAsc

 

再次编译即可在Build目录下看到生成的 cod 文件

tipsb

关键代码部分:

; 28   : 
; 29   : 	Print(L"Buffer [%x %x %x %x]\n",
; 30   : 			Buffer[0],Buffer[1],Buffer[2],Buffer[3]);		

  00048	0f be 7c 24 3e	 movsx	 edi, BYTE PTR _Buffer$[esp+50]
  0004d	0f be 6c 24 3d	 movsx	 ebp, BYTE PTR _Buffer$[esp+49]
  00052	0f be f0	 movsx	 esi, al
  00055	56		 push	 esi
  00056	57		 push	 edi
  00057	0f be db	 movsx	 ebx, bl
  0005a	55		 push	 ebp
  0005b	53		 push	 ebx
  0005c	68 00 00 00 00	 push	 OFFSET ??_C@_1CM@LIBNEIP@?$AAB?$AAu?$AAf?$AAf?$AAe?$AAr?$AA?5?$AA?$FL?$AA?$CF?$AAx?$AA?5?$AA?$CF?$AAx?$AA?5?$AA?$CF?$AAx?$AA?5?$AA?$CF?$AAx?$AA?$FN?$AA?6?$AA?$AA@
  00061	e8 00 00 00 00	 call	 _Print

 

其中 push esi是 Buffer[3], push edi是 Buffer[2], push ebp 是 Buffer[1] , push ebx 是 Buffer[0],看起来一切正常。我们根据简单的结果进行计算0xFFFFFF80+0x5200+0x00+0x00=0x5180 就是说出现问题出在运行期的取值,和 Printf函数 没有关系。所以,关注点在为什么 1byte的0x80被定义成了 0xFFFFFF80。之后,我尝试化简程序,直接定义变量输出查看。我们定义三个变量 a b c用 printf 输出之:

	CHAR8	a=129;
	UINT8	b=130;
	unsigned char	c=131;

	Print(L"A= [%x]\n",a);					
	Print(L"B= [%x]\n",b);		
	Print(L"C= [%x]\n",c);	

 

运行结果:
tipsc

可以看到,如同我们的假设的, CHAR8 的 128被定义为 -127.
具体的 CHAR8定义可以在 MdePkg 中的 ProcessorBind.h 中找到:

  ///
  /// 1-byte Character.
  ///
  typedef char                CHAR8;

 

CHAR 本身是一种有符号的整数(所以才会有 unsigned char)。因此,这就是一个错误的定义数据类型而导致的问题,解决方法很简单,用 UINT8 做定义就好了(从ProcessorBind.h可以看出,UINT8是 unsigned char)。

最后,贴一下修改后的完整INF 文件以便参考:

## @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.
##

[Defines]
  INF_VERSION                    = 0x00010006
  BASE_NAME                      = tipsa
  FILE_GUID                      = 4ea97c46-7491-4dfd-0064-747010f3ce5f
  MODULE_TYPE                    = UEFI_APPLICATION
  VERSION_STRING                 = 0.1
  ENTRY_POINT                    = ShellCEntryLib

#   
#  VALID_ARCHITECTURES           = IA32 X64 IPF
#

[Sources]
  tipsa.c

[Packages]
  StdLib/StdLib.dec   
  MdePkg/MdePkg.dec
  ShellPkg/ShellPkg.dec 


[LibraryClasses]
  LibC
  ShellCEntryLib   
  ShellLib
  
[Protocols]
	
[BuildOptions]
  MSFT:*_*_IA32_CC_FLAGS  = /FAsc
  

 

发表评论

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