| author | |
| committer | |
| log | 798162e5095aff130395ee542c0c0948f95180c9 |
| tree | baa971347a8bad4f2df54dff23f750c6066eff84 |
| parent | 34c21affa2429cf07042eb2f225ee59194998802 |
We can now run binaries! (they segfault, but still run!)5 files changed, 335 insertions(+), 39 deletions(-)
src/Module.zig+5-5| ... | @@ -3517,7 +3517,7 @@ pub fn clearDecl( | ... | @@ -3517,7 +3517,7 @@ pub fn clearDecl( |
| 3517 | .coff => .{ .coff = link.File.Coff.TextBlock.empty }, | 3517 | .coff => .{ .coff = link.File.Coff.TextBlock.empty }, |
| 3518 | .elf => .{ .elf = link.File.Elf.TextBlock.empty }, | 3518 | .elf => .{ .elf = link.File.Elf.TextBlock.empty }, |
| 3519 | .macho => .{ .macho = link.File.MachO.TextBlock.empty }, | 3519 | .macho => .{ .macho = link.File.MachO.TextBlock.empty }, |
| 3520 | .plan9 => @panic("plan9 link"), | 3520 | .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty }, |
| 3521 | .c => .{ .c = link.File.C.DeclBlock.empty }, | 3521 | .c => .{ .c = link.File.C.DeclBlock.empty }, |
| 3522 | .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, | 3522 | .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, |
| 3523 | .spirv => .{ .spirv = {} }, | 3523 | .spirv => .{ .spirv = {} }, |
| ... | @@ -3526,7 +3526,7 @@ pub fn clearDecl( | ... | @@ -3526,7 +3526,7 @@ pub fn clearDecl( |
| 3526 | .coff => .{ .coff = {} }, | 3526 | .coff => .{ .coff = {} }, |
| 3527 | .elf => .{ .elf = link.File.Elf.SrcFn.empty }, | 3527 | .elf => .{ .elf = link.File.Elf.SrcFn.empty }, |
| 3528 | .macho => .{ .macho = link.File.MachO.SrcFn.empty }, | 3528 | .macho => .{ .macho = link.File.MachO.SrcFn.empty }, |
| 3529 | .plan9 => @panic("plan9 fn_link"), | 3529 | .plan9 => .{ .plan9 = {} }, |
| 3530 | .c => .{ .c = link.File.C.FnBlock.empty }, | 3530 | .c => .{ .c = link.File.C.FnBlock.empty }, |
| 3531 | .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, | 3531 | .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, |
| 3532 | .spirv => .{ .spirv = .{} }, | 3532 | .spirv => .{ .spirv = .{} }, |
| ... | @@ -3694,7 +3694,7 @@ fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node | ... | @@ -3694,7 +3694,7 @@ fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node |
| 3694 | .coff => .{ .coff = link.File.Coff.TextBlock.empty }, | 3694 | .coff => .{ .coff = link.File.Coff.TextBlock.empty }, |
| 3695 | .elf => .{ .elf = link.File.Elf.TextBlock.empty }, | 3695 | .elf => .{ .elf = link.File.Elf.TextBlock.empty }, |
| 3696 | .macho => .{ .macho = link.File.MachO.TextBlock.empty }, | 3696 | .macho => .{ .macho = link.File.MachO.TextBlock.empty }, |
| 3697 | .plan9 => @panic("PLan9 export"), | 3697 | .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty }, |
| 3698 | .c => .{ .c = link.File.C.DeclBlock.empty }, | 3698 | .c => .{ .c = link.File.C.DeclBlock.empty }, |
| 3699 | .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, | 3699 | .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, |
| 3700 | .spirv => .{ .spirv = {} }, | 3700 | .spirv => .{ .spirv = {} }, |
| ... | @@ -3703,7 +3703,7 @@ fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node | ... | @@ -3703,7 +3703,7 @@ fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node |
| 3703 | .coff => .{ .coff = {} }, | 3703 | .coff => .{ .coff = {} }, |
| 3704 | .elf => .{ .elf = link.File.Elf.SrcFn.empty }, | 3704 | .elf => .{ .elf = link.File.Elf.SrcFn.empty }, |
| 3705 | .macho => .{ .macho = link.File.MachO.SrcFn.empty }, | 3705 | .macho => .{ .macho = link.File.MachO.SrcFn.empty }, |
| 3706 | .plan9 => .{ .plan9 = link.File.Plan9.SrcFn.empty }, | 3706 | .plan9 => .{ .plan9 = {} }, |
| 3707 | .c => .{ .c = link.File.C.FnBlock.empty }, | 3707 | .c => .{ .c = link.File.C.FnBlock.empty }, |
| 3708 | .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, | 3708 | .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, |
| 3709 | .spirv => .{ .spirv = .{} }, | 3709 | .spirv => .{ .spirv = .{} }, |
| ... | @@ -3773,7 +3773,7 @@ pub fn analyzeExport( | ... | @@ -3773,7 +3773,7 @@ pub fn analyzeExport( |
| 3773 | .coff => .{ .coff = {} }, | 3773 | .coff => .{ .coff = {} }, |
| 3774 | .elf => .{ .elf = link.File.Elf.Export{} }, | 3774 | .elf => .{ .elf = link.File.Elf.Export{} }, |
| 3775 | .macho => .{ .macho = link.File.MachO.Export{} }, | 3775 | .macho => .{ .macho = link.File.MachO.Export{} }, |
| 3776 | .plan9 => @panic("plan9 link"), | 3776 | .plan9 => .{ .plan9 = null }, |
| 3777 | .c => .{ .c = {} }, | 3777 | .c => .{ .c = {} }, |
| 3778 | .wasm => .{ .wasm = {} }, | 3778 | .wasm => .{ .wasm = {} }, |
| 3779 | .spirv => .{ .spirv = {} }, | 3779 | .spirv => .{ .spirv = {} }, |
src/codegen.zig+13-3| ... | @@ -2556,9 +2556,19 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2556,9 +2556,19 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2556 | } else { | 2556 | } else { |
| 2557 | return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); | 2557 | return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); |
| 2558 | } | 2558 | } |
| 2559 | } else { | 2559 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { |
| 2560 | unreachable; | 2560 | if (inst.func.value()) |func_value| { |
| 2561 | } | 2561 | if (func_value.castTag(.function)) |func_payload| { |
| 2562 | try p9.addCallReloc(self.code, .{ | ||
| 2563 | .caller = p9.cur_decl, | ||
| 2564 | .callee = func_payload.data.owner_decl, | ||
| 2565 | .offset_in_caller = self.code.items.len, | ||
| 2566 | }); | ||
| 2567 | } else return self.fail(inst.base.src, "TODO implement calling extern fn on plan9", .{}); | ||
| 2568 | } else { | ||
| 2569 | return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); | ||
| 2570 | } | ||
| 2571 | } else unreachable; | ||
| 2562 | 2572 | ||
| 2563 | switch (info.return_value) { | 2573 | switch (info.return_value) { |
| 2564 | .register => |reg| { | 2574 | .register => |reg| { |
src/link.zig+5-4| ... | @@ -141,6 +141,7 @@ pub const File = struct { | ... | @@ -141,6 +141,7 @@ pub const File = struct { |
| 141 | elf: Elf.TextBlock, | 141 | elf: Elf.TextBlock, |
| 142 | coff: Coff.TextBlock, | 142 | coff: Coff.TextBlock, |
| 143 | macho: MachO.TextBlock, | 143 | macho: MachO.TextBlock, |
| 144 | plan9: Plan9.DeclBlock, | ||
| 144 | c: C.DeclBlock, | 145 | c: C.DeclBlock, |
| 145 | wasm: Wasm.DeclBlock, | 146 | wasm: Wasm.DeclBlock, |
| 146 | spirv: void, | 147 | spirv: void, |
| ... | @@ -150,7 +151,7 @@ pub const File = struct { | ... | @@ -150,7 +151,7 @@ pub const File = struct { |
| 150 | elf: Elf.SrcFn, | 151 | elf: Elf.SrcFn, |
| 151 | coff: Coff.SrcFn, | 152 | coff: Coff.SrcFn, |
| 152 | macho: MachO.SrcFn, | 153 | macho: MachO.SrcFn, |
| 153 | plan9: Plan9.SrcFn, | 154 | plan9: void, |
| 154 | c: C.FnBlock, | 155 | c: C.FnBlock, |
| 155 | wasm: Wasm.FnData, | 156 | wasm: Wasm.FnData, |
| 156 | spirv: SpirV.FnData, | 157 | spirv: SpirV.FnData, |
| ... | @@ -207,12 +208,12 @@ pub const File = struct { | ... | @@ -207,12 +208,12 @@ pub const File = struct { |
| 207 | .coff, .pe => &(try Coff.createEmpty(allocator, options)).base, | 208 | .coff, .pe => &(try Coff.createEmpty(allocator, options)).base, |
| 208 | .elf => &(try Elf.createEmpty(allocator, options)).base, | 209 | .elf => &(try Elf.createEmpty(allocator, options)).base, |
| 209 | .macho => &(try MachO.createEmpty(allocator, options)).base, | 210 | .macho => &(try MachO.createEmpty(allocator, options)).base, |
| 211 | .plan9 => &(try Plan9.createEmpty(allocator, options)).base, | ||
| 210 | .wasm => &(try Wasm.createEmpty(allocator, options)).base, | 212 | .wasm => &(try Wasm.createEmpty(allocator, options)).base, |
| 211 | .c => unreachable, // Reported error earlier. | 213 | .c => unreachable, // Reported error earlier. |
| 212 | .spirv => &(try SpirV.createEmpty(allocator, options)).base, | 214 | .spirv => &(try SpirV.createEmpty(allocator, options)).base, |
| 213 | .hex => return error.HexObjectFormatUnimplemented, | 215 | .hex => return error.HexObjectFormatUnimplemented, |
| 214 | .raw => return error.RawObjectFormatUnimplemented, | 216 | .raw => return error.RawObjectFormatUnimplemented, |
| 215 | .plan9 => return error.Plan9ObjectFormatUnimplemented, | ||
| 216 | }; | 217 | }; |
| 217 | } | 218 | } |
| 218 | // Open a temporary object file, not the final output file because we want to link with LLD. | 219 | // 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 { | ... | @@ -224,12 +225,12 @@ pub const File = struct { |
| 224 | .coff, .pe => &(try Coff.openPath(allocator, sub_path, options)).base, | 225 | .coff, .pe => &(try Coff.openPath(allocator, sub_path, options)).base, |
| 225 | .elf => &(try Elf.openPath(allocator, sub_path, options)).base, | 226 | .elf => &(try Elf.openPath(allocator, sub_path, options)).base, |
| 226 | .macho => &(try MachO.openPath(allocator, sub_path, options)).base, | 227 | .macho => &(try MachO.openPath(allocator, sub_path, options)).base, |
| 228 | .plan9 => &(try Plan9.openPath(allocator, sub_path, options)).base, | ||
| 227 | .wasm => &(try Wasm.openPath(allocator, sub_path, options)).base, | 229 | .wasm => &(try Wasm.openPath(allocator, sub_path, options)).base, |
| 228 | .c => &(try C.openPath(allocator, sub_path, options)).base, | 230 | .c => &(try C.openPath(allocator, sub_path, options)).base, |
| 229 | .spirv => &(try SpirV.openPath(allocator, sub_path, options)).base, | 231 | .spirv => &(try SpirV.openPath(allocator, sub_path, options)).base, |
| 230 | .hex => return error.HexObjectFormatUnimplemented, | 232 | .hex => return error.HexObjectFormatUnimplemented, |
| 231 | .raw => return error.RawObjectFormatUnimplemented, | 233 | .raw => return error.RawObjectFormatUnimplemented, |
| 232 | .plan9 => return error.Plan9ObjectFormatUnimplemented, | ||
| 233 | }; | 234 | }; |
| 234 | 235 | ||
| 235 | if (use_lld) { | 236 | if (use_lld) { |
| ... | @@ -347,7 +348,7 @@ pub const File = struct { | ... | @@ -347,7 +348,7 @@ pub const File = struct { |
| 347 | .macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl), | 348 | .macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl), |
| 348 | .c => return @fieldParentPtr(C, "base", base).allocateDeclIndexes(decl), | 349 | .c => return @fieldParentPtr(C, "base", base).allocateDeclIndexes(decl), |
| 349 | .wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl), | 350 | .wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl), |
| 350 | .plan9 => return @fieldParentPtr(Plan9, "base", base).allocateDeclIndexes(decl), | 351 | .plan9 => {}, |
| 351 | .spirv => {}, | 352 | .spirv => {}, |
| 352 | } | 353 | } |
| 353 | } | 354 | } |
src/link/Plan9.zig+190-27| ... | @@ -4,35 +4,66 @@ const std = @import("std"); | ... | @@ -4,35 +4,66 @@ const std = @import("std"); |
| 4 | const link = @import("../link.zig"); | 4 | const link = @import("../link.zig"); |
| 5 | const Module = @import("../Module.zig"); | 5 | const Module = @import("../Module.zig"); |
| 6 | const Compilation = @import("../Compilation.zig"); | 6 | const Compilation = @import("../Compilation.zig"); |
| 7 | const aout = @import("plan9/a.out.zig"); | ||
| 8 | const codegen = @import("../codegen.zig"); | ||
| 9 | const trace = @import("../tracy.zig").trace; | ||
| 10 | const mem = std.mem; | ||
| 7 | const File = link.File; | 11 | const File = link.File; |
| 8 | const Allocator = std.mem.Allocator; | 12 | const Allocator = std.mem.Allocator; |
| 9 | 13 | ||
| 10 | const log = std.log.scoped(.link); | 14 | const log = std.log.scoped(.link); |
| 15 | const assert = std.debug.assert; | ||
| 16 | |||
| 17 | // TODO use incremental compilation | ||
| 11 | 18 | ||
| 12 | base: link.File, | 19 | base: link.File, |
| 20 | ptr_width: PtrWidth, | ||
| 13 | error_flags: File.ErrorFlags = File.ErrorFlags{}, | 21 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 14 | 22 | ||
| 15 | pub const SrcFn = struct { | 23 | decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{}, |
| 16 | /// Offset from the beginning of the Debug Line Program header that contains this function. | 24 | /// is just casted down when 32 bit |
| 17 | off: u32, | 25 | syms: std.ArrayListUnmanaged(aout.Sym64) = .{}, |
| 18 | /// Size of the line number program component belonging to this function, not | 26 | call_relocs: std.ArrayListUnmanaged(CallReloc) = .{}, |
| 19 | /// including padding. | 27 | text_buf: std.ArrayListUnmanaged(u8) = .{}, |
| 20 | len: u32, | 28 | data_buf: std.ArrayListUnmanaged(u8) = .{}, |
| 21 | 29 | ||
| 22 | /// Points to the previous and next neighbors, based on the offset from .debug_line. | 30 | cur_decl: *Module.Decl = undefined, |
| 23 | /// This can be used to find, for example, the capacity of this `SrcFn`. | 31 | hdr: aout.ExecHdr = undefined, |
| 24 | prev: ?*SrcFn, | 32 | |
| 25 | next: ?*SrcFn, | 33 | fn headerSize(self: Plan9) u32 { |
| 26 | 34 | // fat header (currently unused) | |
| 27 | pub const empty: SrcFn = .{ | 35 | const fat: u4 = if (self.ptr_width == .p64) 8 else 0; |
| 28 | .off = 0, | 36 | return aout.ExecHdr.size() + fat; |
| 29 | .len = 0, | 37 | } |
| 30 | .prev = null, | 38 | pub const DeclBlock = struct { |
| 31 | .next = null, | 39 | type: enum { text, data }, |
| 40 | // offset in the text or data sects | ||
| 41 | offset: u32, | ||
| 42 | pub const empty = DeclBlock{ | ||
| 43 | .type = .text, | ||
| 44 | .offset = 0, | ||
| 32 | }; | 45 | }; |
| 33 | }; | 46 | }; |
| 34 | 47 | ||
| 48 | // TODO change base addr based on target (right now it just works on amd64) | ||
| 49 | const default_base_addr = 0x00200000; | ||
| 50 | |||
| 51 | pub const CallReloc = struct { | ||
| 52 | caller: *Module.Decl, | ||
| 53 | callee: *Module.Decl, | ||
| 54 | offset_in_caller: usize, | ||
| 55 | }; | ||
| 56 | |||
| 57 | pub const PtrWidth = enum { p32, p64 }; | ||
| 58 | |||
| 35 | pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { | 59 | pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { |
| 60 | if (options.use_llvm) | ||
| 61 | return error.LLVMBackendDoesNotSupportPlan9; | ||
| 62 | const ptr_width: PtrWidth = switch (options.target.cpu.arch.ptrBitWidth()) { | ||
| 63 | 0...32 => .p32, | ||
| 64 | 33...64 => .p64, | ||
| 65 | else => return error.UnsupportedELFArchitecture, | ||
| 66 | }; | ||
| 36 | const self = try gpa.create(Plan9); | 67 | const self = try gpa.create(Plan9); |
| 37 | self.* = .{ | 68 | self.* = .{ |
| 38 | .base = .{ | 69 | .base = .{ |
| ... | @@ -41,25 +72,157 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { | ... | @@ -41,25 +72,157 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { |
| 41 | .allocator = gpa, | 72 | .allocator = gpa, |
| 42 | .file = null, | 73 | .file = null, |
| 43 | }, | 74 | }, |
| 75 | .ptr_width = ptr_width, | ||
| 44 | }; | 76 | }; |
| 45 | return self; | 77 | return self; |
| 46 | } | 78 | } |
| 47 | 79 | ||
| 48 | pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void {} | 80 | pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void { |
| 81 | _ = try self.decl_table.getOrPut(self.base.allocator, decl); | ||
| 82 | } | ||
| 83 | |||
| 84 | pub fn flush(self: *Plan9, comp: *Compilation) !void { | ||
| 85 | assert(!self.base.options.use_lld); | ||
| 86 | |||
| 87 | switch (self.base.options.effectiveOutputMode()) { | ||
| 88 | .Exe => {}, | ||
| 89 | // plan9 object files are totally different | ||
| 90 | .Obj => return error.TODOImplementPlan9Objs, | ||
| 91 | .Lib => return error.TODOImplementWritingLibFiles, | ||
| 92 | } | ||
| 93 | return self.flushModule(comp); | ||
| 94 | } | ||
| 95 | pub fn flushModule(self: *Plan9, comp: *Compilation) !void { | ||
| 96 | const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; | ||
| 49 | 97 | ||
| 50 | pub fn allocateDeclIndexes(self: *Plan9, decl: *Module.Decl) !void {} | 98 | // generate the header |
| 99 | self.hdr.magic = try aout.magicFromArch(self.base.options.target.cpu.arch); | ||
| 100 | const file = self.base.file.?; | ||
| 101 | try file.seekTo(self.headerSize()); | ||
| 102 | |||
| 103 | // temporary buffer | ||
| 104 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | ||
| 105 | defer code_buffer.deinit(); | ||
| 106 | { | ||
| 107 | for (self.decl_table.keys()) |decl| { | ||
| 108 | if (!decl.has_tv) continue; | ||
| 109 | self.cur_decl = decl; | ||
| 110 | const is_fn = (decl.ty.zigTypeTag() == .Fn); | ||
| 111 | decl.link.plan9 = if (is_fn) .{ | ||
| 112 | .offset = @intCast(u32, self.text_buf.items.len), | ||
| 113 | .type = .text, | ||
| 114 | } else .{ | ||
| 115 | .offset = @intCast(u32, self.data_buf.items.len), | ||
| 116 | .type = .data, | ||
| 117 | }; | ||
| 118 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | ||
| 119 | .ty = decl.ty, | ||
| 120 | .val = decl.val, | ||
| 121 | }, &code_buffer, .{ .none = {} }); | ||
| 122 | const code = switch (res) { | ||
| 123 | .externally_managed => |x| x, | ||
| 124 | .appended => code_buffer.items, | ||
| 125 | .fail => |em| { | ||
| 126 | decl.analysis = .codegen_failure; | ||
| 127 | try module.failed_decls.put(module.gpa, decl, em); | ||
| 128 | // TODO try to do more decls | ||
| 129 | return; | ||
| 130 | }, | ||
| 131 | }; | ||
| 132 | if (is_fn) | ||
| 133 | try self.text_buf.appendSlice(self.base.allocator, code) | ||
| 134 | else | ||
| 135 | try self.data_buf.appendSlice(self.base.allocator, code); | ||
| 136 | code_buffer.items.len = 0; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | try file.writeAll(self.text_buf.items); | ||
| 140 | try file.writeAll(self.data_buf.items); | ||
| 141 | try file.seekTo(0); | ||
| 142 | self.hdr.text = @intCast(u32, self.text_buf.items.len); | ||
| 143 | self.hdr.data = @intCast(u32, self.data_buf.items.len); | ||
| 144 | self.hdr.pcsz = 0; | ||
| 145 | self.hdr.spsz = 0; | ||
| 146 | inline for (std.meta.fields(aout.ExecHdr)) |f| { | ||
| 147 | try file.writer().writeIntBig(f.field_type, @field(self.hdr, f.name)); | ||
| 148 | } | ||
| 149 | } | ||
| 150 | pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void { | ||
| 151 | assert(self.decl_table.swapRemove(decl)); | ||
| 152 | } | ||
| 51 | 153 | ||
| 52 | pub fn flush(self: *Plan9, comp: *Compilation) !void {} | ||
| 53 | pub fn flushModule(self: *Plan9, comp: *Compilation) !void {} | ||
| 54 | pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void {} | ||
| 55 | pub fn updateDeclExports( | 154 | pub fn updateDeclExports( |
| 56 | self: *Plan9, | 155 | self: *Plan9, |
| 57 | module: *Module, | 156 | module: *Module, |
| 58 | decl: *Module.Decl, | 157 | decl: *Module.Decl, |
| 59 | exports: []const *Module.Export, | 158 | exports: []const *Module.Export, |
| 60 | ) !void {} | 159 | ) !void { |
| 61 | pub fn deinit(self: *Plan9) void {} | 160 | for (exports) |exp| { |
| 161 | if (exp.options.section) |section_name| { | ||
| 162 | if (!mem.eql(u8, section_name, ".text")) { | ||
| 163 | try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.count() + 1); | ||
| 164 | module.failed_exports.putAssumeCapacityNoClobber( | ||
| 165 | exp, | ||
| 166 | try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "plan9 does not support extra sections", .{}), | ||
| 167 | ); | ||
| 168 | continue; | ||
| 169 | } | ||
| 170 | } | ||
| 171 | if (std.mem.eql(u8, exp.options.name, "_start")) { | ||
| 172 | std.debug.assert(decl.link.plan9.type == .text); // we tried to link a non-function as _start | ||
| 173 | self.hdr.entry = Plan9.default_base_addr + self.headerSize() + decl.link.plan9.offset; | ||
| 174 | } | ||
| 175 | if (exp.link.plan9) |i| { | ||
| 176 | const sym = &self.syms.items[i]; | ||
| 177 | sym.* = .{ | ||
| 178 | .value = decl.link.plan9.offset, | ||
| 179 | .type = switch (decl.link.plan9.type) { | ||
| 180 | .text => .T, | ||
| 181 | .data => .D, | ||
| 182 | }, | ||
| 183 | .name = decl.name, | ||
| 184 | }; | ||
| 185 | } else { | ||
| 186 | try self.syms.append(self.base.allocator, .{ | ||
| 187 | .value = decl.link.plan9.offset, | ||
| 188 | .type = switch (decl.link.plan9.type) { | ||
| 189 | .text => .T, | ||
| 190 | .data => .D, | ||
| 191 | }, | ||
| 192 | .name = decl.name, | ||
| 193 | }); | ||
| 194 | } | ||
| 195 | } | ||
| 196 | } | ||
| 197 | pub fn deinit(self: *Plan9) void { | ||
| 198 | self.decl_table.deinit(self.base.allocator); | ||
| 199 | self.call_relocs.deinit(self.base.allocator); | ||
| 200 | self.syms.deinit(self.base.allocator); | ||
| 201 | self.text_buf.deinit(self.base.allocator); | ||
| 202 | self.data_buf.deinit(self.base.allocator); | ||
| 203 | } | ||
| 62 | 204 | ||
| 63 | pub const Export = struct { | 205 | pub const Export = ?usize; |
| 64 | sym_index: ?u32 = null, | 206 | pub const base_tag = .plan9; |
| 65 | }; | 207 | pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Plan9 { |
| 208 | if (options.use_llvm) | ||
| 209 | return error.LLVMBackendDoesNotSupportPlan9; | ||
| 210 | assert(options.object_format == .plan9); | ||
| 211 | const file = try options.emit.?.directory.handle.createFile(sub_path, .{ | ||
| 212 | .truncate = false, | ||
| 213 | .read = true, | ||
| 214 | .mode = link.determineMode(options), | ||
| 215 | }); | ||
| 216 | errdefer file.close(); | ||
| 217 | |||
| 218 | const self = try createEmpty(allocator, options); | ||
| 219 | errdefer self.base.destroy(); | ||
| 220 | |||
| 221 | self.base.file = file; | ||
| 222 | return self; | ||
| 223 | } | ||
| 224 | |||
| 225 | pub fn addCallReloc(self: *Plan9, code: *std.ArrayList(u8), reloc: CallReloc) !void { | ||
| 226 | try self.call_relocs.append(self.base.allocator, reloc); | ||
| 227 | try code.writer().writeIntBig(u64, 0xdeadbeef); | ||
| 228 | } |
src/link/plan9/a.out.zig created+122| ... | @@ -0,0 +1,122 @@ | ||
| 1 | // Copyright © 2021 Plan 9 Foundation | ||
| 2 | // Copyright © 20XX 9front authors | ||
| 3 | |||
| 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 5 | // of this software and associated documentation files (the "Software"), to deal | ||
| 6 | // in the Software without restriction, including without limitation the rights | ||
| 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 8 | // copies of the Software, and to permit persons to whom the Software is | ||
| 9 | // furnished to do so, subject to the following conditions: | ||
| 10 | |||
| 11 | // The above copyright notice and this permission notice shall be included in all | ||
| 12 | // copies or substantial portions of the Software. | ||
| 13 | |||
| 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 20 | // SOFTWARE. | ||
| 21 | |||
| 22 | // Idomatic translation of 9front a.out.h | ||
| 23 | const std = @import("std"); | ||
| 24 | // all integers are in big-endian format (needs a byteswap) | ||
| 25 | pub const ExecHdr = struct { | ||
| 26 | magic: u32, | ||
| 27 | text: u32, | ||
| 28 | data: u32, | ||
| 29 | bss: u32, | ||
| 30 | syms: u32, | ||
| 31 | entry: u32, | ||
| 32 | spsz: u32, | ||
| 33 | pcsz: u32, | ||
| 34 | pub fn size() u8 { | ||
| 35 | return 32; | ||
| 36 | } | ||
| 37 | }; | ||
| 38 | |||
| 39 | // uchar value[4]; | ||
| 40 | // char type; | ||
| 41 | // char name[n]; /* NUL-terminated */ | ||
| 42 | pub const Sym32 = struct { | ||
| 43 | value: u32, // big endian in the file | ||
| 44 | type: SymType, | ||
| 45 | name: [*:0]const u8, | ||
| 46 | }; | ||
| 47 | // uchar value[8]; | ||
| 48 | // char type; | ||
| 49 | // char name[n]; /* NUL-terminated */ | ||
| 50 | pub const Sym64 = struct { | ||
| 51 | value: u64, // big endian in the file | ||
| 52 | type: SymType, | ||
| 53 | name: [*:0]const u8, | ||
| 54 | }; | ||
| 55 | // The type field is one of the following characters with the | ||
| 56 | // high bit set: | ||
| 57 | // T text segment symbol | ||
| 58 | // t static text segment symbol | ||
| 59 | // L leaf function text segment symbol | ||
| 60 | // l static leaf function text segment symbol | ||
| 61 | // D data segment symbol | ||
| 62 | // d static data segment symbol | ||
| 63 | // B bss segment symbol | ||
| 64 | // b static bss segment symbol | ||
| 65 | // a automatic (local) variable symbol | ||
| 66 | // p function parameter symbol | ||
| 67 | // f source file name components | ||
| 68 | // z source file name | ||
| 69 | // Z source file line offset | ||
| 70 | // m for '.frame' | ||
| 71 | pub const SymType = enum(u8) { | ||
| 72 | T = 0x80 | 'T', | ||
| 73 | t = 0x80 | 't', | ||
| 74 | L = 0x80 | 'L', | ||
| 75 | l = 0x80 | 'l', | ||
| 76 | D = 0x80 | 'D', | ||
| 77 | d = 0x80 | 'd', | ||
| 78 | B = 0x80 | 'B', | ||
| 79 | b = 0x80 | 'b', | ||
| 80 | a = 0x80 | 'a', | ||
| 81 | p = 0x80 | 'p', | ||
| 82 | f = 0x80 | 'f', | ||
| 83 | z = 0x80 | 'z', | ||
| 84 | Z = 0x80 | 'Z', | ||
| 85 | m = 0x80 | 'm', | ||
| 86 | }; | ||
| 87 | |||
| 88 | pub const HDR_MAGIC = @import("std").meta.promoteIntLiteral(c_int, 0x00008000, .hexadecimal); | ||
| 89 | pub inline fn _MAGIC(f: anytype, b: anytype) @TypeOf(f | ((((@as(c_int, 4) * b) + @as(c_int, 0)) * b) + @as(c_int, 7))) { | ||
| 90 | return f | ((((@as(c_int, 4) * b) + @as(c_int, 0)) * b) + @as(c_int, 7)); | ||
| 91 | } | ||
| 92 | pub const A_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 8)); // 68020 | ||
| 93 | pub const I_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 11)); // intel 386 | ||
| 94 | pub const J_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 12)); // intel 960 (retired) | ||
| 95 | pub const K_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 13)); // sparc | ||
| 96 | pub const V_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 16)); // mips 3000 BE | ||
| 97 | pub const X_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 17)); // att dsp 3210 (retired) | ||
| 98 | pub const M_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 18)); // mips 4000 BE | ||
| 99 | pub const D_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 19)); // amd 29000 (retired) | ||
| 100 | pub const E_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 20)); // arm | ||
| 101 | pub const Q_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 21)); // powerpc | ||
| 102 | pub const N_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 22)); // mips 4000 LE | ||
| 103 | pub const L_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 23)); // dec alpha (retired) | ||
| 104 | pub const P_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 24)); // mips 3000 LE | ||
| 105 | pub const U_MAGIC = _MAGIC(@as(c_int, 0), @as(c_int, 25)); // sparc64 | ||
| 106 | pub const S_MAGIC = _MAGIC(HDR_MAGIC, @as(c_int, 26)); // amd64 | ||
| 107 | pub const T_MAGIC = _MAGIC(HDR_MAGIC, @as(c_int, 27)); // powerpc64 | ||
| 108 | pub const R_MAGIC = _MAGIC(HDR_MAGIC, @as(c_int, 28)); // arm64 | ||
| 109 | |||
| 110 | pub fn magicFromArch(arch: std.Target.Cpu.Arch) !u32 { | ||
| 111 | return switch (arch) { | ||
| 112 | .i386 => I_MAGIC, | ||
| 113 | .sparc => K_MAGIC, // TODO should sparcv9 and sparcel go here? | ||
| 114 | .mips => V_MAGIC, | ||
| 115 | .arm => E_MAGIC, | ||
| 116 | .aarch64 => R_MAGIC, | ||
| 117 | .powerpc => Q_MAGIC, | ||
| 118 | .powerpc64 => T_MAGIC, | ||
| 119 | .x86_64 => S_MAGIC, | ||
| 120 | else => error.ArchNotSupportedByPlan9, | ||
| 121 | }; | ||
| 122 | } | ||