前面的一篇文章遇到了奇怪的问题,字符串输出看起来很不规整。于是研究一下为什么。
首先,试试 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;
}
我们看到有同样的现象。

为了查看汇编级别的程序,我们可以在 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'
运行结果:

最后,提一个问题,如果程序写成这个样子
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;
}
输出结果应该是什么样的呢?