From 482b995a4963e045860c7fb1a4e11c48cf4de880 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 8 Apr 2021 19:05:05 -0700 Subject: stage2: blaze the trail for std lib integration This branch adds "builtin" and "std" to the import table when using the self-hosted backend. "builtin" gains one additional item: ``` pub const zig_is_stage2 = true; // false when using stage1 backend ``` This allows the std lib to do conditional compilation based on detecting which backend is being used. This will be removed from builtin as soon as self-hosted catches up to feature parity with stage1. Keep a sharp eye out - people are going to be tempted to abuse this. The general rule of thumb is do not use `builtin.zig_is_stage2`. However this commit breaks the rule so that we can gain limited start.zig support as we incrementally improve the self-hosted compiler. This commit also implements `fullyQualifiedNameHash` and related functionality, which effectively puts all Decls in their proper namespaces. `fullyQualifiedName` is not yet implemented. Stop printing "todo" log messages for test decls unless we are in test mode. Add "previous definition here" error notes for Decl name collisions. This commit does not bring us yet to a newly passing test case. Here's what I'm working towards: ```zig const std = @import("std"); export fn main() c_int { const a = std.fs.base64_alphabet[0]; return a - 'A'; } ``` Current output: ``` $ ./zig-cache/bin/zig build-exe test.zig test.zig:3:1: error: TODO implement more analyze elemptr zig-cache/lib/zig/std/start.zig:38:46: error: TODO implement structInitExpr ty ``` So the next steps are clear: * Sema: improve elemptr * AstGen: implement structInitExpr --- lib/std/start.zig | 116 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 89 insertions(+), 27 deletions(-) (limited to 'lib/std/start.zig') diff --git a/lib/std/start.zig b/lib/std/start.zig index 0fb96c768f..5454cc58c6 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -7,7 +7,7 @@ const root = @import("root"); const std = @import("std.zig"); -const builtin = std.builtin; +const builtin = @import("builtin"); const assert = std.debug.assert; const uefi = std.os.uefi; const tlcsprng = @import("crypto/tlcsprng.zig"); @@ -17,39 +17,101 @@ var argc_argv_ptr: [*]usize = undefined; const start_sym_name = if (builtin.arch.isMIPS()) "__start" else "_start"; comptime { - if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) { - if (builtin.os.tag == .windows and !@hasDecl(root, "_DllMainCRTStartup")) { - @export(_DllMainCRTStartup, .{ .name = "_DllMainCRTStartup" }); + // The self-hosted compiler is not fully capable of handling all of this start.zig file. + // Until then, we have simplified logic here for self-hosted. TODO remove this once + // self-hosted is capable enough to handle all of the real start.zig logic. + if (builtin.zig_is_stage2) { + if (builtin.output_mode == .Exe) { + if (builtin.link_libc or builtin.object_format == .c) { + if (!@hasDecl(root, "main")) { + @export(main2, "main"); + } + } else { + if (!@hasDecl(root, "_start")) { + @export(_start2, "_start"); + } + } } - } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) { - if (builtin.link_libc and @hasDecl(root, "main")) { - if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) { - @export(main, .{ .name = "main", .linkage = .Weak }); + } else { + if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) { + if (builtin.os.tag == .windows and !@hasDecl(root, "_DllMainCRTStartup")) { + @export(_DllMainCRTStartup, .{ .name = "_DllMainCRTStartup" }); } - } else if (builtin.os.tag == .windows) { - if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and - !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) - { - @export(WinStartup, .{ .name = "wWinMainCRTStartup" }); - } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and - !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) - { - @compileError("WinMain not supported; declare wWinMain or main instead"); - } else if (@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup") and - !@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup")) - { - @export(wWinMainCRTStartup, .{ .name = "wWinMainCRTStartup" }); + } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) { + if (builtin.link_libc and @hasDecl(root, "main")) { + if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) { + @export(main, .{ .name = "main", .linkage = .Weak }); + } + } else if (builtin.os.tag == .windows) { + if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and + !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) + { + @export(WinStartup, .{ .name = "wWinMainCRTStartup" }); + } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and + !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) + { + @compileError("WinMain not supported; declare wWinMain or main instead"); + } else if (@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup") and + !@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup")) + { + @export(wWinMainCRTStartup, .{ .name = "wWinMainCRTStartup" }); + } + } else if (builtin.os.tag == .uefi) { + if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" }); + } else if (builtin.arch.isWasm() and builtin.os.tag == .freestanding) { + if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name }); + } else if (builtin.os.tag != .other and builtin.os.tag != .freestanding) { + if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name }); } - } else if (builtin.os.tag == .uefi) { - if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" }); - } else if (builtin.arch.isWasm() and builtin.os.tag == .freestanding) { - if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name }); - } else if (builtin.os.tag != .other and builtin.os.tag != .freestanding) { - if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name }); } } } +// Simplified start code for stage2 until it supports more language features /// + +fn main2() callconv(.C) c_int { + root.main(); + return 0; +} + +fn _start2() callconv(.Naked) noreturn { + root.main(); + exit2(0); +} + +fn exit2(code: u8) noreturn { + switch (builtin.arch) { + .x86_64 => { + asm volatile ("syscall" + : + : [number] "{rax}" (231), + [arg1] "{rdi}" (code) + : "rcx", "r11", "memory" + ); + }, + .arm => { + asm volatile ("svc #0" + : + : [number] "{r7}" (1), + [arg1] "{r0}" (code) + : "memory" + ); + }, + .aarch64 => { + asm volatile ("svc #0" + : + : [number] "{x8}" (93), + [arg1] "{x0}" (code) + : "memory", "cc" + ); + }, + else => @compileError("TODO"), + } + unreachable; +} + +//////////////////////////////////////////////////////////////////////////////// + fn _DllMainCRTStartup( hinstDLL: std.os.windows.HINSTANCE, fdwReason: std.os.windows.DWORD, -- cgit v1.2.3