diff --git a/CMakeLists.txt b/CMakeLists.txt index 79534aca66..4e6d2c278c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -612,8 +612,6 @@ set(ZIG_STAGE2_SOURCES src/link/MachO/synthetic.zig src/link/MachO/Thunk.zig src/link/MachO/uuid.zig - src/link/Plan9.zig - src/link/Plan9/aout.zig src/link/Queue.zig src/link/StringTable.zig src/link/Wasm.zig diff --git a/src/arch/riscv64/Emit.zig b/src/arch/riscv64/Emit.zig index 41875ed789..fd8afa677b 100644 --- a/src/arch/riscv64/Emit.zig +++ b/src/arch/riscv64/Emit.zig @@ -125,7 +125,6 @@ pub fn emitMir(emit: *Emit) Error!void { }); try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); }, - .plan9 => {}, .none => {}, } }, @@ -142,7 +141,6 @@ pub fn emitMir(emit: *Emit) Error!void { }); try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); }, - .plan9 => {}, .none => {}, } }, @@ -200,7 +198,6 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void { emit.prev_di_column = column; emit.prev_di_pc = emit.code.items.len; }, - .plan9 => {}, .none => {}, } } diff --git a/src/arch/sparc64/Emit.zig b/src/arch/sparc64/Emit.zig index baab0126c2..d41f1cdf07 100644 --- a/src/arch/sparc64/Emit.zig +++ b/src/arch/sparc64/Emit.zig @@ -179,7 +179,6 @@ fn mirDebugPrologueEnd(emit: *Emit) !void { try dbg_out.setPrologueEnd(); try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); }, - .plan9 => {}, .none => {}, } } @@ -190,7 +189,6 @@ fn mirDebugEpilogueBegin(emit: *Emit) !void { try dbg_out.setEpilogueBegin(); try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); }, - .plan9 => {}, .none => {}, } } diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index 49c67620d5..2880062339 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -82,7 +82,6 @@ pub fn emitMir(emit: *Emit) Error!void { }), else => unreachable, }, - .plan9 => {}, .none => {}, } continue; @@ -173,9 +172,6 @@ pub fn emitMir(emit: *Emit) Error!void { coff_file.getAtom(atom).getSymbolIndex().? else |err| return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) - else if (emit.bin_file.cast(.plan9)) |p9_file| - p9_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err| - return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) else return emit.fail("lazy symbols unimplemented for {s}", .{@tagName(emit.bin_file.tag)}), .is_extern = false, @@ -418,7 +414,6 @@ pub fn emitMir(emit: *Emit) Error!void { else => unreachable, .pseudo_dbg_prologue_end_none => switch (emit.debug_output) { .dwarf => |dwarf| try dwarf.setPrologueEnd(), - .plan9 => {}, .none => {}, }, .pseudo_dbg_line_stmt_line_column => try emit.dbgAdvancePCAndLine(.{ @@ -439,7 +434,6 @@ pub fn emitMir(emit: *Emit) Error!void { }); try emit.dbgAdvancePCAndLine(emit.prev_di_loc); }, - .plan9 => {}, .none => {}, }, .pseudo_dbg_enter_block_none => switch (emit.debug_output) { @@ -449,7 +443,6 @@ pub fn emitMir(emit: *Emit) Error!void { }); try dwarf.enterBlock(emit.code.items.len); }, - .plan9 => {}, .none => {}, }, .pseudo_dbg_leave_block_none => switch (emit.debug_output) { @@ -459,7 +452,6 @@ pub fn emitMir(emit: *Emit) Error!void { }); try dwarf.leaveBlock(emit.code.items.len); }, - .plan9 => {}, .none => {}, }, .pseudo_dbg_enter_inline_func => switch (emit.debug_output) { @@ -469,7 +461,6 @@ pub fn emitMir(emit: *Emit) Error!void { }); try dwarf.enterInlineFunc(mir_inst.data.ip_index, emit.code.items.len, emit.prev_di_loc.line, emit.prev_di_loc.column); }, - .plan9 => {}, .none => {}, }, .pseudo_dbg_leave_inline_func => switch (emit.debug_output) { @@ -479,7 +470,6 @@ pub fn emitMir(emit: *Emit) Error!void { }); try dwarf.leaveInlineFunc(mir_inst.data.ip_index, emit.code.items.len); }, - .plan9 => {}, .none => {}, }, .pseudo_dbg_arg_none, @@ -613,7 +603,7 @@ pub fn emitMir(emit: *Emit) Error!void { loc, ); }, - .plan9, .none => local_index += 1, + .none => local_index += 1, }, .pseudo_dbg_arg_val, .pseudo_dbg_var_val => switch (emit.debug_output) { .dwarf => |dwarf| { @@ -630,11 +620,10 @@ pub fn emitMir(emit: *Emit) Error!void { .fromInterned(mir_inst.data.ip_index), ); }, - .plan9, .none => local_index += 1, + .none => local_index += 1, }, .pseudo_dbg_var_args_none => switch (emit.debug_output) { .dwarf => |dwarf| try dwarf.genVarArgsDebugInfo(), - .plan9 => {}, .none => {}, }, .pseudo_dead_none => {}, @@ -929,38 +918,6 @@ fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void { emit.prev_di_loc = loc; emit.prev_di_pc = emit.code.items.len; }, - .plan9 => |dbg_out| { - if (delta_pc <= 0) return; // only do this when the pc changes - - // increasing the line number - try link.File.Plan9.changeLine(&dbg_out.dbg_line, @intCast(delta_line)); - // increasing the pc - const d_pc_p9 = @as(i64, @intCast(delta_pc)) - dbg_out.pc_quanta; - if (d_pc_p9 > 0) { - // minus one because if its the last one, we want to leave space to change the line which is one pc quanta - var diff = @divExact(d_pc_p9, dbg_out.pc_quanta) - dbg_out.pc_quanta; - while (diff > 0) { - if (diff < 64) { - try dbg_out.dbg_line.append(@intCast(diff + 128)); - diff = 0; - } else { - try dbg_out.dbg_line.append(@intCast(64 + 128)); - diff -= 64; - } - } - if (dbg_out.pcop_change_index) |pci| - dbg_out.dbg_line.items[pci] += 1; - dbg_out.pcop_change_index = @intCast(dbg_out.dbg_line.items.len - 1); - } else if (d_pc_p9 == 0) { - // we don't need to do anything, because adding the pc quanta does it for us - } else unreachable; - if (dbg_out.start_line == null) - dbg_out.start_line = emit.prev_di_loc.line; - dbg_out.end_line = loc.line; - // only do this if the pc changed - emit.prev_di_loc = loc; - emit.prev_di_pc = emit.code.items.len; - }, .none => {}, } } diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig index bc99d871ac..e70018850d 100644 --- a/src/arch/x86_64/Mir.zig +++ b/src/arch/x86_64/Mir.zig @@ -2004,7 +2004,6 @@ pub fn emit( const atom = try cf.getOrCreateAtomForNav(nav); break :sym cf.getAtom(atom).getSymbolIndex().?; } - if (lf.cast(.plan9)) |p9f| break :sym try p9f.seeNav(pt, nav); unreachable; }, .debug_output = debug_output, @@ -2015,7 +2014,6 @@ pub fn emit( .column = func.lbrace_column, .is_stmt = switch (debug_output) { .dwarf => |dwarf| dwarf.dwarf.debug_line.header.default_is_stmt, - .plan9 => undefined, .none => undefined, }, }, @@ -2067,8 +2065,6 @@ pub fn emitLazy( return zcu.codegenFailType(lazy_sym.ty, "{s} creating lazy symbol", .{@errorName(err)}); break :sym cf.getAtom(atom).getSymbolIndex().?; } - if (lf.cast(.plan9)) |p9f| break :sym p9f.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err| - return zcu.codegenFailType(lazy_sym.ty, "{s} creating lazy symbol", .{@errorName(err)}); unreachable; }, .debug_output = debug_output, diff --git a/src/codegen.zig b/src/codegen.zig index 2e06bfb676..b4822077d2 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -997,8 +997,6 @@ pub fn genNavRef( }, .link_once => unreachable, } - } else if (lf.cast(.plan9)) |p9| { - return .{ .sym_index = try p9.seeNav(pt, nav_index) }; } else { const msg = try ErrorMsg.create(zcu.gpa, src_loc, "TODO genNavRef for target {}", .{target}); return .{ .fail = msg }; diff --git a/src/link.zig b/src/link.zig index 7db8a39e2a..a06e8ea932 100644 --- a/src/link.zig +++ b/src/link.zig @@ -530,6 +530,7 @@ pub const File = struct { return &lld.base; } switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) { + .plan9 => return error.UnsupportedObjectFormat, inline else => |tag| { dev.check(tag.devFeature()); const ptr = try tag.Type().open(arena, comp, emit, options); @@ -552,6 +553,7 @@ pub const File = struct { return &lld.base; } switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) { + .plan9 => return error.UnsupportedObjectFormat, inline else => |tag| { dev.check(tag.devFeature()); const ptr = try tag.Type().createEmpty(arena, comp, emit, options); @@ -571,7 +573,7 @@ pub const File = struct { const gpa = comp.gpa; switch (base.tag) { .lld => assert(base.file == null), - .coff, .elf, .macho, .plan9, .wasm, .goff, .xcoff => { + .coff, .elf, .macho, .wasm, .goff, .xcoff => { if (base.file != null) return; dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker, .goff_linker, .xcoff_linker }); const emit = base.emit; @@ -612,6 +614,7 @@ pub const File = struct { }); }, .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }), + .plan9 => unreachable, } } @@ -659,7 +662,7 @@ pub const File = struct { } } }, - .coff, .macho, .plan9, .wasm, .goff, .xcoff => if (base.file) |f| { + .coff, .macho, .wasm, .goff, .xcoff => if (base.file) |f| { dev.checkAny(&.{ .coff_linker, .macho_linker, .plan9_linker, .wasm_linker, .goff_linker, .xcoff_linker }); f.close(); base.file = null; @@ -675,12 +678,12 @@ pub const File = struct { } }, .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }), + .plan9 => unreachable, } } pub const DebugInfoOutput = union(enum) { dwarf: *Dwarf.WipNav, - plan9: *Plan9.DebugInfoOutput, none, }; pub const UpdateDebugInfoError = Dwarf.UpdateError; @@ -699,7 +702,6 @@ pub const File = struct { log.debug("getGlobalSymbol '{s}' (expected in '{?s}')", .{ name, lib_name }); switch (base.tag) { .lld => unreachable, - .plan9 => unreachable, .spirv => unreachable, .c => unreachable, inline else => |tag| { @@ -717,6 +719,7 @@ pub const File = struct { assert(nav.status == .fully_resolved); switch (base.tag) { .lld => unreachable, + .plan9 => unreachable, inline else => |tag| { dev.check(tag.devFeature()); return @as(*tag.Type(), @fieldParentPtr("base", base)).updateNav(pt, nav_index); @@ -759,6 +762,7 @@ pub const File = struct { switch (base.tag) { .lld => unreachable, .spirv => unreachable, // see corresponding special case in `Zcu.PerThread.runCodegenInner` + .plan9 => unreachable, inline else => |tag| { dev.check(tag.devFeature()); return @as(*tag.Type(), @fieldParentPtr("base", base)).updateFunc(pt, func_index, mir); @@ -788,6 +792,7 @@ pub const File = struct { .lld => unreachable, .spirv => {}, .goff, .xcoff => {}, + .plan9 => unreachable, inline else => |tag| { dev.check(tag.devFeature()); return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id); @@ -812,6 +817,7 @@ pub const File = struct { base.releaseLock(); if (base.file) |f| f.close(); switch (base.tag) { + .plan9 => unreachable, inline else => |tag| { dev.check(tag.devFeature()); @as(*tag.Type(), @fieldParentPtr("base", base)).deinit(); @@ -851,6 +857,7 @@ pub const File = struct { } assert(base.post_prelink); switch (base.tag) { + .plan9 => unreachable, inline else => |tag| { dev.check(tag.devFeature()); return @as(*tag.Type(), @fieldParentPtr("base", base)).flush(arena, tid, prog_node); @@ -877,6 +884,7 @@ pub const File = struct { assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { .lld => unreachable, + .plan9 => unreachable, inline else => |tag| { dev.check(tag.devFeature()); return @as(*tag.Type(), @fieldParentPtr("base", base)).updateExports(pt, exported, export_indices); @@ -911,6 +919,7 @@ pub const File = struct { .spirv => unreachable, .wasm => unreachable, .goff, .xcoff => unreachable, + .plan9 => unreachable, inline else => |tag| { dev.check(tag.devFeature()); return @as(*tag.Type(), @fieldParentPtr("base", base)).getNavVAddr(pt, nav_index, reloc_info); @@ -933,6 +942,7 @@ pub const File = struct { .spirv => unreachable, .wasm => unreachable, .goff, .xcoff => unreachable, + .plan9 => unreachable, inline else => |tag| { dev.check(tag.devFeature()); return @as(*tag.Type(), @fieldParentPtr("base", base)).lowerUav(pt, decl_val, decl_align, src_loc); @@ -949,6 +959,7 @@ pub const File = struct { .spirv => unreachable, .wasm => unreachable, .goff, .xcoff => unreachable, + .plan9 => unreachable, inline else => |tag| { dev.check(tag.devFeature()); return @as(*tag.Type(), @fieldParentPtr("base", base)).getUavVAddr(decl_val, reloc_info); @@ -965,8 +976,8 @@ pub const File = struct { assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { .lld => unreachable, + .plan9 => unreachable, - .plan9, .spirv, .goff, .xcoff, @@ -1116,10 +1127,10 @@ pub const File = struct { .c => C, .wasm => Wasm, .spirv => SpirV, - .plan9 => Plan9, .goff => Goff, .xcoff => Xcoff, .lld => Lld, + .plan9 => comptime unreachable, }; } @@ -1211,7 +1222,6 @@ pub const File = struct { pub const Lld = @import("link/Lld.zig"); pub const C = @import("link/C.zig"); pub const Coff = @import("link/Coff.zig"); - pub const Plan9 = @import("link/Plan9.zig"); pub const Elf = @import("link/Elf.zig"); pub const MachO = @import("link/MachO.zig"); pub const SpirV = @import("link/SpirV.zig"); diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index f49406b751..f0c90701bf 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -950,7 +950,6 @@ pub fn getNavVAddr( .target_sym = this_sym_index, .target_off = reloc_info.addend, }), - .plan9 => unreachable, .none => unreachable, }, } @@ -983,7 +982,6 @@ pub fn getUavVAddr( .target_sym = sym_index, .target_off = reloc_info.addend, }), - .plan9 => unreachable, .none => unreachable, }, } diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index ef82f82e72..105439425d 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -650,7 +650,6 @@ pub fn getNavVAddr( .target_sym = sym_index, .target_off = reloc_info.addend, }), - .plan9 => unreachable, .none => unreachable, }, } @@ -690,7 +689,6 @@ pub fn getUavVAddr( .target_sym = sym_index, .target_off = reloc_info.addend, }), - .plan9 => unreachable, .none => unreachable, }, } diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig deleted file mode 100644 index 815e162833..0000000000 --- a/src/link/Plan9.zig +++ /dev/null @@ -1,1426 +0,0 @@ -//! This implementation does all the linking work in flush(). A future improvement -//! would be to add incremental linking in a similar way as ELF does. - -const Plan9 = @This(); -const link = @import("../link.zig"); -const Zcu = @import("../Zcu.zig"); -const InternPool = @import("../InternPool.zig"); -const Compilation = @import("../Compilation.zig"); -const aout = @import("Plan9/aout.zig"); -const codegen = @import("../codegen.zig"); -const trace = @import("../tracy.zig").trace; -const File = link.File; -const build_options = @import("build_options"); -const Air = @import("../Air.zig"); -const Type = @import("../Type.zig"); -const Value = @import("../Value.zig"); -const AnalUnit = InternPool.AnalUnit; - -const std = @import("std"); -const builtin = @import("builtin"); -const mem = std.mem; -const Allocator = std.mem.Allocator; -const log = std.log.scoped(.link); -const assert = std.debug.assert; -const Path = std.Build.Cache.Path; - -base: link.File, -sixtyfour_bit: bool, -bases: Bases, - -/// A symbol's value is just casted down when compiling -/// for a 32 bit target. -/// Does not represent the order or amount of symbols in the file -/// it is just useful for storing symbols. Some other symbols are in -/// file_segments. -syms: std.ArrayListUnmanaged(aout.Sym) = .empty, - -/// The plan9 a.out format requires segments of -/// filenames to be deduplicated, so we use this map to -/// de duplicate it. The value is the value of the path -/// component -file_segments: std.StringArrayHashMapUnmanaged(u16) = .empty, -/// The value of a 'f' symbol increments by 1 every time, so that no 2 'f' -/// symbols have the same value. -file_segments_i: u16 = 1, - -path_arena: std.heap.ArenaAllocator, - -/// maps a file scope to a hash map of decl to codegen output -/// this is useful for line debuginfo, since it makes sense to sort by file -/// The debugger looks for the first file (aout.Sym.Type.z) preceeding the text symbol -/// of the function to know what file it came from. -/// If we group the decls by file, it makes it really easy to do this (put the symbol in the correct place) -fn_nav_table: std.AutoArrayHashMapUnmanaged( - Zcu.File.Index, - struct { sym_index: u32, functions: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, FnNavOutput) = .empty }, -) = .{}, -/// the code is modified when relocated, so that is why it is mutable -data_nav_table: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, []u8) = .empty, -/// When `updateExports` is called, we store the export indices here, to be used -/// during flush. -nav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, []Zcu.Export.Index) = .empty, - -lazy_syms: LazySymbolTable = .{}, - -uavs: std.AutoHashMapUnmanaged(InternPool.Index, Atom.Index) = .empty, - -relocs: std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Reloc)) = .empty, -hdr: aout.ExecHdr = undefined, - -// relocs: std. -magic: u32, - -entry_val: ?u64 = null, - -got_len: usize = 0, -// A list of all the free got indexes, so when making a new decl -// don't make a new one, just use one from here. -got_index_free_list: std.ArrayListUnmanaged(usize) = .empty, - -syms_index_free_list: std.ArrayListUnmanaged(usize) = .empty, - -atoms: std.ArrayListUnmanaged(Atom) = .empty, -navs: std.AutoHashMapUnmanaged(InternPool.Nav.Index, NavMetadata) = .empty, - -/// Indices of the three "special" symbols into atoms -etext_edata_end_atom_indices: [3]?Atom.Index = .{ null, null, null }, - -const Reloc = struct { - target: Atom.Index, - offset: u64, - addend: u32, - type: enum { - pcrel, - nonpcrel, - // for getting the value of the etext symbol; we ignore target - special_etext, - // for getting the value of the edata symbol; we ignore target - special_edata, - // for getting the value of the end symbol; we ignore target - special_end, - } = .nonpcrel, -}; - -const Bases = struct { - text: u64, - /// the Global Offset Table starts at the beginning of the data section - data: u64, -}; - -const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata); - -const LazySymbolMetadata = struct { - const State = enum { unused, pending_flush, flushed }; - text_atom: Atom.Index = undefined, - rodata_atom: Atom.Index = undefined, - text_state: State = .unused, - rodata_state: State = .unused, - - fn numberOfAtoms(self: LazySymbolMetadata) u32 { - var n: u32 = 0; - if (self.text_state != .unused) n += 1; - if (self.rodata_state != .unused) n += 1; - return n; - } -}; - -pub const PtrWidth = enum { p32, p64 }; - -pub const Atom = struct { - type: aout.Sym.Type, - /// offset in the text or data sects - offset: ?u64, - /// offset into syms - sym_index: ?usize, - /// offset into got - got_index: ?usize, - /// We include the code here to be use in relocs - /// In the case of lazy_syms, this atom owns the code. - /// But, in the case of function and data decls, they own the code and this field - /// is just a pointer for convience. - code: CodePtr, - - const CodePtr = struct { - code_ptr: ?[*]u8, - other: union { - code_len: usize, - nav_index: InternPool.Nav.Index, - }, - fn fromSlice(slice: []u8) CodePtr { - return .{ .code_ptr = slice.ptr, .other = .{ .code_len = slice.len } }; - } - fn getCode(self: CodePtr, plan9: *const Plan9) []u8 { - const zcu = plan9.base.comp.zcu.?; - const ip = &zcu.intern_pool; - return if (self.code_ptr) |p| p[0..self.other.code_len] else blk: { - const nav_index = self.other.nav_index; - const nav = ip.getNav(nav_index); - if (ip.isFunctionType(nav.typeOf(ip))) { - const table = plan9.fn_nav_table.get(zcu.navFileScopeIndex(nav_index)).?.functions; - const output = table.get(nav_index).?; - break :blk output.code; - } else { - break :blk plan9.data_nav_table.get(nav_index).?; - } - }; - } - fn getOwnedCode(self: CodePtr) ?[]u8 { - return if (self.code_ptr) |p| p[0..self.other.code_len] else null; - } - }; - - pub const Index = u32; - - pub fn getOrCreateOffsetTableEntry(self: *Atom, plan9: *Plan9) usize { - if (self.got_index == null) self.got_index = plan9.allocateGotIndex(); - return self.got_index.?; - } - - pub fn getOrCreateSymbolTableEntry(self: *Atom, plan9: *Plan9) !usize { - if (self.sym_index == null) self.sym_index = try plan9.allocateSymbolIndex(); - return self.sym_index.?; - } - - // asserts that self.got_index != null - pub fn getOffsetTableAddress(self: Atom, plan9: *Plan9) u64 { - const target = &plan9.base.comp.root_mod.resolved_target.result; - const ptr_bytes = @divExact(target.ptrBitWidth(), 8); - const got_addr = plan9.bases.data; - const got_index = self.got_index.?; - return got_addr + got_index * ptr_bytes; - } -}; - -/// the plan9 debuginfo output is a bytecode with 4 opcodes -/// assume all numbers/variables are bytes -/// 0 w x y z -> interpret w x y z as a big-endian i32, and add it to the line offset -/// x when x < 65 -> add x to line offset -/// x when x < 129 -> subtract 64 from x and subtract it from the line offset -/// x -> subtract 129 from x, multiply it by the quanta of the instruction size -/// (1 on x86_64), and add it to the pc -/// after every opcode, add the quanta of the instruction size to the pc -pub const DebugInfoOutput = struct { - /// the actual opcodes - dbg_line: std.ArrayList(u8), - /// what line the debuginfo starts on - /// this helps because the linker might have to insert some opcodes to make sure that the line count starts at the right amount for the next decl - start_line: ?u32, - /// what the line count ends on after codegen - /// this helps because the linker might have to insert some opcodes to make sure that the line count starts at the right amount for the next decl - end_line: u32, - /// the last pc change op - /// This is very useful for adding quanta - /// to it if its not actually the last one. - pcop_change_index: ?u32, - /// cached pc quanta - pc_quanta: u8, -}; - -const NavMetadata = struct { - index: Atom.Index, - exports: std.ArrayListUnmanaged(usize) = .empty, - - fn getExport(m: NavMetadata, p9: *const Plan9, name: []const u8) ?usize { - for (m.exports.items) |exp| { - const sym = p9.syms.items[exp]; - if (mem.eql(u8, name, sym.name)) return exp; - } - return null; - } -}; - -const FnNavOutput = struct { - /// this code is modified when relocated so it is mutable - code: []u8, - /// this might have to be modified in the linker, so thats why its mutable - lineinfo: []u8, - start_line: u32, - end_line: u32, -}; - -fn getAddr(self: Plan9, addr: u64, t: aout.Sym.Type) u64 { - return addr + switch (t) { - .T, .t, .l, .L => self.bases.text, - .D, .d, .B, .b => self.bases.data, - else => unreachable, - }; -} - -fn getSymAddr(self: Plan9, s: aout.Sym) u64 { - return self.getAddr(s.value, s.type); -} - -pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases { - return switch (arch) { - .x86_64 => .{ - // header size => 40 => 0x28 - .text = 0x200028, - .data = 0x400000, - }, - .x86 => .{ - // header size => 32 => 0x20 - .text = 0x200020, - .data = 0x400000, - }, - .aarch64 => .{ - // header size => 40 => 0x28 - .text = 0x10028, - .data = 0x20000, - }, - else => std.debug.panic("find default base address for {}", .{arch}), - }; -} - -pub fn createEmpty( - arena: Allocator, - comp: *Compilation, - emit: Path, - options: link.File.OpenOptions, -) !*Plan9 { - const target = &comp.root_mod.resolved_target.result; - const gpa = comp.gpa; - const optimize_mode = comp.root_mod.optimize_mode; - const output_mode = comp.config.output_mode; - - const sixtyfour_bit: bool = switch (target.ptrBitWidth()) { - 0...32 => false, - 33...64 => true, - else => return error.UnsupportedP9Architecture, - }; - - const self = try arena.create(Plan9); - self.* = .{ - .path_arena = std.heap.ArenaAllocator.init(gpa), - .base = .{ - .tag = .plan9, - .comp = comp, - .emit = emit, - .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj), - .print_gc_sections = options.print_gc_sections, - .stack_size = options.stack_size orelse 16777216, - .allow_shlib_undefined = options.allow_shlib_undefined orelse false, - .file = null, - .build_id = options.build_id, - }, - .sixtyfour_bit = sixtyfour_bit, - .bases = undefined, - .magic = try aout.magicFromArch(target.cpu.arch), - }; - // a / will always be in a file path - try self.file_segments.put(gpa, "/", 1); - return self; -} - -fn putFn(self: *Plan9, nav_index: InternPool.Nav.Index, out: FnNavOutput) !void { - const comp = self.base.comp; - const gpa = comp.gpa; - const zcu = comp.zcu.?; - const file_scope = zcu.navFileScopeIndex(nav_index); - const fn_map_res = try self.fn_nav_table.getOrPut(gpa, file_scope); - if (fn_map_res.found_existing) { - if (try fn_map_res.value_ptr.functions.fetchPut(gpa, nav_index, out)) |old_entry| { - gpa.free(old_entry.value.code); - gpa.free(old_entry.value.lineinfo); - } - } else { - const file = zcu.fileByIndex(file_scope); - const arena = self.path_arena.allocator(); - // each file gets a symbol - fn_map_res.value_ptr.* = .{ - .sym_index = blk: { - try self.syms.append(gpa, undefined); - try self.syms.append(gpa, undefined); - break :blk @as(u32, @intCast(self.syms.items.len - 1)); - }, - }; - try fn_map_res.value_ptr.functions.put(gpa, nav_index, out); - - var a = std.ArrayList(u8).init(arena); - errdefer a.deinit(); - // every 'z' starts with 0 - try a.append(0); - // path component value of '/' - try a.writer().writeInt(u16, 1, .big); - - // getting the full file path - { - const full_path = try file.path.toAbsolute(comp.dirs, gpa); - defer gpa.free(full_path); - try self.addPathComponents(full_path, &a); - } - - // null terminate - try a.append(0); - const final = try a.toOwnedSlice(); - self.syms.items[fn_map_res.value_ptr.sym_index - 1] = .{ - .type = .z, - .value = 1, - .name = final, - }; - self.syms.items[fn_map_res.value_ptr.sym_index] = .{ - .type = .z, - // just put a giant number, no source file will have this many newlines - .value = std.math.maxInt(u31), - .name = &.{ 0, 0 }, - }; - } -} - -fn addPathComponents(self: *Plan9, path: []const u8, a: *std.ArrayList(u8)) !void { - const gpa = self.base.comp.gpa; - const sep = std.fs.path.sep; - var it = std.mem.tokenizeScalar(u8, path, sep); - while (it.next()) |component| { - if (self.file_segments.get(component)) |num| { - try a.writer().writeInt(u16, num, .big); - } else { - self.file_segments_i += 1; - try self.file_segments.put(gpa, component, self.file_segments_i); - try a.writer().writeInt(u16, self.file_segments_i, .big); - } - } -} - -pub fn updateFunc( - self: *Plan9, - pt: Zcu.PerThread, - func_index: InternPool.Index, - mir: *const codegen.AnyMir, -) link.File.UpdateNavError!void { - if (build_options.skip_non_native and builtin.object_format != .plan9) { - @panic("Attempted to compile for object format that was disabled by build configuration"); - } - - const zcu = pt.zcu; - const gpa = zcu.gpa; - const target = &self.base.comp.root_mod.resolved_target.result; - const func = zcu.funcInfo(func_index); - - const atom_idx = try self.seeNav(pt, func.owner_nav); - - var code_buffer: std.ArrayListUnmanaged(u8) = .empty; - defer code_buffer.deinit(gpa); - var dbg_info_output: DebugInfoOutput = .{ - .dbg_line = std.ArrayList(u8).init(gpa), - .start_line = null, - .end_line = undefined, - .pcop_change_index = null, - // we have already checked the target in the linker to make sure it is compatable - .pc_quanta = aout.getPCQuant(target.cpu.arch) catch unreachable, - }; - defer dbg_info_output.dbg_line.deinit(); - - try codegen.emitFunction( - &self.base, - pt, - zcu.navSrcLoc(func.owner_nav), - func_index, - mir, - &code_buffer, - .{ .plan9 = &dbg_info_output }, - ); - const code = try code_buffer.toOwnedSlice(gpa); - self.getAtomPtr(atom_idx).code = .{ - .code_ptr = null, - .other = .{ .nav_index = func.owner_nav }, - }; - const out: FnNavOutput = .{ - .code = code, - .lineinfo = try dbg_info_output.dbg_line.toOwnedSlice(), - .start_line = dbg_info_output.start_line.?, - .end_line = dbg_info_output.end_line, - }; - try self.putFn(func.owner_nav, out); - return self.updateFinish(pt, func.owner_nav); -} - -pub fn updateNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) link.File.UpdateNavError!void { - const zcu = pt.zcu; - const gpa = zcu.gpa; - const ip = &zcu.intern_pool; - const nav = ip.getNav(nav_index); - const nav_val = zcu.navValue(nav_index); - const nav_init = switch (ip.indexToKey(nav_val.toIntern())) { - .func => return, - .variable => |variable| Value.fromInterned(variable.init), - .@"extern" => { - log.debug("found extern decl: {f}", .{nav.name.fmt(ip)}); - return; - }, - else => nav_val, - }; - - if (nav_init.typeOf(zcu).hasRuntimeBits(zcu)) { - const atom_idx = try self.seeNav(pt, nav_index); - - var code_buffer: std.ArrayListUnmanaged(u8) = .empty; - defer code_buffer.deinit(gpa); - // TODO we need the symbol index for symbol in the table of locals for the containing atom - try codegen.generateSymbol( - &self.base, - pt, - zcu.navSrcLoc(nav_index), - nav_init, - &code_buffer, - .{ .atom_index = @intCast(atom_idx) }, - ); - const code = code_buffer.items; - try self.data_nav_table.ensureUnusedCapacity(gpa, 1); - const duped_code = try gpa.dupe(u8, code); - self.getAtomPtr(self.navs.get(nav_index).?.index).code = .{ .code_ptr = null, .other = .{ .nav_index = nav_index } }; - if (self.data_nav_table.fetchPutAssumeCapacity(nav_index, duped_code)) |old_entry| { - gpa.free(old_entry.value); - } - try self.updateFinish(pt, nav_index); - } -} - -/// called at the end of update{Decl,Func} -fn updateFinish(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { - const zcu = pt.zcu; - const gpa = zcu.gpa; - const ip = &zcu.intern_pool; - const nav = ip.getNav(nav_index); - const is_fn = ip.isFunctionType(nav.typeOf(ip)); - const sym_t: aout.Sym.Type = if (is_fn) .t else .d; - - const atom = self.getAtomPtr(self.navs.get(nav_index).?.index); - // write the internal linker metadata - atom.type = sym_t; - // write the symbol - // we already have the got index - const sym: aout.Sym = .{ - .value = undefined, // the value of stuff gets filled in in flush - .type = atom.type, - .name = try gpa.dupe(u8, nav.name.toSlice(ip)), - }; - - if (atom.sym_index) |s| { - self.syms.items[s] = sym; - } else { - const s = try self.allocateSymbolIndex(); - atom.sym_index = s; - self.syms.items[s] = sym; - } -} - -fn allocateSymbolIndex(self: *Plan9) !usize { - const gpa = self.base.comp.gpa; - if (self.syms_index_free_list.pop()) |i| { - return i; - } else { - _ = try self.syms.addOne(gpa); - return self.syms.items.len - 1; - } -} - -fn allocateGotIndex(self: *Plan9) usize { - if (self.got_index_free_list.pop()) |i| { - return i; - } else { - self.got_len += 1; - return self.got_len - 1; - } -} - -pub fn changeLine(l: *std.ArrayList(u8), delta_line: i32) !void { - if (delta_line > 0 and delta_line < 65) { - const toappend = @as(u8, @intCast(delta_line)); - try l.append(toappend); - } else if (delta_line < 0 and delta_line > -65) { - const toadd: u8 = @as(u8, @intCast(-delta_line + 64)); - try l.append(toadd); - } else if (delta_line != 0) { - try l.append(0); - try l.writer().writeInt(i32, delta_line, .big); - } -} - -fn externCount(self: *Plan9) usize { - var extern_atom_count: usize = 0; - for (self.etext_edata_end_atom_indices) |idx| { - if (idx != null) extern_atom_count += 1; - } - return extern_atom_count; -} -// counts decls, and lazy syms -fn atomCount(self: *Plan9) usize { - var fn_nav_count: usize = 0; - var itf_files = self.fn_nav_table.iterator(); - while (itf_files.next()) |ent| { - // get the submap - var submap = ent.value_ptr.functions; - fn_nav_count += submap.count(); - } - const data_nav_count = self.data_nav_table.count(); - var lazy_atom_count: usize = 0; - var it_lazy = self.lazy_syms.iterator(); - while (it_lazy.next()) |kv| { - lazy_atom_count += kv.value_ptr.numberOfAtoms(); - } - const uav_atom_count = self.uavs.count(); - const extern_atom_count = self.externCount(); - return data_nav_count + fn_nav_count + lazy_atom_count + extern_atom_count + uav_atom_count; -} - -pub fn flush( - self: *Plan9, - arena: Allocator, - /// TODO: stop using this - tid: Zcu.PerThread.Id, - prog_node: std.Progress.Node, -) link.File.FlushError!void { - if (build_options.skip_non_native and builtin.object_format != .plan9) { - @panic("Attempted to compile for object format that was disabled by build configuration"); - } - - const tracy = trace(@src()); - defer tracy.end(); - - _ = arena; // Has the same lifetime as the call to Compilation.update. - - const comp = self.base.comp; - const diags = &comp.link_diags; - const gpa = comp.gpa; - const target = &comp.root_mod.resolved_target.result; - - switch (comp.config.output_mode) { - .Exe => {}, - .Obj => return diags.fail("writing plan9 object files unimplemented", .{}), - .Lib => return diags.fail("writing plan9 lib files unimplemented", .{}), - } - - const sub_prog_node = prog_node.start("Flush Module", 0); - defer sub_prog_node.end(); - - log.debug("flush", .{}); - - defer assert(self.hdr.entry != 0x0); - - const pt: Zcu.PerThread = .activate( - self.base.comp.zcu orelse return diags.fail("linking without zig source unimplemented", .{}), - tid, - ); - defer pt.deactivate(); - - // finish up the lazy syms - if (self.lazy_syms.getPtr(.none)) |metadata| { - // Most lazy symbols can be updated on first use, but - // anyerror needs to wait for everything to be flushed. - if (metadata.text_state != .unused) try self.updateLazySymbolAtom( - pt, - .{ .kind = .code, .ty = .anyerror_type }, - metadata.text_atom, - ); - if (metadata.rodata_state != .unused) try self.updateLazySymbolAtom( - pt, - .{ .kind = .const_data, .ty = .anyerror_type }, - metadata.rodata_atom, - ); - } - for (self.lazy_syms.values()) |*metadata| { - if (metadata.text_state != .unused) metadata.text_state = .flushed; - if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed; - } - // make sure the got table is good - const atom_count = self.atomCount(); - assert(self.got_len == atom_count + self.got_index_free_list.items.len); - const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8; - var got_table = try gpa.alloc(u8, got_size); - defer gpa.free(got_table); - - // + 4 for header, got, symbols, linecountinfo - var iovecs = try gpa.alloc(std.posix.iovec_const, self.atomCount() + 4 - self.externCount()); - defer gpa.free(iovecs); - - const file = self.base.file.?; - - var hdr_buf: [40]u8 = undefined; - // account for the fat header - const hdr_size: usize = if (self.sixtyfour_bit) 40 else 32; - const hdr_slice: []u8 = hdr_buf[0..hdr_size]; - var foff = hdr_size; - iovecs[0] = .{ .base = hdr_slice.ptr, .len = hdr_slice.len }; - var iovecs_i: usize = 1; - var text_i: u64 = 0; - - var linecountinfo = std.ArrayList(u8).init(gpa); - defer linecountinfo.deinit(); - // text - { - var linecount: i64 = -1; - var it_file = self.fn_nav_table.iterator(); - while (it_file.next()) |fentry| { - var it = fentry.value_ptr.functions.iterator(); - while (it.next()) |entry| { - const nav_index = entry.key_ptr.*; - const nav = pt.zcu.intern_pool.getNav(nav_index); - const atom = self.getAtomPtr(self.navs.get(nav_index).?.index); - const out = entry.value_ptr.*; - { - // connect the previous decl to the next - const delta_line = @as(i32, @intCast(out.start_line)) - @as(i32, @intCast(linecount)); - - try changeLine(&linecountinfo, delta_line); - // TODO change the pc too (maybe?) - - // write out the actual info that was generated in codegen now - try linecountinfo.appendSlice(out.lineinfo); - linecount = out.end_line; - } - foff += out.code.len; - iovecs[iovecs_i] = .{ .base = out.code.ptr, .len = out.code.len }; - iovecs_i += 1; - const off = self.getAddr(text_i, .t); - text_i += out.code.len; - atom.offset = off; - log.debug("write text nav 0x{x} ({f}), lines {d} to {d}.;__GOT+0x{x} vaddr: 0x{x}", .{ nav_index, nav.name.fmt(&pt.zcu.intern_pool), out.start_line + 1, out.end_line, atom.got_index.? * 8, off }); - if (!self.sixtyfour_bit) { - mem.writeInt(u32, got_table[atom.got_index.? * 4 ..][0..4], @intCast(off), target.cpu.arch.endian()); - } else { - mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian()); - } - self.syms.items[atom.sym_index.?].value = off; - if (self.nav_exports.get(nav_index)) |export_indices| { - try self.addNavExports(pt.zcu, nav_index, export_indices); - } - } - } - if (linecountinfo.items.len & 1 == 1) { - // just a nop to make it even, the plan9 linker does this - try linecountinfo.append(129); - } - } - // the text lazy symbols - { - var it = self.lazy_syms.iterator(); - while (it.next()) |kv| { - const meta = kv.value_ptr; - const text_atom = if (meta.text_state != .unused) self.getAtomPtr(meta.text_atom) else continue; - const code = text_atom.code.getOwnedCode().?; - foff += code.len; - iovecs[iovecs_i] = .{ .base = code.ptr, .len = code.len }; - iovecs_i += 1; - const off = self.getAddr(text_i, .t); - text_i += code.len; - text_atom.offset = off; - if (!self.sixtyfour_bit) { - mem.writeInt(u32, got_table[text_atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(off)), target.cpu.arch.endian()); - } else { - mem.writeInt(u64, got_table[text_atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian()); - } - self.syms.items[text_atom.sym_index.?].value = off; - } - } - // fix the sym for etext - if (self.etext_edata_end_atom_indices[0]) |etext_atom_idx| { - const etext_atom = self.getAtom(etext_atom_idx); - const val = self.getAddr(text_i, .t); - self.syms.items[etext_atom.sym_index.?].value = val; - if (!self.sixtyfour_bit) { - mem.writeInt(u32, got_table[etext_atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(val)), target.cpu.arch.endian()); - } else { - mem.writeInt(u64, got_table[etext_atom.got_index.? * 8 ..][0..8], val, target.cpu.arch.endian()); - } - } - // global offset table is in data - iovecs[iovecs_i] = .{ .base = got_table.ptr, .len = got_table.len }; - iovecs_i += 1; - // data - var data_i: u64 = got_size; - { - var it = self.data_nav_table.iterator(); - while (it.next()) |entry| { - const nav_index = entry.key_ptr.*; - const atom = self.getAtomPtr(self.navs.get(nav_index).?.index); - const code = entry.value_ptr.*; - - foff += code.len; - iovecs[iovecs_i] = .{ .base = code.ptr, .len = code.len }; - iovecs_i += 1; - const off = self.getAddr(data_i, .d); - data_i += code.len; - atom.offset = off; - if (!self.sixtyfour_bit) { - mem.writeInt(u32, got_table[atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(off)), target.cpu.arch.endian()); - } else { - mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian()); - } - self.syms.items[atom.sym_index.?].value = off; - if (self.nav_exports.get(nav_index)) |export_indices| { - try self.addNavExports(pt.zcu, nav_index, export_indices); - } - } - { - var it_uav = self.uavs.iterator(); - while (it_uav.next()) |kv| { - const atom = self.getAtomPtr(kv.value_ptr.*); - const code = atom.code.getOwnedCode().?; - log.debug("write anon decl: {s}", .{self.syms.items[atom.sym_index.?].name}); - foff += code.len; - iovecs[iovecs_i] = .{ .base = code.ptr, .len = code.len }; - iovecs_i += 1; - const off = self.getAddr(data_i, .d); - data_i += code.len; - atom.offset = off; - if (!self.sixtyfour_bit) { - mem.writeInt(u32, got_table[atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(off)), target.cpu.arch.endian()); - } else { - mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian()); - } - self.syms.items[atom.sym_index.?].value = off; - } - } - // the lazy data symbols - var it_lazy = self.lazy_syms.iterator(); - while (it_lazy.next()) |kv| { - const meta = kv.value_ptr; - const data_atom = if (meta.rodata_state != .unused) self.getAtomPtr(meta.rodata_atom) else continue; - const code = data_atom.code.getOwnedCode().?; // lazy symbols must own their code - foff += code.len; - iovecs[iovecs_i] = .{ .base = code.ptr, .len = code.len }; - iovecs_i += 1; - const off = self.getAddr(data_i, .d); - data_i += code.len; - data_atom.offset = off; - if (!self.sixtyfour_bit) { - mem.writeInt(u32, got_table[data_atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(off)), target.cpu.arch.endian()); - } else { - mem.writeInt(u64, got_table[data_atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian()); - } - self.syms.items[data_atom.sym_index.?].value = off; - } - // edata symbol - if (self.etext_edata_end_atom_indices[1]) |edata_atom_idx| { - const edata_atom = self.getAtom(edata_atom_idx); - const val = self.getAddr(data_i, .b); - self.syms.items[edata_atom.sym_index.?].value = val; - if (!self.sixtyfour_bit) { - mem.writeInt(u32, got_table[edata_atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(val)), target.cpu.arch.endian()); - } else { - mem.writeInt(u64, got_table[edata_atom.got_index.? * 8 ..][0..8], val, target.cpu.arch.endian()); - } - } - // end symbol (same as edata because native backends don't do .bss yet) - if (self.etext_edata_end_atom_indices[2]) |end_atom_idx| { - const end_atom = self.getAtom(end_atom_idx); - const val = self.getAddr(data_i, .b); - self.syms.items[end_atom.sym_index.?].value = val; - if (!self.sixtyfour_bit) { - mem.writeInt(u32, got_table[end_atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(val)), target.cpu.arch.endian()); - } else { - log.debug("write end (got_table[0x{x}] = 0x{x})", .{ end_atom.got_index.? * 8, val }); - mem.writeInt(u64, got_table[end_atom.got_index.? * 8 ..][0..8], val, target.cpu.arch.endian()); - } - } - } - var sym_buf = std.ArrayList(u8).init(gpa); - try self.writeSyms(&sym_buf); - const syms = try sym_buf.toOwnedSlice(); - defer gpa.free(syms); - assert(2 + self.atomCount() - self.externCount() == iovecs_i); // we didn't write all the decls - iovecs[iovecs_i] = .{ .base = syms.ptr, .len = syms.len }; - iovecs_i += 1; - iovecs[iovecs_i] = .{ .base = linecountinfo.items.ptr, .len = linecountinfo.items.len }; - iovecs_i += 1; - // generate the header - self.hdr = .{ - .magic = self.magic, - .text = @as(u32, @intCast(text_i)), - .data = @as(u32, @intCast(data_i)), - .syms = @as(u32, @intCast(syms.len)), - .bss = 0, - .spsz = 0, - .pcsz = @as(u32, @intCast(linecountinfo.items.len)), - .entry = @as(u32, @intCast(self.entry_val.?)), - }; - @memcpy(hdr_slice, self.hdr.toU8s()[0..hdr_size]); - // write the fat header for 64 bit entry points - if (self.sixtyfour_bit) { - mem.writeInt(u64, hdr_buf[32..40], self.entry_val.?, .big); - } - // perform the relocs - { - var it = self.relocs.iterator(); - while (it.next()) |kv| { - const source_atom_index = kv.key_ptr.*; - const source_atom = self.getAtom(source_atom_index); - const source_atom_symbol = self.syms.items[source_atom.sym_index.?]; - const code = source_atom.code.getCode(self); - const endian = target.cpu.arch.endian(); - for (kv.value_ptr.items) |reloc| { - const offset = reloc.offset; - const addend = reloc.addend; - if (reloc.type == .pcrel or reloc.type == .nonpcrel) { - const target_atom_index = reloc.target; - const target_atom = self.getAtomPtr(target_atom_index); - const target_symbol = self.syms.items[target_atom.sym_index.?]; - const target_offset = target_atom.offset.?; - - switch (reloc.type) { - .pcrel => { - const disp = @as(i32, @intCast(target_offset)) - @as(i32, @intCast(source_atom.offset.?)) - 4 - @as(i32, @intCast(offset)); - mem.writeInt(i32, code[@as(usize, @intCast(offset))..][0..4], @as(i32, @intCast(disp)), endian); - }, - .nonpcrel => { - if (!self.sixtyfour_bit) { - mem.writeInt(u32, code[@intCast(offset)..][0..4], @as(u32, @intCast(target_offset + addend)), endian); - } else { - mem.writeInt(u64, code[@intCast(offset)..][0..8], target_offset + addend, endian); - } - }, - else => unreachable, - } - log.debug("relocating the address of '{s}' + {d} into '{s}' + {d} (({s}[{d}] = 0x{x} + 0x{x})", .{ target_symbol.name, addend, source_atom_symbol.name, offset, source_atom_symbol.name, offset, target_offset, addend }); - } else { - const addr = switch (reloc.type) { - .special_etext => self.syms.items[self.getAtom(self.etext_edata_end_atom_indices[0].?).sym_index.?].value, - .special_edata => self.syms.items[self.getAtom(self.etext_edata_end_atom_indices[1].?).sym_index.?].value, - .special_end => self.syms.items[self.getAtom(self.etext_edata_end_atom_indices[2].?).sym_index.?].value, - else => unreachable, - }; - if (!self.sixtyfour_bit) { - mem.writeInt(u32, code[@intCast(offset)..][0..4], @as(u32, @intCast(addr + addend)), endian); - } else { - mem.writeInt(u64, code[@intCast(offset)..][0..8], addr + addend, endian); - } - log.debug("relocating the address of '{s}' + {d} into '{s}' + {d} (({s}[{d}] = 0x{x} + 0x{x})", .{ @tagName(reloc.type), addend, source_atom_symbol.name, offset, source_atom_symbol.name, offset, addr, addend }); - } - } - } - } - file.pwritevAll(iovecs, 0) catch |err| return diags.fail("failed to write file: {s}", .{@errorName(err)}); -} -fn addNavExports( - self: *Plan9, - zcu: *Zcu, - nav_index: InternPool.Nav.Index, - export_indices: []const Zcu.Export.Index, -) !void { - const gpa = self.base.comp.gpa; - const metadata = self.navs.getPtr(nav_index).?; - const atom = self.getAtom(metadata.index); - - for (export_indices) |export_idx| { - const exp = export_idx.ptr(zcu); - const exp_name = exp.opts.name.toSlice(&zcu.intern_pool); - // plan9 does not support custom sections - if (exp.opts.section.unwrap()) |section_name| { - if (!section_name.eqlSlice(".text", &zcu.intern_pool) and - !section_name.eqlSlice(".data", &zcu.intern_pool)) - { - try zcu.failed_exports.put(zcu.gpa, export_idx, try Zcu.ErrorMsg.create( - gpa, - zcu.navSrcLoc(nav_index), - "plan9 does not support extra sections", - .{}, - )); - break; - } - } - const sym: aout.Sym = .{ - .value = atom.offset.?, - .type = atom.type.toGlobal(), - .name = try gpa.dupe(u8, exp_name), - }; - - if (metadata.getExport(self, exp_name)) |i| { - self.syms.items[i] = sym; - } else { - try self.syms.append(gpa, sym); - try metadata.exports.append(gpa, self.syms.items.len - 1); - } - } -} - -fn createAtom(self: *Plan9) !Atom.Index { - const gpa = self.base.comp.gpa; - const index = @as(Atom.Index, @intCast(self.atoms.items.len)); - const atom = try self.atoms.addOne(gpa); - atom.* = .{ - .type = .t, - .offset = null, - .sym_index = null, - .got_index = null, - .code = undefined, - }; - return index; -} - -pub fn seeNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !Atom.Index { - const zcu = pt.zcu; - const ip = &zcu.intern_pool; - const gpa = zcu.gpa; - const gop = try self.navs.getOrPut(gpa, nav_index); - if (!gop.found_existing) { - const index = try self.createAtom(); - self.getAtomPtr(index).got_index = self.allocateGotIndex(); - gop.value_ptr.* = .{ - .index = index, - .exports = .{}, - }; - } - const atom_idx = gop.value_ptr.index; - // handle externs here because they might not get updateDecl called on them - const nav = ip.getNav(nav_index); - if (nav.getExtern(ip) != null) { - // this is a "phantom atom" - it is never actually written to disk, just convenient for us to store stuff about externs - if (nav.name.eqlSlice("etext", ip)) { - self.etext_edata_end_atom_indices[0] = atom_idx; - } else if (nav.name.eqlSlice("edata", ip)) { - self.etext_edata_end_atom_indices[1] = atom_idx; - } else if (nav.name.eqlSlice("end", ip)) { - self.etext_edata_end_atom_indices[2] = atom_idx; - } - try self.updateFinish(pt, nav_index); - log.debug("seeNav(extern) for {f} (got_addr=0x{x})", .{ - nav.name.fmt(ip), - self.getAtom(atom_idx).getOffsetTableAddress(self), - }); - } else log.debug("seeNav for {f}", .{nav.name.fmt(ip)}); - return atom_idx; -} - -pub fn updateExports( - self: *Plan9, - pt: Zcu.PerThread, - exported: Zcu.Exported, - export_indices: []const Zcu.Export.Index, -) !void { - const gpa = self.base.comp.gpa; - switch (exported) { - .uav => @panic("TODO: plan9 updateExports handling values"), - .nav => |nav| { - _ = try self.seeNav(pt, nav); - if (self.nav_exports.fetchSwapRemove(nav)) |kv| { - gpa.free(kv.value); - } - try self.nav_exports.ensureUnusedCapacity(gpa, 1); - const duped_indices = try gpa.dupe(Zcu.Export.Index, export_indices); - self.nav_exports.putAssumeCapacityNoClobber(nav, duped_indices); - }, - } - // all proper work is done in flush -} - -pub fn getOrCreateAtomForLazySymbol(self: *Plan9, pt: Zcu.PerThread, lazy_sym: File.LazySymbol) !Atom.Index { - const gop = try self.lazy_syms.getOrPut(pt.zcu.gpa, lazy_sym.ty); - errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); - - if (!gop.found_existing) gop.value_ptr.* = .{}; - - const atom_ptr, const state_ptr = switch (lazy_sym.kind) { - .code => .{ &gop.value_ptr.text_atom, &gop.value_ptr.text_state }, - .const_data => .{ &gop.value_ptr.rodata_atom, &gop.value_ptr.rodata_state }, - }; - switch (state_ptr.*) { - .unused => atom_ptr.* = try self.createAtom(), - .pending_flush => return atom_ptr.*, - .flushed => {}, - } - state_ptr.* = .pending_flush; - const atom = atom_ptr.*; - _ = try self.getAtomPtr(atom).getOrCreateSymbolTableEntry(self); - _ = self.getAtomPtr(atom).getOrCreateOffsetTableEntry(self); - // anyerror needs to be deferred until flush - if (lazy_sym.ty != .anyerror_type) try self.updateLazySymbolAtom(pt, lazy_sym, atom); - return atom; -} - -fn updateLazySymbolAtom( - self: *Plan9, - pt: Zcu.PerThread, - sym: File.LazySymbol, - atom_index: Atom.Index, -) error{ LinkFailure, OutOfMemory }!void { - const gpa = pt.zcu.gpa; - const comp = self.base.comp; - const diags = &comp.link_diags; - - var required_alignment: InternPool.Alignment = .none; - var code_buffer: std.ArrayListUnmanaged(u8) = .empty; - defer code_buffer.deinit(gpa); - - // create the symbol for the name - const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{ - @tagName(sym.kind), - Type.fromInterned(sym.ty).fmt(pt), - }); - - const symbol: aout.Sym = .{ - .value = undefined, - .type = if (sym.kind == .code) .t else .d, - .name = name, - }; - self.syms.items[self.getAtomPtr(atom_index).sym_index.?] = symbol; - - // generate the code - const src = Type.fromInterned(sym.ty).srcLocOrNull(pt.zcu) orelse Zcu.LazySrcLoc.unneeded; - codegen.generateLazySymbol( - &self.base, - pt, - src, - sym, - &required_alignment, - &code_buffer, - .none, - .{ .atom_index = @intCast(atom_index) }, - ) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.CodegenFail => return error.LinkFailure, - error.Overflow, - error.RelocationNotByteAligned, - => return diags.fail("unable to codegen: {s}", .{@errorName(err)}), - }; - const code = code_buffer.items; - // duped_code is freed when the atom is freed - const duped_code = try gpa.dupe(u8, code); - errdefer gpa.free(duped_code); - self.getAtomPtr(atom_index).code = .{ - .code_ptr = duped_code.ptr, - .other = .{ .code_len = duped_code.len }, - }; -} - -pub fn deinit(self: *Plan9) void { - const gpa = self.base.comp.gpa; - { - var it = self.relocs.valueIterator(); - while (it.next()) |relocs| { - relocs.deinit(gpa); - } - self.relocs.deinit(gpa); - } - var it_lzc = self.lazy_syms.iterator(); - while (it_lzc.next()) |kv| { - if (kv.value_ptr.text_state != .unused) - gpa.free(self.syms.items[self.getAtom(kv.value_ptr.text_atom).sym_index.?].name); - if (kv.value_ptr.rodata_state != .unused) - gpa.free(self.syms.items[self.getAtom(kv.value_ptr.rodata_atom).sym_index.?].name); - } - self.lazy_syms.deinit(gpa); - var itf_files = self.fn_nav_table.iterator(); - while (itf_files.next()) |ent| { - // get the submap - var submap = ent.value_ptr.functions; - defer submap.deinit(gpa); - var itf = submap.iterator(); - while (itf.next()) |entry| { - gpa.free(entry.value_ptr.code); - gpa.free(entry.value_ptr.lineinfo); - } - } - self.fn_nav_table.deinit(gpa); - var itd = self.data_nav_table.iterator(); - while (itd.next()) |entry| { - gpa.free(entry.value_ptr.*); - } - var it_uav = self.uavs.iterator(); - while (it_uav.next()) |entry| { - const sym_index = self.getAtom(entry.value_ptr.*).sym_index.?; - gpa.free(self.syms.items[sym_index].name); - } - self.data_nav_table.deinit(gpa); - for (self.nav_exports.values()) |export_indices| { - gpa.free(export_indices); - } - self.nav_exports.deinit(gpa); - self.syms.deinit(gpa); - self.got_index_free_list.deinit(gpa); - self.syms_index_free_list.deinit(gpa); - self.file_segments.deinit(gpa); - self.path_arena.deinit(); - for (self.atoms.items) |a| { - if (a.code.getOwnedCode()) |c| { - gpa.free(c); - } - } - self.atoms.deinit(gpa); - - { - var it = self.navs.iterator(); - while (it.next()) |entry| { - entry.value_ptr.exports.deinit(gpa); - } - self.navs.deinit(gpa); - } -} - -pub fn open( - arena: Allocator, - comp: *Compilation, - emit: Path, - options: link.File.OpenOptions, -) !*Plan9 { - const target = &comp.root_mod.resolved_target.result; - const use_lld = build_options.have_llvm and comp.config.use_lld; - const use_llvm = comp.config.use_llvm; - - assert(!use_llvm); // Caught by Compilation.Config.resolve. - assert(!use_lld); // Caught by Compilation.Config.resolve. - assert(target.ofmt == .plan9); - - const self = try createEmpty(arena, comp, emit, options); - errdefer self.base.destroy(); - - const file = try emit.root_dir.handle.createFile(emit.sub_path, .{ - .read = true, - .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode), - }); - errdefer file.close(); - self.base.file = file; - - self.bases = defaultBaseAddrs(target.cpu.arch); - - const gpa = comp.gpa; - - try self.syms.appendSlice(gpa, &.{ - // we include the global offset table to make it easier for debugging - .{ - .value = self.getAddr(0, .d), // the global offset table starts at 0 - .type = .d, - .name = "__GOT", - }, - }); - - return self; -} - -pub fn writeSym(self: *Plan9, w: anytype, sym: aout.Sym) !void { - // log.debug("write sym{{name: {s}, value: {x}}}", .{ sym.name, sym.value }); - if (sym.type == .bad) return; // we don't want to write free'd symbols - if (!self.sixtyfour_bit) { - try w.writeInt(u32, @as(u32, @intCast(sym.value)), .big); - } else { - try w.writeInt(u64, sym.value, .big); - } - try w.writeByte(@intFromEnum(sym.type)); - try w.writeAll(sym.name); - try w.writeByte(0); -} - -pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { - const zcu = self.base.comp.zcu.?; - const ip = &zcu.intern_pool; - const writer = buf.writer(); - // write __GOT - try self.writeSym(writer, self.syms.items[0]); - // write the f symbols - { - var it = self.file_segments.iterator(); - while (it.next()) |entry| { - try self.writeSym(writer, .{ - .type = .f, - .value = entry.value_ptr.*, - .name = entry.key_ptr.*, - }); - } - } - - // write the data symbols - { - var it = self.data_nav_table.iterator(); - while (it.next()) |entry| { - const nav_index = entry.key_ptr.*; - const nav_metadata = self.navs.get(nav_index).?; - const atom = self.getAtom(nav_metadata.index); - const sym = self.syms.items[atom.sym_index.?]; - try self.writeSym(writer, sym); - if (self.nav_exports.get(nav_index)) |export_indices| { - for (export_indices) |export_idx| { - const exp = export_idx.ptr(zcu); - if (nav_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| { - try self.writeSym(writer, self.syms.items[exp_i]); - } - } - } - } - } - // the data lazy symbols - { - var it = self.lazy_syms.iterator(); - while (it.next()) |kv| { - const meta = kv.value_ptr; - const data_atom = if (meta.rodata_state != .unused) self.getAtomPtr(meta.rodata_atom) else continue; - const sym = self.syms.items[data_atom.sym_index.?]; - try self.writeSym(writer, sym); - } - } - // text symbols are the hardest: - // the file of a text symbol is the .z symbol before it - // so we have to write everything in the right order - { - var it_file = self.fn_nav_table.iterator(); - while (it_file.next()) |fentry| { - var symidx_and_submap = fentry.value_ptr; - // write the z symbols - try self.writeSym(writer, self.syms.items[symidx_and_submap.sym_index - 1]); - try self.writeSym(writer, self.syms.items[symidx_and_submap.sym_index]); - - // write all the decls come from the file of the z symbol - var submap_it = symidx_and_submap.functions.iterator(); - while (submap_it.next()) |entry| { - const nav_index = entry.key_ptr.*; - const nav_metadata = self.navs.get(nav_index).?; - const atom = self.getAtom(nav_metadata.index); - const sym = self.syms.items[atom.sym_index.?]; - try self.writeSym(writer, sym); - if (self.nav_exports.get(nav_index)) |export_indices| { - for (export_indices) |export_idx| { - const exp = export_idx.ptr(zcu); - if (nav_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| { - const s = self.syms.items[exp_i]; - if (mem.eql(u8, s.name, "_start")) - self.entry_val = s.value; - try self.writeSym(writer, s); - } - } - } - } - } - // the text lazy symbols - { - var it = self.lazy_syms.iterator(); - while (it.next()) |kv| { - const meta = kv.value_ptr; - const text_atom = if (meta.text_state != .unused) self.getAtomPtr(meta.text_atom) else continue; - const sym = self.syms.items[text_atom.sym_index.?]; - try self.writeSym(writer, sym); - } - } - } - // special symbols - for (self.etext_edata_end_atom_indices) |idx| { - if (idx) |atom_idx| { - const atom = self.getAtom(atom_idx); - const sym = self.syms.items[atom.sym_index.?]; - try self.writeSym(writer, sym); - } - } -} - -pub fn updateLineNumber(self: *Plan9, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void { - _ = self; - _ = pt; - _ = ti_id; -} - -pub fn getNavVAddr( - self: *Plan9, - pt: Zcu.PerThread, - nav_index: InternPool.Nav.Index, - reloc_info: link.File.RelocInfo, -) !u64 { - const ip = &pt.zcu.intern_pool; - const nav = ip.getNav(nav_index); - log.debug("getDeclVAddr for {f}", .{nav.name.fmt(ip)}); - if (nav.getExtern(ip) != null) { - if (nav.name.eqlSlice("etext", ip)) { - try self.addReloc(reloc_info.parent.atom_index, .{ - .target = undefined, - .offset = reloc_info.offset, - .addend = reloc_info.addend, - .type = .special_etext, - }); - } else if (nav.name.eqlSlice("edata", ip)) { - try self.addReloc(reloc_info.parent.atom_index, .{ - .target = undefined, - .offset = reloc_info.offset, - .addend = reloc_info.addend, - .type = .special_edata, - }); - } else if (nav.name.eqlSlice("end", ip)) { - try self.addReloc(reloc_info.parent.atom_index, .{ - .target = undefined, - .offset = reloc_info.offset, - .addend = reloc_info.addend, - .type = .special_end, - }); - } - // TODO handle other extern variables and functions - return undefined; - } - // otherwise, we just add a relocation - const atom_index = try self.seeNav(pt, nav_index); - // the parent_atom_index in this case is just the decl_index of the parent - try self.addReloc(reloc_info.parent.atom_index, .{ - .target = atom_index, - .offset = reloc_info.offset, - .addend = reloc_info.addend, - }); - return undefined; -} - -pub fn lowerUav( - self: *Plan9, - pt: Zcu.PerThread, - uav: InternPool.Index, - explicit_alignment: InternPool.Alignment, - src_loc: Zcu.LazySrcLoc, -) !codegen.SymbolResult { - _ = explicit_alignment; - // example: - // const ty = mod.intern_pool.typeOf(decl_val).toType(); - // const val = decl_val.toValue(); - // The symbol name can be something like `__anon_{d}` with `@intFromEnum(decl_val)`. - // It doesn't have an owner decl because it's just an unnamed constant that might - // be used by more than one function, however, its address is being used so we need - // to put it in some location. - // ... - const gpa = self.base.comp.gpa; - const gop = try self.uavs.getOrPut(gpa, uav); - if (gop.found_existing) return .{ .sym_index = gop.value_ptr.* }; - const val = Value.fromInterned(uav); - const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(uav)}); - - const index = try self.createAtom(); - const got_index = self.allocateGotIndex(); - gop.value_ptr.* = index; - // we need to free name latex - var code_buffer: std.ArrayListUnmanaged(u8) = .empty; - defer code_buffer.deinit(gpa); - try codegen.generateSymbol(&self.base, pt, src_loc, val, &code_buffer, .{ .atom_index = index }); - const atom_ptr = self.getAtomPtr(index); - atom_ptr.* = .{ - .type = .d, - .offset = undefined, - .sym_index = null, - .got_index = got_index, - .code = Atom.CodePtr.fromSlice(try code_buffer.toOwnedSlice(gpa)), - }; - _ = try atom_ptr.getOrCreateSymbolTableEntry(self); - self.syms.items[atom_ptr.sym_index.?] = .{ - .type = .d, - .value = undefined, - .name = name, - }; - return .{ .sym_index = index }; -} - -pub fn getUavVAddr(self: *Plan9, uav: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { - const atom_index = self.uavs.get(uav).?; - try self.addReloc(reloc_info.parent.atom_index, .{ - .target = atom_index, - .offset = reloc_info.offset, - .addend = reloc_info.addend, - }); - return undefined; -} - -pub fn addReloc(self: *Plan9, parent_index: Atom.Index, reloc: Reloc) !void { - const gpa = self.base.comp.gpa; - const gop = try self.relocs.getOrPut(gpa, parent_index); - if (!gop.found_existing) { - gop.value_ptr.* = .{}; - } - try gop.value_ptr.append(gpa, reloc); -} - -pub fn getAtom(self: *const Plan9, index: Atom.Index) Atom { - return self.atoms.items[index]; -} - -fn getAtomPtr(self: *Plan9, index: Atom.Index) *Atom { - return &self.atoms.items[index]; -} diff --git a/src/link/Plan9/aout.zig b/src/link/Plan9/aout.zig deleted file mode 100644 index 3d35bb9acb..0000000000 --- a/src/link/Plan9/aout.zig +++ /dev/null @@ -1,131 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; - -/// All integers are in big-endian format (needs a byteswap). -pub const ExecHdr = extern struct { - magic: u32, - text: u32, - data: u32, - bss: u32, - syms: u32, - /// You should truncate this to 32 bits on 64 bit systems, then but the actual 8 bytes - /// in the fat header. - entry: u32, - spsz: u32, - pcsz: u32, - comptime { - assert(@sizeOf(@This()) == 32); - } - /// It is up to the caller to discard the last 8 bytes if the header is not fat. - pub fn toU8s(self: *@This()) [40]u8 { - var buf: [40]u8 = undefined; - var i: u8 = 0; - inline for (std.meta.fields(@This())) |f| { - std.mem.writeInt(u32, buf[i..][0..4], @field(self, f.name), .big); - i += 4; - } - return buf; - } -}; - -pub const Sym = struct { - /// Big endian in the file - value: u64, - type: Type, - name: []const u8, - - pub const undefined_symbol: Sym = .{ - .value = undefined, - .type = .bad, - .name = "undefined_symbol", - }; - - /// 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 Type = 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', - /// represents an undefined symbol, to be removed in flush - bad = 0, - - pub fn toGlobal(self: Type) Type { - return switch (self) { - .t => .T, - .b => .B, - .d => .D, - else => unreachable, - }; - } - }; -}; - -pub const HDR_MAGIC = 0x00008000; -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(0, 8); // 68020 -pub const I_MAGIC = _MAGIC(0, 11); // intel 386 -pub const J_MAGIC = _MAGIC(0, 12); // intel 960 (retired) -pub const K_MAGIC = _MAGIC(0, 13); // sparc -pub const V_MAGIC = _MAGIC(0, 16); // mips 3000 BE -pub const X_MAGIC = _MAGIC(0, 17); // att dsp 3210 (retired) -pub const M_MAGIC = _MAGIC(0, 18); // mips 4000 BE -pub const D_MAGIC = _MAGIC(0, 19); // amd 29000 (retired) -pub const E_MAGIC = _MAGIC(0, 20); // arm -pub const Q_MAGIC = _MAGIC(0, 21); // powerpc -pub const N_MAGIC = _MAGIC(0, 22); // mips 4000 LE -pub const L_MAGIC = _MAGIC(0, 23); // dec alpha (retired) -pub const P_MAGIC = _MAGIC(0, 24); // mips 3000 LE -pub const U_MAGIC = _MAGIC(0, 25); // sparc64 -pub const S_MAGIC = _MAGIC(HDR_MAGIC, 26); // amd64 -pub const T_MAGIC = _MAGIC(HDR_MAGIC, 27); // powerpc64 -pub const R_MAGIC = _MAGIC(HDR_MAGIC, 28); // arm64 - -pub fn magicFromArch(arch: std.Target.Cpu.Arch) !u32 { - return switch (arch) { - .x86 => I_MAGIC, - .sparc => K_MAGIC, // TODO should sparc64 go here? - .mips => V_MAGIC, - .arm => E_MAGIC, - .aarch64 => R_MAGIC, - .powerpc => Q_MAGIC, - .powerpc64 => T_MAGIC, - .x86_64 => S_MAGIC, - else => error.ArchNotSupportedByPlan9, - }; -} - -/// gets the quantization of pc for the arch -pub fn getPCQuant(arch: std.Target.Cpu.Arch) !u8 { - return switch (arch) { - .x86, .x86_64 => 1, - .powerpc, .powerpc64, .mips, .sparc, .arm, .aarch64 => 4, - else => error.ArchNotSupportedByPlan9, - }; -}