| ... | ... | @@ -25,20 +25,22 @@ sixtyfour_bit: bool, |
| 25 | 25 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 26 | 26 | bases: Bases, |
| 27 | 27 | |
| 28 | | decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{}, |
| 29 | | /// is just casted down when 32 bit |
| 28 | /// A symbol's value is just casted down when compiling |
| 29 | /// for a 32 bit target. |
| 30 | 30 | syms: std.ArrayListUnmanaged(aout.Sym) = .{}, |
| 31 | | text_buf: std.ArrayListUnmanaged(u8) = .{}, |
| 32 | | data_buf: std.ArrayListUnmanaged(u8) = .{}, |
| 31 | |
| 32 | fn_decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, []const u8) = .{}, |
| 33 | data_decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, []const u8) = .{}, |
| 33 | 34 | |
| 34 | 35 | hdr: aout.ExecHdr = undefined, |
| 35 | 36 | |
| 36 | 37 | entry_decl: ?*Module.Decl = null, |
| 37 | 38 | |
| 38 | | got: std.ArrayListUnmanaged(u64) = .{}, |
| 39 | got_len: u64 = 0, |
| 40 | |
| 39 | 41 | const Bases = struct { |
| 40 | 42 | text: u64, |
| 41 | | /// the addr of the got |
| 43 | /// the Global Offset Table starts at the beginning of the data section |
| 42 | 44 | data: u64, |
| 43 | 45 | }; |
| 44 | 46 | |
| ... | ... | @@ -49,14 +51,6 @@ fn getAddr(self: Plan9, addr: u64, t: aout.Sym.Type) u64 { |
| 49 | 51 | else => unreachable, |
| 50 | 52 | }; |
| 51 | 53 | } |
| 52 | | /// opposite of getAddr |
| 53 | | fn takeAddr(self: Plan9, addr: u64, t: aout.Sym.Type) u64 { |
| 54 | | return addr - switch (t) { |
| 55 | | .T, .t, .l, .L => self.bases.text, |
| 56 | | .D, .d, .B, .b => self.bases.data, |
| 57 | | else => unreachable, |
| 58 | | }; |
| 59 | | } |
| 60 | 54 | |
| 61 | 55 | fn getSymAddr(self: Plan9, s: aout.Sym) u64 { |
| 62 | 56 | return self.getAddr(s.value, s.type); |
| ... | ... | @@ -127,18 +121,80 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv |
| 127 | 121 | if (build_options.skip_non_native and builtin.object_format != .plan9) { |
| 128 | 122 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 129 | 123 | } |
| 130 | | _ = module; |
| 131 | | // Keep track of all decls so we can iterate over them on flush(). |
| 132 | | _ = try self.decl_table.getOrPut(self.base.allocator, func.owner_decl); |
| 133 | 124 | |
| 134 | | _ = air; |
| 135 | | _ = liveness; |
| 136 | | @panic("TODO Plan9 needs to keep track of Air and Liveness so it can use them later"); |
| 125 | const decl = func.owner_decl; |
| 126 | log.debug("codegen decl {*} ({s})", .{ decl, decl.name }); |
| 127 | |
| 128 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 129 | defer code_buffer.deinit(); |
| 130 | const res = try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ .none = .{} }); |
| 131 | const code = switch (res) { |
| 132 | .appended => code_buffer.toOwnedSlice(), |
| 133 | .fail => |em| { |
| 134 | decl.analysis = .codegen_failure; |
| 135 | try module.failed_decls.put(module.gpa, decl, em); |
| 136 | return; |
| 137 | }, |
| 138 | }; |
| 139 | try self.fn_decl_table.put(self.base.allocator, decl, code); |
| 140 | return self.updateFinish(decl); |
| 137 | 141 | } |
| 138 | 142 | |
| 139 | 143 | pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void { |
| 140 | | _ = module; |
| 141 | | _ = try self.decl_table.getOrPut(self.base.allocator, decl); |
| 144 | if (decl.val.tag() == .extern_fn) { |
| 145 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 146 | } |
| 147 | if (decl.val.castTag(.variable)) |payload| { |
| 148 | const variable = payload.data; |
| 149 | if (variable.is_extern) { |
| 150 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | log.debug("codegen decl {*} ({s})", .{ decl, decl.name }); |
| 155 | |
| 156 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 157 | defer code_buffer.deinit(); |
| 158 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; |
| 159 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ |
| 160 | .ty = decl.ty, |
| 161 | .val = decl_val, |
| 162 | }, &code_buffer, .{ .none = .{} }); |
| 163 | const code = switch (res) { |
| 164 | .externally_managed => |x| x, |
| 165 | .appended => code_buffer.items, |
| 166 | .fail => |em| { |
| 167 | decl.analysis = .codegen_failure; |
| 168 | try module.failed_decls.put(module.gpa, decl, em); |
| 169 | return; |
| 170 | }, |
| 171 | }; |
| 172 | var duped_code = try std.mem.dupe(self.base.allocator, u8, code); |
| 173 | errdefer self.base.allocator.free(duped_code); |
| 174 | try self.data_decl_table.put(self.base.allocator, decl, duped_code); |
| 175 | return self.updateFinish(decl); |
| 176 | } |
| 177 | /// called at the end of update{Decl,Func} |
| 178 | fn updateFinish(self: *Plan9, decl: *Module.Decl) !void { |
| 179 | const is_fn = (decl.ty.zigTypeTag() == .Fn); |
| 180 | log.debug("update the symbol table and got for decl {*} ({s})", .{ decl, decl.name }); |
| 181 | const sym_t: aout.Sym.Type = if (is_fn) .t else .d; |
| 182 | // write the internal linker metadata |
| 183 | decl.link.plan9.type = sym_t; |
| 184 | // write the symbol |
| 185 | // we already have the got index because that got allocated in allocateDeclIndexes |
| 186 | const sym: aout.Sym = .{ |
| 187 | .value = undefined, // the value of stuff gets filled in in flushModule |
| 188 | .type = decl.link.plan9.type, |
| 189 | .name = mem.span(decl.name), |
| 190 | }; |
| 191 | |
| 192 | if (decl.link.plan9.sym_index) |s| { |
| 193 | self.syms.items[s] = sym; |
| 194 | } else { |
| 195 | try self.syms.append(self.base.allocator, sym); |
| 196 | decl.link.plan9.sym_index = self.syms.items.len - 1; |
| 197 | } |
| 142 | 198 | } |
| 143 | 199 | |
| 144 | 200 | pub fn flush(self: *Plan9, comp: *Compilation) !void { |
| ... | ... | @@ -165,160 +221,107 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void { |
| 165 | 221 | |
| 166 | 222 | defer assert(self.hdr.entry != 0x0); |
| 167 | 223 | |
| 168 | | const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; |
| 224 | _ = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; |
| 169 | 225 | |
| 170 | | self.text_buf.items.len = 0; |
| 171 | | self.data_buf.items.len = 0; |
| 172 | | // ensure space to write the got later |
| 173 | | assert(self.got.items.len == self.decl_table.count()); |
| 174 | | try self.data_buf.appendNTimes(self.base.allocator, 0x69, self.got.items.len * if (!self.sixtyfour_bit) @as(u32, 4) else 8); |
| 175 | | // temporary buffer |
| 176 | | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 177 | | defer code_buffer.deinit(); |
| 178 | | { |
| 179 | | for (self.decl_table.keys()) |decl| { |
| 180 | | if (!decl.has_tv) continue; |
| 181 | | const is_fn = (decl.ty.zigTypeTag() == .Fn); |
| 182 | | |
| 183 | | log.debug("update the symbol table and got for decl {*} ({s})", .{ decl, decl.name }); |
| 184 | | decl.link.plan9 = if (is_fn) .{ |
| 185 | | .offset = self.getAddr(self.text_buf.items.len, .t), |
| 186 | | .type = .t, |
| 187 | | .sym_index = decl.link.plan9.sym_index, |
| 188 | | .got_index = decl.link.plan9.got_index, |
| 189 | | } else .{ |
| 190 | | .offset = self.getAddr(self.data_buf.items.len, .d), |
| 191 | | .type = .d, |
| 192 | | .sym_index = decl.link.plan9.sym_index, |
| 193 | | .got_index = decl.link.plan9.got_index, |
| 194 | | }; |
| 195 | | self.got.items[decl.link.plan9.got_index.?] = decl.link.plan9.offset.?; |
| 196 | | if (decl.link.plan9.sym_index) |s| { |
| 197 | | self.syms.items[s] = .{ |
| 198 | | .value = decl.link.plan9.offset.?, |
| 199 | | .type = decl.link.plan9.type, |
| 200 | | .name = mem.span(decl.name), |
| 201 | | }; |
| 202 | | } else { |
| 203 | | try self.syms.append(self.base.allocator, .{ |
| 204 | | .value = decl.link.plan9.offset.?, |
| 205 | | .type = decl.link.plan9.type, |
| 206 | | .name = mem.span(decl.name), |
| 207 | | }); |
| 208 | | decl.link.plan9.sym_index = self.syms.items.len - 1; |
| 209 | | } |
| 226 | assert(self.got_len == self.fn_decl_table.count() + self.data_decl_table.count()); |
| 227 | const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8; |
| 228 | var got_table = try self.base.allocator.alloc(u8, got_size); |
| 229 | defer self.base.allocator.free(got_table); |
| 210 | 230 | |
| 211 | | if (module.decl_exports.get(decl)) |exports| { |
| 212 | | for (exports) |exp| { |
| 213 | | // plan9 does not support custom sections |
| 214 | | if (exp.options.section) |section_name| { |
| 215 | | if (!mem.eql(u8, section_name, ".text") or !mem.eql(u8, section_name, ".data")) { |
| 216 | | try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "plan9 does not support extra sections", .{})); |
| 217 | | break; |
| 218 | | } |
| 219 | | } |
| 220 | | if (std.mem.eql(u8, exp.options.name, "_start")) { |
| 221 | | assert(decl.link.plan9.type == .t); // we tried to link a non-function as the entry |
| 222 | | self.entry_decl = decl; |
| 223 | | } |
| 224 | | if (exp.link.plan9) |i| { |
| 225 | | self.syms.items[i] = .{ |
| 226 | | .value = decl.link.plan9.offset.?, |
| 227 | | .type = decl.link.plan9.type.toGlobal(), |
| 228 | | .name = exp.options.name, |
| 229 | | }; |
| 230 | | } else { |
| 231 | | try self.syms.append(self.base.allocator, .{ |
| 232 | | .value = decl.link.plan9.offset.?, |
| 233 | | .type = decl.link.plan9.type.toGlobal(), |
| 234 | | .name = exp.options.name, |
| 235 | | }); |
| 236 | | exp.link.plan9 = self.syms.items.len - 1; |
| 237 | | } |
| 238 | | } |
| 239 | | } |
| 231 | // + 2 for header, got, symbols |
| 232 | var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.fn_decl_table.count() + self.data_decl_table.count() + 3); |
| 233 | |
| 234 | const file = self.base.file.?; |
| 240 | 235 | |
| 241 | | log.debug("codegen decl {*} ({s})", .{ decl, decl.name }); |
| 242 | | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ |
| 243 | | .ty = decl.ty, |
| 244 | | .val = decl.val, |
| 245 | | }, &code_buffer, .{ .none = {} }); |
| 246 | | const code = switch (res) { |
| 247 | | .externally_managed => |x| x, |
| 248 | | .appended => code_buffer.items, |
| 249 | | .fail => |em| { |
| 250 | | decl.analysis = .codegen_failure; |
| 251 | | try module.failed_decls.put(module.gpa, decl, em); |
| 252 | | // TODO try to do more decls |
| 253 | | return; |
| 254 | | }, |
| 255 | | }; |
| 256 | | if (is_fn) { |
| 257 | | try self.text_buf.appendSlice(self.base.allocator, code); |
| 258 | | code_buffer.items.len = 0; |
| 236 | var hdr_buf: [40]u8 = undefined; |
| 237 | // account for the fat header |
| 238 | const hdr_size = if (self.sixtyfour_bit) @as(usize, 40) else 32; |
| 239 | const hdr_slice: []u8 = hdr_buf[0..hdr_size]; |
| 240 | var foff = hdr_size; |
| 241 | iovecs[0] = .{ .iov_base = hdr_slice.ptr, .iov_len = hdr_slice.len }; |
| 242 | var iovecs_i: u64 = 1; |
| 243 | var text_i: u64 = 0; |
| 244 | // text |
| 245 | { |
| 246 | var it = self.fn_decl_table.iterator(); |
| 247 | while (it.next()) |entry| { |
| 248 | const decl = entry.key_ptr.*; |
| 249 | const code = entry.value_ptr.*; |
| 250 | foff += code.len; |
| 251 | text_i += code.len; |
| 252 | iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len }; |
| 253 | iovecs_i += 1; |
| 254 | const off = self.getAddr(text_i, .t); |
| 255 | decl.link.plan9.offset = off; |
| 256 | if (!self.sixtyfour_bit) { |
| 257 | mem.writeIntNative(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off)); |
| 258 | mem.writeInt(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian()); |
| 259 | 259 | } else { |
| 260 | | try self.data_buf.appendSlice(self.base.allocator, code); |
| 261 | | code_buffer.items.len = 0; |
| 260 | mem.writeInt(u64, got_table[decl.link.plan9.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian()); |
| 262 | 261 | } |
| 262 | self.syms.items[decl.link.plan9.sym_index.?].value = off; |
| 263 | 263 | } |
| 264 | // etext symbol |
| 265 | self.syms.items[2].value = self.getAddr(text_i, .t); |
| 264 | 266 | } |
| 265 | | |
| 266 | | // write the got |
| 267 | | if (!self.sixtyfour_bit) { |
| 268 | | for (self.got.items) |p, i| { |
| 269 | | mem.writeInt(u32, self.data_buf.items[i * 4 ..][0..4], @intCast(u32, p), self.base.options.target.cpu.arch.endian()); |
| 270 | | } |
| 271 | | } else { |
| 272 | | for (self.got.items) |p, i| { |
| 273 | | mem.writeInt(u64, self.data_buf.items[i * 8 ..][0..8], p, self.base.options.target.cpu.arch.endian()); |
| 267 | // data |
| 268 | var data_i: u64 = got_size; |
| 269 | { |
| 270 | var it = self.data_decl_table.iterator(); |
| 271 | while (it.next()) |entry| { |
| 272 | const decl = entry.key_ptr.*; |
| 273 | const code = entry.value_ptr.*; |
| 274 | foff += code.len; |
| 275 | data_i += code.len; |
| 276 | iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len }; |
| 277 | iovecs_i += 1; |
| 278 | const off = self.getAddr(data_i, .d); |
| 279 | decl.link.plan9.offset = off; |
| 280 | if (!self.sixtyfour_bit) { |
| 281 | mem.writeInt(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian()); |
| 282 | } else { |
| 283 | mem.writeInt(u64, got_table[decl.link.plan9.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian()); |
| 284 | } |
| 285 | self.syms.items[decl.link.plan9.sym_index.?].value = off; |
| 274 | 286 | } |
| 287 | // edata symbol |
| 288 | self.syms.items[0].value = self.getAddr(data_i, .b); |
| 275 | 289 | } |
| 276 | | |
| 277 | | self.hdr.entry = @truncate(u32, self.entry_decl.?.link.plan9.offset.?); |
| 278 | | |
| 279 | | // edata, end, etext |
| 280 | | self.syms.items[0].value = self.getAddr(0x0, .b); |
| 290 | // edata |
| 281 | 291 | self.syms.items[1].value = self.getAddr(0x0, .b); |
| 282 | | self.syms.items[2].value = self.getAddr(self.text_buf.items.len, .t); |
| 283 | | |
| 284 | 292 | var sym_buf = std.ArrayList(u8).init(self.base.allocator); |
| 285 | 293 | defer sym_buf.deinit(); |
| 286 | 294 | try self.writeSyms(&sym_buf); |
| 287 | | |
| 295 | iovecs[iovecs_i] = .{ .iov_base = got_table.ptr, .iov_len = got_table.len }; |
| 296 | iovecs_i += 1; |
| 297 | assert(2 + self.fn_decl_table.count() + self.data_decl_table.count() == iovecs_i); // we didn't write all the decls |
| 298 | iovecs[iovecs_i] = .{ .iov_base = sym_buf.items.ptr, .iov_len = sym_buf.items.len }; |
| 299 | iovecs_i += 1; |
| 288 | 300 | // generate the header |
| 289 | 301 | self.hdr = .{ |
| 290 | 302 | .magic = try aout.magicFromArch(self.base.options.target.cpu.arch), |
| 291 | | .text = @intCast(u32, self.text_buf.items.len), |
| 292 | | .data = @intCast(u32, self.data_buf.items.len), |
| 303 | .text = @intCast(u32, text_i), |
| 304 | .data = @intCast(u32, data_i), |
| 293 | 305 | .syms = @intCast(u32, sym_buf.items.len), |
| 294 | 306 | .bss = 0, |
| 295 | 307 | .pcsz = 0, |
| 296 | 308 | .spsz = 0, |
| 297 | | .entry = self.hdr.entry, |
| 309 | .entry = @intCast(u32, self.entry_decl.?.link.plan9.offset.?), |
| 298 | 310 | }; |
| 299 | | |
| 300 | | const file = self.base.file.?; |
| 301 | | |
| 302 | | var hdr_buf = self.hdr.toU8s(); |
| 303 | | const hdr_slice: []const u8 = &hdr_buf; |
| 304 | | // account for the fat header |
| 305 | | const hdr_size: u8 = if (!self.sixtyfour_bit) 32 else 40; |
| 311 | std.mem.copy(u8, hdr_slice, self.hdr.toU8s()[0..hdr_size]); |
| 306 | 312 | // write the fat header for 64 bit entry points |
| 307 | 313 | if (self.sixtyfour_bit) { |
| 308 | | mem.writeIntSliceBig(u64, hdr_buf[32..40], self.hdr.entry); |
| 314 | mem.writeIntSliceBig(u64, hdr_buf[32..40], self.entry_decl.?.link.plan9.offset.?); |
| 309 | 315 | } |
| 310 | 316 | // write it all! |
| 311 | | var vectors: [4]std.os.iovec_const = .{ |
| 312 | | .{ .iov_base = hdr_slice.ptr, .iov_len = hdr_size }, |
| 313 | | .{ .iov_base = self.text_buf.items.ptr, .iov_len = self.text_buf.items.len }, |
| 314 | | .{ .iov_base = self.data_buf.items.ptr, .iov_len = self.data_buf.items.len }, |
| 315 | | .{ .iov_base = sym_buf.items.ptr, .iov_len = sym_buf.items.len }, |
| 316 | | // TODO spsz, pcsz |
| 317 | | }; |
| 318 | | try file.pwritevAll(&vectors, 0); |
| 317 | try file.pwritevAll(iovecs, 0); |
| 319 | 318 | } |
| 320 | 319 | pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void { |
| 321 | | assert(self.decl_table.swapRemove(decl)); |
| 320 | const is_fn = (decl.ty.zigTypeTag() == .Fn); |
| 321 | if (is_fn) |
| 322 | assert(self.fn_decl_table.swapRemove(decl)) |
| 323 | else |
| 324 | assert(self.data_decl_table.swapRemove(decl)); |
| 322 | 325 | } |
| 323 | 326 | |
| 324 | 327 | pub fn updateDeclExports( |
| ... | ... | @@ -334,11 +337,17 @@ pub fn updateDeclExports( |
| 334 | 337 | _ = exports; |
| 335 | 338 | } |
| 336 | 339 | pub fn deinit(self: *Plan9) void { |
| 337 | | self.decl_table.deinit(self.base.allocator); |
| 340 | var itf = self.fn_decl_table.iterator(); |
| 341 | while (itf.next()) |entry| { |
| 342 | self.base.allocator.free(entry.value_ptr.*); |
| 343 | } |
| 344 | self.fn_decl_table.deinit(self.base.allocator); |
| 345 | var itd = self.data_decl_table.iterator(); |
| 346 | while (itd.next()) |entry| { |
| 347 | self.base.allocator.free(entry.value_ptr.*); |
| 348 | } |
| 349 | self.data_decl_table.deinit(self.base.allocator); |
| 338 | 350 | self.syms.deinit(self.base.allocator); |
| 339 | | self.text_buf.deinit(self.base.allocator); |
| 340 | | self.data_buf.deinit(self.base.allocator); |
| 341 | | self.got.deinit(self.base.allocator); |
| 342 | 351 | } |
| 343 | 352 | |
| 344 | 353 | pub const Export = ?usize; |
| ... | ... | @@ -397,6 +406,8 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { |
| 397 | 406 | } |
| 398 | 407 | |
| 399 | 408 | pub fn allocateDeclIndexes(self: *Plan9, decl: *Module.Decl) !void { |
| 400 | | try self.got.append(self.base.allocator, 0xdeadbeef); |
| 401 | | decl.link.plan9.got_index = self.got.items.len - 1; |
| 409 | if (decl.link.plan9.got_index != null) { |
| 410 | self.got_len += 1; |
| 411 | decl.link.plan9.got_index = self.got_len - 1; |
| 412 | } |
| 402 | 413 | } |