在 UEFI 汇编器应用程序中找不到 OutputString Offset

问题描述

我想在 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 字节指针。

我知道创建结构会更简单,但我想直接进行数学运算以找到正确的偏移量。根据我从 SystemTable Offset + 60(Header + SystemTable 的其他部分)获取 ConOut 指针的计算。然后 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,但我无法发现它。

解决方法

Margaret 向我指出了解决方案:

  1. 是的,我错过了参数传递部分,第一个参数是指向输出协议的指针(因此必须在 RCX 中),第二个值是 RDX 中的字符串。所以在 rax 中将指针移动到 OutputString 确实有效

  2. 偏移量仍然不正确。我刚刚再次阅读了规范,它说

除非另有说明,否则所有数据类型都是自然对齐的。 结构在等于最大内部的边界上对齐 结构和内部数据的数据被隐式填充到 实现自然对齐。

因此,作为 UINT32 的 FirmwareRevision 的大小在内存中实际上也是 8 个字节(填充)。因此 ConOut 的偏移量为 0x40(或 64 字节)。

通过这些更改,我终于将字符串打印到屏幕上。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...