Step to UEFI (23) ----- ConOut ->OutputString 的换行问题

前面的一篇文章遇到了奇怪的问题,字符串输出看起来很不规整。于是研究一下为什么。

首先,试试 Application 是否也会有这样的显示问题,修改程序如下

#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellLib.h>
#include <Library/UefiApplicationEntryPoint.h>

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

//
// Entry point function 
//
EFI_STATUS
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  Print(L"www.lab-z.com\n");
  gST->ConOut->OutputString(gST->ConOut,L"LABZ Test1\n");
  gST->ConOut->OutputString(gST->ConOut,L"LABZ Test2\n");
  gST->ConOut->OutputString(gST->ConOut,L"LABZ Test3\n");  
 
  return EFI_SUCCESS;
}

 

我们看到有同样的现象。

23a
为了查看汇编级别的程序,我们可以在 ClsTest.inf 加入下面的代码

[BuildOptions]
  MSFT:*_*_IA32_CC_FLAGS  = /Oi- /FAcs

 

真正有效的成分是 /FAcs,这让编译器在编译过程中生成C语言和汇编代码对应的中间文件。

再次编译之后我们可以在 \Build\AppPkg\DEBUG_VS2008\IA32\AppPkg\Applications\ClsTest\ClsTest 找到 ClsTest.cod

文件。这就是我们想要的。它的内容如下:

; Listing generated by Microsoft (R) Optimizing Compiler Version 15.00.30729.01 

	TITLE	c:\edk2\AppPkg\Applications\ClsTest\ClsTest.c
	.686P
	.XMM
	include listing.inc
	.model	flat

INCLUDELIB OLDNAMES

PUBLIC	??_C@_1BO@BCGMLOBC@?$AAw?$AAw?$AAw?$AA?4?$AAl?$AAa?$AAb?$AA?9?$AAz?$AA?4?$AAc?$AAo?$AAm?$AA?6?$AA?$AA@ ; `string'
PUBLIC	??_C@_1BI@GJIEKEJP@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA1?$AA?6?$AA?$AA@ ; `string'
PUBLIC	??_C@_1BI@OPBANGDB@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA2?$AA?6?$AA?$AA@ ; `string'
PUBLIC	??_C@_1BI@CEEMAFJE@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA3?$AA?6?$AA?$AA@ ; `string'
;	COMDAT ??_C@_1BI@CEEMAFJE@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA3?$AA?6?$AA?$AA@
CONST	SEGMENT
??_C@_1BI@CEEMAFJE@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA3?$AA?6?$AA?$AA@ DB 'L'
	DB	00H, 'A', 00H, 'B', 00H, 'Z', 00H, ' ', 00H, 'T', 00H, 'e', 00H
	DB	's', 00H, 't', 00H, '3', 00H, 0aH, 00H, 00H, 00H ; `string'
CONST	ENDS
;	COMDAT ??_C@_1BI@OPBANGDB@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA2?$AA?6?$AA?$AA@
CONST	SEGMENT
??_C@_1BI@OPBANGDB@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA2?$AA?6?$AA?$AA@ DB 'L'
	DB	00H, 'A', 00H, 'B', 00H, 'Z', 00H, ' ', 00H, 'T', 00H, 'e', 00H
	DB	's', 00H, 't', 00H, '2', 00H, 0aH, 00H, 00H, 00H ; `string'
CONST	ENDS
;	COMDAT ??_C@_1BI@GJIEKEJP@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA1?$AA?6?$AA?$AA@
CONST	SEGMENT
??_C@_1BI@GJIEKEJP@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA1?$AA?6?$AA?$AA@ DB 'L'
	DB	00H, 'A', 00H, 'B', 00H, 'Z', 00H, ' ', 00H, 'T', 00H, 'e', 00H
	DB	's', 00H, 't', 00H, '1', 00H, 0aH, 00H, 00H, 00H ; `string'
CONST	ENDS
;	COMDAT ??_C@_1BO@BCGMLOBC@?$AAw?$AAw?$AAw?$AA?4?$AAl?$AAa?$AAb?$AA?9?$AAz?$AA?4?$AAc?$AAo?$AAm?$AA?6?$AA?$AA@
CONST	SEGMENT
??_C@_1BO@BCGMLOBC@?$AAw?$AAw?$AAw?$AA?4?$AAl?$AAa?$AAb?$AA?9?$AAz?$AA?4?$AAc?$AAo?$AAm?$AA?6?$AA?$AA@ DB 'w'
	DB	00H, 'w', 00H, 'w', 00H, '.', 00H, 'l', 00H, 'a', 00H, 'b', 00H
	DB	'-', 00H, 'z', 00H, '.', 00H, 'c', 00H, 'o', 00H, 'm', 00H, 0aH
	DB	00H, 00H, 00H				; `string'
