| ... | ... | @@ -20,6 +20,14 @@ const Allocator = std.mem.Allocator; |
| 20 | 20 | const log = std.log.scoped(.link); |
| 21 | 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 | 31 | base: link.File, |
| 24 | 32 | sixtyfour_bit: bool, |
| 25 | 33 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| ... | ... | @@ -27,9 +35,31 @@ bases: Bases, |
| 27 | 35 | |
| 28 | 36 | /// A symbol's value is just casted down when compiling |
| 29 | 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 | 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 | 63 | data_decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, []const u8) = .{}, |
| 34 | 64 | |
| 35 | 65 | hdr: aout.ExecHdr = undefined, |
| ... | ... | @@ -110,8 +140,12 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { |
| 110 | 140 | 33...64 => true, |
| 111 | 141 | else => return error.UnsupportedP9Architecture, |
| 112 | 142 | }; |
| 143 | |
| 144 | var arena_allocator = std.heap.ArenaAllocator.init(gpa); |
| 145 | |
| 113 | 146 | const self = try gpa.create(Plan9); |
| 114 | 147 | self.* = .{ |
| 148 | .path_arena = arena_allocator, |
| 115 | 149 | .base = .{ |
| 116 | 150 | .tag = .plan9, |
| 117 | 151 | .options = options, |
| ... | ... | @@ -122,9 +156,66 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { |
| 122 | 156 | .bases = undefined, |
| 123 | 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 | 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 | 219 | pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { |
| 129 | 220 | if (build_options.skip_non_native and builtin.object_format != .plan9) { |
| 130 | 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 | 230 | defer code_buffer.deinit(); |
| 140 | 231 | var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 141 | 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 | 237 | const res = try codegen.generateFunction( |
| 145 | 238 | &self.base, |
| ... | ... | @@ -152,6 +245,8 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv |
| 152 | 245 | .plan9 = .{ |
| 153 | 246 | .dbg_line = &dbg_line_buffer, |
| 154 | 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 | 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 | 268 | return self.updateFinish(decl); |
| 168 | 269 | } |
| 169 | 270 | |
| ... | ... | @@ -242,6 +343,30 @@ pub fn flush(self: *Plan9, comp: *Compilation) !void { |
| 242 | 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 | 370 | pub fn flushModule(self: *Plan9, comp: *Compilation) !void { |
| 246 | 371 | if (build_options.skip_non_native and builtin.object_format != .plan9) { |
| 247 | 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 | 382 | |
| 258 | 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 | 386 | const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8; |
| 262 | 387 | var got_table = try self.base.allocator.alloc(u8, got_size); |
| 263 | 388 | defer self.base.allocator.free(got_table); |
| 264 | 389 | |
| 265 | | // + 3 for header, got, symbols |
| 266 | | var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.fn_decl_table.count() + self.data_decl_table.count() + 3); |
| 390 | // + 4 for header, got, symbols, linecountinfo |
| 391 | var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.declCount() + 4); |
| 267 | 392 | defer self.base.allocator.free(iovecs); |
| 268 | 393 | |
| 269 | 394 | const file = self.base.file.?; |
| ... | ... | @@ -276,30 +401,52 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void { |
| 276 | 401 | iovecs[0] = .{ .iov_base = hdr_slice.ptr, .iov_len = hdr_slice.len }; |
| 277 | 402 | var iovecs_i: usize = 1; |
| 278 | 403 | var text_i: u64 = 0; |
| 404 | |
| 405 | var linecountinfo = std.ArrayList(u8).init(self.base.allocator); |
| 406 | defer linecountinfo.deinit(); |
| 279 | 407 | // text |
| 280 | 408 | { |
| 281 | | var it = self.fn_decl_table.iterator(); |
| 282 | | while (it.next()) |entry| { |
| 283 | | const decl = entry.key_ptr.*; |
| 284 | | const code = entry.value_ptr.*; |
| 285 | | log.debug("write text decl {*} ({s})", .{ decl, decl.name }); |
| 286 | | foff += code.len; |
| 287 | | iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len }; |
| 288 | | iovecs_i += 1; |
| 289 | | const off = self.getAddr(text_i, .t); |
| 290 | | text_i += code.len; |
| 291 | | decl.link.plan9.offset = off; |
| 292 | | if (!self.sixtyfour_bit) { |
| 293 | | mem.writeIntNative(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off)); |
| 294 | | mem.writeInt(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian()); |
| 295 | | } else { |
| 296 | | mem.writeInt(u64, got_table[decl.link.plan9.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian()); |
| 297 | | } |
| 298 | | self.syms.items[decl.link.plan9.sym_index.?].value = off; |
| 299 | | if (mod.decl_exports.get(decl)) |exports| { |
| 300 | | try self.addDeclExports(mod, decl, exports); |
| 409 | var linecount: u32 = 0; |
| 410 | var it_file = self.fn_decl_table.iterator(); |
| 411 | while (it_file.next()) |fentry| { |
| 412 | var it = fentry.value_ptr.functions.iterator(); |
| 413 | while (it.next()) |entry| { |
| 414 | const decl = entry.key_ptr.*; |
| 415 | const out = entry.value_ptr.*; |
| 416 | log.debug("write text decl {*} ({s}), lines {d} to {d}", .{ decl, decl.name, out.start_line, out.end_line }); |
| 417 | { |
| 418 | // connect the previous decl to the next |
| 419 | const delta_line = @intCast(i32, out.start_line) - @intCast(i32, linecount); |
| 420 | |
| 421 | try changeLine(&linecountinfo, delta_line); |
| 422 | // TODO change the pc too (maybe?) |
| 423 | |
| 424 | // write out the actual info that was generated in codegen now |
| 425 | try linecountinfo.appendSlice(out.lineinfo); |
| 426 | linecount = out.end_line; |
| 427 | } |
| 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 | 450 | // etext symbol |
| 304 | 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 | 484 | // edata |
| 338 | 485 | self.syms.items[1].value = self.getAddr(0x0, .b); |
| 339 | 486 | var sym_buf = std.ArrayList(u8).init(self.base.allocator); |
| 340 | | defer sym_buf.deinit(); |
| 341 | 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 |
| 343 | | iovecs[iovecs_i] = .{ .iov_base = sym_buf.items.ptr, .iov_len = sym_buf.items.len }; |
| 488 | const syms = sym_buf.toOwnedSlice(); |
| 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 | 494 | iovecs_i += 1; |
| 345 | 495 | // generate the header |
| 346 | 496 | self.hdr = .{ |
| 347 | 497 | .magic = self.magic, |
| 348 | 498 | .text = @intCast(u32, text_i), |
| 349 | 499 | .data = @intCast(u32, data_i), |
| 350 | | .syms = @intCast(u32, sym_buf.items.len), |
| 500 | .syms = @intCast(u32, syms.len), |
| 351 | 501 | .bss = 0, |
| 352 | | .pcsz = 0, |
| 353 | 502 | .spsz = 0, |
| 503 | .pcsz = @intCast(u32, linecountinfo.items.len), |
| 354 | 504 | .entry = @intCast(u32, self.entry_val.?), |
| 355 | 505 | }; |
| 356 | 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 | 547 | // in the deleteUnusedDecl function. |
| 398 | 548 | const is_fn = (decl.val.tag() == .function); |
| 399 | 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 | 559 | } else { |
| 402 | 560 | _ = self.data_decl_table.swapRemove(decl); |
| 403 | 561 | } |
| ... | ... | @@ -407,7 +565,7 @@ pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void { |
| 407 | 565 | } |
| 408 | 566 | if (decl.link.plan9.sym_index) |i| { |
| 409 | 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 | 594 | _ = exports; |
| 437 | 595 | } |
| 438 | 596 | pub fn deinit(self: *Plan9) void { |
| 439 | | var itf = self.fn_decl_table.iterator(); |
| 440 | | while (itf.next()) |entry| { |
| 441 | | self.base.allocator.free(entry.value_ptr.*); |
| 597 | const gpa = self.base.allocator; |
| 598 | var itf_files = self.fn_decl_table.iterator(); |
| 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 | 610 | var itd = self.data_decl_table.iterator(); |
| 445 | 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); |
| 449 | | self.syms.deinit(self.base.allocator); |
| 450 | | self.got_index_free_list.deinit(self.base.allocator); |
| 451 | | self.syms_index_free_list.deinit(self.base.allocator); |
| 614 | self.data_decl_table.deinit(gpa); |
| 615 | self.syms.deinit(gpa); |
| 616 | self.got_index_free_list.deinit(gpa); |
| 617 | self.syms_index_free_list.deinit(gpa); |
| 618 | self.file_segments.deinit(gpa); |
| 619 | self.path_arena.deinit(); |
| 452 | 620 | } |
| 453 | 621 | |
| 454 | 622 | pub const Export = ?usize; |
| ... | ... | @@ -458,7 +626,6 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 458 | 626 | return error.LLVMBackendDoesNotSupportPlan9; |
| 459 | 627 | assert(options.object_format == .plan9); |
| 460 | 628 | const file = try options.emit.?.directory.handle.createFile(sub_path, .{ |
| 461 | | .truncate = false, |
| 462 | 629 | .read = true, |
| 463 | 630 | .mode = link.determineMode(options), |
| 464 | 631 | }); |
| ... | ... | @@ -492,21 +659,72 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 492 | 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 | 675 | pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { |
| 496 | 676 | const writer = buf.writer(); |
| 497 | | for (self.syms.items) |sym| { |
| 498 | | log.debug("sym.name: {s}", .{sym.name}); |
| 499 | | log.debug("sym.value: {x}", .{sym.value}); |
| 500 | | if (mem.eql(u8, sym.name, "_start")) |
| 501 | | self.entry_val = sym.value; |
| 502 | | if (!self.sixtyfour_bit) { |
| 503 | | try writer.writeIntBig(u32, @intCast(u32, sym.value)); |
| 504 | | } else { |
| 505 | | try writer.writeIntBig(u64, sym.value); |
| 677 | // write the f symbols |
| 678 | { |
| 679 | var it = self.file_segments.iterator(); |
| 680 | while (it.next()) |entry| { |
| 681 | try self.writeSym(writer, .{ |
| 682 | .type = .f, |
| 683 | .value = entry.value_ptr.*, |
| 684 | .name = entry.key_ptr.*, |
| 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 | |