| ... | @@ -32,16 +32,18 @@ hdr: aout.ExecHdr = undefined, | ... | @@ -32,16 +32,18 @@ hdr: aout.ExecHdr = undefined, |
| 32 | | 32 | |
| 33 | fn headerSize(self: Plan9) u32 { | 33 | fn headerSize(self: Plan9) u32 { |
| 34 | // fat header (currently unused) | 34 | // fat header (currently unused) |
| 35 | const fat: u4 = if (self.ptr_width == .p64) 8 else 0; | 35 | const fat: u8 = if (self.ptr_width == .p64) 8 else 0; |
| 36 | return aout.ExecHdr.size() + fat; | 36 | return @sizeOf(aout.ExecHdr) + fat; |
| 37 | } | 37 | } |
| 38 | pub const DeclBlock = struct { | 38 | pub const DeclBlock = struct { |
| 39 | type: enum { text, data }, | 39 | type: enum { text, data }, |
| 40 | // offset in the text or data sects | 40 | // offset in the text or data sects |
| 41 | offset: u32, | 41 | offset: u32, |
| | 42 | sym_index: usize, |
| 42 | pub const empty = DeclBlock{ | 43 | pub const empty = DeclBlock{ |
| 43 | .type = .text, | 44 | .type = .text, |
| 44 | .offset = 0, | 45 | .offset = 0, |
| | 46 | .sym_index = 0, |
| 45 | }; | 47 | }; |
| 46 | }; | 48 | }; |
| 47 | | 49 | |
| ... | @@ -62,7 +64,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { | ... | @@ -62,7 +64,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { |
| 62 | const ptr_width: PtrWidth = switch (options.target.cpu.arch.ptrBitWidth()) { | 64 | const ptr_width: PtrWidth = switch (options.target.cpu.arch.ptrBitWidth()) { |
| 63 | 0...32 => .p32, | 65 | 0...32 => .p32, |
| 64 | 33...64 => .p64, | 66 | 33...64 => .p64, |
| 65 | else => return error.UnsupportedELFArchitecture, | 67 | else => return error.UnsupportedP9Architecture, |
| 66 | }; | 68 | }; |
| 67 | const self = try gpa.create(Plan9); | 69 | const self = try gpa.create(Plan9); |
| 68 | self.* = .{ | 70 | self.* = .{ |
| ... | @@ -93,13 +95,14 @@ pub fn flush(self: *Plan9, comp: *Compilation) !void { | ... | @@ -93,13 +95,14 @@ pub fn flush(self: *Plan9, comp: *Compilation) !void { |
| 93 | return self.flushModule(comp); | 95 | return self.flushModule(comp); |
| 94 | } | 96 | } |
| 95 | pub fn flushModule(self: *Plan9, comp: *Compilation) !void { | 97 | pub fn flushModule(self: *Plan9, comp: *Compilation) !void { |
| 96 | const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; | 98 | const tracy = trace(@src()); |
| | 99 | defer tracy.end(); |
| 97 | | 100 | |
| 98 | // generate the header | 101 | const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; |
| 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 | | 102 | |
| | 103 | self.text_buf.items.len = 0; |
| | 104 | self.data_buf.items.len = 0; |
| | 105 | self.call_relocs.items.len = 0; |
| 103 | // temporary buffer | 106 | // temporary buffer |
| 104 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | 107 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 105 | defer code_buffer.deinit(); | 108 | defer code_buffer.deinit(); |
| ... | @@ -111,10 +114,32 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void { | ... | @@ -111,10 +114,32 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void { |
| 111 | decl.link.plan9 = if (is_fn) .{ | 114 | decl.link.plan9 = if (is_fn) .{ |
| 112 | .offset = @intCast(u32, self.text_buf.items.len), | 115 | .offset = @intCast(u32, self.text_buf.items.len), |
| 113 | .type = .text, | 116 | .type = .text, |
| | 117 | .sym_index = decl.link.plan9.sym_index, |
| 114 | } else .{ | 118 | } else .{ |
| 115 | .offset = @intCast(u32, self.data_buf.items.len), | 119 | .offset = @intCast(u32, self.data_buf.items.len), |
| 116 | .type = .data, | 120 | .type = .data, |
| | 121 | .sym_index = decl.link.plan9.sym_index, |
| 117 | }; | 122 | }; |
| | 123 | if (decl.link.plan9.sym_index == 0) { |
| | 124 | try self.syms.append(self.base.allocator, .{ |
| | 125 | .value = decl.link.plan9.offset, |
| | 126 | .type = switch (decl.link.plan9.type) { |
| | 127 | .text => .t, |
| | 128 | .data => .d, |
| | 129 | }, |
| | 130 | .name = mem.span(decl.name), |
| | 131 | }); |
| | 132 | decl.link.plan9.sym_index = self.syms.items.len - 1; |
| | 133 | } else { |
| | 134 | self.syms.items[decl.link.plan9.sym_index] = .{ |
| | 135 | .value = decl.link.plan9.offset, |
| | 136 | .type = switch (decl.link.plan9.type) { |
| | 137 | .text => .t, |
| | 138 | .data => .d, |
| | 139 | }, |
| | 140 | .name = mem.span(decl.name), |
| | 141 | }; |
| | 142 | } |
| 118 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | 143 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ |
| 119 | .ty = decl.ty, | 144 | .ty = decl.ty, |
| 120 | .val = decl.val, | 145 | .val = decl.val, |
| ... | @@ -136,16 +161,35 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void { | ... | @@ -136,16 +161,35 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void { |
| 136 | code_buffer.items.len = 0; | 161 | code_buffer.items.len = 0; |
| 137 | } | 162 | } |
| 138 | } | 163 | } |
| 139 | try file.writeAll(self.text_buf.items); | 164 | |
| 140 | try file.writeAll(self.data_buf.items); | 165 | var sym_buf = std.ArrayList(u8).init(self.base.allocator); |
| 141 | try file.seekTo(0); | 166 | defer sym_buf.deinit(); |
| | 167 | try self.writeSyms(&sym_buf); |
| | 168 | |
| | 169 | // generate the header |
| | 170 | self.hdr.magic = try aout.magicFromArch(self.base.options.target.cpu.arch); |
| 142 | self.hdr.text = @intCast(u32, self.text_buf.items.len); | 171 | self.hdr.text = @intCast(u32, self.text_buf.items.len); |
| 143 | self.hdr.data = @intCast(u32, self.data_buf.items.len); | 172 | self.hdr.data = @intCast(u32, self.data_buf.items.len); |
| | 173 | self.hdr.syms = @intCast(u32, sym_buf.items.len); |
| | 174 | self.hdr.bss = 0; |
| 144 | self.hdr.pcsz = 0; | 175 | self.hdr.pcsz = 0; |
| 145 | self.hdr.spsz = 0; | 176 | self.hdr.spsz = 0; |
| 146 | inline for (std.meta.fields(aout.ExecHdr)) |f| { | 177 | |
| 147 | try file.writer().writeIntBig(f.field_type, @field(self.hdr, f.name)); | 178 | const file = self.base.file.?; |
| 148 | } | 179 | |
| | 180 | const hdr_buf = self.hdr.toU8s(); |
| | 181 | const hdr_slice: []const u8 = &hdr_buf; |
| | 182 | // account for the fat header |
| | 183 | const hdr_size: u8 = if (self.ptr_width == .p32) 32 else 40; |
| | 184 | // write it all! |
| | 185 | var vectors: [4]std.os.iovec_const = .{ |
| | 186 | .{ .iov_base = hdr_slice.ptr, .iov_len = hdr_size }, |
| | 187 | .{ .iov_base = self.text_buf.items.ptr, .iov_len = self.text_buf.items.len }, |
| | 188 | .{ .iov_base = self.data_buf.items.ptr, .iov_len = self.data_buf.items.len }, |
| | 189 | .{ .iov_base = sym_buf.items.ptr, .iov_len = sym_buf.items.len }, |
| | 190 | // TODO spsz, pcsz |
| | 191 | }; |
| | 192 | try file.pwritevAll(&vectors, 0); |
| 149 | } | 193 | } |
| 150 | pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void { | 194 | pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void { |
| 151 | assert(self.decl_table.swapRemove(decl)); | 195 | assert(self.decl_table.swapRemove(decl)); |
| ... | @@ -173,14 +217,13 @@ pub fn updateDeclExports( | ... | @@ -173,14 +217,13 @@ pub fn updateDeclExports( |
| 173 | self.hdr.entry = Plan9.default_base_addr + self.headerSize() + decl.link.plan9.offset; | 217 | self.hdr.entry = Plan9.default_base_addr + self.headerSize() + decl.link.plan9.offset; |
| 174 | } | 218 | } |
| 175 | if (exp.link.plan9) |i| { | 219 | if (exp.link.plan9) |i| { |
| 176 | const sym = &self.syms.items[i]; | 220 | self.syms.items[i] = .{ |
| 177 | sym.* = .{ | | |
| 178 | .value = decl.link.plan9.offset, | 221 | .value = decl.link.plan9.offset, |
| 179 | .type = switch (decl.link.plan9.type) { | 222 | .type = switch (decl.link.plan9.type) { |
| 180 | .text => .T, | 223 | .text => .T, |
| 181 | .data => .D, | 224 | .data => .D, |
| 182 | }, | 225 | }, |
| 183 | .name = decl.name, | 226 | .name = exp.options.name, |
| 184 | }; | 227 | }; |
| 185 | } else { | 228 | } else { |
| 186 | try self.syms.append(self.base.allocator, .{ | 229 | try self.syms.append(self.base.allocator, .{ |
| ... | @@ -189,8 +232,9 @@ pub fn updateDeclExports( | ... | @@ -189,8 +232,9 @@ pub fn updateDeclExports( |
| 189 | .text => .T, | 232 | .text => .T, |
| 190 | .data => .D, | 233 | .data => .D, |
| 191 | }, | 234 | }, |
| 192 | .name = decl.name, | 235 | .name = exp.options.name, |
| 193 | }); | 236 | }); |
| | 237 | exp.link.plan9 = self.syms.items.len - 1; |
| 194 | } | 238 | } |
| 195 | } | 239 | } |
| 196 | } | 240 | } |
| ... | @@ -226,3 +270,17 @@ pub fn addCallReloc(self: *Plan9, code: *std.ArrayList(u8), reloc: CallReloc) !v | ... | @@ -226,3 +270,17 @@ pub fn addCallReloc(self: *Plan9, code: *std.ArrayList(u8), reloc: CallReloc) !v |
| 226 | try self.call_relocs.append(self.base.allocator, reloc); | 270 | try self.call_relocs.append(self.base.allocator, reloc); |
| 227 | try code.writer().writeIntBig(u64, 0xdeadbeef); | 271 | try code.writer().writeIntBig(u64, 0xdeadbeef); |
| 228 | } | 272 | } |
| | 273 | |
| | 274 | pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { |
| | 275 | const writer = buf.writer(); |
| | 276 | for (self.syms.items) |sym| { |
| | 277 | if (self.ptr_width == .p32) { |
| | 278 | try writer.writeIntBig(u32, @intCast(u32, sym.value)); |
| | 279 | } else { |
| | 280 | try writer.writeIntBig(u64, sym.value); |
| | 281 | } |
| | 282 | try writer.writeByte(@enumToInt(sym.type)); |
| | 283 | try writer.writeAll(std.mem.span(sym.name)); |
| | 284 | try writer.writeByte(0); |
| | 285 | } |
| | 286 | } |