diff --git a/CMakeLists.txt b/CMakeLists.txt index 2baf4dcbd8..671a6ad236 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -519,6 +519,7 @@ set(ZIG_STAGE2_SOURCES src/Air/Legalize.zig src/Air/Liveness.zig src/Air/Liveness/Verify.zig + src/Air/print.zig src/Air/types_resolved.zig src/Builtin.zig src/Compilation.zig @@ -675,7 +676,6 @@ set(ZIG_STAGE2_SOURCES src/libs/mingw.zig src/libs/musl.zig src/mutable_value.zig - src/print_air.zig src/print_env.zig src/print_targets.zig src/print_value.zig diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 1683cc500b..88e2304332 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -61,7 +61,7 @@ pub const StackTrace = struct { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. -pub const GlobalLinkage = enum { +pub const GlobalLinkage = enum(u2) { internal, strong, weak, @@ -70,7 +70,7 @@ pub const GlobalLinkage = enum { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. -pub const SymbolVisibility = enum { +pub const SymbolVisibility = enum(u2) { default, hidden, protected, @@ -1030,8 +1030,19 @@ pub const ExternOptions = struct { name: []const u8, library_name: ?[]const u8 = null, linkage: GlobalLinkage = .strong, + visibility: SymbolVisibility = .default, + /// Setting this to `true` makes the `@extern` a runtime value. is_thread_local: bool = false, is_dll_import: bool = false, + relocation: Relocation = .any, + + pub const Relocation = enum(u1) { + /// Any type of relocation is allowed. + any, + /// A program-counter-relative relocation is required. + /// Using this value makes the `@extern` a runtime value. + pcrel, + }; }; /// This data structure is used by the Zig language code generation and diff --git a/lib/std/dynamic_library.zig b/lib/std/dynamic_library.zig index 4b1faa87ba..bac31f5760 100644 --- a/lib/std/dynamic_library.zig +++ b/lib/std/dynamic_library.zig @@ -83,13 +83,16 @@ const RDebug = extern struct { r_ldbase: usize, }; -/// TODO make it possible to reference this same external symbol 2x so we don't need this -/// helper function. -pub fn get_DYNAMIC() ?[*]elf.Dyn { - return @extern([*]elf.Dyn, .{ .name = "_DYNAMIC", .linkage = .weak }); +/// TODO fix comparisons of extern symbol pointers so we don't need this helper function. +pub fn get_DYNAMIC() ?[*]const elf.Dyn { + return @extern([*]const elf.Dyn, .{ + .name = "_DYNAMIC", + .linkage = .weak, + .visibility = .hidden, + }); } -pub fn linkmap_iterator(phdrs: []elf.Phdr) error{InvalidExe}!LinkMap.Iterator { +pub fn linkmap_iterator(phdrs: []const elf.Phdr) error{InvalidExe}!LinkMap.Iterator { _ = phdrs; const _DYNAMIC = get_DYNAMIC() orelse { // No PT_DYNAMIC means this is either a statically-linked program or a diff --git a/lib/std/pie.zig b/lib/std/pie.zig index 572f3ddf96..0f4b4ff4b3 100644 --- a/lib/std/pie.zig +++ b/lib/std/pie.zig @@ -39,167 +39,175 @@ const R_RELATIVE = switch (builtin.cpu.arch) { // Obtain a pointer to the _DYNAMIC array. // We have to compute its address as a PC-relative quantity not to require a // relocation that, at this point, is not yet applied. -inline fn getDynamicSymbol() [*]elf.Dyn { - return switch (builtin.cpu.arch) { - .x86 => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ call 1f - \\ 1: pop %[ret] - \\ lea _DYNAMIC-1b(%[ret]), %[ret] - : [ret] "=r" (-> [*]elf.Dyn), - ), - .x86_64 => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ lea _DYNAMIC(%%rip), %[ret] - : [ret] "=r" (-> [*]elf.Dyn), - ), - .arc => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ add %[ret], pcl, _DYNAMIC@pcl - : [ret] "=r" (-> [*]elf.Dyn), - ), - // Work around the limited offset range of `ldr` - .arm, .armeb, .thumb, .thumbeb => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ ldr %[ret], 1f - \\ add %[ret], pc - \\ b 2f - \\ 1: .word _DYNAMIC-1b - \\ 2: - : [ret] "=r" (-> [*]elf.Dyn), - ), - // A simple `adr` is not enough as it has a limited offset range - .aarch64, .aarch64_be => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ adrp %[ret], _DYNAMIC - \\ add %[ret], %[ret], #:lo12:_DYNAMIC - : [ret] "=r" (-> [*]elf.Dyn), - ), - // The CSKY ABI requires the gb register to point to the GOT. Additionally, the first - // entry in the GOT is defined to hold the address of _DYNAMIC. - .csky => asm volatile ( - \\ mov %[ret], gb - \\ ldw %[ret], %[ret] - : [ret] "=r" (-> [*]elf.Dyn), - ), - .hexagon => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ jump 1f - \\ .word _DYNAMIC - . - \\ 1: - \\ r1 = pc - \\ r1 = add(r1, #-4) - \\ %[ret] = memw(r1) - \\ %[ret] = add(r1, %[ret]) - : [ret] "=r" (-> [*]elf.Dyn), - : - : "r1" - ), - .loongarch32, .loongarch64 => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ la.local %[ret], _DYNAMIC - : [ret] "=r" (-> [*]elf.Dyn), - ), - // Note that the - 8 is needed because pc in the second lea instruction points into the - // middle of that instruction. (The first lea is 6 bytes, the second is 4 bytes.) - .m68k => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ lea _DYNAMIC - . - 8, %[ret] - \\ lea (%[ret], %%pc), %[ret] - : [ret] "=r" (-> [*]elf.Dyn), - ), - .mips, .mipsel => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ bal 1f - \\ .gpword _DYNAMIC - \\ 1: - \\ lw %[ret], 0($ra) - \\ addu %[ret], %[ret], $gp - : [ret] "=r" (-> [*]elf.Dyn), - : - : "lr" - ), - .mips64, .mips64el => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ .balign 8 - \\ bal 1f - \\ .gpdword _DYNAMIC - \\ 1: - \\ ld %[ret], 0($ra) - \\ daddu %[ret], %[ret], $gp - : [ret] "=r" (-> [*]elf.Dyn), - : - : "lr" - ), - .powerpc, .powerpcle => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ bl 1f - \\ .long _DYNAMIC - . - \\ 1: - \\ mflr %[ret] - \\ lwz 4, 0(%[ret]) - \\ add %[ret], 4, %[ret] - : [ret] "=r" (-> [*]elf.Dyn), - : - : "lr", "r4" - ), - .powerpc64, .powerpc64le => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ bl 1f - \\ .quad _DYNAMIC - . - \\ 1: - \\ mflr %[ret] - \\ ld 4, 0(%[ret]) - \\ add %[ret], 4, %[ret] - : [ret] "=r" (-> [*]elf.Dyn), - : - : "lr", "r4" - ), - .riscv32, .riscv64 => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ lla %[ret], _DYNAMIC - : [ret] "=r" (-> [*]elf.Dyn), - ), - .s390x => asm volatile ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - \\ larl %[ret], 1f - \\ ag %[ret], 0(%[ret]) - \\ jg 2f - \\ 1: .quad _DYNAMIC - . - \\ 2: - : [ret] "=r" (-> [*]elf.Dyn), - ), - // The compiler does not necessarily have any obligation to load the `l7` register (pointing - // to the GOT), so do it ourselves just in case. - .sparc, .sparc64 => asm volatile ( - \\ sethi %%hi(_GLOBAL_OFFSET_TABLE_ - 4), %%l7 - \\ call 1f - \\ add %%l7, %%lo(_GLOBAL_OFFSET_TABLE_ + 4), %%l7 - \\ 1: - \\ add %%l7, %%o7, %[ret] - : [ret] "=r" (-> [*]elf.Dyn), - ), - else => { - @compileError("PIE startup is not yet supported for this target!"); +inline fn getDynamicSymbol() [*]const elf.Dyn { + return switch (builtin.zig_backend) { + else => switch (builtin.cpu.arch) { + .x86 => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ call 1f + \\ 1: pop %[ret] + \\ lea _DYNAMIC-1b(%[ret]), %[ret] + : [ret] "=r" (-> [*]const elf.Dyn), + ), + .x86_64 => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ lea _DYNAMIC(%%rip), %[ret] + : [ret] "=r" (-> [*]const elf.Dyn), + ), + .arc => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ add %[ret], pcl, _DYNAMIC@pcl + : [ret] "=r" (-> [*]const elf.Dyn), + ), + // Work around the limited offset range of `ldr` + .arm, .armeb, .thumb, .thumbeb => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ ldr %[ret], 1f + \\ add %[ret], pc + \\ b 2f + \\ 1: .word _DYNAMIC-1b + \\ 2: + : [ret] "=r" (-> [*]const elf.Dyn), + ), + // A simple `adr` is not enough as it has a limited offset range + .aarch64, .aarch64_be => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ adrp %[ret], _DYNAMIC + \\ add %[ret], %[ret], #:lo12:_DYNAMIC + : [ret] "=r" (-> [*]const elf.Dyn), + ), + // The CSKY ABI requires the gb register to point to the GOT. Additionally, the first + // entry in the GOT is defined to hold the address of _DYNAMIC. + .csky => asm volatile ( + \\ mov %[ret], gb + \\ ldw %[ret], %[ret] + : [ret] "=r" (-> [*]const elf.Dyn), + ), + .hexagon => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ jump 1f + \\ .word _DYNAMIC - . + \\ 1: + \\ r1 = pc + \\ r1 = add(r1, #-4) + \\ %[ret] = memw(r1) + \\ %[ret] = add(r1, %[ret]) + : [ret] "=r" (-> [*]const elf.Dyn), + : + : "r1" + ), + .loongarch32, .loongarch64 => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ la.local %[ret], _DYNAMIC + : [ret] "=r" (-> [*]const elf.Dyn), + ), + // Note that the - 8 is needed because pc in the second lea instruction points into the + // middle of that instruction. (The first lea is 6 bytes, the second is 4 bytes.) + .m68k => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ lea _DYNAMIC - . - 8, %[ret] + \\ lea (%[ret], %%pc), %[ret] + : [ret] "=r" (-> [*]const elf.Dyn), + ), + .mips, .mipsel => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ bal 1f + \\ .gpword _DYNAMIC + \\ 1: + \\ lw %[ret], 0($ra) + \\ addu %[ret], %[ret], $gp + : [ret] "=r" (-> [*]const elf.Dyn), + : + : "lr" + ), + .mips64, .mips64el => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ .balign 8 + \\ bal 1f + \\ .gpdword _DYNAMIC + \\ 1: + \\ ld %[ret], 0($ra) + \\ daddu %[ret], %[ret], $gp + : [ret] "=r" (-> [*]const elf.Dyn), + : + : "lr" + ), + .powerpc, .powerpcle => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ bl 1f + \\ .long _DYNAMIC - . + \\ 1: + \\ mflr %[ret] + \\ lwz 4, 0(%[ret]) + \\ add %[ret], 4, %[ret] + : [ret] "=r" (-> [*]const elf.Dyn), + : + : "lr", "r4" + ), + .powerpc64, .powerpc64le => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ bl 1f + \\ .quad _DYNAMIC - . + \\ 1: + \\ mflr %[ret] + \\ ld 4, 0(%[ret]) + \\ add %[ret], 4, %[ret] + : [ret] "=r" (-> [*]const elf.Dyn), + : + : "lr", "r4" + ), + .riscv32, .riscv64 => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ lla %[ret], _DYNAMIC + : [ret] "=r" (-> [*]const elf.Dyn), + ), + .s390x => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + \\ larl %[ret], 1f + \\ ag %[ret], 0(%[ret]) + \\ jg 2f + \\ 1: .quad _DYNAMIC - . + \\ 2: + : [ret] "=r" (-> [*]const elf.Dyn), + ), + // The compiler does not necessarily have any obligation to load the `l7` register (pointing + // to the GOT), so do it ourselves just in case. + .sparc, .sparc64 => asm volatile ( + \\ sethi %%hi(_GLOBAL_OFFSET_TABLE_ - 4), %%l7 + \\ call 1f + \\ add %%l7, %%lo(_GLOBAL_OFFSET_TABLE_ + 4), %%l7 + \\ 1: + \\ add %%l7, %%o7, %[ret] + : [ret] "=r" (-> [*]const elf.Dyn), + ), + else => { + @compileError("PIE startup is not yet supported for this target!"); + }, }, + .stage2_x86_64 => @extern([*]const elf.Dyn, .{ + .name = "_DYNAMIC", + .linkage = .weak, + .visibility = .hidden, + .relocation = .pcrel, + }).?, }; } -pub fn relocate(phdrs: []elf.Phdr) void { +pub fn relocate(phdrs: []const elf.Phdr) void { @setRuntimeSafety(false); @disableInstrumentation(); @@ -256,10 +264,9 @@ pub fn relocate(phdrs: []elf.Phdr) void { const rel = sorted_dynv[elf.DT_REL]; if (rel != 0) { - const rels = @call(.always_inline, std.mem.bytesAsSlice, .{ - elf.Rel, - @as([*]u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]], - }); + const rels: []const elf.Rel = @alignCast(@ptrCast( + @as([*]align(@alignOf(elf.Rel)) const u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]], + )); for (rels) |r| { if (r.r_type() != R_RELATIVE) continue; @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr; @@ -268,10 +275,9 @@ pub fn relocate(phdrs: []elf.Phdr) void { const rela = sorted_dynv[elf.DT_RELA]; if (rela != 0) { - const relas = @call(.always_inline, std.mem.bytesAsSlice, .{ - elf.Rela, - @as([*]u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]], - }); + const relas: []const elf.Rela = @alignCast(@ptrCast( + @as([*]align(@alignOf(elf.Rela)) const u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]], + )); for (relas) |r| { if (r.r_type() != R_RELATIVE) continue; @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* = base_addr + @as(usize, @bitCast(r.r_addend)); @@ -280,10 +286,9 @@ pub fn relocate(phdrs: []elf.Phdr) void { const relr = sorted_dynv[elf.DT_RELR]; if (relr != 0) { - const relrs = @call(.always_inline, std.mem.bytesAsSlice, .{ - elf.Relr, - @as([*]u8, @ptrFromInt(base_addr + relr))[0..sorted_dynv[elf.DT_RELRSZ]], - }); + const relrs: []const elf.Relr = @ptrCast( + @as([*]align(@alignOf(elf.Relr)) const u8, @ptrFromInt(base_addr + relr))[0..sorted_dynv[elf.DT_RELRSZ]], + ); var current: [*]usize = undefined; for (relrs) |r| { if ((r & 1) == 0) { diff --git a/lib/std/start.zig b/lib/std/start.zig index 2280bea9e7..9b4897260e 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -163,7 +163,7 @@ fn exit2(code: usize) noreturn { // exits(0) .plan9 => std.os.plan9.exits(null), .windows => { - std.os.windows.ntdll.RtlExitUserProcess(@as(u32, @truncate(code))); + std.os.windows.ntdll.RtlExitUserProcess(@truncate(code)); }, else => @compileError("TODO"), } @@ -511,7 +511,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn { // Code coverage instrumentation might try to use thread local variables. @disableInstrumentation(); const argc = argc_argv_ptr[0]; - const argv = @as([*][*:0]u8, @ptrCast(argc_argv_ptr + 1)); + const argv: [*][*:0]u8 = @ptrCast(argc_argv_ptr + 1); const envp_optional: [*:null]?[*:0]u8 = @ptrCast(@alignCast(argv + argc + 1)); var envp_count: usize = 0; @@ -573,11 +573,11 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn { expandStackSize(phdrs); } - const opt_init_array_start = @extern([*]*const fn () callconv(.c) void, .{ + const opt_init_array_start = @extern([*]const *const fn () callconv(.c) void, .{ .name = "__init_array_start", .linkage = .weak, }); - const opt_init_array_end = @extern([*]*const fn () callconv(.c) void, .{ + const opt_init_array_end = @extern([*]const *const fn () callconv(.c) void, .{ .name = "__init_array_end", .linkage = .weak, }); @@ -651,7 +651,7 @@ fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) cal } fn mainWithoutEnv(c_argc: c_int, c_argv: [*][*:0]c_char) callconv(.c) c_int { - std.os.argv = @as([*][*:0]u8, @ptrCast(c_argv))[0..@as(usize, @intCast(c_argc))]; + std.os.argv = @as([*][*:0]u8, @ptrCast(c_argv))[0..@intCast(c_argc)]; return callMain(); } @@ -701,7 +701,7 @@ pub inline fn callMain() u8 { pub fn call_wWinMain() std.os.windows.INT { const peb = std.os.windows.peb(); const MAIN_HINSTANCE = @typeInfo(@TypeOf(root.wWinMain)).@"fn".params[0].type.?; - const hInstance = @as(MAIN_HINSTANCE, @ptrCast(peb.ImageBaseAddress)); + const hInstance: MAIN_HINSTANCE = @ptrCast(peb.ImageBaseAddress); const lpCmdLine: [*:0]u16 = @ptrCast(peb.ProcessParameters.CommandLine.Buffer); // There are various types used for the 'show window' variable through the Win32 APIs: diff --git a/lib/std/zig/llvm/Builder.zig b/lib/std/zig/llvm/Builder.zig index d8d5ff19c7..865e1efa6d 100644 --- a/lib/std/zig/llvm/Builder.zig +++ b/lib/std/zig/llvm/Builder.zig @@ -1823,6 +1823,14 @@ pub const Visibility = enum(u2) { hidden = 1, protected = 2, + pub fn fromSymbolVisibility(sv: std.builtin.SymbolVisibility) Visibility { + return switch (sv) { + .default => .default, + .hidden => .hidden, + .protected => .protected, + }; + } + pub fn format( self: Visibility, comptime _: []const u8, @@ -2555,6 +2563,10 @@ pub const Variable = struct { return self.ptrConst(builder).global.setLinkage(linkage, builder); } + pub fn setVisibility(self: Index, visibility: Visibility, builder: *Builder) void { + return self.ptrConst(builder).global.setVisibility(visibility, builder); + } + pub fn setDllStorageClass(self: Index, class: DllStorageClass, builder: *Builder) void { return self.ptrConst(builder).global.setDllStorageClass(class, builder); } diff --git a/lib/zig.h b/lib/zig.h index 229d6a7973..188800cde4 100644 --- a/lib/zig.h +++ b/lib/zig.h @@ -272,6 +272,15 @@ #define zig_linksection_fn zig_linksection #endif +#if zig_has_attribute(visibility) +#define zig_visibility(name) __attribute__((visibility(#name))) +#else +#define zig_visibility(name) zig_visibility_##name +#define zig_visibility_default +#define zig_visibility_hidden zig_visibility_hidden_unavailable +#define zig_visibility_protected zig_visibility_protected_unavailable +#endif + #if zig_has_builtin(unreachable) || defined(zig_gcc) || defined(zig_tinyc) #define zig_unreachable() __builtin_unreachable() #elif defined(zig_msvc) diff --git a/src/Air.zig b/src/Air.zig index b315acecce..4810766e71 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -13,6 +13,7 @@ const InternPool = @import("InternPool.zig"); const Type = @import("Type.zig"); const Value = @import("Value.zig"); const Zcu = @import("Zcu.zig"); +const print = @import("Air/print.zig"); const types_resolved = @import("Air/types_resolved.zig"); pub const Legalize = @import("Air/Legalize.zig"); @@ -863,16 +864,17 @@ pub const Inst = struct { /// Uses the `vector_store_elem` field. vector_store_elem, - /// Compute a pointer to a threadlocal or dllimport `Nav`, meaning one of: + /// Compute a pointer to a `Nav` at runtime, always one of: /// /// * `threadlocal var` /// * `extern threadlocal var` (or corresponding `@extern`) /// * `@extern` with `.is_dll_import = true` + /// * `@extern` with `.relocation = .pcrel` /// /// Such pointers are runtime values, so cannot be represented with an InternPool index. /// /// Uses the `ty_nav` field. - tlv_dllimport_ptr, + runtime_nav_ptr, /// Implements @cVaArg builtin. /// Uses the `ty_op` field. @@ -1708,7 +1710,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool) return .fromInterned(ip.indexToKey(err_union_ty.ip_index).error_union_type.payload_type); }, - .tlv_dllimport_ptr => return .fromInterned(datas[@intFromEnum(inst)].ty_nav.ty), + .runtime_nav_ptr => return .fromInterned(datas[@intFromEnum(inst)].ty_nav.ty), .work_item_id, .work_group_size, @@ -1983,7 +1985,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool { .err_return_trace, .addrspace_cast, .save_err_return_trace_index, - .tlv_dllimport_ptr, + .runtime_nav_ptr, .work_item_id, .work_group_size, .work_group_id, @@ -2141,6 +2143,10 @@ pub const typesFullyResolved = types_resolved.typesFullyResolved; pub const typeFullyResolved = types_resolved.checkType; pub const valFullyResolved = types_resolved.checkVal; pub const legalize = Legalize.legalize; +pub const write = print.write; +pub const writeInst = print.writeInst; +pub const dump = print.dump; +pub const dumpInst = print.dumpInst; pub const CoveragePoint = enum(u1) { /// Indicates the block is not a place of interest corresponding to diff --git a/src/Air/Legalize.zig b/src/Air/Legalize.zig index b5d579c2d3..01304d78e8 100644 --- a/src/Air/Legalize.zig +++ b/src/Air/Legalize.zig @@ -622,7 +622,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { .addrspace_cast, .save_err_return_trace_index, .vector_store_elem, - .tlv_dllimport_ptr, + .runtime_nav_ptr, .c_va_arg, .c_va_copy, .c_va_end, diff --git a/src/Air/Liveness.zig b/src/Air/Liveness.zig index 7acba48ed0..94efaf114c 100644 --- a/src/Air/Liveness.zig +++ b/src/Air/Liveness.zig @@ -339,7 +339,7 @@ pub fn categorizeOperand( .wasm_memory_size, .err_return_trace, .save_err_return_trace_index, - .tlv_dllimport_ptr, + .runtime_nav_ptr, .c_va_start, .work_item_id, .work_group_size, @@ -972,7 +972,7 @@ fn analyzeInst( .wasm_memory_size, .err_return_trace, .save_err_return_trace_index, - .tlv_dllimport_ptr, + .runtime_nav_ptr, .c_va_start, .work_item_id, .work_group_size, diff --git a/src/Air/Liveness/Verify.zig b/src/Air/Liveness/Verify.zig index 4ad24cf924..2fafc44ab7 100644 --- a/src/Air/Liveness/Verify.zig +++ b/src/Air/Liveness/Verify.zig @@ -63,7 +63,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { .wasm_memory_size, .err_return_trace, .save_err_return_trace_index, - .tlv_dllimport_ptr, + .runtime_nav_ptr, .c_va_start, .work_item_id, .work_group_size, diff --git a/src/print_air.zig b/src/Air/print.zig similarity index 97% rename from src/print_air.zig rename to src/Air/print.zig index 6085adbcdc..343c640a63 100644 --- a/src/print_air.zig +++ b/src/Air/print.zig @@ -2,13 +2,15 @@ const std = @import("std"); const Allocator = std.mem.Allocator; const fmtIntSizeBin = std.fmt.fmtIntSizeBin; -const Zcu = @import("Zcu.zig"); -const Value = @import("Value.zig"); -const Type = @import("Type.zig"); -const Air = @import("Air.zig"); -const InternPool = @import("InternPool.zig"); +const build_options = @import("build_options"); +const Zcu = @import("../Zcu.zig"); +const Value = @import("../Value.zig"); +const Type = @import("../Type.zig"); +const Air = @import("../Air.zig"); +const InternPool = @import("../InternPool.zig"); -pub fn write(stream: anytype, pt: Zcu.PerThread, air: Air, liveness: ?Air.Liveness) void { +pub fn write(air: Air, stream: anytype, pt: Zcu.PerThread, liveness: ?Air.Liveness) void { + comptime std.debug.assert(build_options.enable_debug_extensions); const instruction_bytes = air.instructions.len * // Here we don't use @sizeOf(Air.Inst.Data) because it would include // the debug safety tag but we want to measure release size. @@ -52,12 +54,13 @@ pub fn write(stream: anytype, pt: Zcu.PerThread, air: Air, liveness: ?Air.Livene } pub fn writeInst( + air: Air, stream: anytype, inst: Air.Inst.Index, pt: Zcu.PerThread, - air: Air, liveness: ?Air.Liveness, ) void { + comptime std.debug.assert(build_options.enable_debug_extensions); var writer: Writer = .{ .pt = pt, .gpa = pt.zcu.gpa, @@ -69,12 +72,12 @@ pub fn writeInst( writer.writeInst(stream, inst) catch return; } -pub fn dump(pt: Zcu.PerThread, air: Air, liveness: ?Air.Liveness) void { - write(std.io.getStdErr().writer(), pt, air, liveness); +pub fn dump(air: Air, pt: Zcu.PerThread, liveness: ?Air.Liveness) void { + air.write(std.io.getStdErr().writer(), pt, liveness); } -pub fn dumpInst(inst: Air.Inst.Index, pt: Zcu.PerThread, air: Air, liveness: ?Air.Liveness) void { - writeInst(std.io.getStdErr().writer(), inst, pt, air, liveness); +pub fn dumpInst(air: Air, inst: Air.Inst.Index, pt: Zcu.PerThread, liveness: ?Air.Liveness) void { + air.writeInst(std.io.getStdErr().writer(), inst, pt, liveness); } const Writer = struct { @@ -320,7 +323,7 @@ const Writer = struct { .reduce, .reduce_optimized => try w.writeReduce(s, inst), .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst), .vector_store_elem => try w.writeVectorStoreElem(s, inst), - .tlv_dllimport_ptr => try w.writeTlvDllimportPtr(s, inst), + .runtime_nav_ptr => try w.writeRuntimeNavPtr(s, inst), .work_item_id, .work_group_size, @@ -578,7 +581,7 @@ const Writer = struct { try w.writeOperand(s, inst, 2, extra.rhs); } - fn writeTlvDllimportPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + fn writeRuntimeNavPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { const ip = &w.pt.zcu.intern_pool; const ty_nav = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav; try w.writeType(s, .fromInterned(ty_nav.ty)); diff --git a/src/Air/types_resolved.zig b/src/Air/types_resolved.zig index eb17402ebe..1def679794 100644 --- a/src/Air/types_resolved.zig +++ b/src/Air/types_resolved.zig @@ -321,7 +321,7 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool { if (!checkRef(bin.rhs, zcu)) return false; }, - .tlv_dllimport_ptr => { + .runtime_nav_ptr => { if (!checkType(.fromInterned(data.ty_nav.ty), zcu)) return false; }, diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index 626b2c3631..637a4bb280 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -345,11 +345,19 @@ pub fn resolve(options: Options) ResolveError!Config { } else false; }; + const is_dyn_lib = switch (options.output_mode) { + .Obj, .Exe => false, + .Lib => link_mode == .dynamic, + }; + // Make a decision on whether to use LLVM backend for machine code generation. // Note that using the LLVM backend does not necessarily mean using LLVM libraries. // For example, Zig can emit .bc and .ll files directly, and this is still considered // using "the LLVM backend". - const prefer_llvm = b: { + const use_llvm = b: { + // If we have no zig code to compile, no need for LLVM. + if (!options.have_zcu) break :b false; + // If emitting to LLVM bitcode object format, must use LLVM backend. if (options.emit_llvm_ir or options.emit_llvm_bc) { if (options.use_llvm == false) @@ -382,9 +390,9 @@ pub fn resolve(options: Options) ResolveError!Config { // Prefer LLVM for release builds. if (root_optimize_mode != .Debug) break :b true; - // Self-hosted backends can't handle the inline assembly in std.pie yet - // https://github.com/ziglang/zig/issues/24046 - if (pie) break :b true; + // load_dynamic_library standalone test not passing on this combination + // https://github.com/ziglang/zig/issues/24080 + if (target.os.tag == .macos and is_dyn_lib) break :b true; // At this point we would prefer to use our own self-hosted backend, // because the compilation speed is better than LLVM. But only do it if @@ -392,13 +400,6 @@ pub fn resolve(options: Options) ResolveError!Config { break :b !target_util.selfHostedBackendIsAsRobustAsLlvm(target); }; - const use_llvm = b: { - // If we have no zig code to compile, no need for LLVM. - if (!options.have_zcu) break :b false; - - break :b prefer_llvm; - }; - if (options.emit_bin and options.have_zcu) { if (!use_lib_llvm and use_llvm) { // Explicit request to use LLVM to produce an object file, but without @@ -435,7 +436,13 @@ pub fn resolve(options: Options) ResolveError!Config { } if (options.use_lld) |x| break :b x; - break :b prefer_llvm; + + // If we have no zig code to compile, no need for the self-hosted linker. + if (!options.have_zcu) break :b true; + + // If we do have zig code, match the decision for whether to use the llvm backend, + // so that the llvm backend defaults to lld and the self-hosted backends do not. + break :b use_llvm; }; const lto: std.zig.LtoMode = b: { diff --git a/src/InternPool.zig b/src/InternPool.zig index 44f19e3e29..de1a434c02 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -526,10 +526,10 @@ pub const Nav = struct { /// The type of this `Nav` is resolved; the value is queued for resolution. type_resolved: struct { type: InternPool.Index, + is_const: bool, alignment: Alignment, @"linksection": OptionalNullTerminatedString, @"addrspace": std.builtin.AddressSpace, - is_const: bool, is_threadlocal: bool, /// This field is whether this `Nav` is a literal `extern` definition. /// It does *not* tell you whether this might alias an extern fn (see #21027). @@ -538,6 +538,7 @@ pub const Nav = struct { /// The value of this `Nav` is resolved. fully_resolved: struct { val: InternPool.Index, + is_const: bool, alignment: Alignment, @"linksection": OptionalNullTerminatedString, @"addrspace": std.builtin.AddressSpace, @@ -727,12 +728,12 @@ pub const Nav = struct { const Bits = packed struct(u16) { status: enum(u2) { unresolved, type_resolved, fully_resolved, type_resolved_extern_decl }, /// Populated only if `bits.status != .unresolved`. + is_const: bool, + /// Populated only if `bits.status != .unresolved`. alignment: Alignment, /// Populated only if `bits.status != .unresolved`. @"addrspace": std.builtin.AddressSpace, /// Populated only if `bits.status == .type_resolved`. - is_const: bool, - /// Populated only if `bits.status == .type_resolved`. is_threadlocal: bool, is_usingnamespace: bool, }; @@ -753,15 +754,16 @@ pub const Nav = struct { .unresolved => .unresolved, .type_resolved, .type_resolved_extern_decl => .{ .type_resolved = .{ .type = repr.type_or_val, + .is_const = repr.bits.is_const, .alignment = repr.bits.alignment, .@"linksection" = repr.@"linksection", .@"addrspace" = repr.bits.@"addrspace", - .is_const = repr.bits.is_const, .is_threadlocal = repr.bits.is_threadlocal, .is_extern_decl = repr.bits.status == .type_resolved_extern_decl, } }, .fully_resolved => .{ .fully_resolved = .{ .val = repr.type_or_val, + .is_const = repr.bits.is_const, .alignment = repr.bits.alignment, .@"linksection" = repr.@"linksection", .@"addrspace" = repr.bits.@"addrspace", @@ -792,26 +794,26 @@ pub const Nav = struct { .bits = switch (nav.status) { .unresolved => .{ .status = .unresolved, + .is_const = false, .alignment = .none, .@"addrspace" = .generic, .is_usingnamespace = nav.is_usingnamespace, - .is_const = false, .is_threadlocal = false, }, .type_resolved => |r| .{ .status = if (r.is_extern_decl) .type_resolved_extern_decl else .type_resolved, + .is_const = r.is_const, .alignment = r.alignment, .@"addrspace" = r.@"addrspace", .is_usingnamespace = nav.is_usingnamespace, - .is_const = r.is_const, .is_threadlocal = r.is_threadlocal, }, .fully_resolved => |r| .{ .status = .fully_resolved, + .is_const = r.is_const, .alignment = r.alignment, .@"addrspace" = r.@"addrspace", .is_usingnamespace = nav.is_usingnamespace, - .is_const = false, .is_threadlocal = false, }, }, @@ -2221,7 +2223,6 @@ pub const Key = union(enum) { init: Index, owner_nav: Nav.Index, is_threadlocal: bool, - is_weak_linkage: bool, }; pub const Extern = struct { @@ -2234,10 +2235,12 @@ pub const Key = union(enum) { /// For example `extern "c" fn write(...) usize` would have 'c' as library name. /// Index into the string table bytes. lib_name: OptionalNullTerminatedString, - is_const: bool, + linkage: std.builtin.GlobalLinkage, + visibility: std.builtin.SymbolVisibility, is_threadlocal: bool, - is_weak_linkage: bool, is_dll_import: bool, + relocation: std.builtin.ExternOptions.Relocation, + is_const: bool, alignment: Alignment, @"addrspace": std.builtin.AddressSpace, /// The ZIR instruction which created this extern; used only for source locations. @@ -2844,9 +2847,10 @@ pub const Key = union(enum) { .@"extern" => |e| Hash.hash(seed, asBytes(&e.name) ++ asBytes(&e.ty) ++ asBytes(&e.lib_name) ++ - asBytes(&e.is_const) ++ asBytes(&e.is_threadlocal) ++ - asBytes(&e.is_weak_linkage) ++ asBytes(&e.alignment) ++ - asBytes(&e.is_dll_import) ++ asBytes(&e.@"addrspace") ++ + asBytes(&e.linkage) ++ asBytes(&e.visibility) ++ + asBytes(&e.is_threadlocal) ++ asBytes(&e.is_dll_import) ++ + asBytes(&e.relocation) ++ + asBytes(&e.is_const) ++ asBytes(&e.alignment) ++ asBytes(&e.@"addrspace") ++ asBytes(&e.zir_index)), }; } @@ -2928,21 +2932,22 @@ pub const Key = union(enum) { .variable => |a_info| { const b_info = b.variable; - return a_info.owner_nav == b_info.owner_nav and - a_info.ty == b_info.ty and + return a_info.ty == b_info.ty and a_info.init == b_info.init and - a_info.is_threadlocal == b_info.is_threadlocal and - a_info.is_weak_linkage == b_info.is_weak_linkage; + a_info.owner_nav == b_info.owner_nav and + a_info.is_threadlocal == b_info.is_threadlocal; }, .@"extern" => |a_info| { const b_info = b.@"extern"; return a_info.name == b_info.name and a_info.ty == b_info.ty and a_info.lib_name == b_info.lib_name and - a_info.is_const == b_info.is_const and + a_info.linkage == b_info.linkage and + a_info.visibility == b_info.visibility and a_info.is_threadlocal == b_info.is_threadlocal and - a_info.is_weak_linkage == b_info.is_weak_linkage and a_info.is_dll_import == b_info.is_dll_import and + a_info.relocation == b_info.relocation and + a_info.is_const == b_info.is_const and a_info.alignment == b_info.alignment and a_info.@"addrspace" == b_info.@"addrspace" and a_info.zir_index == b_info.zir_index; @@ -4889,6 +4894,7 @@ pub const Index = enum(u32) { float_c_longdouble_f128: struct { data: *Float128 }, float_comptime_float: struct { data: *Float128 }, variable: struct { data: *Tag.Variable }, + threadlocal_variable: struct { data: *Tag.Variable }, @"extern": struct { data: *Tag.Extern }, func_decl: struct { const @"data.analysis.inferred_error_set" = opaque {}; @@ -5548,6 +5554,9 @@ pub const Tag = enum(u8) { /// A global variable. /// data is extra index to Variable. variable, + /// A global threadlocal variable. + /// data is extra index to Variable. + threadlocal_variable, /// An extern function or variable. /// data is extra index to Extern. /// Some parts of the key are stored in `owner_nav`. @@ -5863,6 +5872,7 @@ pub const Tag = enum(u8) { .float_c_longdouble_f128 = .{ .summary = .@"@as(c_longdouble, {.payload%value})", .payload = f128 }, .float_comptime_float = .{ .summary = .@"{.payload%value}", .payload = f128 }, .variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable }, + .threadlocal_variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable }, .@"extern" = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Extern }, .func_decl = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", @@ -5913,24 +5923,24 @@ pub const Tag = enum(u8) { /// May be `none`. init: Index, owner_nav: Nav.Index, - flags: Flags, - - pub const Flags = packed struct(u32) { - is_const: bool, - is_threadlocal: bool, - is_weak_linkage: bool, - is_dll_import: bool, - _: u28 = 0, - }; }; pub const Extern = struct { - // name, alignment, addrspace come from `owner_nav`. + // name, is_const, alignment, addrspace come from `owner_nav`. ty: Index, lib_name: OptionalNullTerminatedString, - flags: Variable.Flags, + flags: Flags, owner_nav: Nav.Index, zir_index: TrackedInst.Index, + + pub const Flags = packed struct(u32) { + linkage: std.builtin.GlobalLinkage, + visibility: std.builtin.SymbolVisibility, + is_threadlocal: bool, + is_dll_import: bool, + relocation: std.builtin.ExternOptions.Relocation, + _: u25 = 0, + }; }; /// Trailing: @@ -7248,14 +7258,17 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { .ty = .comptime_float_type, .storage = .{ .f128 = extraData(unwrapped_index.getExtra(ip), Float128, data).get() }, } }, - .variable => { + .variable, .threadlocal_variable => { const extra = extraData(unwrapped_index.getExtra(ip), Tag.Variable, data); return .{ .variable = .{ .ty = extra.ty, .init = extra.init, .owner_nav = extra.owner_nav, - .is_threadlocal = extra.flags.is_threadlocal, - .is_weak_linkage = extra.flags.is_weak_linkage, + .is_threadlocal = switch (item.tag) { + else => unreachable, + .variable => false, + .threadlocal_variable => true, + }, } }; }, .@"extern" => { @@ -7265,10 +7278,12 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { .name = nav.name, .ty = extra.ty, .lib_name = extra.lib_name, - .is_const = extra.flags.is_const, + .linkage = extra.flags.linkage, + .visibility = extra.flags.visibility, .is_threadlocal = extra.flags.is_threadlocal, - .is_weak_linkage = extra.flags.is_weak_linkage, .is_dll_import = extra.flags.is_dll_import, + .relocation = extra.flags.relocation, + .is_const = nav.status.fully_resolved.is_const, .alignment = nav.status.fully_resolved.alignment, .@"addrspace" = nav.status.fully_resolved.@"addrspace", .zir_index = extra.zir_index, @@ -7895,17 +7910,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All const has_init = variable.init != .none; if (has_init) assert(variable.ty == ip.typeOf(variable.init)); items.appendAssumeCapacity(.{ - .tag = .variable, + .tag = switch (variable.is_threadlocal) { + false => .variable, + true => .threadlocal_variable, + }, .data = try addExtra(extra, Tag.Variable{ .ty = variable.ty, .init = variable.init, .owner_nav = variable.owner_nav, - .flags = .{ - .is_const = false, - .is_threadlocal = variable.is_threadlocal, - .is_weak_linkage = variable.is_weak_linkage, - .is_dll_import = false, - }, }), }); }, @@ -9128,6 +9140,7 @@ pub fn getExtern( .name = key.name, .fqn = key.name, .val = extern_index, + .is_const = key.is_const, .alignment = key.alignment, .@"linksection" = .none, .@"addrspace" = key.@"addrspace", @@ -9136,10 +9149,11 @@ pub fn getExtern( .ty = key.ty, .lib_name = key.lib_name, .flags = .{ - .is_const = key.is_const, + .linkage = key.linkage, + .visibility = key.visibility, .is_threadlocal = key.is_threadlocal, - .is_weak_linkage = key.is_weak_linkage, .is_dll_import = key.is_dll_import, + .relocation = key.relocation, }, .zir_index = key.zir_index, .owner_nav = owner_nav, @@ -9714,6 +9728,7 @@ fn finishFuncInstance( .name = nav_name, .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, tid, nav_name), .val = func_index, + .is_const = fn_owner_nav.status.fully_resolved.is_const, .alignment = fn_owner_nav.status.fully_resolved.alignment, .@"linksection" = fn_owner_nav.status.fully_resolved.@"linksection", .@"addrspace" = fn_owner_nav.status.fully_resolved.@"addrspace", @@ -10300,13 +10315,13 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 { u32, i32, FuncAnalysis, + Tag.Extern.Flags, Tag.TypePointer.Flags, Tag.TypeFunction.Flags, Tag.TypePointer.PackedOffset, Tag.TypeUnion.Flags, Tag.TypeStruct.Flags, Tag.TypeStructPacked.Flags, - Tag.Variable.Flags, => @bitCast(@field(item, field.name)), else => @compileError("bad field type: " ++ @typeName(field.type)), @@ -10361,13 +10376,13 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat u32, i32, + Tag.Extern.Flags, Tag.TypePointer.Flags, Tag.TypeFunction.Flags, Tag.TypePointer.PackedOffset, Tag.TypeUnion.Flags, Tag.TypeStruct.Flags, Tag.TypeStructPacked.Flags, - Tag.Variable.Flags, FuncAnalysis, => @bitCast(extra_item), @@ -11162,7 +11177,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { .float_c_longdouble_f80 => @sizeOf(Float80), .float_c_longdouble_f128 => @sizeOf(Float128), .float_comptime_float => @sizeOf(Float128), - .variable => @sizeOf(Tag.Variable), + .variable, .threadlocal_variable => @sizeOf(Tag.Variable), .@"extern" => @sizeOf(Tag.Extern), .func_decl => @sizeOf(Tag.FuncDecl), .func_instance => b: { @@ -11282,6 +11297,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void { .float_c_longdouble_f128, .float_comptime_float, .variable, + .threadlocal_variable, .@"extern", .func_decl, .func_instance, @@ -11414,6 +11430,7 @@ pub fn createNav( name: NullTerminatedString, fqn: NullTerminatedString, val: InternPool.Index, + is_const: bool, alignment: Alignment, @"linksection": OptionalNullTerminatedString, @"addrspace": std.builtin.AddressSpace, @@ -11430,6 +11447,7 @@ pub fn createNav( .analysis = null, .status = .{ .fully_resolved = .{ .val = opts.val, + .is_const = opts.is_const, .alignment = opts.alignment, .@"linksection" = opts.@"linksection", .@"addrspace" = opts.@"addrspace", @@ -11482,10 +11500,10 @@ pub fn resolveNavType( nav: Nav.Index, resolved: struct { type: InternPool.Index, + is_const: bool, alignment: Alignment, @"linksection": OptionalNullTerminatedString, @"addrspace": std.builtin.AddressSpace, - is_const: bool, is_threadlocal: bool, is_extern_decl: bool, }, @@ -11512,9 +11530,9 @@ pub fn resolveNavType( var bits = nav_bits[unwrapped.index]; bits.status = if (resolved.is_extern_decl) .type_resolved_extern_decl else .type_resolved; + bits.is_const = resolved.is_const; bits.alignment = resolved.alignment; bits.@"addrspace" = resolved.@"addrspace"; - bits.is_const = resolved.is_const; bits.is_threadlocal = resolved.is_threadlocal; @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release); } @@ -11526,6 +11544,7 @@ pub fn resolveNavValue( nav: Nav.Index, resolved: struct { val: InternPool.Index, + is_const: bool, alignment: Alignment, @"linksection": OptionalNullTerminatedString, @"addrspace": std.builtin.AddressSpace, @@ -11553,6 +11572,7 @@ pub fn resolveNavValue( var bits = nav_bits[unwrapped.index]; bits.status = .fully_resolved; + bits.is_const = resolved.is_const; bits.alignment = resolved.alignment; bits.@"addrspace" = resolved.@"addrspace"; @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release); @@ -12007,6 +12027,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { .error_union_error, .enum_tag, .variable, + .threadlocal_variable, .@"extern", .func_decl, .func_instance, @@ -12391,6 +12412,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId { .float_c_longdouble_f128, .float_comptime_float, .variable, + .threadlocal_variable, .@"extern", .func_decl, .func_instance, diff --git a/src/Sema.zig b/src/Sema.zig index c732a283a0..e20fb17f26 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -26089,10 +26089,12 @@ fn resolveExternOptions( zir_ref: Zir.Inst.Ref, ) CompileError!struct { name: InternPool.NullTerminatedString, - library_name: InternPool.OptionalNullTerminatedString = .none, - linkage: std.builtin.GlobalLinkage = .strong, - is_thread_local: bool = false, - is_dll_import: bool = false, + library_name: InternPool.OptionalNullTerminatedString, + linkage: std.builtin.GlobalLinkage, + visibility: std.builtin.SymbolVisibility, + is_thread_local: bool, + is_dll_import: bool, + relocation: std.builtin.ExternOptions.Relocation, } { const pt = sema.pt; const zcu = pt.zcu; @@ -26105,8 +26107,10 @@ fn resolveExternOptions( const name_src = block.src(.{ .init_field_name = src.offset.node_offset_builtin_call_arg.builtin_call_node }); const library_src = block.src(.{ .init_field_library = src.offset.node_offset_builtin_call_arg.builtin_call_node }); const linkage_src = block.src(.{ .init_field_linkage = src.offset.node_offset_builtin_call_arg.builtin_call_node }); + const visibility_src = block.src(.{ .init_field_visibility = src.offset.node_offset_builtin_call_arg.builtin_call_node }); const thread_local_src = block.src(.{ .init_field_thread_local = src.offset.node_offset_builtin_call_arg.builtin_call_node }); const dll_import_src = block.src(.{ .init_field_dll_import = src.offset.node_offset_builtin_call_arg.builtin_call_node }); + const relocation_src = block.src(.{ .init_field_relocation = src.offset.node_offset_builtin_call_arg.builtin_call_node }); const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), name_src); const name = try sema.toConstString(block, name_src, name_ref, .{ .simple = .extern_options }); @@ -26118,6 +26122,10 @@ fn resolveExternOptions( const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_ref, .{ .simple = .extern_options }); const linkage = try sema.interpretBuiltinType(block, linkage_src, linkage_val, std.builtin.GlobalLinkage); + const visibility_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "visibility", .no_embedded_nulls), visibility_src); + const visibility_val = try sema.resolveConstDefinedValue(block, visibility_src, visibility_ref, .{ .simple = .extern_options }); + const visibility = try sema.interpretBuiltinType(block, visibility_src, visibility_val, std.builtin.SymbolVisibility); + const is_thread_local = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "is_thread_local", .no_embedded_nulls), thread_local_src); const is_thread_local_val = try sema.resolveConstDefinedValue(block, thread_local_src, is_thread_local, .{ .simple = .extern_options }); @@ -26133,6 +26141,10 @@ fn resolveExternOptions( const is_dll_import_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "is_dll_import", .no_embedded_nulls), dll_import_src); const is_dll_import_val = try sema.resolveConstDefinedValue(block, dll_import_src, is_dll_import_ref, .{ .simple = .extern_options }); + const relocation_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "relocation", .no_embedded_nulls), relocation_src); + const relocation_val = try sema.resolveConstDefinedValue(block, relocation_src, relocation_ref, .{ .simple = .extern_options }); + const relocation = try sema.interpretBuiltinType(block, relocation_src, relocation_val, std.builtin.ExternOptions.Relocation); + if (name.len == 0) { return sema.fail(block, name_src, "extern symbol name cannot be empty", .{}); } @@ -26145,8 +26157,10 @@ fn resolveExternOptions( .name = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls), .library_name = try ip.getOrPutStringOpt(gpa, pt.tid, library_name, .no_embedded_nulls), .linkage = linkage, + .visibility = visibility, .is_thread_local = is_thread_local_val.toBool(), .is_dll_import = is_dll_import_val.toBool(), + .relocation = relocation, }; } @@ -26178,6 +26192,17 @@ fn zirBuiltinExtern( } const options = try sema.resolveExternOptions(block, options_src, extra.rhs); + switch (options.linkage) { + .internal => if (options.visibility != .default) { + return sema.fail(block, options_src, "internal symbol cannot have non-default visibility", .{}); + }, + .strong, .weak => {}, + .link_once => return sema.fail(block, options_src, "external symbol cannot have link once linkage", .{}), + } + switch (options.relocation) { + .any => {}, + .pcrel => if (options.visibility == .default) return sema.fail(block, options_src, "cannot require a pc-relative relocation to a symbol with default visibility", .{}), + } // TODO: error for threadlocal functions, non-const functions, etc @@ -26190,10 +26215,12 @@ fn zirBuiltinExtern( .name = options.name, .ty = ptr_info.child, .lib_name = options.library_name, - .is_const = ptr_info.flags.is_const, + .linkage = options.linkage, + .visibility = options.visibility, .is_threadlocal = options.is_thread_local, - .is_weak_linkage = options.linkage == .weak, .is_dll_import = options.is_dll_import, + .relocation = options.relocation, + .is_const = ptr_info.flags.is_const, .alignment = ptr_info.flags.alignment, .@"addrspace" = ptr_info.flags.address_space, // This instruction is just for source locations. @@ -31685,12 +31712,15 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde const nav_status = ip.getNav(nav_index).status; - const is_tlv_or_dllimport = switch (nav_status) { + const is_runtime = switch (nav_status) { .unresolved => unreachable, // dllimports go straight to `fully_resolved`; the only option is threadlocal .type_resolved => |r| r.is_threadlocal, .fully_resolved => |r| switch (ip.indexToKey(r.val)) { - .@"extern" => |e| e.is_threadlocal or e.is_dll_import, + .@"extern" => |e| e.is_threadlocal or e.is_dll_import or switch (e.relocation) { + .any => false, + .pcrel => true, + }, .variable => |v| v.is_threadlocal, else => false, }, @@ -31699,7 +31729,7 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde const ty, const alignment, const @"addrspace", const is_const = switch (nav_status) { .unresolved => unreachable, .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const }, - .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", zcu.navValIsConst(r.val) }, + .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", r.is_const }, }; const ptr_ty = try pt.ptrTypeSema(.{ .child = ty, @@ -31710,10 +31740,10 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde }, }); - if (is_tlv_or_dllimport) { + if (is_runtime) { // This pointer is runtime-known; we need to emit an AIR instruction to create it. return block.addInst(.{ - .tag = .tlv_dllimport_ptr, + .tag = .runtime_nav_ptr, .data = .{ .ty_nav = .{ .ty = ptr_ty.toIntern(), .nav = nav_index, @@ -36432,6 +36462,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { .float_c_longdouble_f128, .float_comptime_float, .variable, + .threadlocal_variable, .@"extern", .func_decl, .func_instance, diff --git a/src/Zcu.zig b/src/Zcu.zig index d4a0adf284..7223e5a55e 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -2047,6 +2047,7 @@ pub const SrcLoc = struct { .init_field_library, .init_field_thread_local, .init_field_dll_import, + .init_field_relocation, => |builtin_call_node| { const wanted = switch (src_loc.lazy) { .init_field_name => "name", @@ -2059,6 +2060,7 @@ pub const SrcLoc = struct { .init_field_library => "library", .init_field_thread_local => "thread_local", .init_field_dll_import => "dll_import", + .init_field_relocation => "relocation", else => unreachable, }; const tree = try src_loc.file_scope.getTree(zcu); @@ -2506,6 +2508,7 @@ pub const LazySrcLoc = struct { init_field_library: Ast.Node.Offset, init_field_thread_local: Ast.Node.Offset, init_field_dll_import: Ast.Node.Offset, + init_field_relocation: Ast.Node.Offset, /// The source location points to the value of an item in a specific /// case of a `switch`. switch_case_item: SwitchItem, @@ -4562,15 +4565,6 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu return .ok; } -/// Given that a `Nav` has value `val`, determine if a ref of that `Nav` gives a `const` pointer. -pub fn navValIsConst(zcu: *const Zcu, val: InternPool.Index) bool { - return switch (zcu.intern_pool.indexToKey(val)) { - .variable => false, - .@"extern" => |e| e.is_const, - else => true, - }; -} - pub const CodegenFailError = error{ /// Indicates the error message has been already stored at `Zcu.failed_codegen`. CodegenFail, diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 8e3d07627f..8b35d8d799 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -1153,18 +1153,23 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr // First, we must resolve the declaration's type. To do this, we analyze the type body if available, // or otherwise, we analyze the value body, populating `early_val` in the process. - switch (zir_decl.kind) { + const is_const = is_const: switch (zir_decl.kind) { .@"comptime" => unreachable, // this is not a Nav - .unnamed_test, .@"test", .decltest => assert(nav_ty.zigTypeTag(zcu) == .@"fn"), - .@"usingnamespace" => {}, - .@"const" => {}, - .@"var" => try sema.validateVarType( - &block, - if (zir_decl.type_body != null) ty_src else init_src, - nav_ty, - zir_decl.linkage == .@"extern", - ), - } + .unnamed_test, .@"test", .decltest => { + assert(nav_ty.zigTypeTag(zcu) == .@"fn"); + break :is_const true; + }, + .@"usingnamespace", .@"const" => true, + .@"var" => { + try sema.validateVarType( + &block, + if (zir_decl.type_body != null) ty_src else init_src, + nav_ty, + zir_decl.linkage == .@"extern", + ); + break :is_const false; + }, + }; // Now that we know the type, we can evaluate the alignment, linksection, and addrspace, to determine // the full pointer type of this declaration. @@ -1195,7 +1200,6 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr .init = final_val.?.toIntern(), .owner_nav = nav_id, .is_threadlocal = zir_decl.is_threadlocal, - .is_weak_linkage = false, } })), else => final_val.?, }, @@ -1212,10 +1216,12 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr .name = old_nav.name, .ty = nav_ty.toIntern(), .lib_name = try ip.getOrPutStringOpt(gpa, pt.tid, lib_name, .no_embedded_nulls), - .is_const = zir_decl.kind == .@"const", .is_threadlocal = zir_decl.is_threadlocal, - .is_weak_linkage = false, + .linkage = .strong, + .visibility = .default, .is_dll_import = false, + .relocation = .any, + .is_const = is_const, .alignment = modifiers.alignment, .@"addrspace" = modifiers.@"addrspace", .zir_index = old_nav.analysis.?.zir_index, // `declaration` instruction @@ -1243,6 +1249,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr } ip.resolveNavValue(nav_id, .{ .val = nav_val.toIntern(), + .is_const = is_const, .alignment = .none, .@"linksection" = .none, .@"addrspace" = .generic, @@ -1286,6 +1293,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr ip.resolveNavValue(nav_id, .{ .val = nav_val.toIntern(), + .is_const = is_const, .alignment = modifiers.alignment, .@"linksection" = modifiers.@"linksection", .@"addrspace" = modifiers.@"addrspace", @@ -1515,8 +1523,6 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr // the pointer modifiers, i.e. alignment, linksection, addrspace. const modifiers = try sema.resolveNavPtrModifiers(&block, zir_decl, inst_resolved.inst, resolved_ty); - // Usually, we can infer this information from the resolved `Nav` value; see `Zcu.navValIsConst`. - // However, since we don't have one, we need to quickly check the ZIR to figure this out. const is_const = switch (zir_decl.kind) { .@"comptime" => unreachable, .unnamed_test, .@"test", .decltest, .@"usingnamespace", .@"const" => true, @@ -1542,7 +1548,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr r.alignment != modifiers.alignment or r.@"linksection" != modifiers.@"linksection" or r.@"addrspace" != modifiers.@"addrspace" or - zcu.navValIsConst(r.val) != is_const or + r.is_const != is_const or (old_nav.getExtern(ip) != null) != is_extern_decl, }; @@ -1550,10 +1556,10 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr ip.resolveNavType(nav_id, .{ .type = resolved_ty.toIntern(), + .is_const = is_const, .alignment = modifiers.alignment, .@"linksection" = modifiers.@"linksection", .@"addrspace" = modifiers.@"addrspace", - .is_const = is_const, .is_threadlocal = zir_decl.is_threadlocal, .is_extern_decl = is_extern_decl, }); @@ -1750,7 +1756,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: *A if (build_options.enable_debug_extensions and comp.verbose_air) { std.debug.print("# Begin Function AIR: {}:\n", .{nav.fqn.fmt(ip)}); - @import("../print_air.zig").dump(pt, air.*, liveness); + air.dump(pt, liveness); std.debug.print("# End Function AIR: {}\n\n", .{nav.fqn.fmt(ip)}); } @@ -3577,8 +3583,10 @@ pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!V .lib_name = e.lib_name, .is_const = e.is_const, .is_threadlocal = e.is_threadlocal, - .is_weak_linkage = e.is_weak_linkage, + .linkage = e.linkage, + .visibility = e.visibility, .is_dll_import = e.is_dll_import, + .relocation = e.relocation, .alignment = e.alignment, .@"addrspace" = e.@"addrspace", .zir_index = e.zir_index, @@ -3954,7 +3962,7 @@ pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Err const ty, const alignment, const @"addrspace", const is_const = switch (ip.getNav(nav_id).status) { .unresolved => unreachable, .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const }, - .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", zcu.navValIsConst(r.val) }, + .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", r.is_const }, }; return pt.ptrType(.{ .child = ty, diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index c01fa24ecc..00cceb0c67 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -880,7 +880,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), - .tlv_dllimport_ptr => return self.fail("TODO implement tlv_dllimport_ptr", .{}), + .runtime_nav_ptr => return self.fail("TODO implement runtime_nav_ptr", .{}), .c_va_arg => return self.fail("TODO implement c_va_arg", .{}), .c_va_copy => return self.fail("TODO implement c_va_copy", .{}), diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 9c7793df27..421ba7d753 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -869,7 +869,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), - .tlv_dllimport_ptr => return self.fail("TODO implement tlv_dllimport_ptr", .{}), + .runtime_nav_ptr => return self.fail("TODO implement runtime_nav_ptr", .{}), .c_va_arg => return self.fail("TODO implement c_va_arg", .{}), .c_va_copy => return self.fail("TODO implement c_va_copy", .{}), diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 530af98a0d..9fc51bd2d3 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -1041,12 +1041,7 @@ fn formatAir( _: std.fmt.FormatOptions, writer: anytype, ) @TypeOf(writer).Error!void { - @import("../../print_air.zig").dumpInst( - data.inst, - data.func.pt, - data.func.air, - data.func.liveness, - ); + data.func.air.dumpInst(data.inst, data.func.pt, data.func.liveness); } fn fmtAir(func: *Func, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) { return .{ .data = .{ .func = func, .inst = inst } }; @@ -1656,7 +1651,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { .wrap_errunion_payload => try func.airWrapErrUnionPayload(inst), .wrap_errunion_err => try func.airWrapErrUnionErr(inst), - .tlv_dllimport_ptr => try func.airTlvDllimportPtr(inst), + .runtime_nav_ptr => try func.airRuntimeNavPtr(inst), .add_optimized, .sub_optimized, @@ -3626,7 +3621,7 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void { return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } -fn airTlvDllimportPtr(func: *Func, inst: Air.Inst.Index) !void { +fn airRuntimeNavPtr(func: *Func, inst: Air.Inst.Index) !void { const zcu = func.pt.zcu; const ip = &zcu.intern_pool; const ty_nav = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav; @@ -3641,7 +3636,7 @@ fn airTlvDllimportPtr(func: *Func, inst: Air.Inst.Index) !void { break :sym sym; } break :sym try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav); - } else return func.fail("TODO tlv_dllimport_ptr on {}", .{func.bin_file.tag}); + } else return func.fail("TODO runtime_nav_ptr on {}", .{func.bin_file.tag}); const dest_mcv = try func.allocRegOrMem(ptr_ty, inst, true); if (dest_mcv.isRegister()) { diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 439e5e6dbb..ad9884dcdb 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -723,7 +723,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .is_named_enum_value => @panic("TODO implement is_named_enum_value"), .error_set_has_value => @panic("TODO implement error_set_has_value"), .vector_store_elem => @panic("TODO implement vector_store_elem"), - .tlv_dllimport_ptr => @panic("TODO implement tlv_dllimport_ptr"), + .runtime_nav_ptr => @panic("TODO implement runtime_nav_ptr"), .c_va_arg => return self.fail("TODO implement c_va_arg", .{}), .c_va_copy => return self.fail("TODO implement c_va_copy", .{}), diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index c4f72dd6c3..264b1e732d 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -2057,7 +2057,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { .error_set_has_value => cg.airErrorSetHasValue(inst), .frame_addr => cg.airFrameAddress(inst), - .tlv_dllimport_ptr => cg.airTlvDllimportPtr(inst), + .runtime_nav_ptr => cg.airRuntimeNavPtr(inst), .assembly, .is_err_ptr, @@ -7616,7 +7616,7 @@ fn airFrameAddress(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { return cg.finishAir(inst, .stack, &.{}); } -fn airTlvDllimportPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { +fn airRuntimeNavPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const ty_nav = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav; const mod = cg.pt.zcu.navFileScope(cg.owner_nav).mod.?; if (mod.single_threaded) { diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index cd12bf72d5..396c0f7318 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -274,6 +274,12 @@ pub const MCValue = union(enum) { load_symbol: bits.SymbolOffset, /// The address of the memory location not-yet-allocated by the linker. lea_symbol: bits.SymbolOffset, + /// The value is in memory at an address not-yet-allocated by the linker. + /// This must use a non-got pc-relative relocation. + load_pcrel: bits.SymbolOffset, + /// The address of the memory location not-yet-allocated by the linker. + /// This must use a non-got pc-relative relocation. + lea_pcrel: bits.SymbolOffset, /// The value is in memory at a constant offset from the address in a register. indirect: bits.RegisterOffset, /// The value is in memory. @@ -314,6 +320,7 @@ pub const MCValue = union(enum) { .eflags, .register_overflow, .lea_symbol, + .lea_pcrel, .lea_direct, .lea_got, .lea_frame, @@ -327,6 +334,7 @@ pub const MCValue = union(enum) { .register_quadruple, .memory, .load_symbol, + .load_pcrel, .load_got, .load_direct, .indirect, @@ -429,6 +437,7 @@ pub const MCValue = union(enum) { .register_overflow, .register_mask, .lea_symbol, + .lea_pcrel, .lea_direct, .lea_got, .lea_frame, @@ -445,6 +454,7 @@ pub const MCValue = union(enum) { .load_got => |sym_index| .{ .lea_got = sym_index }, .load_frame => |frame_addr| .{ .lea_frame = frame_addr }, .load_symbol => |sym_off| .{ .lea_symbol = sym_off }, + .load_pcrel => |sym_off| .{ .lea_pcrel = sym_off }, }; } @@ -466,6 +476,7 @@ pub const MCValue = union(enum) { .load_got, .load_frame, .load_symbol, + .load_pcrel, .elementwise_args, .reserved_frame, .air_ref, @@ -477,6 +488,7 @@ pub const MCValue = union(enum) { .lea_got => |sym_index| .{ .load_got = sym_index }, .lea_frame => |frame_addr| .{ .load_frame = frame_addr }, .lea_symbol => |sym_index| .{ .load_symbol = sym_index }, + .lea_pcrel => |sym_index| .{ .load_pcrel = sym_index }, }; } @@ -505,6 +517,8 @@ pub const MCValue = union(enum) { .load_frame, .load_symbol, .lea_symbol, + .load_pcrel, + .lea_pcrel, => switch (off) { 0 => mcv, else => unreachable, // not offsettable @@ -543,6 +557,7 @@ pub const MCValue = union(enum) { .elementwise_args, .reserved_frame, .lea_symbol, + .lea_pcrel, => unreachable, .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| .{ .base = .{ .reg = .ds }, @@ -583,6 +598,18 @@ pub const MCValue = union(enum) { } }, }; }, + .load_pcrel => |sym_off| { + assert(sym_off.off == 0); + return .{ + .base = .{ .pcrel = sym_off.sym_index }, + .mod = .{ .rm = .{ + .size = mod_rm.size, + .index = mod_rm.index, + .scale = mod_rm.scale, + .disp = sym_off.off + mod_rm.disp, + } }, + }; + }, .air_ref => |ref| (try function.resolveInst(ref)).mem(function, mod_rm), }; } @@ -618,6 +645,8 @@ pub const MCValue = union(enum) { }), .load_symbol => |pl| try writer.print("[sym:{} + 0x{x}]", .{ pl.sym_index, pl.off }), .lea_symbol => |pl| try writer.print("sym:{} + 0x{x}", .{ pl.sym_index, pl.off }), + .load_pcrel => |pl| try writer.print("[sym@pcrel:{} + 0x{x}]", .{ pl.sym_index, pl.off }), + .lea_pcrel => |pl| try writer.print("sym@pcrel:{} + 0x{x}", .{ pl.sym_index, pl.off }), .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }), .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}), .lea_direct => |pl| try writer.print("direct:{d}", .{pl}), @@ -655,6 +684,8 @@ const InstTracking = struct { .lea_frame, .load_symbol, .lea_symbol, + .load_pcrel, + .lea_pcrel, => result, .dead, .elementwise_args, @@ -755,6 +786,8 @@ const InstTracking = struct { .lea_frame, .load_symbol, .lea_symbol, + .load_pcrel, + .lea_pcrel, => assert(std.meta.eql(self.long, target.long)), .dead, .eflags, @@ -1228,12 +1261,7 @@ fn formatAir( _: std.fmt.FormatOptions, writer: anytype, ) @TypeOf(writer).Error!void { - @import("../../print_air.zig").dumpInst( - data.inst, - data.self.pt, - data.self.air, - data.self.liveness, - ); + data.self.air.dumpInst(data.inst, data.self.pt, data.self.liveness); } fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) { return .{ .data = .{ .self = self, .inst = inst } }; @@ -163487,31 +163515,49 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }; for (ops) |op| try op.die(cg); }, - .tlv_dllimport_ptr => switch (cg.bin_file.tag) { + .runtime_nav_ptr => switch (cg.bin_file.tag) { .elf, .macho => { const ty_nav = air_datas[@intFromEnum(inst)].ty_nav; const nav = ip.getNav(ty_nav.nav); - const tlv_sym_index = sym: { + const sym_index, const relocation = sym: { if (cg.bin_file.cast(.elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; if (nav.getExtern(ip)) |e| { const sym = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip)); - zo.symbol(sym).flags.is_extern_ptr = true; - break :sym sym; - } - break :sym try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav); - } - if (cg.bin_file.cast(.macho)) |macho_file| { + linkage: switch (e.linkage) { + .internal => {}, + .strong => switch (e.visibility) { + .default => zo.symbol(sym).flags.is_extern_ptr = true, + .hidden, .protected => {}, + }, + .weak => { + zo.symbol(sym).flags.weak = true; + continue :linkage .strong; + }, + .link_once => unreachable, + } + break :sym .{ sym, e.relocation }; + } else break :sym .{ try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav), .any }; + } else if (cg.bin_file.cast(.macho)) |macho_file| { const zo = macho_file.getZigObject().?; if (nav.getExtern(ip)) |e| { const sym = try macho_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip)); - zo.symbols.items[sym].flags.is_extern_ptr = true; - break :sym sym; - } - break :sym try zo.getOrCreateMetadataForNav(macho_file, ty_nav.nav); - } - unreachable; + linkage: switch (e.linkage) { + .internal => {}, + .strong => switch (e.visibility) { + .default => zo.symbols.items[sym].flags.is_extern_ptr = true, + .hidden, .protected => {}, + }, + .weak => { + zo.symbols.items[sym].flags.weak = true; + continue :linkage .strong; + }, + .link_once => unreachable, + } + break :sym .{ sym, e.relocation }; + } else break :sym .{ try zo.getOrCreateMetadataForNav(macho_file, ty_nav.nav), .any }; + } else unreachable; }; if (cg.mod.pic) { @@ -163520,13 +163566,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { try cg.spillRegisters(&.{.rax}); } - var slot = try cg.tempInit(.usize, .{ .lea_symbol = .{ - .sym_index = tlv_sym_index, - } }); + var slot = try cg.tempInit(.usize, switch (relocation) { + .any => .{ .lea_symbol = .{ .sym_index = sym_index } }, + .pcrel => .{ .lea_pcrel = .{ .sym_index = sym_index } }, + }); while (try slot.toRegClass(true, .general_purpose, cg)) {} try slot.finish(inst, &.{}, &.{}, cg); }, - else => return cg.fail("TODO implement tlv/dllimport on {}", .{cg.bin_file.tag}), + else => return cg.fail("TODO implement runtime_nav_ptr on {}", .{cg.bin_file.tag}), }, .c_va_arg => try cg.airVaArg(inst), .c_va_copy => try cg.airVaCopy(inst), @@ -169189,6 +169236,7 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE .register, .register_offset, .lea_symbol, + .lea_pcrel, .lea_direct, .lea_got, .lea_frame, @@ -169196,6 +169244,7 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE .memory, .indirect, .load_symbol, + .load_pcrel, .load_direct, .load_got, .load_frame, @@ -169407,6 +169456,7 @@ fn store( .register, .register_offset, .lea_symbol, + .lea_pcrel, .lea_direct, .lea_got, .lea_frame, @@ -169414,6 +169464,7 @@ fn store( .memory, .indirect, .load_symbol, + .load_pcrel, .load_direct, .load_got, .load_frame, @@ -169883,6 +169934,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: .register_overflow, .register_mask, .lea_symbol, + .lea_pcrel, .lea_direct, .lea_got, .lea_frame, @@ -169892,7 +169944,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: => unreachable, // unmodifiable destination .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)), .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented - .memory, .load_symbol, .load_got, .load_direct => { + .memory, .load_symbol, .load_pcrel, .load_got, .load_direct => { const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); defer self.register_manager.unlockReg(addr_reg_lock); @@ -171552,6 +171604,8 @@ fn genBinOp( .register_mask, .load_symbol, .lea_symbol, + .load_pcrel, + .lea_pcrel, .load_direct, .lea_direct, .load_got, @@ -172740,6 +172794,7 @@ fn genBinOpMir( .lea_got, .lea_frame, .lea_symbol, + .lea_pcrel, .elementwise_args, .reserved_frame, .air_ref, @@ -172831,6 +172886,8 @@ fn genBinOpMir( .indirect, .load_symbol, .lea_symbol, + .load_pcrel, + .lea_pcrel, .load_direct, .lea_direct, .load_got, @@ -172906,7 +172963,7 @@ fn genBinOpMir( } } }, - .memory, .indirect, .load_symbol, .load_got, .load_direct, .load_frame => { + .memory, .indirect, .load_symbol, .load_pcrel, .load_got, .load_direct, .load_frame => { const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock }; const limb_abi_size: u32 = @min(abi_size, 8); @@ -172953,8 +173010,9 @@ fn genBinOpMir( .load_frame, .lea_frame, .lea_symbol, + .lea_pcrel, => null, - .memory, .load_symbol, .load_got, .load_direct => src: { + .memory, .load_symbol, .load_pcrel, .load_got, .load_direct => src: { switch (resolved_src_mcv) { .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr))) != null and std.math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null) @@ -173093,6 +173151,8 @@ fn genBinOpMir( .indirect, .load_symbol, .lea_symbol, + .load_pcrel, + .lea_pcrel, .load_direct, .lea_direct, .load_got, @@ -173160,6 +173220,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv .register_overflow, .register_mask, .lea_symbol, + .lea_pcrel, .lea_direct, .lea_got, .lea_frame, @@ -173222,6 +173283,8 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv .eflags, .load_symbol, .lea_symbol, + .load_pcrel, + .lea_pcrel, .load_direct, .lea_direct, .load_got, @@ -173281,7 +173344,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv } }, .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented - .memory, .indirect, .load_symbol, .load_direct, .load_got, .load_frame => { + .memory, .indirect, .load_symbol, .load_pcrel, .load_direct, .load_got, .load_frame => { const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv); const tmp_mcv = MCValue{ .register = tmp_reg }; const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); @@ -173450,7 +173513,8 @@ fn genLocalDebugInfo( .disp = frame_addr.off, } }, }), - .lea_symbol => |sym_off| try self.asmAirMemory(.dbg_local, inst, .{ + // debug info should explicitly ignore pcrel requirements + .lea_symbol, .lea_pcrel => |sym_off| try self.asmAirMemory(.dbg_local, inst, .{ .base = .{ .reloc = sym_off.sym_index }, .mod = .{ .rm = .{ .size = .qword, @@ -174108,12 +174172,13 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v .lea_got, .lea_frame, .lea_symbol, + .lea_pcrel, .elementwise_args, .reserved_frame, .air_ref, => unreachable, .register, .register_pair, .register_triple, .register_quadruple, .load_frame => null, - .memory, .load_symbol, .load_got, .load_direct => dst: { + .memory, .load_symbol, .load_pcrel, .load_got, .load_direct => dst: { switch (resolved_dst_mcv) { .memory => |addr| if (std.math.cast( i32, @@ -174122,7 +174187,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v i32, @as(i64, @bitCast(addr)) + abi_size - 8, ) != null) break :dst null, - .load_symbol, .load_got, .load_direct => {}, + .load_symbol, .load_pcrel, .load_got, .load_direct => {}, else => unreachable, } @@ -174160,6 +174225,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v .register_mask, .indirect, .lea_symbol, + .lea_pcrel, .lea_direct, .lea_got, .lea_frame, @@ -174168,7 +174234,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v .air_ref, => unreachable, .register_pair, .register_triple, .register_quadruple, .load_frame => null, - .memory, .load_symbol, .load_got, .load_direct => src: { + .memory, .load_symbol, .load_pcrel, .load_got, .load_direct => src: { switch (resolved_src_mcv) { .memory => |addr| if (std.math.cast( i32, @@ -174177,7 +174243,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v i32, @as(i64, @bitCast(addr)) + abi_size - 8, ) != null) break :src null, - .load_symbol, .load_got, .load_direct => {}, + .load_symbol, .load_pcrel, .load_got, .load_direct => {}, else => unreachable, } @@ -174568,6 +174634,7 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) .lea_direct, .lea_got, .lea_symbol, + .lea_pcrel, .elementwise_args, .reserved_frame, .air_ref, @@ -174616,6 +174683,7 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) .memory, .load_symbol, + .load_pcrel, .load_got, .load_direct, => { @@ -176625,6 +176693,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C .lea_got, .lea_frame, .lea_symbol, + .lea_pcrel, .elementwise_args, .reserved_frame, .air_ref, @@ -176719,7 +176788,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C } return; }, - .load_symbol, .load_direct, .load_got => { + .load_symbol, .load_pcrel, .load_direct, .load_got => { const src_addr_reg = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64(); const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg); @@ -176752,7 +176821,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C .undef => if (opts.safety and part_i > 0) .{ .register = dst_regs[0] } else .undef, dst_tag => |src_regs| .{ .register = src_regs[part_i] }, .memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(), - .load_symbol, .load_direct, .load_got => .{ .indirect = .{ + .load_symbol, .load_pcrel, .load_direct, .load_got => .{ .indirect = .{ .reg = src_info.?.addr_reg, .off = part_disp, } }, @@ -176773,11 +176842,11 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C src_mcv, opts, ), - .memory, .load_symbol, .load_direct, .load_got => { + .memory, .load_symbol, .load_pcrel, .load_direct, .load_got => { switch (dst_mcv) { .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| return self.genSetMem(.{ .reg = .ds }, small_addr, ty, src_mcv, opts), - .load_symbol, .load_direct, .load_got => {}, + .load_symbol, .load_pcrel, .load_direct, .load_got => {}, else => unreachable, } @@ -177234,7 +177303,7 @@ fn genSetReg( if (src_reg_mask.info.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size)); try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{}); }, - .memory, .load_symbol, .load_direct, .load_got => { + .memory, .load_symbol, .load_pcrel, .load_direct, .load_got => { switch (src_mcv) { .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| return (try self.moveStrategy( @@ -177263,6 +177332,21 @@ fn genSetReg( .segment, .mmx, .ip, .cr, .dr => unreachable, .x87, .sse => {}, }, + .load_pcrel => |sym_off| switch (dst_reg.class()) { + .general_purpose, .gphi => { + assert(sym_off.off == 0); + try self.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{ + .base = .{ .pcrel = sym_off.sym_index }, + .mod = .{ .rm = .{ + .size = self.memSize(ty), + .disp = sym_off.off, + } }, + }); + return; + }, + .segment, .mmx, .ip, .cr, .dr => unreachable, + .x87, .sse => {}, + }, .load_direct => |sym_index| switch (dst_reg.class()) { .general_purpose, .gphi => { _ = try self.addInst(.{ @@ -177313,6 +177397,28 @@ fn genSetReg( @tagName(self.bin_file.tag), }), }, + .lea_pcrel => |sym_off| switch (self.bin_file.tag) { + .elf, .macho => { + try self.asmRegisterMemory( + .{ ._, .lea }, + dst_reg.to64(), + .{ + .base = .{ .pcrel = sym_off.sym_index }, + }, + ); + if (sym_off.off != 0) try self.asmRegisterMemory( + .{ ._, .lea }, + dst_reg.to64(), + .{ + .base = .{ .reg = dst_reg.to64() }, + .mod = .{ .rm = .{ .disp = sym_off.off } }, + }, + ); + }, + else => return self.fail("TODO emit symbol sequence on {s}", .{ + @tagName(self.bin_file.tag), + }), + }, .lea_direct, .lea_got => |sym_index| _ = try self.addInst(.{ .tag = switch (src_mcv) { .lea_direct => .lea, @@ -177350,6 +177456,7 @@ fn genSetMem( .frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } }, .table, .rip_inst => unreachable, .reloc => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index, .off = disp } }, + .pcrel => |sym_index| .{ .lea_pcrel = .{ .sym_index = sym_index, .off = disp } }, }; switch (src_mcv) { .none, @@ -177466,7 +177573,7 @@ fn genSetMem( .off = disp, }).compare(.gte, src_align), .table, .rip_inst => unreachable, - .reloc => false, + .reloc, .pcrel => false, })).write( self, .{ .base = base, .mod = .{ .rm = .{ @@ -177557,6 +177664,8 @@ fn genSetMem( .lea_frame, .load_symbol, .lea_symbol, + .load_pcrel, + .lea_pcrel, => switch (abi_size) { 0 => {}, 1, 2, 4, 8 => { @@ -178110,7 +178219,7 @@ fn airCmpxchg(self: *CodeGen, inst: Air.Inst.Index) !void { .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}), } const ptr_lock = switch (ptr_mem.base) { - .none, .frame, .reloc => null, + .none, .frame, .reloc, .pcrel => null, .reg => |reg| self.register_manager.lockReg(reg), .table, .rip_inst => unreachable, }; @@ -178193,7 +178302,7 @@ fn atomicOp( .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}), } const mem_lock = switch (ptr_mem.base) { - .none, .frame, .reloc => null, + .none, .frame, .reloc, .pcrel => null, .reg => |reg| self.register_manager.lockReg(reg), .table, .rip_inst => unreachable, }; @@ -182266,6 +182375,8 @@ const Temp = struct { .memory, .load_symbol, .lea_symbol, + .load_pcrel, + .lea_pcrel, .indirect, .load_direct, .lea_direct, @@ -182427,6 +182538,22 @@ const Temp = struct { assert(limb_index == 0); new_temp_index.tracking(cg).* = .init(.{ .lea_symbol = sym_off }); }, + .load_pcrel => |sym_off| { + const new_reg = + try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp); + new_temp_index.tracking(cg).* = .init(.{ .register = new_reg }); + try cg.asmRegisterMemory(.{ ._, .mov }, new_reg.to64(), .{ + .base = .{ .pcrel = sym_off.sym_index }, + .mod = .{ .rm = .{ + .size = .qword, + .disp = sym_off.off + @as(u31, limb_index) * 8, + } }, + }); + }, + .lea_pcrel => |sym_off| { + assert(limb_index == 0); + new_temp_index.tracking(cg).* = .init(.{ .lea_pcrel = sym_off }); + }, .load_frame => |frame_addr| { const new_reg = try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp); @@ -182721,11 +182848,12 @@ const Temp = struct { .memory, .indirect, .load_symbol, + .load_pcrel, .load_direct, .load_got, .load_frame, => return temp.toRegClass(true, .general_purpose, cg), - .lea_symbol => |sym_off| { + .lea_symbol, .lea_pcrel => |sym_off| { const off = sym_off.off; // hack around linker relocation bugs if (false and off == 0) return false; @@ -187464,6 +187592,8 @@ const Temp = struct { .memory, .load_symbol, .lea_symbol, + .load_pcrel, + .lea_pcrel, .indirect, .load_direct, .lea_direct, @@ -190044,6 +190174,7 @@ const Select = struct { .register => |base_reg| .{ .reg = base_reg.toSize(.ptr, s.cg.target) }, .register_offset => |base_reg_off| .{ .reg = base_reg_off.reg.toSize(.ptr, s.cg.target) }, .lea_symbol => |base_sym_off| .{ .reloc = base_sym_off.sym_index }, + .lea_pcrel => |base_sym_off| .{ .pcrel = base_sym_off.sym_index }, }, .mod = .{ .rm = .{ .size = op.flags.base.size, diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index 92114095bf..d4116974cf 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -189,12 +189,12 @@ pub fn emitMir(emit: *Emit) Error!void { .r_addend = lowered_relocs[0].off, }, zo); }, - .linker_reloc => |sym_index| if (emit.lower.bin_file.cast(.elf)) |elf_file| { + .linker_reloc, .linker_pcrel => |sym_index| if (emit.lower.bin_file.cast(.elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; const atom = zo.symbol(emit.atom_index).atom(elf_file).?; const sym = zo.symbol(sym_index); if (emit.lower.pic) { - const r_type: u32 = if (sym.flags.is_extern_ptr) + const r_type: u32 = if (sym.flags.is_extern_ptr and lowered_relocs[0].target != .linker_pcrel) @intFromEnum(std.elf.R_X86_64.GOTPCREL) else @intFromEnum(std.elf.R_X86_64.PC32); @@ -218,7 +218,7 @@ pub fn emitMir(emit: *Emit) Error!void { const zo = macho_file.getZigObject().?; const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; const sym = &zo.symbols.items[sym_index]; - const @"type": link.File.MachO.Relocation.Type = if (sym.flags.is_extern_ptr) + const @"type": link.File.MachO.Relocation.Type = if (sym.flags.is_extern_ptr and lowered_relocs[0].target != .linker_pcrel) .got_load else if (sym.flags.tlv) .tlv @@ -438,6 +438,7 @@ pub fn emitMir(emit: *Emit) Error!void { .reg => |reg| .{ .breg = reg.dwarfNum() }, .frame, .table, .rip_inst => unreachable, .reloc => |sym_index| .{ .addr_reloc = sym_index }, + .pcrel => unreachable, }; break :base &loc_buf[0]; }, diff --git a/src/arch/x86_64/Lower.zig b/src/arch/x86_64/Lower.zig index 7a69d58abc..838f155d10 100644 --- a/src/arch/x86_64/Lower.zig +++ b/src/arch/x86_64/Lower.zig @@ -66,6 +66,7 @@ pub const Reloc = struct { inst: Mir.Inst.Index, table, linker_reloc: u32, + linker_pcrel: u32, linker_tlsld: u32, linker_dtpoff: u32, linker_extern_fn: u32, @@ -421,9 +422,9 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) for (emit_ops, ops, 0..) |*emit_op, op, op_index| { emit_op.* = switch (op) { else => op, - .mem => |mem_op| switch (mem_op.base()) { + .mem => |mem_op| op: switch (mem_op.base()) { else => op, - .reloc => |sym_index| op: { + .reloc => |sym_index| { assert(prefix == .none); assert(mem_op.sib.disp == 0); assert(mem_op.sib.scale_index.scale == 0); @@ -559,6 +560,22 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) return lower.fail("TODO: bin format '{s}'", .{@tagName(lower.bin_file.tag)}); } }, + .pcrel => |sym_index| { + assert(prefix == .none); + assert(mem_op.sib.disp == 0); + assert(mem_op.sib.scale_index.scale == 0); + + _ = lower.reloc(@intCast(op_index), .{ .linker_pcrel = sym_index }, 0); + break :op switch (lower.bin_file.tag) { + .elf => op, + .macho => switch (mnemonic) { + .lea => .{ .mem = Memory.initRip(.none, 0) }, + .mov => .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) }, + else => unreachable, + }, + else => |tag| return lower.fail("TODO: bin format '{s}'", .{@tagName(tag)}), + }; + }, }, }; } diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig index 83dbc855ec..8d202e6bae 100644 --- a/src/arch/x86_64/Mir.zig +++ b/src/arch/x86_64/Mir.zig @@ -1866,7 +1866,7 @@ pub const Memory = struct { .none, .table => undefined, .reg => |reg| @intFromEnum(reg), .frame => |frame_index| @intFromEnum(frame_index), - .reloc => |sym_index| sym_index, + .reloc, .pcrel => |sym_index| sym_index, .rip_inst => |inst_index| inst_index, }, .off = switch (mem.mod) { @@ -1895,6 +1895,7 @@ pub const Memory = struct { .frame => .{ .frame = @enumFromInt(mem.base) }, .table => .table, .reloc => .{ .reloc = mem.base }, + .pcrel => .{ .pcrel = mem.base }, .rip_inst => .{ .rip_inst = mem.base }, }, .scale_index = switch (mem.info.index) { @@ -1959,7 +1960,7 @@ pub fn resolveFrameAddr(mir: Mir, frame_addr: bits.FrameAddr) bits.RegisterOffse pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory { return switch (mem.info.base) { - .none, .reg, .table, .reloc, .rip_inst => mem, + .none, .reg, .table, .reloc, .pcrel, .rip_inst => mem, .frame => if (mir.frame_locs.len > 0) .{ .info = .{ .base = .reg, diff --git a/src/arch/x86_64/bits.zig b/src/arch/x86_64/bits.zig index 062a57981c..63b5d4b238 100644 --- a/src/arch/x86_64/bits.zig +++ b/src/arch/x86_64/bits.zig @@ -762,6 +762,7 @@ pub const Memory = struct { frame: FrameIndex, table, reloc: u32, + pcrel: u32, rip_inst: Mir.Inst.Index, pub const Tag = @typeInfo(Base).@"union".tag_type.?; diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig index 9cacd955d7..cb1272fba0 100644 --- a/src/arch/x86_64/encoder.zig +++ b/src/arch/x86_64/encoder.zig @@ -138,7 +138,7 @@ pub const Instruction = struct { .moffs => true, .rip => false, .sib => |s| switch (s.base) { - .none, .frame, .table, .reloc, .rip_inst => false, + .none, .frame, .table, .reloc, .pcrel, .rip_inst => false, .reg => |reg| reg.isClass(.segment), }, }; @@ -211,7 +211,7 @@ pub const Instruction = struct { .none, .imm => 0b00, .reg => |reg| @truncate(reg.enc() >> 3), .mem => |mem| switch (mem.base()) { - .none, .frame, .table, .reloc, .rip_inst => 0b00, // rsp, rbp, and rip are not extended + .none, .frame, .table, .reloc, .pcrel, .rip_inst => 0b00, // rsp, rbp, and rip are not extended .reg => |reg| @truncate(reg.enc() >> 3), }, .bytes => unreachable, @@ -282,6 +282,7 @@ pub const Instruction = struct { .frame => |frame_index| try writer.print("{}", .{frame_index}), .table => try writer.print("Table", .{}), .reloc => |sym_index| try writer.print("Symbol({d})", .{sym_index}), + .pcrel => |sym_index| try writer.print("PcRelSymbol({d})", .{sym_index}), .rip_inst => |inst_index| try writer.print("RipInst({d})", .{inst_index}), } if (mem.scaleIndex()) |si| { @@ -721,7 +722,7 @@ pub const Instruction = struct { try encoder.modRm_indirectDisp32(operand_enc, 0); try encoder.disp32(undefined); } else return error.CannotEncode, - .rip_inst => { + .pcrel, .rip_inst => { try encoder.modRm_RIPDisp32(operand_enc); try encoder.disp32(sib.disp); }, diff --git a/src/codegen.zig b/src/codegen.zig index 1f794bbeea..a2de3e2d01 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -921,41 +921,74 @@ fn genNavRef( const nav = ip.getNav(nav_index); assert(!nav.isThreadlocal(ip)); - const is_extern, const lib_name = if (nav.getExtern(ip)) |e| - .{ true, e.lib_name } + const lib_name, const linkage, const visibility = if (nav.getExtern(ip)) |e| + .{ e.lib_name, e.linkage, e.visibility } else - .{ false, .none }; + .{ .none, .internal, .default }; const name = nav.name; if (lf.cast(.elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; - if (is_extern) { - const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip)); - zo.symbol(sym_index).flags.is_extern_ptr = true; - return .{ .mcv = .{ .lea_symbol = sym_index } }; + switch (linkage) { + .internal => { + const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index); + return .{ .mcv = .{ .lea_symbol = sym_index } }; + }, + .strong, .weak => { + const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip)); + switch (linkage) { + .internal => unreachable, + .strong => {}, + .weak => zo.symbol(sym_index).flags.weak = true, + .link_once => unreachable, + } + switch (visibility) { + .default => zo.symbol(sym_index).flags.is_extern_ptr = true, + .hidden, .protected => {}, + } + return .{ .mcv = .{ .lea_symbol = sym_index } }; + }, + .link_once => unreachable, } - const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index); - return .{ .mcv = .{ .lea_symbol = sym_index } }; } else if (lf.cast(.macho)) |macho_file| { const zo = macho_file.getZigObject().?; - if (is_extern) { - const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip)); - zo.symbols.items[sym_index].flags.is_extern_ptr = true; - return .{ .mcv = .{ .lea_symbol = sym_index } }; + switch (linkage) { + .internal => { + const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index); + const sym = zo.symbols.items[sym_index]; + return .{ .mcv = .{ .lea_symbol = sym.nlist_idx } }; + }, + .strong, .weak => { + const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip)); + switch (linkage) { + .internal => unreachable, + .strong => {}, + .weak => zo.symbols.items[sym_index].flags.weak = true, + .link_once => unreachable, + } + switch (visibility) { + .default => zo.symbols.items[sym_index].flags.is_extern_ptr = true, + .hidden, .protected => {}, + } + return .{ .mcv = .{ .lea_symbol = sym_index } }; + }, + .link_once => unreachable, } - const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index); - const sym = zo.symbols.items[sym_index]; - return .{ .mcv = .{ .lea_symbol = sym.nlist_idx } }; } else if (lf.cast(.coff)) |coff_file| { - if (is_extern) { - // TODO audit this - const global_index = try coff_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip)); - try coff_file.need_got_table.put(gpa, global_index, {}); // needs GOT - return .{ .mcv = .{ .load_got = link.File.Coff.global_symbol_bit | global_index } }; + // TODO audit this + switch (linkage) { + .internal => { + const atom_index = try coff_file.getOrCreateAtomForNav(nav_index); + const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; + return .{ .mcv = .{ .load_got = sym_index } }; + }, + .strong, .weak => { + const global_index = try coff_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip)); + try coff_file.need_got_table.put(gpa, global_index, {}); // needs GOT + return .{ .mcv = .{ .load_got = link.File.Coff.global_symbol_bit | global_index } }; + }, + .link_once => unreachable, } - const atom_index = try coff_file.getOrCreateAtomForNav(nav_index); - const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; - return .{ .mcv = .{ .load_got = sym_index } }; } else if (lf.cast(.plan9)) |p9| { const atom_index = try p9.seeNav(pt, nav_index); const atom = p9.getAtom(atom_index); diff --git a/src/codegen/c.zig b/src/codegen/c.zig index c68abc06ce..3b8ab52982 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -2255,19 +2255,30 @@ pub const DeclGen = struct { fn renderFwdDecl( dg: *DeclGen, nav_index: InternPool.Nav.Index, - flags: struct { - is_extern: bool, + flags: packed struct { is_const: bool, is_threadlocal: bool, - is_weak_linkage: bool, + linkage: std.builtin.GlobalLinkage, + visibility: std.builtin.SymbolVisibility, }, ) !void { const zcu = dg.pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); const fwd = dg.fwdDeclWriter(); - try fwd.writeAll(if (flags.is_extern) "zig_extern " else "static "); - if (flags.is_weak_linkage) try fwd.writeAll("zig_weak_linkage "); + try fwd.writeAll(switch (flags.linkage) { + .internal => "static ", + .strong, .weak, .link_once => "zig_extern ", + }); + switch (flags.linkage) { + .internal, .strong => {}, + .weak => try fwd.writeAll("zig_weak_linkage "), + .link_once => return dg.fail("TODO: CBE: implement linkonce linkage?", .{}), + } + switch (flags.linkage) { + .internal => {}, + .strong, .weak, .link_once => try fwd.print("zig_visibility({s}) ", .{@tagName(flags.visibility)}), + } if (flags.is_threadlocal and !dg.mod.single_threaded) try fwd.writeAll("zig_threadlocal "); try dg.renderTypeAndName( fwd, @@ -2994,10 +3005,10 @@ pub fn genDecl(o: *Object) !void { switch (ip.indexToKey(nav.status.fully_resolved.val)) { .@"extern" => |@"extern"| { if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{ - .is_extern = true, .is_const = @"extern".is_const, .is_threadlocal = @"extern".is_threadlocal, - .is_weak_linkage = @"extern".is_weak_linkage, + .linkage = @"extern".linkage, + .visibility = @"extern".visibility, }); const fwd = o.dg.fwdDeclWriter(); @@ -3016,13 +3027,12 @@ pub fn genDecl(o: *Object) !void { }, .variable => |variable| { try o.dg.renderFwdDecl(o.dg.pass.nav, .{ - .is_extern = false, .is_const = false, .is_threadlocal = variable.is_threadlocal, - .is_weak_linkage = variable.is_weak_linkage, + .linkage = .internal, + .visibility = .default, }); const w = o.writer(); - if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage "); if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal "); if (nav.status.fully_resolved.@"linksection".toSlice(&zcu.intern_pool)) |s| try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)}); @@ -3467,7 +3477,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}), .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}), - .tlv_dllimport_ptr => try airTlvDllimportPtr(f, inst), + .runtime_nav_ptr => try airRuntimeNavPtr(f, inst), .c_va_start => try airCVaStart(f, inst), .c_va_arg => try airCVaArg(f, inst), @@ -7672,7 +7682,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { return local; } -fn airTlvDllimportPtr(f: *Function, inst: Air.Inst.Index) !CValue { +fn airRuntimeNavPtr(f: *Function, inst: Air.Inst.Index) !CValue { const ty_nav = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav; const writer = f.object.writer(); const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty)); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 7790840d20..3fc6250d3f 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -2979,36 +2979,49 @@ pub const Object = struct { const zcu = pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); - const is_extern, const is_threadlocal, const is_weak_linkage, const is_dll_import = switch (nav.status) { + const linkage: std.builtin.GlobalLinkage, const visibility: Builder.Visibility, const is_threadlocal, const is_dll_import = switch (nav.status) { .unresolved => unreachable, .fully_resolved => |r| switch (ip.indexToKey(r.val)) { - .variable => |variable| .{ false, variable.is_threadlocal, variable.is_weak_linkage, false }, - .@"extern" => |@"extern"| .{ true, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import }, - else => .{ false, false, false, false }, + .variable => |variable| .{ .internal, .default, variable.is_threadlocal, false }, + .@"extern" => |@"extern"| .{ @"extern".linkage, .fromSymbolVisibility(@"extern".visibility), @"extern".is_threadlocal, @"extern".is_dll_import }, + else => .{ .internal, .default, false, false }, }, // This means it's a source declaration which is not `extern`! - .type_resolved => |r| .{ false, r.is_threadlocal, false, false }, + .type_resolved => |r| .{ .internal, .default, r.is_threadlocal, false }, }; const variable_index = try o.builder.addVariable( - try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)), + try o.builder.strtabString(switch (linkage) { + .internal => nav.fqn, + .strong, .weak => nav.name, + .link_once => unreachable, + }.toSlice(ip)), try o.lowerType(Type.fromInterned(nav.typeOf(ip))), toLlvmGlobalAddressSpace(nav.getAddrspace(), zcu.getTarget()), ); gop.value_ptr.* = variable_index.ptrConst(&o.builder).global; // This is needed for declarations created by `@extern`. - if (is_extern) { - variable_index.setLinkage(.external, &o.builder); - variable_index.setUnnamedAddr(.default, &o.builder); - if (is_threadlocal and !zcu.navFileScope(nav_index).mod.?.single_threaded) - variable_index.setThreadLocal(.generaldynamic, &o.builder); - if (is_weak_linkage) variable_index.setLinkage(.extern_weak, &o.builder); - if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder); - } else { - variable_index.setLinkage(.internal, &o.builder); - variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); + switch (linkage) { + .internal => { + variable_index.setLinkage(.internal, &o.builder); + variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); + }, + .strong, .weak => { + variable_index.setLinkage(switch (linkage) { + .internal => unreachable, + .strong => .external, + .weak => .extern_weak, + .link_once => unreachable, + }, &o.builder); + variable_index.setUnnamedAddr(.default, &o.builder); + if (is_threadlocal and !zcu.navFileScope(nav_index).mod.?.single_threaded) + variable_index.setThreadLocal(.generaldynamic, &o.builder); + if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder); + }, + .link_once => unreachable, } + variable_index.setVisibility(visibility, &o.builder); return variable_index; } @@ -4530,14 +4543,14 @@ pub const NavGen = struct { const nav = ip.getNav(nav_index); const resolved = nav.status.fully_resolved; - const is_extern, const lib_name, const is_threadlocal, const is_weak_linkage, const is_dll_import, const is_const, const init_val, const owner_nav = switch (ip.indexToKey(resolved.val)) { - .variable => |variable| .{ false, .none, variable.is_threadlocal, variable.is_weak_linkage, false, false, variable.init, variable.owner_nav }, - .@"extern" => |@"extern"| .{ true, @"extern".lib_name, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import, @"extern".is_const, .none, @"extern".owner_nav }, - else => .{ false, .none, false, false, false, true, resolved.val, nav_index }, + const lib_name, const linkage, const visibility: Builder.Visibility, const is_threadlocal, const is_dll_import, const is_const, const init_val, const owner_nav = switch (ip.indexToKey(resolved.val)) { + .variable => |variable| .{ .none, .internal, .default, variable.is_threadlocal, false, false, variable.init, variable.owner_nav }, + .@"extern" => |@"extern"| .{ @"extern".lib_name, @"extern".linkage, .fromSymbolVisibility(@"extern".visibility), @"extern".is_threadlocal, @"extern".is_dll_import, @"extern".is_const, .none, @"extern".owner_nav }, + else => .{ .none, .internal, .default, false, false, true, resolved.val, nav_index }, }; const ty = Type.fromInterned(nav.typeOf(ip)); - if (is_extern and ip.isFunctionType(ty.toIntern())) { + if (linkage != .internal and ip.isFunctionType(ty.toIntern())) { _ = try o.resolveLlvmFunction(owner_nav); } else { const variable_index = try o.resolveGlobalNav(nav_index); @@ -4549,6 +4562,7 @@ pub const NavGen = struct { .none => .no_init, else => try o.lowerValue(init_val), }, &o.builder); + variable_index.setVisibility(visibility, &o.builder); const file_scope = zcu.navFileScopeIndex(nav_index); const mod = zcu.fileByIndex(file_scope).mod.?; @@ -4568,7 +4582,7 @@ pub const NavGen = struct { line_number, try o.lowerDebugType(ty), variable_index, - .{ .local = !is_extern }, + .{ .local = linkage == .internal }, ); const debug_expression = try o.builder.debugExpression(&.{}); @@ -4583,38 +4597,47 @@ pub const NavGen = struct { } } - if (is_extern) { - const global_index = o.nav_map.get(nav_index).?; + switch (linkage) { + .internal => {}, + .strong, .weak => { + const global_index = o.nav_map.get(nav_index).?; - const decl_name = decl_name: { - if (zcu.getTarget().cpu.arch.isWasm() and ty.zigTypeTag(zcu) == .@"fn") { - if (lib_name.toSlice(ip)) |lib_name_slice| { - if (!std.mem.eql(u8, lib_name_slice, "c")) { - break :decl_name try o.builder.strtabStringFmt("{}|{s}", .{ nav.name.fmt(ip), lib_name_slice }); + const decl_name = decl_name: { + if (zcu.getTarget().cpu.arch.isWasm() and ty.zigTypeTag(zcu) == .@"fn") { + if (lib_name.toSlice(ip)) |lib_name_slice| { + if (!std.mem.eql(u8, lib_name_slice, "c")) { + break :decl_name try o.builder.strtabStringFmt("{}|{s}", .{ nav.name.fmt(ip), lib_name_slice }); + } } } + break :decl_name try o.builder.strtabString(nav.name.toSlice(ip)); + }; + + if (o.builder.getGlobal(decl_name)) |other_global| { + if (other_global != global_index) { + // Another global already has this name; just use it in place of this global. + try global_index.replace(other_global, &o.builder); + return; + } } - break :decl_name try o.builder.strtabString(nav.name.toSlice(ip)); - }; - if (o.builder.getGlobal(decl_name)) |other_global| { - if (other_global != global_index) { - // Another global already has this name; just use it in place of this global. - try global_index.replace(other_global, &o.builder); - return; + try global_index.rename(decl_name, &o.builder); + global_index.setUnnamedAddr(.default, &o.builder); + if (is_dll_import) { + global_index.setDllStorageClass(.dllimport, &o.builder); + } else if (zcu.comp.config.dll_export_fns) { + global_index.setDllStorageClass(.default, &o.builder); } - } - try global_index.rename(decl_name, &o.builder); - global_index.setLinkage(.external, &o.builder); - global_index.setUnnamedAddr(.default, &o.builder); - if (is_dll_import) { - global_index.setDllStorageClass(.dllimport, &o.builder); - } else if (zcu.comp.config.dll_export_fns) { - global_index.setDllStorageClass(.default, &o.builder); - } - - if (is_weak_linkage) global_index.setLinkage(.extern_weak, &o.builder); + global_index.setLinkage(switch (linkage) { + .internal => unreachable, + .strong => .external, + .weak => .extern_weak, + .link_once => unreachable, + }, &o.builder); + global_index.setVisibility(visibility, &o.builder); + }, + .link_once => unreachable, } } }; @@ -5023,7 +5046,7 @@ pub const FuncGen = struct { .vector_store_elem => try self.airVectorStoreElem(inst), - .tlv_dllimport_ptr => try self.airTlvDllimportPtr(inst), + .runtime_nav_ptr => try self.airRuntimeNavPtr(inst), .inferred_alloc, .inferred_alloc_comptime => unreachable, @@ -8122,7 +8145,7 @@ pub const FuncGen = struct { return .none; } - fn airTlvDllimportPtr(fg: *FuncGen, inst: Air.Inst.Index) !Builder.Value { + fn airRuntimeNavPtr(fg: *FuncGen, inst: Air.Inst.Index) !Builder.Value { const o = fg.ng.object; const ty_nav = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav; const llvm_ptr_const = try o.lowerNavRefValue(ty_nav.nav); diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index d65646744f..70405d8b5e 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -785,7 +785,6 @@ const Entry = struct { } const Index = enum(u32) { - //got_proc, _, const Optional = enum(u32) { @@ -1041,7 +1040,7 @@ const Entry = struct { const symbol = zo.symbol(reloc.target_sym); try dwarf.resolveReloc( entry_off + reloc.source_off, - @bitCast(symbol.address(.{}, elf_file) + @as(i64, @intCast(@intFromEnum(reloc.target_off))) - + @bitCast(symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off)) - if (symbol.flags.is_tls) elf_file.dtpAddress() else 0), @intFromEnum(dwarf.address_size), ); @@ -1052,7 +1051,7 @@ const Entry = struct { const ref = zo.getSymbolRef(reloc.target_sym, macho_file); try dwarf.resolveReloc( entry_off + reloc.source_off, - ref.getSymbol(macho_file).?.getAddress(.{}, macho_file) + @as(i64, @intCast(@intFromEnum(reloc.target_off))), + ref.getSymbol(macho_file).?.getAddress(.{}, macho_file) + @as(i64, @intCast(reloc.target_off)), @intFromEnum(dwarf.address_size), ); } @@ -1081,27 +1080,12 @@ const CrossSectionReloc = struct { const ExternalReloc = struct { source_off: u32 = 0, target_sym: u32, - target_off: enum(u64) { - none = 0, - got = std.math.maxInt(i64) + 1, - _, - - pub fn rel(off: u64) @This() { - const res: @This() = @enumFromInt(off); - switch (res) { - .none => {}, - _ => {}, - .got => unreachable, // assertion failure - } - return res; - } - } = .none, + target_off: u64 = 0, }; pub const Loc = union(enum) { empty, addr_reloc: u32, - got_reloc: u32, deref: *const Loc, constu: u64, consts: i64, @@ -1166,10 +1150,6 @@ pub const Loc = union(enum) { try addr.write(adapter); try writer.writeByte(DW.OP.deref); }, - .got_reloc => |sym_index| { - try writer.writeByte(DW.OP.const4s); - try adapter.gotSym(sym_index); - }, .constu => |constu| if (std.math.cast(u5, constu)) |lit| { try writer.writeByte(@as(u8, DW.OP.lit0) + lit); } else if (std.math.cast(u8, constu)) |const1u| { @@ -1766,9 +1746,6 @@ pub const WipNav = struct { fn endian(_: ExprLocCounter) std.builtin.Endian { return @import("builtin").cpu.arch.endian(); } - fn gotSym(counter: *ExprLocCounter, _: u32) error{}!void { - counter.stream.bytes_written += 4; - } fn addrSym(counter: *ExprLocCounter, _: u32) error{}!void { counter.stream.bytes_written += @intFromEnum(counter.address_size); } @@ -1789,14 +1766,6 @@ pub const WipNav = struct { fn endian(ctx: @This()) std.builtin.Endian { return ctx.wip_nav.dwarf.endian; } - fn gotSym(ctx: @This(), sym_index: u32) UpdateError!void { - try ctx.wip_nav.infoExternalReloc(.{ - .source_off = @intCast(ctx.wip_nav.debug_info.items.len), - .target_sym = sym_index, - .target_off = .got, - }); - try ctx.wip_nav.debug_info.appendNTimes(ctx.wip_nav.dwarf.gpa, 0, 4); - } fn addrSym(ctx: @This(), sym_index: u32) UpdateError!void { try ctx.wip_nav.infoAddrSym(sym_index, 0); } @@ -1812,7 +1781,7 @@ pub const WipNav = struct { try wip_nav.infoExternalReloc(.{ .source_off = @intCast(wip_nav.debug_info.items.len), .target_sym = sym_index, - .target_off = .rel(sym_off), + .target_off = sym_off, }); try wip_nav.debug_info.appendNTimes(wip_nav.dwarf.gpa, 0, @intFromEnum(wip_nav.dwarf.address_size)); } @@ -1829,14 +1798,6 @@ pub const WipNav = struct { fn endian(ctx: @This()) std.builtin.Endian { return ctx.wip_nav.dwarf.endian; } - fn gotSym(ctx: @This(), sym_index: u32) UpdateError!void { - try ctx.wip_nav.frameExternalReloc(.{ - .source_off = @intCast(ctx.wip_nav.debug_frame.items.len), - .target_sym = sym_index, - .target_off = .got, - }); - try ctx.wip_nav.debug_frame.appendNTimes(ctx.wip_nav.dwarf.gpa, 0, 4); - } fn addrSym(ctx: @This(), sym_index: u32) UpdateError!void { try ctx.wip_nav.frameAddrSym(sym_index, 0); } @@ -1852,7 +1813,7 @@ pub const WipNav = struct { try wip_nav.frameExternalReloc(.{ .source_off = @intCast(wip_nav.debug_frame.items.len), .target_sym = sym_index, - .target_off = .rel(sym_off), + .target_off = sym_off, }); try wip_nav.debug_frame.appendNTimes(wip_nav.dwarf.gpa, 0, @intFromEnum(wip_nav.dwarf.address_size)); } @@ -2338,81 +2299,50 @@ fn getUnit(dwarf: *Dwarf, mod: *Module) !Unit.Index { const mod_gop = try dwarf.mods.getOrPut(dwarf.gpa, mod); const unit: Unit.Index = @enumFromInt(mod_gop.index); if (!mod_gop.found_existing) { - { - errdefer _ = dwarf.mods.pop(); - mod_gop.value_ptr.* = .{ - .root_dir_path = undefined, - .dirs = .empty, - .files = .empty, - }; - errdefer mod_gop.value_ptr.dirs.deinit(dwarf.gpa); - try mod_gop.value_ptr.dirs.putNoClobber(dwarf.gpa, unit, {}); - assert(try dwarf.debug_aranges.section.addUnit( - DebugAranges.headerBytes(dwarf), - DebugAranges.trailerBytes(dwarf), - dwarf, - ) == unit); - errdefer dwarf.debug_aranges.section.popUnit(dwarf.gpa); - assert(try dwarf.debug_frame.section.addUnit( - DebugFrame.headerBytes(dwarf), - DebugFrame.trailerBytes(dwarf), - dwarf, - ) == unit); - errdefer dwarf.debug_frame.section.popUnit(dwarf.gpa); - assert(try dwarf.debug_info.section.addUnit( - DebugInfo.headerBytes(dwarf), - DebugInfo.trailer_bytes, - dwarf, - ) == unit); - errdefer dwarf.debug_info.section.popUnit(dwarf.gpa); - assert(try dwarf.debug_line.section.addUnit( - DebugLine.headerBytes(dwarf, 5, 25), - DebugLine.trailer_bytes, - dwarf, - ) == unit); - errdefer dwarf.debug_line.section.popUnit(dwarf.gpa); - assert(try dwarf.debug_loclists.section.addUnit( - DebugLocLists.headerBytes(dwarf), - DebugLocLists.trailer_bytes, - dwarf, - ) == unit); - errdefer dwarf.debug_loclists.section.popUnit(dwarf.gpa); - assert(try dwarf.debug_rnglists.section.addUnit( - DebugRngLists.headerBytes(dwarf), - DebugRngLists.trailer_bytes, - dwarf, - ) == unit); - errdefer dwarf.debug_rnglists.section.popUnit(dwarf.gpa); - } - //if (dwarf.bin_file.cast(.elf)) |elf_file| { - // if (unit == .main) assert(try dwarf.addCommonEntry(unit) == .got_proc); - // if (mod.pic and dwarf.debug_info.section.getUnit(.main).getEntry(.got_proc).len == 0) { - // var wip_nav: WipNav = .{ - // .dwarf = dwarf, - // .pt = undefined, - // .unit = .main, - // .entry = .got_proc, - // .any_children = false, - // .func = .none, - // .func_sym_index = undefined, - // .func_high_pc = undefined, - // .blocks = undefined, - // .cfi = undefined, - // .debug_frame = .empty, - // .debug_info = .empty, - // .debug_line = .empty, - // .debug_loclists = .empty, - // .pending_lazy = .empty, - // }; - // defer wip_nav.deinit(); - // try wip_nav.abbrevCode(.proc); - // try wip_nav.infoExprLoc(.{ .deref = &.{ .plus = .{ - // &.empty, - // &.{ .addr_reloc = try elf_file.zigObjectPtr().?.getGlobalSymbol(elf_file, "_GLOBAL_OFFSET_TABLE_", null) }, - // } } }); - // try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); - // } - //} + errdefer _ = dwarf.mods.pop(); + mod_gop.value_ptr.* = .{ + .root_dir_path = undefined, + .dirs = .empty, + .files = .empty, + }; + errdefer mod_gop.value_ptr.dirs.deinit(dwarf.gpa); + try mod_gop.value_ptr.dirs.putNoClobber(dwarf.gpa, unit, {}); + assert(try dwarf.debug_aranges.section.addUnit( + DebugAranges.headerBytes(dwarf), + DebugAranges.trailerBytes(dwarf), + dwarf, + ) == unit); + errdefer dwarf.debug_aranges.section.popUnit(dwarf.gpa); + assert(try dwarf.debug_frame.section.addUnit( + DebugFrame.headerBytes(dwarf), + DebugFrame.trailerBytes(dwarf), + dwarf, + ) == unit); + errdefer dwarf.debug_frame.section.popUnit(dwarf.gpa); + assert(try dwarf.debug_info.section.addUnit( + DebugInfo.headerBytes(dwarf), + DebugInfo.trailer_bytes, + dwarf, + ) == unit); + errdefer dwarf.debug_info.section.popUnit(dwarf.gpa); + assert(try dwarf.debug_line.section.addUnit( + DebugLine.headerBytes(dwarf, 5, 25), + DebugLine.trailer_bytes, + dwarf, + ) == unit); + errdefer dwarf.debug_line.section.popUnit(dwarf.gpa); + assert(try dwarf.debug_loclists.section.addUnit( + DebugLocLists.headerBytes(dwarf), + DebugLocLists.trailer_bytes, + dwarf, + ) == unit); + errdefer dwarf.debug_loclists.section.popUnit(dwarf.gpa); + assert(try dwarf.debug_rnglists.section.addUnit( + DebugRngLists.headerBytes(dwarf), + DebugRngLists.trailer_bytes, + dwarf, + ) == unit); + errdefer dwarf.debug_rnglists.section.popUnit(dwarf.gpa); } return unit; } @@ -2510,16 +2440,7 @@ fn initWipNavInner( try wip_nav.strp(nav.fqn.toSlice(ip)); const ty: Type = nav_val.typeOf(zcu); const addr: Loc = .{ .addr_reloc = sym_index }; - const loc: Loc = loc: { - if (dwarf.bin_file.cast(.elf)) |elf_file| if (decl.linkage == .@"extern" and mod.pic) - // TODO: lldb doesn't support call :( - //.{ .call = .{ .args = &.{.{ .got_reloc = sym_index }}, .unit = .main, .entry = .got_proc } } - break :loc .{ .deref = &.{ .plus = .{ - &.{ .addr_reloc = try elf_file.zigObjectPtr().?.getGlobalSymbol(elf_file, "_GLOBAL_OFFSET_TABLE_", null) }, - &.{ .got_reloc = sym_index }, - } } }; - break :loc if (decl.is_threadlocal) .{ .form_tls_address = &addr } else addr; - }; + const loc: Loc = if (decl.is_threadlocal) .{ .form_tls_address = &addr } else addr; switch (decl.kind) { .unnamed_test, .@"test", .decltest, .@"comptime", .@"usingnamespace" => unreachable, .@"const" => { @@ -2605,7 +2526,7 @@ fn initWipNavInner( try wip_nav.infoAddrSym(sym_index, 0); wip_nav.func_high_pc = @intCast(wip_nav.debug_info.items.len); try diw.writeInt(u32, 0, dwarf.endian); - const target = file.mod.?.resolved_target.result; + const target = mod.resolved_target.result; try uleb128(diw, switch (nav.status.fully_resolved.alignment) { .none => target_info.defaultFunctionAlignment(target), else => |a| a.maxStrict(target_info.minFunctionAlignment(target)), @@ -2742,7 +2663,7 @@ pub fn finishWipNavFunc( .{ .source_off = 1 + @intFromEnum(dwarf.address_size), .target_sym = wip_nav.func_sym_index, - .target_off = .rel(code_size), + .target_off = code_size, }, }); try dwarf.debug_rnglists.section.replaceEntry( @@ -4981,7 +4902,6 @@ const AbbrevCode = enum { comptime_value_field_comptime_state, comptime_value_elem_runtime_bits, comptime_value_elem_comptime_state, - //proc, const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_instance_func_generic)); comptime { @@ -5851,12 +5771,6 @@ const AbbrevCode = enum { .{ .ZIG_comptime_value, .ref_addr }, }, }, - //.proc = .{ - // .tag = .dwarf_procedure, - // .attrs = &.{ - // .{ .location, .exprloc }, - // }, - //}, .null = undefined, }); }; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index d947f1219b..1516993c74 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -959,6 +959,12 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void { self.rela_plt.clearRetainingCapacity(); if (self.zigObjectPtr()) |zo| { + var undefs: std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)) = .init(gpa); + defer { + for (undefs.values()) |*refs| refs.deinit(); + undefs.deinit(); + } + var has_reloc_errors = false; for (zo.atoms_indexes.items) |atom_index| { const atom_ptr = zo.atom(atom_index) orelse continue; @@ -969,7 +975,10 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void { const code = try zo.codeAlloc(self, atom_index); defer gpa.free(code); const file_offset = atom_ptr.offset(self); - atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) { + (if (shdr.sh_flags & elf.SHF_ALLOC == 0) + atom_ptr.resolveRelocsNonAlloc(self, code, &undefs) + else + atom_ptr.resolveRelocsAlloc(self, code)) catch |err| switch (err) { error.RelocFailure, error.RelaxFailure => has_reloc_errors = true, error.UnsupportedCpuArch => { try self.reportUnsupportedCpuArch(); @@ -980,6 +989,8 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void { try self.pwriteAll(code, file_offset); } + try self.reportUndefinedSymbols(&undefs); + if (has_reloc_errors) return error.LinkFailure; } @@ -1392,11 +1403,9 @@ fn scanRelocs(self: *Elf) !void { const gpa = self.base.comp.gpa; const shared_objects = self.shared_objects.values(); - var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa); + var undefs: std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)) = .init(gpa); defer { - for (undefs.values()) |*refs| { - refs.deinit(); - } + for (undefs.values()) |*refs| refs.deinit(); undefs.deinit(); } @@ -2702,15 +2711,16 @@ fn initSyntheticSections(self: *Elf) !void { }); } - const needs_interp = blk: { - // On Ubuntu with musl-gcc, we get a weird combo of options looking like this: - // -dynamic-linker= -static - // In this case, if we do generate .interp section and segment, we will get - // a segfault in the dynamic linker trying to load a binary that is static - // and doesn't contain .dynamic section. - if (self.base.isStatic() and !comp.config.pie) break :blk false; - break :blk target.dynamic_linker.get() != null; + const is_exe_or_dyn_lib = switch (comp.config.output_mode) { + .Exe => true, + .Lib => comp.config.link_mode == .dynamic, + .Obj => false, }; + const have_dynamic_linker = comp.config.link_mode == .dynamic and is_exe_or_dyn_lib and !target.dynamic_linker.eql(.none); + + const needs_interp = have_dynamic_linker and + (comp.config.link_libc or comp.root_mod.resolved_target.is_explicit_dynamic_linker); + if (needs_interp and self.section_indexes.interp == null) { self.section_indexes.interp = try self.addSection(.{ .name = try self.insertShString(".interp"), @@ -3707,11 +3717,9 @@ fn allocateSpecialPhdrs(self: *Elf) void { fn writeAtoms(self: *Elf) !void { const gpa = self.base.comp.gpa; - var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa); + var undefs: std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)) = .init(gpa); defer { - for (undefs.values()) |*refs| { - refs.deinit(); - } + for (undefs.values()) |*refs| refs.deinit(); undefs.deinit(); } diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index cb145f772c..0869d6582e 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -497,14 +497,14 @@ fn dynAbsRelocAction(symbol: *const Symbol, elf_file: *Elf) RelocAction { } fn outputType(elf_file: *Elf) u2 { - const comp = elf_file.base.comp; assert(!elf_file.base.isRelocatable()); - return switch (elf_file.base.comp.config.output_mode) { + const config = &elf_file.base.comp.config; + return switch (config.output_mode) { .Obj => unreachable, .Lib => 0, .Exe => switch (elf_file.getTarget().os.tag) { .haiku => 0, - else => if (comp.config.pie) 1 else 2, + else => if (config.pie) 1 else 2, }, }; } diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index d1b1512828..13816940fe 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -463,11 +463,8 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void { for (entry.external_relocs.items) |reloc| { const target_sym = self.symbol(reloc.target_sym); const r_offset = entry_off + reloc.source_off; - const r_addend: i64 = switch (reloc.target_off) { - .none, .got => 0, - else => |off| @intCast(@intFromEnum(off)), - }; - const r_type = relocation.dwarf.externalRelocType(target_sym.*, reloc.target_off == .got, sect_index, dwarf.address_size, cpu_arch); + const r_addend: i64 = @intCast(reloc.target_off); + const r_type = relocation.dwarf.externalRelocType(target_sym.*, sect_index, dwarf.address_size, cpu_arch); atom_ptr.addRelocAssumeCapacity(.{ .r_offset = r_offset, .r_addend = r_addend, @@ -660,6 +657,7 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void { const atom_ptr = self.atom(atom_index) orelse continue; if (!atom_ptr.alive) continue; const shdr = atom_ptr.inputShdr(elf_file); + if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; if (shdr.sh_type == elf.SHT_NOBITS) continue; if (atom_ptr.scanRelocsRequiresCode(elf_file)) { // TODO ideally we don't have to fetch the code here. @@ -950,7 +948,7 @@ pub fn getNavVAddr( .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{ .source_off = @intCast(reloc_info.offset), .target_sym = this_sym_index, - .target_off = .rel(reloc_info.addend), + .target_off = reloc_info.addend, }), .plan9 => unreachable, .none => unreachable, @@ -983,7 +981,7 @@ pub fn getUavVAddr( .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{ .source_off = @intCast(reloc_info.offset), .target_sym = sym_index, - .target_off = .rel(reloc_info.addend), + .target_off = reloc_info.addend, }), .plan9 => unreachable, .none => unreachable, diff --git a/src/link/Elf/relocation.zig b/src/link/Elf/relocation.zig index 9af4453948..047312cd68 100644 --- a/src/link/Elf/relocation.zig +++ b/src/link/Elf/relocation.zig @@ -108,13 +108,12 @@ pub const dwarf = struct { pub fn externalRelocType( target: Symbol, - is_got: bool, source_section: Dwarf.Section.Index, address_size: Dwarf.AddressSize, cpu_arch: std.Target.Cpu.Arch, ) u32 { return switch (cpu_arch) { - .x86_64 => @intFromEnum(@as(elf.R_X86_64, if (is_got) .GOT32 else switch (source_section) { + .x86_64 => @intFromEnum(@as(elf.R_X86_64, switch (source_section) { else => switch (address_size) { .@"32" => if (target.flags.is_tls) .DTPOFF32 else .@"32", .@"64" => if (target.flags.is_tls) .DTPOFF64 else .@"64", diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index aebfe6275f..a0de866544 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -648,7 +648,7 @@ pub fn getNavVAddr( .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{ .source_off = @intCast(reloc_info.offset), .target_sym = sym_index, - .target_off = .rel(reloc_info.addend), + .target_off = reloc_info.addend, }), .plan9 => unreachable, .none => unreachable, @@ -688,7 +688,7 @@ pub fn getUavVAddr( .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{ .source_off = @intCast(reloc_info.offset), .target_sym = sym_index, - .target_off = .rel(reloc_info.addend), + .target_off = reloc_info.addend, }), .plan9 => unreachable, .none => unreachable, diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 338eff4e7b..69684724a5 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -2376,7 +2376,7 @@ pub const FunctionImportId = enum(u32) { const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; const ext = ip.getNav(i.ptr(wasm).*).getResolvedExtern(ip).?; - return !ext.is_weak_linkage and ext.lib_name != .none; + return ext.linkage != .weak and ext.lib_name != .none; }, }; } diff --git a/test/cases/compile_errors/@import_zon_bad_type.zig b/test/cases/compile_errors/@import_zon_bad_type.zig index d1ccfc312c..88bf6205dd 100644 --- a/test/cases/compile_errors/@import_zon_bad_type.zig +++ b/test/cases/compile_errors/@import_zon_bad_type.zig @@ -117,9 +117,9 @@ export fn testMutablePointer() void { // tmp.zig:37:38: note: imported here // neg_inf.zon:1:1: error: expected type '?u8' // tmp.zig:57:28: note: imported here -// neg_inf.zon:1:1: error: expected type 'tmp.testNonExhaustiveEnum__enum_522' +// neg_inf.zon:1:1: error: expected type 'tmp.testNonExhaustiveEnum__enum_525' // tmp.zig:62:39: note: imported here -// neg_inf.zon:1:1: error: expected type 'tmp.testUntaggedUnion__union_524' +// neg_inf.zon:1:1: error: expected type 'tmp.testUntaggedUnion__union_527' // tmp.zig:67:44: note: imported here -// neg_inf.zon:1:1: error: expected type 'tmp.testTaggedUnionVoid__union_527' +// neg_inf.zon:1:1: error: expected type 'tmp.testTaggedUnionVoid__union_530' // tmp.zig:72:50: note: imported here diff --git a/test/cases/compile_errors/anytype_param_requires_comptime.zig b/test/cases/compile_errors/anytype_param_requires_comptime.zig index c0990a9ed3..7bbb1d3c6e 100644 --- a/test/cases/compile_errors/anytype_param_requires_comptime.zig +++ b/test/cases/compile_errors/anytype_param_requires_comptime.zig @@ -15,6 +15,6 @@ pub export fn entry() void { // error // // :7:25: error: unable to resolve comptime value -// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_496.C' must be comptime-known +// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_499.C' must be comptime-known // :4:16: note: struct requires comptime because of this field // :4:16: note: types are not available at runtime diff --git a/test/cases/compile_errors/bogus_method_call_on_slice.zig b/test/cases/compile_errors/bogus_method_call_on_slice.zig index 4e35c4264e..b5ffe15549 100644 --- a/test/cases/compile_errors/bogus_method_call_on_slice.zig +++ b/test/cases/compile_errors/bogus_method_call_on_slice.zig @@ -16,5 +16,5 @@ pub export fn entry2() void { // // :3:6: error: no field or member function named 'copy' in '[]const u8' // :9:8: error: no field or member function named 'bar' in '@TypeOf(.{})' -// :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_500' +// :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_503' // :12:6: note: struct declared here diff --git a/test/cases/compile_errors/coerce_anon_struct.zig b/test/cases/compile_errors/coerce_anon_struct.zig index 9b515762b1..2de29e8aae 100644 --- a/test/cases/compile_errors/coerce_anon_struct.zig +++ b/test/cases/compile_errors/coerce_anon_struct.zig @@ -6,6 +6,6 @@ export fn foo() void { // error // -// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_489' +// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_492' // :3:16: note: struct declared here // :1:11: note: struct declared here diff --git a/test/cases/compile_errors/redundant_try.zig b/test/cases/compile_errors/redundant_try.zig index b6d030686b..19d8070f80 100644 --- a/test/cases/compile_errors/redundant_try.zig +++ b/test/cases/compile_errors/redundant_try.zig @@ -44,9 +44,9 @@ comptime { // // :5:23: error: expected error union type, found 'comptime_int' // :10:23: error: expected error union type, found '@TypeOf(.{})' -// :15:23: error: expected error union type, found 'tmp.test2__struct_526' +// :15:23: error: expected error union type, found 'tmp.test2__struct_529' // :15:23: note: struct declared here -// :20:27: error: expected error union type, found 'tmp.test3__struct_528' +// :20:27: error: expected error union type, found 'tmp.test3__struct_531' // :20:27: note: struct declared here // :25:23: error: expected error union type, found 'struct { comptime *const [5:0]u8 = "hello" }' // :31:13: error: expected error union type, found 'u32' diff --git a/test/tests.zig b/test/tests.zig index c45e3ef561..ab42dbba26 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -1598,7 +1598,9 @@ const c_abi_targets = blk: { break :blk [_]CAbiTarget{ // Native Targets - .{}, + .{ + .use_llvm = true, + }, // Linux Targets @@ -1837,7 +1839,6 @@ const c_abi_targets = blk: { .abi = .musl, }, .use_llvm = false, - .use_lld = false, .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"}, }, .{ @@ -1848,7 +1849,6 @@ const c_abi_targets = blk: { .abi = .musl, }, .use_llvm = false, - .use_lld = false, .strip = true, .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"}, }, @@ -1860,7 +1860,6 @@ const c_abi_targets = blk: { .abi = .musl, }, .use_llvm = false, - .use_lld = false, .pic = true, .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"}, }, @@ -1870,6 +1869,7 @@ const c_abi_targets = blk: { .os_tag = .linux, .abi = .musl, }, + .use_llvm = true, }, .{ .target = .{ @@ -1877,6 +1877,7 @@ const c_abi_targets = blk: { .os_tag = .linux, .abi = .muslx32, }, + .use_llvm = true, }, // WASI Targets