PUBLIC	_UefiMain
; Function compile flags: /Ogspy
; File c:\edk2\apppkg\applications\clstest\clstest.c
;	COMDAT _UefiMain
_TEXT	SEGMENT
_UefiMain PROC						; COMDAT

; 22   :   Print(L"www.lab-z.com\n");

  00000	68 00 00 00 00	 push	 OFFSET ??_C@_1BO@BCGMLOBC@?$AAw?$AAw?$AAw?$AA?4?$AAl?$AAa?$AAb?$AA?9?$AAz?$AA?4?$AAc?$AAo?$AAm?$AA?6?$AA?$AA@
  00005	e8 00 00 00 00	 call	 _Print

; 23   :   gST->ConOut->OutputString(gST->ConOut,L"LABZ Test1\n");

  0000a	a1 00 00 00 00	 mov	 eax, DWORD PTR _gST
  0000f	8b 40 2c	 mov	 eax, DWORD PTR [eax+44]
  00012	c7 04 24 00 00
	00 00		 mov	 DWORD PTR [esp], OFFSET ??_C@_1BI@GJIEKEJP@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA1?$AA?6?$AA?$AA@
  00019	50		 push	 eax
  0001a	ff 50 04	 call	 DWORD PTR [eax+4]

; 24   :   gST->ConOut->OutputString(gST->ConOut,L"LABZ Test2\n");

  0001d	a1 00 00 00 00	 mov	 eax, DWORD PTR _gST
  00022	8b 40 2c	 mov	 eax, DWORD PTR [eax+44]
  00025	68 00 00 00 00	 push	 OFFSET ??_C@_1BI@OPBANGDB@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA2?$AA?6?$AA?$AA@
  0002a	50		 push	 eax
  0002b	ff 50 04	 call	 DWORD PTR [eax+4]

; 25   :   gST->ConOut->OutputString(gST->ConOut,L"LABZ Test3\n");  

  0002e	a1 00 00 00 00	 mov	 eax, DWORD PTR _gST
  00033	8b 40 2c	 mov	 eax, DWORD PTR [eax+44]
  00036	68 00 00 00 00	 push	 OFFSET ??_C@_1BI@CEEMAFJE@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA3?$AA?6?$AA?$AA@
  0003b	50		 push	 eax
  0003c	ff 50 04	 call	 DWORD PTR [eax+4]
  0003f	83 c4 18	 add	 esp, 24			; 00000018H

; 26   :   
; 27   :   return EFI_SUCCESS;

  00042	33 c0		 xor	 eax, eax

; 28   : }

  00044	c3		 ret	 0
_UefiMain ENDP
END

 

特别注意到,编译后,我们定义的字符串汇编写成下面这样形式的Unicode字符串

CONST	SEGMENT
??_C@_1BI@CEEMAFJE@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA3?$AA?6?$AA?$AA@ DB 'L'
	DB	00H, 'A', 00H, 'B', 00H, 'Z', 00H, ' ', 00H, 'T', 00H, 'e', 00H
	DB	's', 00H, 't', 00H, '3', 00H, 0aH, 00H, 00H, 00H ; `string'
CONST	ENDS

 

可以看到上面只有 0ah 这是换行的意思,并没有“换行然后切换到下行行首”的意思。

找到原因,我们可以加上切换到行首,就是下面这个样子

  gST->ConOut->OutputString(gST->ConOut,L"LABZ Test4\n\r");    
  gST->ConOut->OutputString(gST->ConOut,L"LABZ Test5\n\r");   

 

再编译查看生成的 COD 文件

CONST	SEGMENT
??_C@_1BK@FBECEOIH@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA5?$AA?6?$AA?$AN?$AA?$AA@ DB 'L'
	DB	00H, 'A', 00H, 'B', 00H, 'Z', 00H, ' ', 00H, 'T', 00H, 'e', 00H
	DB	's', 00H, 't', 00H, '5', 00H, 0aH, 00H, 0dH, 00H, 00H, 00H ; `string'
