authorgravatar for brad@comstyle.comBrad Smith <brad@comstyle.com> 2026-10-10 02:20:48-04:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-10-12 10:31:49+02:00
log8149fffb1b67da3d20089144d71787e73493e38b
tree9e1c2f09729ae923d3085ba01528bdcce559f6ed
parentec6ab51c26983de3d6f8fcdecd209e95f1e9a3ea
signature Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

link/Lld: always pass -pie or -no-pie for executables

When linking an executable, Zig only passed -pie when building a PIE and otherwise relied on LLD defaulting to non-PIE. That default isn't guaranteed: OpenBSD's system LLD defaults to PIE. With Zig built against it, non-PIE executables were linked as PIE, failing against non-PIC objects. For example, building stage3 on OpenBSD/aarch64 fails while generating the langref, when the global assembly doctest is linked for x86_64-linux: error: ld.lld: relocation R_X86_64_32S cannot be used against local symbol; recompile with -fPIC note: referenced by atomics.zig:104 (compiler_rt/atomics.zig:104) Pass -no-pie explicitly in the non-PIE case so the output matches comp.config.pie regardless of how LLD was built.

1 files changed, 4 insertions(+), 2 deletions(-)

src/link/Lld.zig+4-2
...@@ -1029,8 +1029,10 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {...@@ -1029,8 +1029,10 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
1029 try argv.append("-shared");1029 try argv.append("-shared");
1030 }1030 }
10311031
1032 if (comp.config.pie and output_mode == .Exe) {1032 if (output_mode == .Exe) {
1033 try argv.append("-pie");1033 // Always be explicit: some lld builds (e.g. OpenBSD's) default
1034 // to PIE, which breaks non-PIE executables for other targets.
1035 try argv.append(if (comp.config.pie) "-pie" else "-no-pie");
1034 }1036 }
10351037
1036 if (is_exe_or_dyn_lib and target.os.tag == .netbsd) {1038 if (is_exe_or_dyn_lib and target.os.tag == .netbsd) {