ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
33.73k stars 2.48k forks source link

On UEFI, std.debug.ModuleDebugInfo errors at missing fd_t #19367

Open T-rex08 opened 5 months ago

T-rex08 commented 5 months ago

Zig Version

0.12.0-dev.3381+7057bffc1

Steps to Reproduce and Observed Behavior

When compiling to UEFI, the ModuleBuildInfo struct will use std.pdb.Pdb. This PDB struct fails to compile on UEFI because it attempts to use std.os.uefi.fd_t, which doesn't exist.

Example:

const std = @import("std");

pub fn main() void {
    var bytes: [100 * 1024]u8 = undefined;
    var allocator_state = std.heap.FixedBufferAllocator.init(bytes[0..]);
    _ = std.debug.DebugInfo.init(allocator_state.allocator()) catch {};
}

This code currently returns following error (zig build-exe main.zig -target x86_64-uefi-msvc -freference-trace):

/usr/lib/zig/lib/std/os.zig:149:24: error: root struct of file 'os.uefi' has no member named 'fd_t'
pub const fd_t = system.fd_t;
                 ~~~~~~^~~~~
/usr/lib/zig/lib/std/os/uefi.zig:1:1: note: struct declared here
const std = @import("../std.zig");
^~~~~
referenced by:
    Handle: /usr/lib/zig/lib/std/fs/File.zig:4:25
    fs.File: /usr/lib/zig/lib/std/fs/File.zig:2:9
    File: /usr/lib/zig/lib/std/fs.zig:17:26
    File: /usr/lib/zig/lib/std/pdb.zig:8:20
    Pdb: /usr/lib/zig/lib/std/pdb.zig:485:14

Expected Behavior

ModuleBuildInfo should not attempt to use fd_t on UEFI and should get the PDB file some other way.

nektro commented 5 months ago

cc @truemedian

RossComputerGuy commented 5 months ago

If we fix this then can we support !void in root.main?

T-rex08 commented 5 months ago

I don't think so, as it is unclear how the error could be reported (whether SimpleTextOutput or GOP should be used, boot services could even already be exited).

truemedian commented 5 months ago

firstly: UEFI does not document or even mention the use of PDB for UEFI applications.

should get the PDB file some other way.

The only way to get the PDB file is to read it from the file system, and additionally to assume that it is always adjacent to the UEFI application.

boot services could even already be exited

This can easily be asserted, and should. However, most of the standard library should assume boot services are present, because that's what the majority of the UEFI application bindings are for. When boot services are not present, the standard library functions as if freestanding, as there is no interface to accomplish the system interface.

Once an application exits boot services, it is past that point it's own operating system, and should call into freestanding code. Runtime services are the only thing available past that point.

whether SimpleTextOutput or GOP should be used

GOP should definitely not be used. It is not always present. stderr should be sent to ConErr, much like stdout should be sent to ConOut. However, this will likely cause some confusion with those unfamiliar with how these are generally bound.

For example: OVMF binds ConOut to the screen and serial console, but binds ConErr to only the serial console.

This might be slightly confusing at first, but the screen is not a reliable output source, the content may be too large and be overflowed off screen, or the screen could be in GOP mode and therefore not print anything.

On the other hand, ConErr is almost always connected to a serial console.


As for the implementation, fixing this without significantly complicating std.debug requires implementing a few things for UEFI like fd_t and the related std.os functions.

You can see some related progress in https://github.com/truemedian/zig/commit/3fb6a6ecd64d9a4e35d332b1c6f0e7518f790ecf


If we fix this then can we support !void in root.main?

Yes, this is the only thing blocking this use case.

RossComputerGuy commented 5 months ago

I'll be looking into this in my #19486 PR.