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