authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-04-28 07:50:37+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-04-28 07:50:37+02:00
logfc55c1b7a1b62f0ffa4de5dfcfba03c84feb1ca5
treea115485358a93df33064bb293074ea1b537e9db5
parent410298271eae2535e39a9de433afc8159704e7c6
parent2d44bc5d2baac8b49e7e570e13f18132d8bdc6f2
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #23698 from alexrp/goff-xcoff-stubs

`link`: Stub out GOFF/XCOFF linker code based on LLVM

7 files changed, 267 insertions(+), 9 deletions(-)

CMakeLists.txt+2
......@@ -612,6 +612,7 @@ set(ZIG_STAGE2_SOURCES
612612 src/link/Elf/relocatable.zig
613613 src/link/Elf/relocation.zig
614614 src/link/Elf/synthetic_sections.zig
615 src/link/Goff.zig
615616 src/link/LdScript.zig
616617 src/link/MachO.zig
617618 src/link/MachO/Archive.zig
......@@ -652,6 +653,7 @@ set(ZIG_STAGE2_SOURCES
652653 src/link/Wasm/Archive.zig
653654 src/link/Wasm/Flush.zig
654655 src/link/Wasm/Object.zig
656 src/link/Xcoff.zig
655657 src/link/aarch64.zig
656658 src/link/riscv.zig
657659 src/link/table_section.zig
src/codegen/llvm.zig+1-1
......@@ -398,7 +398,7 @@ pub fn dataLayout(target: std.Target) []const u8 {
398398 .sparc => "E-m:e-p:32:32-i64:64-i128:128-f128:64-n32-S64",
399399 .sparc64 => "E-m:e-i64:64-i128:128-n32:64-S128",
400400 .s390x => if (target.os.tag == .zos)
401 "E-m:l-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64"
401 "E-m:l-p1:32:32-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64"
402402 else
403403 "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64",
404404 .x86 => if (target.os.tag == .windows) switch (target.abi) {
src/dev.zig+4
......@@ -82,6 +82,8 @@ pub const Env = enum {
8282 .spirv_linker,
8383 .plan9_linker,
8484 .nvptx_linker,
85 .goff_linker,
86 .xcoff_linker,
8587 => true,
8688 .cc_command,
8789 .translate_c_command,
......@@ -228,6 +230,8 @@ pub const Feature = enum {
228230 spirv_linker,
229231 plan9_linker,
230232 nvptx_linker,
233 goff_linker,
234 xcoff_linker,
231235};
232236
233237/// Makes the code following the call to this function unreachable if `feature` is disabled.
src/link.zig+18-6
......@@ -556,9 +556,9 @@ pub const File = struct {
556556 const comp = base.comp;
557557 const gpa = comp.gpa;
558558 switch (base.tag) {
559 .coff, .elf, .macho, .plan9, .wasm => {
559 .coff, .elf, .macho, .plan9, .wasm, .goff, .xcoff => {
560560 if (base.file != null) return;
561 dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker });
561 dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker, .goff_linker, .xcoff_linker });
562562 const emit = base.emit;
563563 if (base.child_pid) |pid| {
564564 if (builtin.os.tag == .windows) {
......@@ -650,8 +650,8 @@ pub const File = struct {
650650 }
651651 }
652652 },
653 .coff, .macho, .plan9, .wasm => if (base.file) |f| {
654 dev.checkAny(&.{ .coff_linker, .macho_linker, .plan9_linker, .wasm_linker });
653 .coff, .macho, .plan9, .wasm, .goff, .xcoff => if (base.file) |f| {
654 dev.checkAny(&.{ .coff_linker, .macho_linker, .plan9_linker, .wasm_linker, .goff_linker, .xcoff_linker });
655655 if (base.zcu_object_sub_path != null) {
656656 // The file we have open is not the final file that we want to
657657 // make executable, so we don't have to close it.
......@@ -767,6 +767,7 @@ pub const File = struct {
767767
768768 switch (base.tag) {
769769 .spirv, .nvptx => {},
770 .goff, .xcoff => {},
770771 inline else => |tag| {
771772 dev.check(tag.devFeature());
772773 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id);
......@@ -902,6 +903,7 @@ pub const File = struct {
902903 .spirv => unreachable,
903904 .nvptx => unreachable,
904905 .wasm => unreachable,
906 .goff, .xcoff => unreachable,
905907 inline else => |tag| {
906908 dev.check(tag.devFeature());
907909 return @as(*tag.Type(), @fieldParentPtr("base", base)).getNavVAddr(pt, nav_index, reloc_info);
......@@ -921,6 +923,7 @@ pub const File = struct {
921923 .spirv => unreachable,
922924 .nvptx => unreachable,
923925 .wasm => unreachable,
926 .goff, .xcoff => unreachable,
924927 inline else => |tag| {
925928 dev.check(tag.devFeature());
926929 return @as(*tag.Type(), @fieldParentPtr("base", base)).lowerUav(pt, decl_val, decl_align, src_loc);
......@@ -934,6 +937,7 @@ pub const File = struct {
934937 .spirv => unreachable,
935938 .nvptx => unreachable,
936939 .wasm => unreachable,
940 .goff, .xcoff => unreachable,
937941 inline else => |tag| {
938942 dev.check(tag.devFeature());
939943 return @as(*tag.Type(), @fieldParentPtr("base", base)).getUavVAddr(decl_val, reloc_info);
......@@ -950,6 +954,8 @@ pub const File = struct {
950954 .plan9,
951955 .spirv,
952956 .nvptx,
957 .goff,
958 .xcoff,
953959 => {},
954960
955961 inline else => |tag| {
......@@ -1246,6 +1252,8 @@ pub const File = struct {
12461252 spirv,
12471253 plan9,
12481254 nvptx,
1255 goff,
1256 xcoff,
12491257
12501258 pub fn Type(comptime tag: Tag) type {
12511259 return switch (tag) {
......@@ -1257,6 +1265,8 @@ pub const File = struct {
12571265 .spirv => SpirV,
12581266 .plan9 => Plan9,
12591267 .nvptx => NvPtx,
1268 .goff => Goff,
1269 .xcoff => Xcoff,
12601270 };
12611271 }
12621272
......@@ -1270,8 +1280,8 @@ pub const File = struct {
12701280 .c => .c,
12711281 .spirv => .spirv,
12721282 .nvptx => .nvptx,
1273 .goff => @panic("TODO implement goff object format"),
1274 .xcoff => @panic("TODO implement xcoff object format"),
1283 .goff => .goff,
1284 .xcoff => .xcoff,
12751285 .hex => @panic("TODO implement hex object format"),
12761286 .raw => @panic("TODO implement raw object format"),
12771287 };
......@@ -1377,6 +1387,8 @@ pub const File = struct {
13771387 pub const SpirV = @import("link/SpirV.zig");
13781388 pub const Wasm = @import("link/Wasm.zig");
13791389 pub const NvPtx = @import("link/NvPtx.zig");
1390 pub const Goff = @import("link/Goff.zig");
1391 pub const Xcoff = @import("link/Xcoff.zig");
13801392 pub const Dwarf = @import("link/Dwarf.zig");
13811393};
13821394
src/link/Goff.zig created+120
......@@ -0,0 +1,120 @@
1//! Stub linker support for GOFF based on LLVM.
2
3const Goff = @This();
4
5const std = @import("std");
6const builtin = @import("builtin");
7
8const Allocator = std.mem.Allocator;
9const assert = std.debug.assert;
10const log = std.log.scoped(.link);
11const Path = std.Build.Cache.Path;
12
13const Zcu = @import("../Zcu.zig");
14const InternPool = @import("../InternPool.zig");
15const Compilation = @import("../Compilation.zig");
16const link = @import("../link.zig");
17const trace = @import("../tracy.zig").trace;
18const build_options = @import("build_options");
19const Air = @import("../Air.zig");
20const Liveness = @import("../Liveness.zig");
21const LlvmObject = @import("../codegen/llvm.zig").Object;
22
23base: link.File,
24llvm_object: LlvmObject.Ptr,
25
26pub fn createEmpty(
27 arena: Allocator,
28 comp: *Compilation,
29 emit: Path,
30 options: link.File.OpenOptions,
31) !*Goff {
32 const target = comp.root_mod.resolved_target.result;
33 const use_lld = build_options.have_llvm and comp.config.use_lld;
34 const use_llvm = comp.config.use_llvm;
35
36 assert(use_llvm); // Caught by Compilation.Config.resolve.
37 assert(!use_lld); // Caught by Compilation.Config.resolve.
38 assert(target.os.tag == .zos); // Caught by Compilation.Config.resolve.
39
40 const llvm_object = try LlvmObject.create(arena, comp);
41 const goff = try arena.create(Goff);
42 goff.* = .{
43 .base = .{
44 .tag = .goff,
45 .comp = comp,
46 .emit = emit,
47 .zcu_object_sub_path = emit.sub_path,
48 .gc_sections = options.gc_sections orelse false,
49 .print_gc_sections = options.print_gc_sections,
50 .stack_size = options.stack_size orelse 0,
51 .allow_shlib_undefined = options.allow_shlib_undefined orelse false,
52 .file = null,
53 .disable_lld_caching = options.disable_lld_caching,
54 .build_id = options.build_id,
55 },
56 .llvm_object = llvm_object,
57 };
58
59 return goff;
60}
61
62pub fn open(
63 arena: Allocator,
64 comp: *Compilation,
65 emit: Path,
66 options: link.File.OpenOptions,
67) !*Goff {
68 const target = comp.root_mod.resolved_target.result;
69 assert(target.ofmt == .goff);
70 return createEmpty(arena, comp, emit, options);
71}
72
73pub fn deinit(self: *Goff) void {
74 self.llvm_object.deinit();
75}
76
77pub fn updateFunc(
78 self: *Goff,
79 pt: Zcu.PerThread,
80 func_index: InternPool.Index,
81 air: Air,
82 liveness: Liveness,
83) link.File.UpdateNavError!void {
84 if (build_options.skip_non_native and builtin.object_format != .goff)
85 @panic("Attempted to compile for object format that was disabled by build configuration");
86
87 try self.llvm_object.updateFunc(pt, func_index, air, liveness);
88}
89
90pub fn updateNav(self: *Goff, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.File.UpdateNavError!void {
91 if (build_options.skip_non_native and builtin.object_format != .goff)
92 @panic("Attempted to compile for object format that was disabled by build configuration");
93
94 return self.llvm_object.updateNav(pt, nav);
95}
96
97pub fn updateExports(
98 self: *Goff,
99 pt: Zcu.PerThread,
100 exported: Zcu.Exported,
101 export_indices: []const Zcu.Export.Index,
102) !void {
103 if (build_options.skip_non_native and builtin.object_format != .goff)
104 @panic("Attempted to compile for object format that was disabled by build configuration");
105
106 return self.llvm_object.updateExports(pt, exported, export_indices);
107}
108
109pub fn flush(self: *Goff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
110 return self.flushModule(arena, tid, prog_node);
111}
112
113pub fn flushModule(self: *Goff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
114 if (build_options.skip_non_native and builtin.object_format != .goff)
115 @panic("Attempted to compile for object format that was disabled by build configuration");
116
117 _ = tid;
118
119 try self.base.emitLlvmObject(arena, self.llvm_object, prog_node);
120}
src/link/Xcoff.zig created+120
......@@ -0,0 +1,120 @@
1//! Stub linker support for GOFF based on LLVM.
2
3const Xcoff = @This();
4
5const std = @import("std");
6const builtin = @import("builtin");
7
8const Allocator = std.mem.Allocator;
9const assert = std.debug.assert;
10const log = std.log.scoped(.link);
11const Path = std.Build.Cache.Path;
12
13const Zcu = @import("../Zcu.zig");
14const InternPool = @import("../InternPool.zig");
15const Compilation = @import("../Compilation.zig");
16const link = @import("../link.zig");
17const trace = @import("../tracy.zig").trace;
18const build_options = @import("build_options");
19const Air = @import("../Air.zig");
20const Liveness = @import("../Liveness.zig");
21const LlvmObject = @import("../codegen/llvm.zig").Object;
22
23base: link.File,
24llvm_object: LlvmObject.Ptr,
25
26pub fn createEmpty(
27 arena: Allocator,
28 comp: *Compilation,
29 emit: Path,
30 options: link.File.OpenOptions,
31) !*Xcoff {
32 const target = comp.root_mod.resolved_target.result;
33 const use_lld = build_options.have_llvm and comp.config.use_lld;
34 const use_llvm = comp.config.use_llvm;
35
36 assert(use_llvm); // Caught by Compilation.Config.resolve.
37 assert(!use_lld); // Caught by Compilation.Config.resolve.
38 assert(target.os.tag == .aix); // Caught by Compilation.Config.resolve.
39
40 const llvm_object = try LlvmObject.create(arena, comp);
41 const xcoff = try arena.create(Xcoff);
42 xcoff.* = .{
43 .base = .{
44 .tag = .xcoff,
45 .comp = comp,
46 .emit = emit,
47 .zcu_object_sub_path = emit.sub_path,
48 .gc_sections = options.gc_sections orelse false,
49 .print_gc_sections = options.print_gc_sections,
50 .stack_size = options.stack_size orelse 0,
51 .allow_shlib_undefined = options.allow_shlib_undefined orelse false,
52 .file = null,
53 .disable_lld_caching = options.disable_lld_caching,
54 .build_id = options.build_id,
55 },
56 .llvm_object = llvm_object,
57 };
58
59 return xcoff;
60}
61
62pub fn open(
63 arena: Allocator,
64 comp: *Compilation,
65 emit: Path,
66 options: link.File.OpenOptions,
67) !*Xcoff {
68 const target = comp.root_mod.resolved_target.result;
69 assert(target.ofmt == .xcoff);
70 return createEmpty(arena, comp, emit, options);
71}
72
73pub fn deinit(self: *Xcoff) void {
74 self.llvm_object.deinit();
75}
76
77pub fn updateFunc(
78 self: *Xcoff,
79 pt: Zcu.PerThread,
80 func_index: InternPool.Index,
81 air: Air,
82 liveness: Liveness,
83) link.File.UpdateNavError!void {
84 if (build_options.skip_non_native and builtin.object_format != .xcoff)
85 @panic("Attempted to compile for object format that was disabled by build configuration");
86
87 try self.llvm_object.updateFunc(pt, func_index, air, liveness);
88}
89
90pub fn updateNav(self: *Xcoff, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.File.UpdateNavError!void {
91 if (build_options.skip_non_native and builtin.object_format != .xcoff)
92 @panic("Attempted to compile for object format that was disabled by build configuration");
93
94 return self.llvm_object.updateNav(pt, nav);
95}
96
97pub fn updateExports(
98 self: *Xcoff,
99 pt: Zcu.PerThread,
100 exported: Zcu.Exported,
101 export_indices: []const Zcu.Export.Index,
102) !void {
103 if (build_options.skip_non_native and builtin.object_format != .xcoff)
104 @panic("Attempted to compile for object format that was disabled by build configuration");
105
106 return self.llvm_object.updateExports(pt, exported, export_indices);
107}
108
109pub fn flush(self: *Xcoff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
110 return self.flushModule(arena, tid, prog_node);
111}
112
113pub fn flushModule(self: *Xcoff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
114 if (build_options.skip_non_native and builtin.object_format != .xcoff)
115 @panic("Attempted to compile for object format that was disabled by build configuration");
116
117 _ = tid;
118
119 try self.base.emitLlvmObject(arena, self.llvm_object, prog_node);
120}
test/llvm_targets.zig+2-2
......@@ -176,7 +176,7 @@ const targets = [_]std.Target.Query{
176176 .{ .cpu_arch = .nvptx64, .os_tag = .cuda, .abi = .none },
177177 .{ .cpu_arch = .nvptx64, .os_tag = .nvcl, .abi = .none },
178178
179 // .{ .cpu_arch = .powerpc, .os_tag = .aix, .abi = .eabihf },
179 .{ .cpu_arch = .powerpc, .os_tag = .aix, .abi = .eabihf },
180180 .{ .cpu_arch = .powerpc, .os_tag = .freebsd, .abi = .eabi },
181181 .{ .cpu_arch = .powerpc, .os_tag = .freebsd, .abi = .eabihf },
182182 .{ .cpu_arch = .powerpc, .os_tag = .freestanding, .abi = .eabi },
......@@ -199,7 +199,7 @@ const targets = [_]std.Target.Query{
199199 .{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .eabi },
200200 .{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .eabihf },
201201
202 // .{ .cpu_arch = .powerpc64, .os_tag = .aix, .abi = .none },
202 .{ .cpu_arch = .powerpc64, .os_tag = .aix, .abi = .none },
203203 .{ .cpu_arch = .powerpc64, .os_tag = .freebsd, .abi = .none },
204204 .{ .cpu_arch = .powerpc64, .os_tag = .freestanding, .abi = .none },
205205 .{ .cpu_arch = .powerpc64, .os_tag = .linux, .abi = .gnu },