ziglang / zig

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

`std.os.arg` is `undefined` when using _start() instead of main() as Zig "entry point" on Linux #22144

Open rxvoid opened 9 hours ago

rxvoid commented 9 hours ago

Zig Version

0.14.0-dev.2245+4fc295dc0

Steps to Reproduce and Observed Behavior

std.os.arg is undefined when using _start() instead of main() as Zig "entry point" on Linux (or maybe even another Unix-like systems). I have tested it on my x86_64 and aarch64 device and the result is the same.

Given a Zig source:

const std = @import("std");
const linux = std.os.linux;

pub export fn _start() noreturn {
        const stdout = std.io.getStdOut().writer();
        stdout.print("{*}\n", .{ std.os.argv }) catch {};
        linux.exit(0);
}

When you compile and run it, you'll get [*:0]u8@0 printed out. If you trying to print std.os.argv.len, you will get 0 as the result. And if you trying to print std.os.argv[0], you will get segfault instead.

However, when you change the "entry point" to main(), it will run and prints the command-line args perfectly fine. Which basically tells you that the std.os.argv variable was not correctly initialized if you use _start() instead of main() as the "entry point", which is a little bit weird considering that std.os.argv is not portable for non Unix-like and the compiler can directly address std.os.argv to the stack pointer and doesn't need any kind of initialization, but it still only linked when it links to main() instead of _start(). And apparently, it doesn't work even if you use -target xxx-linux-xxx compiler flag.

Expected Behavior

std.os.argv should directly address to command-line arguments in stack pointer on Unix-like systems as it doesn't need any kind of initialization.

rxvoid commented 9 hours ago

And just a bit of my suggestion, maybe it's better to move std.os.argv to std.posix.argv. And to avoid sudden breaking change, we can leave std.os.argv alone while also implementing std.posix.argv, and then deprecate it on the next release.

rohlem commented 7 hours ago

Currently std.os.argv is defined here. The startup code can be seen in lib/std/start.zig. For POSIX, it seems like the default _start function determines argv and passes it to a call to posixCallMainAndExit, which overwrites the global std.os.argv. By manually providing _start, you tell Zig that you want to be the one to do that. Therefore it not happening unless you do it doesn't seem like a bug to me.

If you want to suggest a way to do the same thing differently, maybe at link time, maybe there is a way (maybe that way has drawbacks, idk). I'm sure if you suggest an alternative implementation, and maybe present it in a PR if you get it working, there will be some discussion around it. But I wouldn't call status-quo a bug.