| author | |
| committer | |
| log | 30e254fc311875720466d9a2b19d06e5599cd8c1 |
| tree | e0ade21398e53abe485c50d274c9cf8b968c79f8 |
| parent | 5668c8b7babfdc00ace04feceb9bcf8b95681982 |
| signature |
This allows emitting object files for s390x-zos (GOFF) and powerpc(64)-aix
(XCOFF).
Note that GOFF emission in LLVM is still being worked on upstream for LLVM 21;
the resulting object files are useless right now. Also, -fstrip is required, or
LLVM will SIGSEGV during DWARF emission.5 files changed, 264 insertions(+), 6 deletions(-)
CMakeLists.txt+2| ... | ... | @@ -612,6 +612,7 @@ set(ZIG_STAGE2_SOURCES |
| 612 | 612 | src/link/Elf/relocatable.zig |
| 613 | 613 | src/link/Elf/relocation.zig |
| 614 | 614 | src/link/Elf/synthetic_sections.zig |
| 615 | src/link/Goff.zig | |
| 615 | 616 | src/link/LdScript.zig |
| 616 | 617 | src/link/MachO.zig |
| 617 | 618 | src/link/MachO/Archive.zig |
| ... | ... | @@ -652,6 +653,7 @@ set(ZIG_STAGE2_SOURCES |
| 652 | 653 | src/link/Wasm/Archive.zig |
| 653 | 654 | src/link/Wasm/Flush.zig |
| 654 | 655 | src/link/Wasm/Object.zig |
| 656 | src/link/Xcoff.zig | |
| 655 | 657 | src/link/aarch64.zig |
| 656 | 658 | src/link/riscv.zig |
| 657 | 659 | src/link/table_section.zig |
src/dev.zig+4| ... | ... | @@ -82,6 +82,8 @@ pub const Env = enum { |
| 82 | 82 | .spirv_linker, |
| 83 | 83 | .plan9_linker, |
| 84 | 84 | .nvptx_linker, |
| 85 | .goff_linker, | |
| 86 | .xcoff_linker, | |
| 85 | 87 | => true, |
| 86 | 88 | .cc_command, |
| 87 | 89 | .translate_c_command, |
| ... | ... | @@ -228,6 +230,8 @@ pub const Feature = enum { |
| 228 | 230 | spirv_linker, |
| 229 | 231 | plan9_linker, |
| 230 | 232 | nvptx_linker, |
| 233 | goff_linker, | |
| 234 | xcoff_linker, | |
| 231 | 235 | }; |
| 232 | 236 | |
| 233 | 237 | /// 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 { |
| 556 | 556 | const comp = base.comp; |
| 557 | 557 | const gpa = comp.gpa; |
| 558 | 558 | switch (base.tag) { |
| 559 | .coff, .elf, .macho, .plan9, .wasm => { | |
| 559 | .coff, .elf, .macho, .plan9, .wasm, .goff, .xcoff => { | |
| 560 | 560 | 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 }); | |
| 562 | 562 | const emit = base.emit; |
| 563 | 563 | if (base.child_pid) |pid| { |
| 564 | 564 | if (builtin.os.tag == .windows) { |
| ... | ... | @@ -650,8 +650,8 @@ pub const File = struct { |
| 650 | 650 | } |
| 651 | 651 | } |
| 652 | 652 | }, |
| 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 }); | |
| 655 | 655 | if (base.zcu_object_sub_path != null) { |
| 656 | 656 | // The file we have open is not the final file that we want to |
| 657 | 657 | // make executable, so we don't have to close it. |
| ... | ... | @@ -767,6 +767,7 @@ pub const File = struct { |
| 767 | 767 | |
| 768 | 768 | switch (base.tag) { |
| 769 | 769 | .spirv, .nvptx => {}, |
| 770 | .goff, .xcoff => {}, | |
| 770 | 771 | inline else => |tag| { |
| 771 | 772 | dev.check(tag.devFeature()); |
| 772 | 773 | return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id); |
| ... | ... | @@ -902,6 +903,7 @@ pub const File = struct { |
| 902 | 903 | .spirv => unreachable, |
| 903 | 904 | .nvptx => unreachable, |
| 904 | 905 | .wasm => unreachable, |
| 906 | .goff, .xcoff => unreachable, | |
| 905 | 907 | inline else => |tag| { |
| 906 | 908 | dev.check(tag.devFeature()); |
| 907 | 909 | return @as(*tag.Type(), @fieldParentPtr("base", base)).getNavVAddr(pt, nav_index, reloc_info); |
| ... | ... | @@ -921,6 +923,7 @@ pub const File = struct { |
| 921 | 923 | .spirv => unreachable, |
| 922 | 924 | .nvptx => unreachable, |
| 923 | 925 | .wasm => unreachable, |
| 926 | .goff, .xcoff => unreachable, | |
| 924 | 927 | inline else => |tag| { |
| 925 | 928 | dev.check(tag.devFeature()); |
| 926 | 929 | return @as(*tag.Type(), @fieldParentPtr("base", base)).lowerUav(pt, decl_val, decl_align, src_loc); |
| ... | ... | @@ -934,6 +937,7 @@ pub const File = struct { |
| 934 | 937 | .spirv => unreachable, |
| 935 | 938 | .nvptx => unreachable, |
| 936 | 939 | .wasm => unreachable, |
| 940 | .goff, .xcoff => unreachable, | |
| 937 | 941 | inline else => |tag| { |
| 938 | 942 | dev.check(tag.devFeature()); |
| 939 | 943 | return @as(*tag.Type(), @fieldParentPtr("base", base)).getUavVAddr(decl_val, reloc_info); |
| ... | ... | @@ -950,6 +954,8 @@ pub const File = struct { |
| 950 | 954 | .plan9, |
| 951 | 955 | .spirv, |
| 952 | 956 | .nvptx, |
| 957 | .goff, | |
| 958 | .xcoff, | |
| 953 | 959 | => {}, |
| 954 | 960 | |
| 955 | 961 | inline else => |tag| { |
| ... | ... | @@ -1246,6 +1252,8 @@ pub const File = struct { |
| 1246 | 1252 | spirv, |
| 1247 | 1253 | plan9, |
| 1248 | 1254 | nvptx, |
| 1255 | goff, | |
| 1256 | xcoff, | |
| 1249 | 1257 | |
| 1250 | 1258 | pub fn Type(comptime tag: Tag) type { |
| 1251 | 1259 | return switch (tag) { |
| ... | ... | @@ -1257,6 +1265,8 @@ pub const File = struct { |
| 1257 | 1265 | .spirv => SpirV, |
| 1258 | 1266 | .plan9 => Plan9, |
| 1259 | 1267 | .nvptx => NvPtx, |
| 1268 | .goff => Goff, | |
| 1269 | .xcoff => Xcoff, | |
| 1260 | 1270 | }; |
| 1261 | 1271 | } |
| 1262 | 1272 | |
| ... | ... | @@ -1270,8 +1280,8 @@ pub const File = struct { |
| 1270 | 1280 | .c => .c, |
| 1271 | 1281 | .spirv => .spirv, |
| 1272 | 1282 | .nvptx => .nvptx, |
| 1273 | .goff => @panic("TODO implement goff object format"), | |
| 1274 | .xcoff => @panic("TODO implement xcoff object format"), | |
| 1283 | .goff => .goff, | |
| 1284 | .xcoff => .xcoff, | |
| 1275 | 1285 | .hex => @panic("TODO implement hex object format"), |
| 1276 | 1286 | .raw => @panic("TODO implement raw object format"), |
| 1277 | 1287 | }; |
| ... | ... | @@ -1377,6 +1387,8 @@ pub const File = struct { |
| 1377 | 1387 | pub const SpirV = @import("link/SpirV.zig"); |
| 1378 | 1388 | pub const Wasm = @import("link/Wasm.zig"); |
| 1379 | 1389 | pub const NvPtx = @import("link/NvPtx.zig"); |
| 1390 | pub const Goff = @import("link/Goff.zig"); | |
| 1391 | pub const Xcoff = @import("link/Xcoff.zig"); | |
| 1380 | 1392 | pub const Dwarf = @import("link/Dwarf.zig"); |
| 1381 | 1393 | }; |
| 1382 | 1394 |
src/link/Goff.zig created+120| ... | ... | @@ -0,0 +1,120 @@ |
| 1 | //! Stub linker support for GOFF based on LLVM. | |
| 2 | ||
| 3 | const Goff = @This(); | |
| 4 | ||
| 5 | const std = @import("std"); | |
| 6 | const builtin = @import("builtin"); | |
| 7 | ||
| 8 | const Allocator = std.mem.Allocator; | |
| 9 | const assert = std.debug.assert; | |
| 10 | const log = std.log.scoped(.link); | |
| 11 | const Path = std.Build.Cache.Path; | |
| 12 | ||
| 13 | const Zcu = @import("../Zcu.zig"); | |
| 14 | const InternPool = @import("../InternPool.zig"); | |
| 15 | const Compilation = @import("../Compilation.zig"); | |
| 16 | const link = @import("../link.zig"); | |
| 17 | const trace = @import("../tracy.zig").trace; | |
| 18 | const build_options = @import("build_options"); | |
| 19 | const Air = @import("../Air.zig"); | |
| 20 | const Liveness = @import("../Liveness.zig"); | |
| 21 | const LlvmObject = @import("../codegen/llvm.zig").Object; | |
| 22 | ||
| 23 | base: link.File, | |
| 24 | llvm_object: LlvmObject.Ptr, | |
| 25 | ||
| 26 | pub 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 | ||
| 62 | pub 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 | ||
| 73 | pub fn deinit(self: *Goff) void { | |
| 74 | self.llvm_object.deinit(); | |
| 75 | } | |
| 76 | ||
| 77 | pub 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 | ||
| 90 | pub 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 | ||
| 97 | pub 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 | ||
| 109 | pub 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 | ||
| 113 | pub 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 | ||
| 3 | const Xcoff = @This(); | |
| 4 | ||
| 5 | const std = @import("std"); | |
| 6 | const builtin = @import("builtin"); | |
| 7 | ||
| 8 | const Allocator = std.mem.Allocator; | |
| 9 | const assert = std.debug.assert; | |
| 10 | const log = std.log.scoped(.link); | |
| 11 | const Path = std.Build.Cache.Path; | |
| 12 | ||
| 13 | const Zcu = @import("../Zcu.zig"); | |
| 14 | const InternPool = @import("../InternPool.zig"); | |
| 15 | const Compilation = @import("../Compilation.zig"); | |
| 16 | const link = @import("../link.zig"); | |
| 17 | const trace = @import("../tracy.zig").trace; | |
| 18 | const build_options = @import("build_options"); | |
| 19 | const Air = @import("../Air.zig"); | |
| 20 | const Liveness = @import("../Liveness.zig"); | |
| 21 | const LlvmObject = @import("../codegen/llvm.zig").Object; | |
| 22 | ||
| 23 | base: link.File, | |
| 24 | llvm_object: LlvmObject.Ptr, | |
| 25 | ||
| 26 | pub 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 | ||
| 62 | pub 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 | ||
| 73 | pub fn deinit(self: *Xcoff) void { | |
| 74 | self.llvm_object.deinit(); | |
| 75 | } | |
| 76 | ||
| 77 | pub 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 | ||
| 90 | pub 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 | ||
| 97 | pub 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 | ||
| 109 | pub 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 | ||
| 113 | pub 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 | } |