【发布时间】:2021-04-09 10:58:29
【问题描述】:
我想在 Flat Assembler 制作的 EFI 应用程序中通过 UEFI 输出字符串。 这是我的代码
format pe64 dll efi
entry efimain
section '.text' code readable executable
efimain:
sub rsp, 20h
mov [EfiHandle], rcx
mov [SystemTable], rdx
mov [ReturnAddr], rsp
lea rdx, [_hello]
mov rcx, [SystemTable]
mov rcx, [rcx + 60]
mov rcx, [rcx + 8]
call rcx
jmp $
section '.data' data readable writeable
EfiHandle dq 0
SystemTable dq 0
ReturnAddr dq 0
ConOutAddr dq 0
_hello du 'Hello from UEFI'
基于最新的 UEFI 规范,SystemTable 在 x64 架构上的 RDX 中移交。除了基于规范之外,系统表还描述为
typedef struct {
EFI_TABLE_HEADER Hdr;
CHAR16 *FirmwareVendor;
UINT32 FirmwareRevision;
EFI_HANDLE ConsoleInHandle;
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
EFI_HANDLE ConsoleOutHandle;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
EFI_HANDLE StandardErrorHandle;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr;
EFI_RUNTIME_SERVICES *RuntimeServices;
EFI_BOOT_SERVICES *BootServices;
UINTN NumberOfTableEntries;
EFI_CONFIGURATION_TABLE *ConfigurationTable;
} EFI_SYSTEM_TABLE;
表头定义为
typedef struct {
UINT64 Signature;
UINT32 Revision;
UINT32 HeaderSize;
UINT32 CRC32;
UINT32 Reserved;
} EFI_TABLE_HEADER;
EFI_HANDLE 被定义为 VOID *,假设它们表示 x64 架构上的 8 字节指针。
我知道创建结构会更简单,但我想直接进行数学运算以找到正确的偏移量。根据我获得 ConOut 指针的计算,我从 SystemTable Offset + 60(标题 + SystemTable 的其他部分)开始。那么OutPutString方法在输出协议中,定义为:
typedef struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
EFI_TEXT_RESET Reset;
EFI_TEXT_STRING OutputString;
EFI_TEXT_TEST_STRING TestString;
EFI_TEXT_QUERY_MODE QueryMode;
EFI_TEXT_SET_MODE SetMode;
EFI_TEXT_SET_ATTRIBUTE SetAttribute;
EFI_TEXT_CLEAR_SCREEN ClearScreen;
EFI_TEXT_SET_CURSOR_POSITION SetCursorPosition;
EFI_TEXT_ENABLE_CURSOR EnableCursor;
SIMPLE_TEXT_OUTPUT_MODE *Mode;
} EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
所以在通过mov rcx, [rcx + 60]移动输出协议的偏移量后,我需要跳转到我想调用的OutputString,所以我需要再次跳过8个字节mov rcx, [rcx + 8]。
由于我对 Assembler 不太熟悉,我很确定问题一定在于找到 OutputString 方法的正确 OffSet,但我无法发现它。
【问题讨论】:
-
偏移似乎没问题。但是
OutputString不是一个方法吗?即,看看它的签名,它不需要一个EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL指针作为它的第一个参数吗?如果在最后两行使用mov rax, [rcx+8] / call rax会发生什么?