| ... | @@ -20,6 +20,14 @@ const Allocator = std.mem.Allocator; | ... | @@ -20,6 +20,14 @@ const Allocator = std.mem.Allocator; |
| 20 | const log = std.log.scoped(.link); | 20 | const log = std.log.scoped(.link); |
| 21 | const assert = std.debug.assert; | 21 | const assert = std.debug.assert; |
| 22 | | 22 | |
| | 23 | const FnDeclOutput = struct { |
| | 24 | code: []const u8, |
| | 25 | /// this might have to be modified in the linker, so thats why its mutable |
| | 26 | lineinfo: []u8, |
| | 27 | start_line: u32, |
| | 28 | end_line: u32, |
| | 29 | }; |
| | 30 | |
| 23 | base: link.File, | 31 | base: link.File, |
| 24 | sixtyfour_bit: bool, | 32 | sixtyfour_bit: bool, |
| 25 | error_flags: File.ErrorFlags = File.ErrorFlags{}, | 33 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| ... | @@ -27,9 +35,31 @@ bases: Bases, | ... | @@ -27,9 +35,31 @@ bases: Bases, |
| 27 | | 35 | |
| 28 | /// A symbol's value is just casted down when compiling | 36 | /// A symbol's value is just casted down when compiling |
| 29 | /// for a 32 bit target. | 37 | /// for a 32 bit target. |
| | 38 | /// Does not represent the order or amount of symbols in the file |
| | 39 | /// it is just useful for storing symbols. Some other symbols are in |
| | 40 | /// file_segments. |
| 30 | syms: std.ArrayListUnmanaged(aout.Sym) = .{}, | 41 | syms: std.ArrayListUnmanaged(aout.Sym) = .{}, |
| 31 | | 42 | |
| 32 | fn_decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, []const u8) = .{}, | 43 | /// The plan9 a.out format requires segments of |
| | 44 | /// filenames to be deduplicated, so we use this map to |
| | 45 | /// de duplicate it. The value is the value of the path |
| | 46 | /// component |
| | 47 | file_segments: std.StringArrayHashMapUnmanaged(u16) = .{}, |
| | 48 | /// The value of a 'f' symbol increments by 1 every time, so that no 2 'f' |
| | 49 | /// symbols have the same value. |
| | 50 | file_segments_i: u16 = 1, |
| | 51 | |
| | 52 | path_arena: std.heap.ArenaAllocator, |
| | 53 | |
| | 54 | /// maps a file scope to a hash map of decl to codegen output |
| | 55 | /// this is useful for line debuginfo, since it makes sense to sort by file |
| | 56 | /// The debugger looks for the first file (aout.Sym.Type.z) preceeding the text symbol |
| | 57 | /// of the function to know what file it came from. |
| | 58 | /// If we group the decls by file, it makes it really easy to do this (put the symbol in the correct place) |
| | 59 | fn_decl_table: std.AutoArrayHashMapUnmanaged( |
| | 60 | *Module.Scope.File, |
| | 61 | struct { sym_index: u32, functions: std.AutoArrayHashMapUnmanaged(*Module.Decl, FnDeclOutput) = .{} }, |
| | 62 | ) = .{}, |
| 33 | data_decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, []const u8) = .{}, | 63 | data_decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, []const u8) = .{}, |
| 34 | | 64 | |
| 35 | hdr: aout.ExecHdr = undefined, | 65 | hdr: aout.ExecHdr = undefined, |
| ... | @@ -110,8 +140,12 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { | ... | @@ -110,8 +140,12 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { |
| 110 | 33...64 => true, | 140 | 33...64 => true, |
| 111 | else => return error.UnsupportedP9Architecture, | 141 | else => return error.UnsupportedP9Architecture, |
| 112 | }; | 142 | }; |
| | 143 | |
| | 144 | var arena_allocator = std.heap.ArenaAllocator.init(gpa); |
| | 145 | |
| 113 | const self = try gpa.create(Plan9); | 146 | const self = try gpa.create(Plan9); |
| 114 | self.* = .{ | 147 | self.* = .{ |
| | 148 | .path_arena = arena_allocator, |
| 115 | .base = .{ | 149 | .base = .{ |
| 116 | .tag = .plan9, | 150 | .tag = .plan9, |
| 117 | .options = options, | 151 | .options = options, |
| ... | @@ -122,9 +156,66 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { | ... | @@ -122,9 +156,66 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { |
| 122 | .bases = undefined, | 156 | .bases = undefined, |
| 123 | .magic = try aout.magicFromArch(self.base.options.target.cpu.arch), | 157 | .magic = try aout.magicFromArch(self.base.options.target.cpu.arch), |
| 124 | }; | 158 | }; |
| | 159 | // a / will always be in a file path |
| | 160 | try self.file_segments.put(self.base.allocator, "/", 1); |
| 125 | return self; | 161 | return self; |
| 126 | } | 162 | } |
| 127 | | 163 | |
| | 164 | fn putFn(self: *Plan9, decl: *Module.Decl, out: FnDeclOutput) !void { |
| | 165 | const gpa = self.base.allocator; |
| | 166 | const fn_map_res = try self.fn_decl_table.getOrPut(gpa, decl.namespace.file_scope); |
| | 167 | if (fn_map_res.found_existing) { |
| | 168 | try fn_map_res.value_ptr.functions.put(gpa, decl, out); |
| | 169 | } else { |
| | 170 | const file = decl.namespace.file_scope; |
| | 171 | const arena = &self.path_arena.allocator; |
| | 172 | // each file gets a symbol |
| | 173 | fn_map_res.value_ptr.* = .{ |
| | 174 | .sym_index = blk: { |
| | 175 | try self.syms.append(gpa, undefined); |
| | 176 | break :blk @intCast(u32, self.syms.items.len - 1); |
| | 177 | }, |
| | 178 | }; |
| | 179 | try fn_map_res.value_ptr.functions.put(gpa, decl, out); |
| | 180 | |
| | 181 | var a = std.ArrayList(u8).init(arena); |
| | 182 | errdefer a.deinit(); |
| | 183 | // every 'z' starts with 0 |
| | 184 | try a.append(0); |
| | 185 | // path component value of '/' |
| | 186 | try a.writer().writeIntBig(u16, 1); |
| | 187 | |
| | 188 | // getting the full file path |
| | 189 | var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; |
| | 190 | const dir = file.pkg.root_src_directory.path orelse try std.os.getcwd(&buf); |
| | 191 | const sub_path = try std.fs.path.join(arena, &.{ dir, file.sub_file_path }); |
| | 192 | try self.addPathComponents(sub_path, &a); |
| | 193 | |
| | 194 | // null terminate |
| | 195 | try a.append(0); |
| | 196 | const final = a.toOwnedSlice(); |
| | 197 | self.syms.items[fn_map_res.value_ptr.sym_index] = .{ |
| | 198 | .type = .z, |
| | 199 | .value = 1, |
| | 200 | .name = final, |
| | 201 | }; |
| | 202 | } |
| | 203 | } |
| | 204 | |
| | 205 | fn addPathComponents(self: *Plan9, path: []const u8, a: *std.ArrayList(u8)) !void { |
| | 206 | const sep = std.fs.path.sep; |
| | 207 | var it = std.mem.tokenize(u8, path, &.{sep}); |
| | 208 | while (it.next()) |component| { |
| | 209 | if (self.file_segments.get(component)) |num| { |
| | 210 | try a.writer().writeIntBig(u16, num); |
| | 211 | } else { |
| | 212 | self.file_segments_i += 1; |
| | 213 | try self.file_segments.put(self.base.allocator, component, self.file_segments_i); |
| | 214 | try a.writer().writeIntBig(u16, self.file_segments_i); |
| | 215 | } |
| | 216 | } |
| | 217 | } |
| | 218 | |
| 128 | pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | 219 | pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { |
| 129 | if (build_options.skip_non_native and builtin.object_format != .plan9) { | 220 | if (build_options.skip_non_native and builtin.object_format != .plan9) { |
| 130 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 221 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| ... | @@ -139,7 +230,9 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv | ... | @@ -139,7 +230,9 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv |
| 139 | defer code_buffer.deinit(); | 230 | defer code_buffer.deinit(); |
| 140 | var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator); | 231 | var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 141 | defer dbg_line_buffer.deinit(); | 232 | defer dbg_line_buffer.deinit(); |
| 142 | var end_line: u32 = 0; | 233 | var start_line: ?u32 = null; |
| | 234 | var end_line: u32 = undefined; |
| | 235 | var pcop_change_index: ?u32 = null; |
| 143 | | 236 | |
| 144 | const res = try codegen.generateFunction( | 237 | const res = try codegen.generateFunction( |
| 145 | &self.base, | 238 | &self.base, |
| ... | @@ -152,6 +245,8 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv | ... | @@ -152,6 +245,8 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv |
| 152 | .plan9 = .{ | 245 | .plan9 = .{ |
| 153 | .dbg_line = &dbg_line_buffer, | 246 | .dbg_line = &dbg_line_buffer, |
| 154 | .end_line = &end_line, | 247 | .end_line = &end_line, |
| | 248 | .start_line = &start_line, |
| | 249 | .pcop_change_index = &pcop_change_index, |
| 155 | }, | 250 | }, |
| 156 | }, | 251 | }, |
| 157 | ); | 252 | ); |
| ... | @@ -163,7 +258,13 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv | ... | @@ -163,7 +258,13 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv |
| 163 | return; | 258 | return; |
| 164 | }, | 259 | }, |
| 165 | }; | 260 | }; |
| 166 | try self.fn_decl_table.put(self.base.allocator, decl, code); | 261 | const out: FnDeclOutput = .{ |
| | 262 | .code = code, |
| | 263 | .lineinfo = dbg_line_buffer.toOwnedSlice(), |
| | 264 | .start_line = start_line.?, |
| | 265 | .end_line = end_line, |
| | 266 | }; |
| | 267 | try self.putFn(decl, out); |
| 167 | return self.updateFinish(decl); | 268 | return self.updateFinish(decl); |
| 168 | } | 269 | } |
| 169 | | 270 | |
| ... | @@ -242,6 +343,30 @@ pub fn flush(self: *Plan9, comp: *Compilation) !void { | ... | @@ -242,6 +343,30 @@ pub fn flush(self: *Plan9, comp: *Compilation) !void { |
| 242 | return self.flushModule(comp); | 343 | return self.flushModule(comp); |
| 243 | } | 344 | } |
| 244 | | 345 | |
| | 346 | pub fn changeLine(l: *std.ArrayList(u8), delta_line: i32) !void { |
| | 347 | if (delta_line > 0 and delta_line < 65) { |
| | 348 | const toappend = @intCast(u8, delta_line); |
| | 349 | try l.append(toappend); |
| | 350 | } else if (delta_line < 0 and delta_line > -65) { |
| | 351 | const toadd: u8 = @intCast(u8, -delta_line + 64); |
| | 352 | try l.append(toadd); |
| | 353 | } else if (delta_line != 0) { |
| | 354 | try l.append(0); |
| | 355 | try l.writer().writeIntBig(i32, delta_line); |
| | 356 | } |
| | 357 | } |
| | 358 | |
| | 359 | fn declCount(self: *Plan9) u64 { |
| | 360 | var fn_decl_count: u64 = 0; |
| | 361 | var itf_files = self.fn_decl_table.iterator(); |
| | 362 | while (itf_files.next()) |ent| { |
| | 363 | // get the submap |
| | 364 | var submap = ent.value_ptr.functions; |
| | 365 | fn_decl_count += submap.count(); |
| | 366 | } |
| | 367 | return self.data_decl_table.count() + fn_decl_count; |
| | 368 | } |
| | 369 | |
| 245 | pub fn flushModule(self: *Plan9, comp: *Compilation) !void { | 370 | pub fn flushModule(self: *Plan9, comp: *Compilation) !void { |
| 246 | if (build_options.skip_non_native and builtin.object_format != .plan9) { | 371 | if (build_options.skip_non_native and builtin.object_format != .plan9) { |
| 247 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 372 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| ... | @@ -257,13 +382,13 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void { | ... | @@ -257,13 +382,13 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void { |
| 257 | | 382 | |
| 258 | const mod = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; | 383 | const mod = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; |
| 259 | | 384 | |
| 260 | assert(self.got_len == self.fn_decl_table.count() + self.data_decl_table.count() + self.got_index_free_list.items.len); | 385 | assert(self.got_len == self.declCount() + self.got_index_free_list.items.len); |
| 261 | const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8; | 386 | const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8; |
| 262 | var got_table = try self.base.allocator.alloc(u8, got_size); | 387 | var got_table = try self.base.allocator.alloc(u8, got_size); |
| 263 | defer self.base.allocator.free(got_table); | 388 | defer self.base.allocator.free(got_table); |
| 264 | | 389 | |
| 265 | // + 3 for header, got, symbols | 390 | // + 4 for header, got, symbols, linecountinfo |
| 266 | var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.fn_decl_table.count() + self.data_decl_table.count() + 3); | 391 | var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.declCount() + 4); |
| 267 | defer self.base.allocator.free(iovecs); | 392 | defer self.base.allocator.free(iovecs); |
| 268 | | 393 | |
| 269 | const file = self.base.file.?; | 394 | const file = self.base.file.?; |
| ... | @@ -276,30 +401,52 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void { | ... | @@ -276,30 +401,52 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void { |
| 276 | iovecs[0] = .{ .iov_base = hdr_slice.ptr, .iov_len = hdr_slice.len }; | 401 | iovecs[0] = .{ .iov_base = hdr_slice.ptr, .iov_len = hdr_slice.len }; |
| 277 | var iovecs_i: usize = 1; | 402 | var iovecs_i: usize = 1; |
| 278 | var text_i: u64 = 0; | 403 | var text_i: u64 = 0; |
| | 404 | |
| | 405 | var linecountinfo = std.ArrayList(u8).init(self.base.allocator); |
| | 406 | defer linecountinfo.deinit(); |
| 279 | // text | 407 | // text |
| 280 | { | 408 | { |
| 281 | var it = self.fn_decl_table.iterator(); | 409 | var linecount: u32 = 0; |
| 282 | while (it.next()) |entry| { | 410 | var it_file = self.fn_decl_table.iterator(); |
| 283 | const decl = entry.key_ptr.*; | 411 | while (it_file.next()) |fentry| { |
| 284 | const code = entry.value_ptr.*; | 412 | var it = fentry.value_ptr.functions.iterator(); |
| 285 | log.debug("write text decl {*} ({s})", .{ decl, decl.name }); | 413 | while (it.next()) |entry| { |
| 286 | foff += code.len; | 414 | const decl = entry.key_ptr.*; |
| 287 | iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len }; | 415 | const out = entry.value_ptr.*; |
| 288 | iovecs_i += 1; | 416 | log.debug("write text decl {*} ({s}), lines {d} to {d}", .{ decl, decl.name, out.start_line, out.end_line }); |
| 289 | const off = self.getAddr(text_i, .t); | 417 | { |
| 290 | text_i += code.len; | 418 | // connect the previous decl to the next |
| 291 | decl.link.plan9.offset = off; | 419 | const delta_line = @intCast(i32, out.start_line) - @intCast(i32, linecount); |
| 292 | if (!self.sixtyfour_bit) { | 420 | |
| 293 | mem.writeIntNative(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off)); | 421 | try changeLine(&linecountinfo, delta_line); |
| 294 | mem.writeInt(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian()); | 422 | // TODO change the pc too (maybe?) |
| 295 | } else { | 423 | |
| 296 | mem.writeInt(u64, got_table[decl.link.plan9.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian()); | 424 | // write out the actual info that was generated in codegen now |
| 297 | } | 425 | try linecountinfo.appendSlice(out.lineinfo); |
| 298 | self.syms.items[decl.link.plan9.sym_index.?].value = off; | 426 | linecount = out.end_line; |
| 299 | if (mod.decl_exports.get(decl)) |exports| { | 427 | } |
| 300 | try self.addDeclExports(mod, decl, exports); | 428 | foff += out.code.len; |
| | 429 | iovecs[iovecs_i] = .{ .iov_base = out.code.ptr, .iov_len = out.code.len }; |
| | 430 | iovecs_i += 1; |
| | 431 | const off = self.getAddr(text_i, .t); |
| | 432 | text_i += out.code.len; |
| | 433 | decl.link.plan9.offset = off; |
| | 434 | if (!self.sixtyfour_bit) { |
| | 435 | mem.writeIntNative(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off)); |
| | 436 | mem.writeInt(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian()); |
| | 437 | } else { |
| | 438 | mem.writeInt(u64, got_table[decl.link.plan9.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian()); |
| | 439 | } |
| | 440 | self.syms.items[decl.link.plan9.sym_index.?].value = off; |
| | 441 | if (mod.decl_exports.get(decl)) |exports| { |
| | 442 | try self.addDeclExports(mod, decl, exports); |
| | 443 | } |
| 301 | } | 444 | } |
| 302 | } | 445 | } |
| | 446 | if (linecountinfo.items.len & 1 == 1) { |
| | 447 | // just a nop to make it even, the plan9 linker does this |
| | 448 | try linecountinfo.append(129); |
| | 449 | } |
| 303 | // etext symbol | 450 | // etext symbol |
| 304 | self.syms.items[2].value = self.getAddr(text_i, .t); | 451 | self.syms.items[2].value = self.getAddr(text_i, .t); |
| 305 | } | 452 | } |
| ... | @@ -337,20 +484,23 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void { | ... | @@ -337,20 +484,23 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void { |
| 337 | // edata | 484 | // edata |
| 338 | self.syms.items[1].value = self.getAddr(0x0, .b); | 485 | self.syms.items[1].value = self.getAddr(0x0, .b); |
| 339 | var sym_buf = std.ArrayList(u8).init(self.base.allocator); | 486 | var sym_buf = std.ArrayList(u8).init(self.base.allocator); |
| 340 | defer sym_buf.deinit(); | | |
| 341 | try self.writeSyms(&sym_buf); | 487 | try self.writeSyms(&sym_buf); |
| 342 | assert(2 + self.fn_decl_table.count() + self.data_decl_table.count() == iovecs_i); // we didn't write all the decls | 488 | const syms = sym_buf.toOwnedSlice(); |
| 343 | iovecs[iovecs_i] = .{ .iov_base = sym_buf.items.ptr, .iov_len = sym_buf.items.len }; | 489 | defer self.base.allocator.free(syms); |
| | 490 | assert(2 + self.declCount() == iovecs_i); // we didn't write all the decls |
| | 491 | iovecs[iovecs_i] = .{ .iov_base = syms.ptr, .iov_len = syms.len }; |
| | 492 | iovecs_i += 1; |
| | 493 | iovecs[iovecs_i] = .{ .iov_base = linecountinfo.items.ptr, .iov_len = linecountinfo.items.len }; |
| 344 | iovecs_i += 1; | 494 | iovecs_i += 1; |
| 345 | // generate the header | 495 | // generate the header |
| 346 | self.hdr = .{ | 496 | self.hdr = .{ |
| 347 | .magic = self.magic, | 497 | .magic = self.magic, |
| 348 | .text = @intCast(u32, text_i), | 498 | .text = @intCast(u32, text_i), |
| 349 | .data = @intCast(u32, data_i), | 499 | .data = @intCast(u32, data_i), |
| 350 | .syms = @intCast(u32, sym_buf.items.len), | 500 | .syms = @intCast(u32, syms.len), |
| 351 | .bss = 0, | 501 | .bss = 0, |
| 352 | .pcsz = 0, | | |
| 353 | .spsz = 0, | 502 | .spsz = 0, |
| | 503 | .pcsz = @intCast(u32, linecountinfo.items.len), |
| 354 | .entry = @intCast(u32, self.entry_val.?), | 504 | .entry = @intCast(u32, self.entry_val.?), |
| 355 | }; | 505 | }; |
| 356 | std.mem.copy(u8, hdr_slice, self.hdr.toU8s()[0..hdr_size]); | 506 | std.mem.copy(u8, hdr_slice, self.hdr.toU8s()[0..hdr_size]); |
| ... | @@ -397,7 +547,15 @@ pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void { | ... | @@ -397,7 +547,15 @@ pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void { |
| 397 | // in the deleteUnusedDecl function. | 547 | // in the deleteUnusedDecl function. |
| 398 | const is_fn = (decl.val.tag() == .function); | 548 | const is_fn = (decl.val.tag() == .function); |
| 399 | if (is_fn) { | 549 | if (is_fn) { |
| 400 | _ = self.fn_decl_table.swapRemove(decl); | 550 | var symidx_and_submap = |
| | 551 | self.fn_decl_table.get(decl.namespace.file_scope).?; |
| | 552 | var submap = symidx_and_submap.functions; |
| | 553 | _ = submap.swapRemove(decl); |
| | 554 | if (submap.count() == 0) { |
| | 555 | self.syms.items[symidx_and_submap.sym_index] = aout.Sym.undefined_symbol; |
| | 556 | self.syms_index_free_list.append(self.base.allocator, symidx_and_submap.sym_index) catch {}; |
| | 557 | submap.deinit(self.base.allocator); |
| | 558 | } |
| 401 | } else { | 559 | } else { |
| 402 | _ = self.data_decl_table.swapRemove(decl); | 560 | _ = self.data_decl_table.swapRemove(decl); |
| 403 | } | 561 | } |
| ... | @@ -407,7 +565,7 @@ pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void { | ... | @@ -407,7 +565,7 @@ pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void { |
| 407 | } | 565 | } |
| 408 | if (decl.link.plan9.sym_index) |i| { | 566 | if (decl.link.plan9.sym_index) |i| { |
| 409 | self.syms_index_free_list.append(self.base.allocator, i) catch {}; | 567 | self.syms_index_free_list.append(self.base.allocator, i) catch {}; |
| 410 | self.syms.items[i] = undefined; | 568 | self.syms.items[i] = aout.Sym.undefined_symbol; |
| 411 | } | 569 | } |
| 412 | } | 570 | } |
| 413 | | 571 | |
| ... | @@ -436,19 +594,29 @@ pub fn updateDeclExports( | ... | @@ -436,19 +594,29 @@ pub fn updateDeclExports( |
| 436 | _ = exports; | 594 | _ = exports; |
| 437 | } | 595 | } |
| 438 | pub fn deinit(self: *Plan9) void { | 596 | pub fn deinit(self: *Plan9) void { |
| 439 | var itf = self.fn_decl_table.iterator(); | 597 | const gpa = self.base.allocator; |
| 440 | while (itf.next()) |entry| { | 598 | var itf_files = self.fn_decl_table.iterator(); |
| 441 | self.base.allocator.free(entry.value_ptr.*); | 599 | while (itf_files.next()) |ent| { |
| | 600 | // get the submap |
| | 601 | var submap = ent.value_ptr.functions; |
| | 602 | defer submap.deinit(gpa); |
| | 603 | var itf = submap.iterator(); |
| | 604 | while (itf.next()) |entry| { |
| | 605 | gpa.free(entry.value_ptr.code); |
| | 606 | gpa.free(entry.value_ptr.lineinfo); |
| | 607 | } |
| 442 | } | 608 | } |
| 443 | self.fn_decl_table.deinit(self.base.allocator); | 609 | self.fn_decl_table.deinit(gpa); |
| 444 | var itd = self.data_decl_table.iterator(); | 610 | var itd = self.data_decl_table.iterator(); |
| 445 | while (itd.next()) |entry| { | 611 | while (itd.next()) |entry| { |
| 446 | self.base.allocator.free(entry.value_ptr.*); | 612 | gpa.free(entry.value_ptr.*); |
| 447 | } | 613 | } |
| 448 | self.data_decl_table.deinit(self.base.allocator); | 614 | self.data_decl_table.deinit(gpa); |
| 449 | self.syms.deinit(self.base.allocator); | 615 | self.syms.deinit(gpa); |
| 450 | self.got_index_free_list.deinit(self.base.allocator); | 616 | self.got_index_free_list.deinit(gpa); |
| 451 | self.syms_index_free_list.deinit(self.base.allocator); | 617 | self.syms_index_free_list.deinit(gpa); |
| | 618 | self.file_segments.deinit(gpa); |
| | 619 | self.path_arena.deinit(); |
| 452 | } | 620 | } |
| 453 | | 621 | |
| 454 | pub const Export = ?usize; | 622 | pub const Export = ?usize; |
| ... | @@ -458,7 +626,6 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio | ... | @@ -458,7 +626,6 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 458 | return error.LLVMBackendDoesNotSupportPlan9; | 626 | return error.LLVMBackendDoesNotSupportPlan9; |
| 459 | assert(options.object_format == .plan9); | 627 | assert(options.object_format == .plan9); |
| 460 | const file = try options.emit.?.directory.handle.createFile(sub_path, .{ | 628 | const file = try options.emit.?.directory.handle.createFile(sub_path, .{ |
| 461 | .truncate = false, | | |
| 462 | .read = true, | 629 | .read = true, |
| 463 | .mode = link.determineMode(options), | 630 | .mode = link.determineMode(options), |
| 464 | }); | 631 | }); |
| ... | @@ -492,21 +659,72 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio | ... | @@ -492,21 +659,72 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 492 | return self; | 659 | return self; |
| 493 | } | 660 | } |
| 494 | | 661 | |
| | 662 | pub fn writeSym(self: *Plan9, w: anytype, sym: aout.Sym) !void { |
| | 663 | log.debug("write sym.name: {s}", .{sym.name}); |
| | 664 | log.debug("write sym.value: {x}", .{sym.value}); |
| | 665 | if (sym.type == .bad) return; // we don't want to write free'd symbols |
| | 666 | if (!self.sixtyfour_bit) { |
| | 667 | try w.writeIntBig(u32, @intCast(u32, sym.value)); |
| | 668 | } else { |
| | 669 | try w.writeIntBig(u64, sym.value); |
| | 670 | } |
| | 671 | try w.writeByte(@enumToInt(sym.type)); |
| | 672 | try w.writeAll(sym.name); |
| | 673 | try w.writeByte(0); |
| | 674 | } |
| 495 | pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { | 675 | pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { |
| 496 | const writer = buf.writer(); | 676 | const writer = buf.writer(); |
| 497 | for (self.syms.items) |sym| { | 677 | // write the f symbols |
| 498 | log.debug("sym.name: {s}", .{sym.name}); | 678 | { |
| 499 | log.debug("sym.value: {x}", .{sym.value}); | 679 | var it = self.file_segments.iterator(); |
| 500 | if (mem.eql(u8, sym.name, "_start")) | 680 | while (it.next()) |entry| { |
| 501 | self.entry_val = sym.value; | 681 | try self.writeSym(writer, .{ |
| 502 | if (!self.sixtyfour_bit) { | 682 | .type = .f, |
| 503 | try writer.writeIntBig(u32, @intCast(u32, sym.value)); | 683 | .value = entry.value_ptr.*, |
| 504 | } else { | 684 | .name = entry.key_ptr.*, |
| 505 | try writer.writeIntBig(u64, sym.value); | 685 | }); |
| | 686 | } |
| | 687 | } |
| | 688 | // write the data symbols |
| | 689 | { |
| | 690 | var it = self.data_decl_table.iterator(); |
| | 691 | while (it.next()) |entry| { |
| | 692 | const decl = entry.key_ptr.*; |
| | 693 | const sym = self.syms.items[decl.link.plan9.sym_index.?]; |
| | 694 | try self.writeSym(writer, sym); |
| | 695 | if (self.base.options.module.?.decl_exports.get(decl)) |exports| { |
| | 696 | for (exports) |e| { |
| | 697 | try self.writeSym(writer, self.syms.items[e.link.plan9.?]); |
| | 698 | } |
| | 699 | } |
| | 700 | } |
| | 701 | } |
| | 702 | // text symbols are the hardest: |
| | 703 | // the file of a text symbol is the .z symbol before it |
| | 704 | // so we have to write everything in the right order |
| | 705 | { |
| | 706 | var it_file = self.fn_decl_table.iterator(); |
| | 707 | while (it_file.next()) |fentry| { |
| | 708 | var symidx_and_submap = fentry.value_ptr; |
| | 709 | // write the z symbol |
| | 710 | try self.writeSym(writer, self.syms.items[symidx_and_submap.sym_index]); |
| | 711 | |
| | 712 | // write all the decls come from the file of the z symbol |
| | 713 | var submap_it = symidx_and_submap.functions.iterator(); |
| | 714 | while (submap_it.next()) |entry| { |
| | 715 | const decl = entry.key_ptr.*; |
| | 716 | const sym = self.syms.items[decl.link.plan9.sym_index.?]; |
| | 717 | try self.writeSym(writer, sym); |
| | 718 | if (self.base.options.module.?.decl_exports.get(decl)) |exports| { |
| | 719 | for (exports) |e| { |
| | 720 | const s = self.syms.items[e.link.plan9.?]; |
| | 721 | if (mem.eql(u8, s.name, "_start")) |
| | 722 | self.entry_val = s.value; |
| | 723 | try self.writeSym(writer, s); |
| | 724 | } |
| | 725 | } |
| | 726 | } |
| 506 | } | 727 | } |
| 507 | try writer.writeByte(@enumToInt(sym.type)); | | |
| 508 | try writer.writeAll(sym.name); | | |
| 509 | try writer.writeByte(0); | | |
| 510 | } | 728 | } |
| 511 | } | 729 | } |
| 512 | | 730 | |