From 34c21affa2429cf07042eb2f225ee59194998802 Mon Sep 17 00:00:00 2001 From: jacob gw Date: Tue, 1 Jun 2021 16:07:08 -0400 Subject: initial plan9 boilerplate The code now compiles and fails with Plan9ObjectFormatUnimplemented --- src/Module.zig | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/Module.zig') diff --git a/src/Module.zig b/src/Module.zig index 8ae184a377..e95d6bf245 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -3437,6 +3437,9 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo // in `Decl` to notice that the line number did not change. mod.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl }); }, + .plan9 => { + // TODO implement for plan9 + }, .c, .wasm, .spirv => {}, } } @@ -3514,6 +3517,7 @@ pub fn clearDecl( .coff => .{ .coff = link.File.Coff.TextBlock.empty }, .elf => .{ .elf = link.File.Elf.TextBlock.empty }, .macho => .{ .macho = link.File.MachO.TextBlock.empty }, + .plan9 => @panic("plan9 link"), .c => .{ .c = link.File.C.DeclBlock.empty }, .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, .spirv => .{ .spirv = {} }, @@ -3522,6 +3526,7 @@ pub fn clearDecl( .coff => .{ .coff = {} }, .elf => .{ .elf = link.File.Elf.SrcFn.empty }, .macho => .{ .macho = link.File.MachO.SrcFn.empty }, + .plan9 => @panic("plan9 fn_link"), .c => .{ .c = link.File.C.FnBlock.empty }, .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, .spirv => .{ .spirv = .{} }, @@ -3689,6 +3694,7 @@ fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node .coff => .{ .coff = link.File.Coff.TextBlock.empty }, .elf => .{ .elf = link.File.Elf.TextBlock.empty }, .macho => .{ .macho = link.File.MachO.TextBlock.empty }, + .plan9 => @panic("PLan9 export"), .c => .{ .c = link.File.C.DeclBlock.empty }, .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, .spirv => .{ .spirv = {} }, @@ -3697,6 +3703,7 @@ fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node .coff => .{ .coff = {} }, .elf => .{ .elf = link.File.Elf.SrcFn.empty }, .macho => .{ .macho = link.File.MachO.SrcFn.empty }, + .plan9 => .{ .plan9 = link.File.Plan9.SrcFn.empty }, .c => .{ .c = link.File.C.FnBlock.empty }, .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, .spirv => .{ .spirv = .{} }, @@ -3766,6 +3773,7 @@ pub fn analyzeExport( .coff => .{ .coff = {} }, .elf => .{ .elf = link.File.Elf.Export{} }, .macho => .{ .macho = link.File.MachO.Export{} }, + .plan9 => @panic("plan9 link"), .c => .{ .c = {} }, .wasm => .{ .wasm = {} }, .spirv => .{ .spirv = {} }, -- cgit v1.2.3 From 798162e5095aff130395ee542c0c0948f95180c9 Mon Sep 17 00:00:00 2001 From: Jacob G-W Date: Tue, 1 Jun 2021 22:48:20 -0400 Subject: plan9 linker: make runnable binaries We can now run binaries! (they segfault, but still run!) --- src/Module.zig | 10 +-- src/codegen.zig | 16 +++- src/link.zig | 9 +- src/link/Plan9.zig | 217 +++++++++++++++++++++++++++++++++++++++++------ src/link/plan9/a.out.zig | 122 ++++++++++++++++++++++++++ 5 files changed, 335 insertions(+), 39 deletions(-) create mode 100644 src/link/plan9/a.out.zig (limited to 'src/Module.zig') diff --git a/src/Module.zig b/src/Module.zig index e95d6bf245..a1f6887fbd 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -3517,7 +3517,7 @@ pub fn clearDecl( .coff => .{ .coff = link.File.Coff.TextBlock.empty }, .elf => .{ .elf = link.File.Elf.TextBlock.empty }, .macho => .{ .macho = link.File.MachO.TextBlock.empty }, - .plan9 => @panic("plan9 link"), + .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty }, .c => .{ .c = link.File.C.DeclBlock.empty }, .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, .spirv => .{ .spirv = {} }, @@ -3526,7 +3526,7 @@ pub fn clearDecl( .coff => .{ .coff = {} }, .elf => .{ .elf = link.File.Elf.SrcFn.empty }, .macho => .{ .macho = link.File.MachO.SrcFn.empty }, - .plan9 => @panic("plan9 fn_link"), + .plan9 => .{ .plan9 = {} }, .c => .{ .c = link.File.C.FnBlock.empty }, .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, .spirv => .{ .spirv = .{} }, @@ -3694,7 +3694,7 @@ fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node .coff => .{ .coff = link.File.Coff.TextBlock.empty }, .elf => .{ .elf = link.File.Elf.TextBlock.empty }, .macho => .{ .macho = link.File.MachO.TextBlock.empty }, - .plan9 => @panic("PLan9 export"), + .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty }, .c => .{ .c = link.File.C.DeclBlock.empty }, .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, .spirv => .{ .spirv = {} }, @@ -3703,7 +3703,7 @@ fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node .coff => .{ .coff = {} }, .elf => .{ .elf = link.File.Elf.SrcFn.empty }, .macho => .{ .macho = link.File.MachO.SrcFn.empty }, - .plan9 => .{ .plan9 = link.File.Plan9.SrcFn.empty }, + .plan9 => .{ .plan9 = {} }, .c => .{ .c = link.File.C.FnBlock.empty }, .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, .spirv => .{ .spirv = .{} }, @@ -3773,7 +3773,7 @@ pub fn analyzeExport( .coff => .{ .coff = {} }, .elf => .{ .elf = link.File.Elf.Export{} }, .macho => .{ .macho = link.File.MachO.Export{} }, - .plan9 => @panic("plan9 link"), + .plan9 => .{ .plan9 = null }, .c => .{ .c = {} }, .wasm => .{ .wasm = {} }, .spirv => .{ .spirv = {} }, diff --git a/src/codegen.zig b/src/codegen.zig index 6b9bd633d0..61607407d3 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -2556,9 +2556,19 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { } else { return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); } - } else { - unreachable; - } + } else if (self.bin_file.cast(link.File.Plan9)) |p9| { + if (inst.func.value()) |func_value| { + if (func_value.castTag(.function)) |func_payload| { + try p9.addCallReloc(self.code, .{ + .caller = p9.cur_decl, + .callee = func_payload.data.owner_decl, + .offset_in_caller = self.code.items.len, + }); + } else return self.fail(inst.base.src, "TODO implement calling extern fn on plan9", .{}); + } else { + return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); + } + } else unreachable; switch (info.return_value) { .register => |reg| { diff --git a/src/link.zig b/src/link.zig index e5eb45ec91..9447397428 100644 --- a/src/link.zig +++ b/src/link.zig @@ -141,6 +141,7 @@ pub const File = struct { elf: Elf.TextBlock, coff: Coff.TextBlock, macho: MachO.TextBlock, + plan9: Plan9.DeclBlock, c: C.DeclBlock, wasm: Wasm.DeclBlock, spirv: void, @@ -150,7 +151,7 @@ pub const File = struct { elf: Elf.SrcFn, coff: Coff.SrcFn, macho: MachO.SrcFn, - plan9: Plan9.SrcFn, + plan9: void, c: C.FnBlock, wasm: Wasm.FnData, spirv: SpirV.FnData, @@ -207,12 +208,12 @@ pub const File = struct { .coff, .pe => &(try Coff.createEmpty(allocator, options)).base, .elf => &(try Elf.createEmpty(allocator, options)).base, .macho => &(try MachO.createEmpty(allocator, options)).base, + .plan9 => &(try Plan9.createEmpty(allocator, options)).base, .wasm => &(try Wasm.createEmpty(allocator, options)).base, .c => unreachable, // Reported error earlier. .spirv => &(try SpirV.createEmpty(allocator, options)).base, .hex => return error.HexObjectFormatUnimplemented, .raw => return error.RawObjectFormatUnimplemented, - .plan9 => return error.Plan9ObjectFormatUnimplemented, }; } // Open a temporary object file, not the final output file because we want to link with LLD. @@ -224,12 +225,12 @@ pub const File = struct { .coff, .pe => &(try Coff.openPath(allocator, sub_path, options)).base, .elf => &(try Elf.openPath(allocator, sub_path, options)).base, .macho => &(try MachO.openPath(allocator, sub_path, options)).base, + .plan9 => &(try Plan9.openPath(allocator, sub_path, options)).base, .wasm => &(try Wasm.openPath(allocator, sub_path, options)).base, .c => &(try C.openPath(allocator, sub_path, options)).base, .spirv => &(try SpirV.openPath(allocator, sub_path, options)).base, .hex => return error.HexObjectFormatUnimplemented, .raw => return error.RawObjectFormatUnimplemented, - .plan9 => return error.Plan9ObjectFormatUnimplemented, }; if (use_lld) { @@ -347,7 +348,7 @@ pub const File = struct { .macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl), .c => return @fieldParentPtr(C, "base", base).allocateDeclIndexes(decl), .wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl), - .plan9 => return @fieldParentPtr(Plan9, "base", base).allocateDeclIndexes(decl), + .plan9 => {}, .spirv => {}, } } diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 4459288f58..d179836fa6 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -4,35 +4,66 @@ const std = @import("std"); const link = @import("../link.zig"); const Module = @import("../Module.zig"); const Compilation = @import("../Compilation.zig"); +const aout = @import("plan9/a.out.zig"); +const codegen = @import("../codegen.zig"); +const trace = @import("../tracy.zig").trace; +const mem = std.mem; const File = link.File; const Allocator = std.mem.Allocator; const log = std.log.scoped(.link); +const assert = std.debug.assert; + +// TODO use incremental compilation base: link.File, +ptr_width: PtrWidth, error_flags: File.ErrorFlags = File.ErrorFlags{}, -pub const SrcFn = struct { - /// Offset from the beginning of the Debug Line Program header that contains this function. - off: u32, - /// Size of the line number program component belonging to this function, not - /// including padding. - len: u32, - - /// Points to the previous and next neighbors, based on the offset from .debug_line. - /// This can be used to find, for example, the capacity of this `SrcFn`. - prev: ?*SrcFn, - next: ?*SrcFn, - - pub const empty: SrcFn = .{ - .off = 0, - .len = 0, - .prev = null, - .next = null, +decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{}, +/// is just casted down when 32 bit +syms: std.ArrayListUnmanaged(aout.Sym64) = .{}, +call_relocs: std.ArrayListUnmanaged(CallReloc) = .{}, +text_buf: std.ArrayListUnmanaged(u8) = .{}, +data_buf: std.ArrayListUnmanaged(u8) = .{}, + +cur_decl: *Module.Decl = undefined, +hdr: aout.ExecHdr = undefined, + +fn headerSize(self: Plan9) u32 { + // fat header (currently unused) + const fat: u4 = if (self.ptr_width == .p64) 8 else 0; + return aout.ExecHdr.size() + fat; +} +pub const DeclBlock = struct { + type: enum { text, data }, + // offset in the text or data sects + offset: u32, + pub const empty = DeclBlock{ + .type = .text, + .offset = 0, }; }; +// TODO change base addr based on target (right now it just works on amd64) +const default_base_addr = 0x00200000; + +pub const CallReloc = struct { + caller: *Module.Decl, + callee: *Module.Decl, + offset_in_caller: usize, +}; + +pub const PtrWidth = enum { p32, p64 }; + pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { + if (options.use_llvm) + return error.LLVMBackendDoesNotSupportPlan9; + const ptr_width: PtrWidth = switch (options.target.cpu.arch.ptrBitWidth()) { + 0...32 => .p32, + 33...64 => .p64, + else => return error.UnsupportedELFArchitecture, + }; const self = try gpa.create(Plan9); self.* = .{ .base = .{ @@ -41,25 +72,157 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { .allocator = gpa, .file = null, }, + .ptr_width = ptr_width, }; return self; } -pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void {} +pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void { + _ = try self.decl_table.getOrPut(self.base.allocator, decl); +} + +pub fn flush(self: *Plan9, comp: *Compilation) !void { + assert(!self.base.options.use_lld); + + switch (self.base.options.effectiveOutputMode()) { + .Exe => {}, + // plan9 object files are totally different + .Obj => return error.TODOImplementPlan9Objs, + .Lib => return error.TODOImplementWritingLibFiles, + } + return self.flushModule(comp); +} +pub fn flushModule(self: *Plan9, comp: *Compilation) !void { + const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; -pub fn allocateDeclIndexes(self: *Plan9, decl: *Module.Decl) !void {} + // generate the header + self.hdr.magic = try aout.magicFromArch(self.base.options.target.cpu.arch); + const file = self.base.file.?; + try file.seekTo(self.headerSize()); + + // temporary buffer + var code_buffer = std.ArrayList(u8).init(self.base.allocator); + defer code_buffer.deinit(); + { + for (self.decl_table.keys()) |decl| { + if (!decl.has_tv) continue; + self.cur_decl = decl; + const is_fn = (decl.ty.zigTypeTag() == .Fn); + decl.link.plan9 = if (is_fn) .{ + .offset = @intCast(u32, self.text_buf.items.len), + .type = .text, + } else .{ + .offset = @intCast(u32, self.data_buf.items.len), + .type = .data, + }; + const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ + .ty = decl.ty, + .val = decl.val, + }, &code_buffer, .{ .none = {} }); + const code = switch (res) { + .externally_managed => |x| x, + .appended => code_buffer.items, + .fail => |em| { + decl.analysis = .codegen_failure; + try module.failed_decls.put(module.gpa, decl, em); + // TODO try to do more decls + return; + }, + }; + if (is_fn) + try self.text_buf.appendSlice(self.base.allocator, code) + else + try self.data_buf.appendSlice(self.base.allocator, code); + code_buffer.items.len = 0; + } + } + try file.writeAll(self.text_buf.items); + try file.writeAll(self.data_buf.items); + try file.seekTo(0); + self.hdr.text = @intCast(u32, self.text_buf.items.len); + self.hdr.data = @intCast(u32, self.data_buf.items.len); + self.hdr.pcsz = 0; + self.hdr.spsz = 0; + inline for (std.meta.fields(aout.ExecHdr)) |f| { + try file.writer().writeIntBig(f.field_type, @field(self.hdr, f.name)); + } +} +pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void { + assert(self.decl_table.swapRemove(decl)); +} -pub fn flush(self: *Plan9, comp: *Compilation) !void {} -pub fn flushModule(self: *Plan9, comp: *Compilation) !void {} -pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void {} pub fn updateDeclExports( self: *Plan9, module: *Module, decl: *Module.Decl, exports: []const *Module.Export, -) !void {} -pub fn deinit(self: *Plan9) void {} +) !void { + for (exports) |exp| { + if (exp.options.section) |section_name| { + if (!mem.eql(u8, section_name, ".text")) { + try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.count() + 1); + module.failed_exports.putAssumeCapacityNoClobber( + exp, + try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "plan9 does not support extra sections", .{}), + ); + continue; + } + } + if (std.mem.eql(u8, exp.options.name, "_start")) { + std.debug.assert(decl.link.plan9.type == .text); // we tried to link a non-function as _start + self.hdr.entry = Plan9.default_base_addr + self.headerSize() + decl.link.plan9.offset; + } + if (exp.link.plan9) |i| { + const sym = &self.syms.items[i]; + sym.* = .{ + .value = decl.link.plan9.offset, + .type = switch (decl.link.plan9.type) { + .text => .T, + .data => .D, + }, + .name = decl.name, + }; + } else { + try self.syms.append(self.base.allocator, .{ + .value = decl.link.plan9.offset, + .type = switch (decl.link.plan9.type) { + .text => .T, + .data => .D, + }, + .name = decl.name, + }); + } + } +} +pub fn deinit(self: *Plan9) void { + self.decl_table.deinit(self.base.allocator); + self.call_relocs.deinit(self.base.allocator); + self.syms.deinit(self.base.allocator); + self.text_buf.deinit(self.base.allocator); + self.data_buf.deinit(self.base.allocator); +} -pub const Export = struct { - sym_index: ?u32 = null, -}; +pub const Export = ?usize; +pub const base_tag = .plan9; +pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Plan9 { + if (options.use_llvm) + return error.LLVMBackendDoesNotSupportPlan9; + assert(options.object_format == .plan9); + const file = try options.emit.?.directory.handle.createFile(sub_path, .{ + .truncate = false, + .read = true, + .mode = link.determineMode(options), + }); + errdefer file.close(); + + const self = try createEmpty(allocator, options); + errdefer self.base.destroy(); + + self.base.file = file; + return self; +} + +pub fn addCallReloc(self: *Plan9, code: *std.ArrayList(u8), reloc: CallReloc) !void { + try self.call_relocs.append(self.base.allocator, reloc); + try code.writer().writeIntBig(u64, 0xdeadbeef); +} diff --git a/src/link/plan9/a.out.zig b/src/link/plan9/a.out.zig new file mode 100644 index 0000000000..724bd4fa25 --- /dev/null +++ b/src/link/plan9/a.out.zig @@ -0,0 +1,122 @@ +// Copyright © 2021 Plan 9 Foundation +// Copyright © 20XX 9front authors + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +// Idomatic translation of 9front a.out.h +const std = @import("std"); +// all integers are in big-endian format (needs a byteswap) +pub const ExecHdr = struct { + magic: u32, + text: u32, + data: u32, + bss: u32, + syms: u32, + entry: u32, + spsz: u32, + pcsz: u32, + pub fn size() u8 { + return 32; + } +}; + +// uchar value[4]; +// char type; +// char name[n]; /* NUL-terminated */ +pub const Sym32 = struct { + value: u32, // big endian in the file + type: SymType, + name: [*:0]const u8, +}; +// uchar value[8]; +// char type; +// char name[n]; /* NUL-terminated */ +pub const Sym64 = struct { + value: u64, // big endian in the file + type: SymType, + name: [*:0]const u8, +}; +// The type field is one of the following characters with the +// high bit set: +// T text segment symbol +// t static text segment symbol +// L leaf function text segment symbol +// l static leaf function text segment symbol +// D data segment symbol +// d static data segment symbol +// B bss segment symbol +// b static bss segment symbol +// a automatic (local) variable symbol +// p function parameter symbol +// f source file name components +// z source file name +// Z source file line offset +// m for '.frame' +pub const SymType = enum(u8) { + T = 0x80 | 'T', + t = 0x80 | 't', + L = 0x80 | 'L', + l = 0x80 | 'l', + D = 0x80 | 'D', + d = 0x80 | 'd', + B = 0x80 | 'B', + b = 0x80 | 'b', + a = 0x80 | 'a', + p = 0x80 | 'p', + f = 0x80 | 'f', + z = 0x80 | 'z', + Z = 0x80 | 'Z', + m = 0x80 | 'm', +}; + +pub const HDR_MAGIC = @import("std").meta.promoteIntLiteral(c_int, 0x00008000, .hexadecimal); +pub inline fn _MAGIC(f: anytype, b: anytype) @TypeOf(f | ((((@as(c_int, 4) * b) + @as(c_int, 0)) * b) + @as(c_int, 7))) { + return f | ((((@as(c_int, 4) * b) + @as(c_int, 0)) * b) + @as(c_int, 7)); +} +pub const A_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 8)); // 68020 +pub const I_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 11)); // intel 386 +pub const J_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 12)); // intel 960 (retired) +pub const K_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 13)); // sparc +pub const V_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 16)); // mips 3000 BE +pub const X_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 17)); // att dsp 3210 (retired) +pub const M_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 18)); // mips 4000 BE +pub const D_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 19)); // amd 29000 (retired) +pub const E_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 20)); // arm +pub const Q_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 21)); // powerpc +pub const N_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 22)); // mips 4000 LE +pub const L_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 23)); // dec alpha (retired) +pub const P_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 24)); // mips 3000 LE +pub const U_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 25)); // sparc64 +pub const S_MAGIC = _MAGIC(HDR_MAGIC, @as(c_int, 26)); // amd64 +pub const T_MAGIC = _MAGIC(HDR_MAGIC, @as(c_int, 27)); // powerpc64 +pub const R_MAGIC = _MAGIC(HDR_MAGIC, @as(c_int, 28)); // arm64 + +pub fn magicFromArch(arch: std.Target.Cpu.Arch) !u32 { + return switch (arch) { + .i386 => I_MAGIC, + .sparc => K_MAGIC, // TODO should sparcv9 and sparcel go here? + .mips => V_MAGIC, + .arm => E_MAGIC, + .aarch64 => R_MAGIC, + .powerpc => Q_MAGIC, + .powerpc64 => T_MAGIC, + .x86_64 => S_MAGIC, + else => error.ArchNotSupportedByPlan9, + }; +} -- cgit v1.2.3