From 000b053271c5adb54f65230d559bfba3cbe1508b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 7 Oct 2026 09:27:14 +0200 Subject: [PATCH 1/6] Elf2: handle R_SPARC_WDISP30 as pltrel like R_SPARC_WPLT30 Matches what other linkers do and what compilers seem to expect. --- src/link/Elf2.zig | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig index a08d5add1320da6a52a8bc63e75765aa97588a85..c73fc01c3917478444bd1c19a33aeb276eb0ddc8 100644 --- a/src/link/Elf2.zig +++ b/src/link/Elf2.zig @@ -9070,11 +9070,10 @@ fn addRelocAssumeCapacity( .PLT32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.pltabs, .{ .dest = .@"32", .cast = .unsigned, .shift = .@"0" })), .PLT64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.pltabs, .{ .dest = .@"64", .cast = .unsigned, .shift = .@"0" })), - .WDISP30 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.rel, .{ .dest = .@"32[29:0]", .cast = .signed, .shift = .@"2_exact" })), - .WPLT30 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.pltrel, .{ .dest = .@"32[29:0]", .cast = .signed, .shift = .@"2_exact" })), - .PC22 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.rel, .{ .dest = .@"32[21:0]", .cast = .unsigned, .shift = .@"10" })), - .H44 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.abs, .{ .dest = .@"32[21:0]", .cast = .unsigned, .shift = .@"22" })), - .M44 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.abs, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"12" })), + .WDISP30, .WPLT30 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.pltrel, .{ .dest = .@"32[29:0]", .cast = .signed, .shift = .@"2_exact" })), + .PC22 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.rel, .{ .dest = .@"32[21:0]", .cast = .unsigned, .shift = .@"10" })), + .H44 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.abs, .{ .dest = .@"32[21:0]", .cast = .unsigned, .shift = .@"22" })), + .M44 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.abs, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"12" })), .TLS_LDO_HIX22 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.dtpoff, .{ .dest = .@"32[21:0]", .cast = .trunc, .shift = .@"10" })), .TLS_LE_HIX22 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .special(.sparc_le_hix22)), -- 2.54.0 From 20529b8e566f174db633112eeecb017db6140632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 7 Oct 2026 09:46:13 +0200 Subject: [PATCH 2/6] Elf2: fix sparc64 lazy PLT stub branching in the wrong direction --- src/link/Elf2.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig index c73fc01c3917478444bd1c19a33aeb276eb0ddc8..b94a2099056b1a997b4fda6dc28f892c4c490b90 100644 --- a/src/link/Elf2.zig +++ b/src/link/Elf2.zig @@ -11943,7 +11943,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool { // sethi (. - .plt[0]), %g1 .{ .imm22 = .{ .imm = @truncate(got_plt_offset), .op = 0b0000001100 } }, // ba,a %xcc, .plt[1] - .{ .disp19 = .{ .disp = @truncate((got_plt_offset + 4 - 32) >> 2), .op = 0b0011000001101 } }, + .{ .disp19 = .{ .disp = @truncate((32 -% (got_plt_offset + 4)) >> 2), .op = 0b0011000001101 } }, // nop .{ .raw = 0x0100_0000 }, // nop -- 2.54.0 From 199d0b90294af4fbec6890b2675c3272da0be1cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 16 Aug 2026 09:38:02 +0200 Subject: [PATCH 3/6] glibc: build Scrt1.o and libc_nonshared.a as PIC These have to be PIC; don't rely on the compiler's defaults for the target. --- src/libs/glibc.zig | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libs/glibc.zig b/src/libs/glibc.zig index 86c5360cc17cce248afeac8ddcfb5bb4b2f9ceca..024588644a8c69c12fc323c4c812468abff565d1 100644 --- a/src/libs/glibc.zig +++ b/src/libs/glibc.zig @@ -243,7 +243,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre }; var files = [_]Compilation.CSourceFile{ start_o, abi_note_o, init_o }; const basename = if (comp.config.output_mode == .Exe and !comp.config.pie) "crt1" else "Scrt1"; - return comp.build_crt_file(basename, .Obj, .@"glibc Scrt1.o", prog_node, &files, .{}); + return comp.build_crt_file(basename, .Obj, .@"glibc Scrt1.o", prog_node, &files, .{ + .pic = true, + }); }, .libc_nonshared_a => { const s = path.sep_str; @@ -356,7 +358,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre files_index += 1; } const files = files_buf[0..files_index]; - return comp.build_crt_file("c_nonshared", .Lib, .@"glibc libc_nonshared.a", prog_node, files, .{}); + return comp.build_crt_file("c_nonshared", .Lib, .@"glibc libc_nonshared.a", prog_node, files, .{ + .pic = true, + }); }, } } -- 2.54.0 From 701cae9d6b54f180fb2e2d62e55a0d890af8b182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 16 Aug 2026 09:38:30 +0200 Subject: [PATCH 4/6] compiler: don't require PIC when linking libc This allows linking statically against native libc with -fno-PIC. --- src/Module.zig | 2 +- src/target.zig | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index e66982fa3af97ce9d4ff70522d8bd2073560ed51..6e8efa1591a0cb05910ae3aa6efb68ce085af7b8 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -174,7 +174,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module { }; const pic = b: { - if (target_util.requiresPic(target, options.global.link_libc)) { + if (target_util.requiresPic(target)) { if (options.inherited.pic == false) return error.TargetRequiresPic; break :b true; diff --git a/src/target.zig b/src/target.zig index 244b95d154fa12af2e70b8cc3cd39f0322272def..f3fe06954f6789aec3a18bb1d91f2fb1ef6642b2 100644 --- a/src/target.zig +++ b/src/target.zig @@ -72,10 +72,8 @@ pub fn requiresPie(target: *const std.Target, link_mode: std.lang.LinkMode) bool } /// This function returns whether non-pic code is completely invalid on the given target. -pub fn requiresPic(target: *const std.Target, linking_libc: bool) bool { - return ((target.os.tag == .windows or target.os.tag == .uefi) and (target.cpu.arch == .aarch64 or target.cpu.arch == .x86_64)) or - target.requiresLibC() or - (linking_libc and target.isGnuLibC()); +pub fn requiresPic(target: *const std.Target) bool { + return (target.os.tag == .windows or target.os.tag == .uefi) and (target.cpu.arch == .aarch64 or target.cpu.arch == .x86_64); } pub fn requiresPicForDynamicLink(target: *const std.Target) bool { -- 2.54.0 From c19cd5b8920ae242e582bbb1f843c9c255318ea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 16 Aug 2026 11:51:03 +0200 Subject: [PATCH 5/6] compiler: only require PIC for dynamic *library* compilations --- src/Module.zig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Module.zig b/src/Module.zig index 6e8efa1591a0cb05910ae3aa6efb68ce085af7b8..a6054a9181278e73390f9a04e9ee19c96111fb05 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -184,7 +184,10 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module { return error.PieRequiresPic; break :b true; } - if (options.global.link_mode == .dynamic and target_util.requiresPicForDynamicLink(target)) { + if (options.global.output_mode == .Lib and + options.global.link_mode == .dynamic and + target_util.requiresPicForDynamicLink(target)) + { if (options.inherited.pic == false) return error.DynamicLinkingRequiresPic; break :b true; -- 2.54.0 From 399eaa3d410da35de6f5d1869932a7c0e8ca46b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 16 Aug 2026 14:59:34 +0200 Subject: [PATCH 6/6] compiler: default to PIC for objects and static libraries This makes it so that objects and static libraries produced by Zig can be linked into PIEs and shared libraries by default. This matches how almost all C/C++ toolchains are configured in Linux/BSD distros today. For cases where the user knows better and wants to squeeze out some (usually very minor) extra performance, they can just explicitly disable PIC when producing the object or static library. --- src/Module.zig | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index a6054a9181278e73390f9a04e9ee19c96111fb05..5154b853641c4ed2af01fd0aed1b8c1f911204a6 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -195,10 +195,9 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module { if (options.inherited.pic) |x| break :b x; if (options.parent) |p| break :b p.pic; - // Default to PIC on targets where we default to producing PIEs to make - // the common case of linking objects and static libraries into an - // executable work out of the box. - break :b target_util.defaultPie(target); + // Default to PIC for objects and static libraries to make the common + // cases of linking those into a PIE or a shared library just work. + break :b options.global.output_mode != .Exe; }; const red_zone = b: { -- 2.54.0