| ... | ... | @@ -51,9 +51,11 @@ got_section_index: ?u16 = null, |
| 51 | 51 | rdata_section_index: ?u16 = null, |
| 52 | 52 | data_section_index: ?u16 = null, |
| 53 | 53 | reloc_section_index: ?u16 = null, |
| 54 | idata_section_index: ?u16 = null, |
| 54 | 55 | |
| 55 | 56 | locals: std.ArrayListUnmanaged(coff.Symbol) = .{}, |
| 56 | 57 | globals: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{}, |
| 58 | unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{}, |
| 57 | 59 | |
| 58 | 60 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 59 | 61 | |
| ... | ... | @@ -63,6 +65,9 @@ strtab_offset: ?u32 = null, |
| 63 | 65 | got_entries: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 64 | 66 | got_entries_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 65 | 67 | |
| 68 | imports_table: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 69 | imports_table_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 70 | |
| 66 | 71 | /// Virtual address of the entry point procedure relative to image base. |
| 67 | 72 | entry_addr: ?u32 = null, |
| 68 | 73 | |
| ... | ... | @@ -109,6 +114,11 @@ relocs: RelocTable = .{}, |
| 109 | 114 | /// this will be a table indexed by index into the list of Atoms. |
| 110 | 115 | base_relocs: BaseRelocationTable = .{}, |
| 111 | 116 | |
| 117 | /// A table of bindings indexed by the owning them `Atom`. |
| 118 | /// Note that once we refactor `Atom`'s lifetime and ownership rules, |
| 119 | /// this will be a table indexed by index into the list of Atoms. |
| 120 | bindings: BindingTable = .{}, |
| 121 | |
| 112 | 122 | pub const Reloc = struct { |
| 113 | 123 | @"type": enum { |
| 114 | 124 | got, |
| ... | ... | @@ -124,6 +134,7 @@ pub const Reloc = struct { |
| 124 | 134 | |
| 125 | 135 | const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Reloc)); |
| 126 | 136 | const BaseRelocationTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(u32)); |
| 137 | const BindingTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(SymbolWithLoc)); |
| 127 | 138 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom)); |
| 128 | 139 | |
| 129 | 140 | const default_file_alignment: u16 = 0x200; |
| ... | ... | @@ -269,10 +280,13 @@ pub fn deinit(self: *Coff) void { |
| 269 | 280 | |
| 270 | 281 | self.locals.deinit(gpa); |
| 271 | 282 | self.globals.deinit(gpa); |
| 283 | self.unresolved.deinit(gpa); |
| 272 | 284 | self.locals_free_list.deinit(gpa); |
| 273 | 285 | self.strtab.deinit(gpa); |
| 274 | 286 | self.got_entries.deinit(gpa); |
| 275 | 287 | self.got_entries_free_list.deinit(gpa); |
| 288 | self.imports_table.deinit(gpa); |
| 289 | self.imports_table_free_list.deinit(gpa); |
| 276 | 290 | self.decls.deinit(gpa); |
| 277 | 291 | self.atom_by_index_table.deinit(gpa); |
| 278 | 292 | |
| ... | ... | @@ -299,6 +313,14 @@ pub fn deinit(self: *Coff) void { |
| 299 | 313 | } |
| 300 | 314 | self.base_relocs.deinit(gpa); |
| 301 | 315 | } |
| 316 | |
| 317 | { |
| 318 | var it = self.bindings.valueIterator(); |
| 319 | while (it.next()) |bindings| { |
| 320 | bindings.deinit(gpa); |
| 321 | } |
| 322 | self.bindings.deinit(gpa); |
| 323 | } |
| 302 | 324 | } |
| 303 | 325 | |
| 304 | 326 | fn populateMissingMetadata(self: *Coff) !void { |
| ... | ... | @@ -420,7 +442,7 @@ fn populateMissingMetadata(self: *Coff) !void { |
| 420 | 442 | .number_of_linenumbers = 0, |
| 421 | 443 | .flags = .{ |
| 422 | 444 | .CNT_INITIALIZED_DATA = 1, |
| 423 | | .MEM_PURGEABLE = 1, |
| 445 | .MEM_DISCARDABLE = 1, |
| 424 | 446 | .MEM_READ = 1, |
| 425 | 447 | }, |
| 426 | 448 | }; |
| ... | ... | @@ -428,6 +450,30 @@ fn populateMissingMetadata(self: *Coff) !void { |
| 428 | 450 | try self.sections.append(gpa, .{ .header = header }); |
| 429 | 451 | } |
| 430 | 452 | |
| 453 | if (self.idata_section_index == null) { |
| 454 | self.idata_section_index = @intCast(u16, self.sections.slice().len); |
| 455 | const file_size = @intCast(u32, self.base.options.symbol_count_hint) * self.ptr_width.abiSize(); |
| 456 | const off = self.findFreeSpace(file_size, self.page_size); |
| 457 | log.debug("found .idata free space 0x{x} to 0x{x}", .{ off, off + file_size }); |
| 458 | var header = coff.SectionHeader{ |
| 459 | .name = undefined, |
| 460 | .virtual_size = file_size, |
| 461 | .virtual_address = off, |
| 462 | .size_of_raw_data = file_size, |
| 463 | .pointer_to_raw_data = off, |
| 464 | .pointer_to_relocations = 0, |
| 465 | .pointer_to_linenumbers = 0, |
| 466 | .number_of_relocations = 0, |
| 467 | .number_of_linenumbers = 0, |
| 468 | .flags = .{ |
| 469 | .CNT_INITIALIZED_DATA = 1, |
| 470 | .MEM_READ = 1, |
| 471 | }, |
| 472 | }; |
| 473 | try self.setSectionName(&header, ".idata"); |
| 474 | try self.sections.append(gpa, .{ .header = header }); |
| 475 | } |
| 476 | |
| 431 | 477 | if (self.strtab_offset == null) { |
| 432 | 478 | try self.strtab.buffer.append(gpa, 0); |
| 433 | 479 | self.strtab_offset = self.findFreeSpace(@intCast(u32, self.strtab.len()), 1); |
| ... | ... | @@ -626,6 +672,27 @@ pub fn allocateGotEntry(self: *Coff, target: SymbolWithLoc) !u32 { |
| 626 | 672 | return index; |
| 627 | 673 | } |
| 628 | 674 | |
| 675 | pub fn allocateImportEntry(self: *Coff, target: SymbolWithLoc) !u32 { |
| 676 | const gpa = self.base.allocator; |
| 677 | try self.imports_table.ensureUnusedCapacity(gpa, 1); |
| 678 | const index: u32 = blk: { |
| 679 | if (self.imports_table_free_list.popOrNull()) |index| { |
| 680 | log.debug(" (reusing import entry index {d})", .{index}); |
| 681 | if (self.imports_table.getIndex(target)) |existing| { |
| 682 | assert(existing == index); |
| 683 | } |
| 684 | break :blk index; |
| 685 | } else { |
| 686 | log.debug(" (allocating import entry at index {d})", .{self.imports_table.keys().len}); |
| 687 | const index = @intCast(u32, self.imports_table.keys().len); |
| 688 | self.imports_table.putAssumeCapacityNoClobber(target, 0); |
| 689 | break :blk index; |
| 690 | } |
| 691 | }; |
| 692 | self.imports_table.keys()[index] = target; |
| 693 | return index; |
| 694 | } |
| 695 | |
| 629 | 696 | fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { |
| 630 | 697 | const gpa = self.base.allocator; |
| 631 | 698 | const atom = try gpa.create(Atom); |
| ... | ... | @@ -666,6 +733,32 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { |
| 666 | 733 | return atom; |
| 667 | 734 | } |
| 668 | 735 | |
| 736 | fn createImportAtom(self: *Coff, target: SymbolWithLoc) !*Atom { |
| 737 | const gpa = self.base.allocator; |
| 738 | const atom = try gpa.create(Atom); |
| 739 | errdefer gpa.destroy(atom); |
| 740 | atom.* = Atom.empty; |
| 741 | atom.sym_index = try self.allocateSymbol(); |
| 742 | atom.size = @sizeOf(u64); |
| 743 | atom.alignment = @alignOf(u64); |
| 744 | |
| 745 | try self.managed_atoms.append(gpa, atom); |
| 746 | try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom); |
| 747 | self.imports_table.getPtr(target).?.* = atom.sym_index; |
| 748 | |
| 749 | const sym = atom.getSymbolPtr(self); |
| 750 | sym.section_number = @intToEnum(coff.SectionNumber, self.idata_section_index.? + 1); |
| 751 | sym.value = try self.allocateAtom(atom, atom.size, atom.alignment); |
| 752 | |
| 753 | log.debug("allocated import atom at 0x{x}", .{sym.value}); |
| 754 | |
| 755 | const target_sym = self.getSymbol(target); |
| 756 | assert(target_sym.section_number == .UNDEFINED); |
| 757 | try atom.addBinding(self, target); |
| 758 | |
| 759 | return atom; |
| 760 | } |
| 761 | |
| 669 | 762 | fn growAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u32 { |
| 670 | 763 | const sym = atom.getSymbol(self); |
| 671 | 764 | const align_ok = mem.alignBackwardGeneric(u32, sym.value, alignment) == sym.value; |
| ... | ... | @@ -691,7 +784,7 @@ fn writeAtom(self: *Coff, atom: *Atom, code: []const u8) !void { |
| 691 | 784 | try self.resolveRelocs(atom); |
| 692 | 785 | } |
| 693 | 786 | |
| 694 | | fn writeGotAtom(self: *Coff, atom: *Atom) !void { |
| 787 | fn writePtrWidthAtom(self: *Coff, atom: *Atom) !void { |
| 695 | 788 | switch (self.ptr_width) { |
| 696 | 789 | .p32 => { |
| 697 | 790 | var buffer: [@sizeOf(u32)]u8 = [_]u8{0} ** @sizeOf(u32); |
| ... | ... | @@ -718,7 +811,12 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { |
| 718 | 811 | const got_atom = self.getGotAtomForSymbol(reloc.target) orelse continue; |
| 719 | 812 | break :blk got_atom.getSymbol(self).value; |
| 720 | 813 | }, |
| 721 | | .direct => self.getSymbol(reloc.target).value, |
| 814 | .direct => blk: { |
| 815 | if (self.getImportAtomForSymbol(reloc.target)) |import_atom| { |
| 816 | break :blk import_atom.getSymbol(self).value; |
| 817 | } |
| 818 | break :blk self.getSymbol(reloc.target).value; |
| 819 | }, |
| 722 | 820 | }; |
| 723 | 821 | const target_vaddr_with_addend = target_vaddr + reloc.addend; |
| 724 | 822 | |
| ... | ... | @@ -971,7 +1069,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, |
| 971 | 1069 | sym.value = vaddr; |
| 972 | 1070 | log.debug(" (updating GOT entry)", .{}); |
| 973 | 1071 | const got_atom = self.getGotAtomForSymbol(.{ .sym_index = atom.sym_index, .file = null }).?; |
| 974 | | try self.writeGotAtom(got_atom); |
| 1072 | try self.writePtrWidthAtom(got_atom); |
| 975 | 1073 | } |
| 976 | 1074 | } else if (code_len < atom.size) { |
| 977 | 1075 | self.shrinkAtom(atom, code_len); |
| ... | ... | @@ -992,7 +1090,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, |
| 992 | 1090 | const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null }; |
| 993 | 1091 | _ = try self.allocateGotEntry(got_target); |
| 994 | 1092 | const got_atom = try self.createGotAtom(got_target); |
| 995 | | try self.writeGotAtom(got_atom); |
| 1093 | try self.writePtrWidthAtom(got_atom); |
| 996 | 1094 | } |
| 997 | 1095 | |
| 998 | 1096 | try self.writeAtom(atom, code); |
| ... | ... | @@ -1227,6 +1325,16 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1227 | 1325 | sub_prog_node.activate(); |
| 1228 | 1326 | defer sub_prog_node.end(); |
| 1229 | 1327 | |
| 1328 | while (self.unresolved.popOrNull()) |entry| { |
| 1329 | assert(entry.value); // We only expect imports generated by the incremental linker for now. |
| 1330 | const global = self.globals.values()[entry.key]; |
| 1331 | if (self.imports_table.contains(global)) continue; |
| 1332 | |
| 1333 | _ = try self.allocateImportEntry(global); |
| 1334 | const import_atom = try self.createImportAtom(global); |
| 1335 | try self.writePtrWidthAtom(import_atom); |
| 1336 | } |
| 1337 | |
| 1230 | 1338 | if (build_options.enable_logging) { |
| 1231 | 1339 | self.logSymtab(); |
| 1232 | 1340 | } |
| ... | ... | @@ -1272,7 +1380,6 @@ pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 { |
| 1272 | 1380 | const gpa = self.base.allocator; |
| 1273 | 1381 | const sym_name = try gpa.dupe(u8, name); |
| 1274 | 1382 | const global_index = @intCast(u32, self.globals.values().len); |
| 1275 | | _ = global_index; |
| 1276 | 1383 | const gop = try self.globals.getOrPut(gpa, sym_name); |
| 1277 | 1384 | defer if (gop.found_existing) gpa.free(sym_name); |
| 1278 | 1385 | |
| ... | ... | @@ -1288,6 +1395,7 @@ pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 { |
| 1288 | 1395 | try self.setSymbolName(sym, sym_name); |
| 1289 | 1396 | sym.storage_class = .EXTERNAL; |
| 1290 | 1397 | gop.value_ptr.* = sym_loc; |
| 1398 | try self.unresolved.putNoClobber(gpa, global_index, true); |
| 1291 | 1399 | |
| 1292 | 1400 | return sym_index; |
| 1293 | 1401 | } |
| ... | ... | @@ -1676,6 +1784,13 @@ pub fn getGotAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom { |
| 1676 | 1784 | return self.atom_by_index_table.get(got_index); |
| 1677 | 1785 | } |
| 1678 | 1786 | |
| 1787 | /// Returns import atom that references `sym_with_loc` if one exists. |
| 1788 | /// Returns null otherwise. |
| 1789 | pub fn getImportAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom { |
| 1790 | const imports_index = self.imports_table.get(sym_loc) orelse return null; |
| 1791 | return self.atom_by_index_table.get(imports_index); |
| 1792 | } |
| 1793 | |
| 1679 | 1794 | fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !void { |
| 1680 | 1795 | if (name.len <= 8) { |
| 1681 | 1796 | mem.copy(u8, &header.name, name); |