CONST	ENDS
;	COMDAT ??_C@_1BK@JNOIEOBJ@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA4?$AA?6?$AA?$AN?$AA?$AA@
CONST	SEGMENT
??_C@_1BK@JNOIEOBJ@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA4?$AA?6?$AA?$AN?$AA?$AA@ DB 'L'
	DB	00H, 'A', 00H, 'B', 00H, 'Z', 00H, ' ', 00H, 'T', 00H, 'e', 00H
	DB	's', 00H, 't', 00H, '4', 00H, 0aH, 00H, 0dH, 00H, 00H, 00H ; `string'
CONST	ENDS
;	COMDAT ??_C@_1BI@CEEMAFJE@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA3?$AA?6?$AA?$AA@
CONST	SEGMENT
??_C@_1BI@CEEMAFJE@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA3?$AA?6?$AA?$AA@ DB 'L'
	DB	00H, 'A', 00H, 'B', 00H, 'Z', 00H, ' ', 00H, 'T', 00H, 'e', 00H
	DB	's', 00H, 't', 00H, '3', 00H, 0aH, 00H, 00H, 00H ; `string'
CONST	ENDS
;	COMDAT ??_C@_1BI@OPBANGDB@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA2?$AA?6?$AA?$AA@
CONST	SEGMENT
??_C@_1BI@OPBANGDB@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA2?$AA?6?$AA?$AA@ DB 'L'
	DB	00H, 'A', 00H, 'B', 00H, 'Z', 00H, ' ', 00H, 'T', 00H, 'e', 00H
	DB	's', 00H, 't', 00H, '2', 00H, 0aH, 00H, 00H, 00H ; `string'
CONST	ENDS
;	COMDAT ??_C@_1BI@GJIEKEJP@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA1?$AA?6?$AA?$AA@
CONST	SEGMENT
??_C@_1BI@GJIEKEJP@?$AAL?$AAA?$AAB?$AAZ?$AA?5?$AAT?$AAe?$AAs?$AAt?$AA1?$AA?6?$AA?$AA@ DB 'L'
	DB	00H, 'A', 00H, 'B', 00H, 'Z', 00H, ' ', 00H, 'T', 00H, 'e', 00H
	DB	's', 00H, 't', 00H, '1', 00H, 0aH, 00H, 00H, 00H ; `string'
CONST	ENDS
;	COMDAT ??_C@_1BO@BCGMLOBC@?$AAw?$AAw?$AAw?$AA?4?$AAl?$AAa?$AAb?$AA?9?$AAz?$AA?4?$AAc?$AAo?$AAm?$AA?6?$AA?$AA@
CONST	SEGMENT
??_C@_1BO@BCGMLOBC@?$AAw?$AAw?$AAw?$AA?4?$AAl?$AAa?$AAb?$AA?9?$AAz?$AA?4?$AAc?$AAo?$AAm?$AA?6?$AA?$AA@ DB 'w'
	DB	00H, 'w', 00H, 'w', 00H, '.', 00H, 'l', 00H, 'a', 00H, 'b', 00H
	DB	'-', 00H, 'z', 00H, '.', 00H, 'c', 00H, 'o', 00H, 'm', 00H, 0aH
	DB	00H, 00H, 00H				; `string'

 

运行结果:

23b

最后,提一个问题,如果程序写成这个样子

EFI_STATUS
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  Print(L"www.lab-z.com\n");
  gST->ConOut->OutputString(gST->ConOut,L"LABZ Test1\r");
  gST->ConOut->OutputString(gST->ConOut,L"LABZ Test2\r");
  gST->ConOut->OutputString(gST->ConOut,L"LABZ Test3\n");  
  
  return EFI_SUCCESS;
}

 

输出结果应该是什么样的呢?

发表回复

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