You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

gnu-efi开发:QEMU中Hello World输出乱码问题求助

gnu-efi开发Hello World乱码问题

我刚接触gnu-efi开发,尝试为QEMU编写一个简单的Hello World程序。官方提供的示例程序运行正常,但当我复用其中一个示例的C代码自行构建后,在QEMU shell中输出了奇怪的类中文字符。以下是我的Makefile和C代码片段:

Makefile

ARCH = x86_64
CC = cc
LD = ld
OBJCOPY = objcopy
OBJS = myapp.o
TARGET = myapp.efi

# Use your local gnu-efi build
GNUEFI_DIR = gnu-efi
EFIINC = $(GNUEFI_DIR)/inc
EFIINCS = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol
EFILIB = $(GNUEFI_DIR)/x86_64
EFI_CRT_OBJS = $(EFILIB)/gnuefi/crt0-efi-$(ARCH).o
EFI_LDS = $(GNUEFI_DIR)/gnuefi/elf_$(ARCH)_efi.lds

CFLAGS = $(EFIINCS) -fno-stack-protector -fpic \
         -fshort-wchar -mno-red-zone -Wall
         
ifeq ($(ARCH),x86_64)
    CFLAGS += -DEFI_FUNCTION_WRAPPER
endif

LDFLAGS = -nostdlib -znocombreloc -T $(EFI_LDS) -shared \
          -Bsymbolic -L $(EFILIB)/lib -L $(EFILIB)/gnuefi

all: check_gnuefi $(TARGET)

myapp.so: $(OBJS)
    $(LD) $(LDFLAGS) $(EFI_CRT_OBJS) $(OBJS) -o $@ -lefi -lgnuefi

%.efi: %.so
    objcopy -j .text -j .sdata -j .data -j .dynamic \
            -j .dynsym -j .rel -j .rela -j .reloc \
            --target=efi-app-$(ARCH) $^ $@

%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

clean:
    rm -f $(OBJS) *.so *.efi

OVMF_CODE ?= OVMF_CODE_4M.fd
OVMF_VARS ?= OVMF_VARS_4M.fd

.PHONY: check_gnuefi build-gnuefi
check_gnuefi:
    @if [ -f "$(EFI_CRT_OBJS)" ]; then \
        echo "Found $(EFI_CRT_OBJS) — OK"; \
    else \
        echo "crt0 not found in $(EFILIB)/gnuefi — run 'make build-gnuefi' to build the gnu-efi subdir or install a system package"; exit 1; \
    fi

build-gnuefi:
    @echo "Building gnu-efi subdir (may require tools & privileges)..."; \
    $(MAKE) -C $(GNUEFI_DIR) || { echo 'Failed to build gnu-efi'; exit 1; }

test: $(TARGET)
    mkdir -p test-disk
    cp $(TARGET) test-disk/BOOTX64.EFI
    qemu-system-x86_64 \
        -drive if=pflash,format=raw,readonly=on,file=$(CURDIR)/$(OVMF_CODE) \
        -drive if=pflash,format=raw,file=$(CURDIR)/$(OVMF_VARS) \
        -drive file=fat:rw:test-disk,format=raw,media=disk \
        -nographic -serial mon:stdio -m 256M
    rm -rf test-disk

.PHONY: all clean test

C代码

#include <efi.h>
#include <efilib.h>

EFI_STATUS
efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
{
    SIMPLE_TEXT_OUTPUT_INTERFACE *conout;

        InitializeLib(image, systab);
    conout = systab->ConOut;
    uefi_call_wrapper(conout->OutputString, 2, conout, u"Hello World!\n");

    return EFI_SUCCESS;
}

问题原因与修复方案

问题核心是EFI输出接口要求UTF-16编码的宽字符字符串,你代码中使用的u""字符串在编译处理时不符合EFI的CHAR16规范,加上换行符的编码问题,导致输出乱码。

修复方案1:使用gnu-efi提供的Print宏(推荐)

Print宏会自动处理字符串编码和格式化逻辑,无需手动调用底层接口:

#include <efi.h>
#include <efilib.h>

EFI_STATUS
efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
{
    InitializeLib(image, systab);
    Print(L"Hello World!\n");
    return EFI_SUCCESS;
}

修复方案2:修正手动调用的字符串格式

如果坚持使用OutputString,需要将字符串前缀改为L""(符合EFI宽字符要求),确保是正确的UTF-16编码:

#include <efi.h>
#include <efilib.h>

EFI_STATUS
efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
{
    SIMPLE_TEXT_OUTPUT_INTERFACE *conout;

    InitializeLib(image, systab);
    conout = systab->ConOut;
    uefi_call_wrapper(conout->OutputString, 2, conout, L"Hello World!\n");

    return EFI_SUCCESS;
}

另外,你的Makefile中已经包含了-fshort-wchar参数,这个参数确保wchar_t是16位(匹配EFI的CHAR16类型),无需额外修改。


内容的提问来源于stack exchange,提问作者Malaika

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 22:47:01