| ... | @@ -51,9 +51,11 @@ got_section_index: ?u16 = null, | ... | @@ -51,9 +51,11 @@ got_section_index: ?u16 = null, |
| 51 | rdata_section_index: ?u16 = null, | 51 | rdata_section_index: ?u16 = null, |
| 52 | data_section_index: ?u16 = null, | 52 | data_section_index: ?u16 = null, |
| 53 | reloc_section_index: ?u16 = null, | 53 | reloc_section_index: ?u16 = null, |
| | 54 | idata_section_index: ?u16 = null, |
| 54 | | 55 | |
| 55 | locals: std.ArrayListUnmanaged(coff.Symbol) = .{}, | 56 | locals: std.ArrayListUnmanaged(coff.Symbol) = .{}, |
| 56 | globals: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{}, | 57 | globals: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{}, |
| | 58 | unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{}, |
| 57 | | 59 | |
| 58 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, | 60 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 59 | | 61 | |
| ... | @@ -63,6 +65,9 @@ strtab_offset: ?u32 = null, | ... | @@ -63,6 +65,9 @@ strtab_offset: ?u32 = null, |
| 63 | got_entries: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{}, | 65 | got_entries: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 64 | got_entries_free_list: std.ArrayListUnmanaged(u32) = .{}, | 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 | /// Virtual address of the entry point procedure relative to image base. | 71 | /// Virtual address of the entry point procedure relative to image base. |
| 67 | entry_addr: ?u32 = null, | 72 | entry_addr: ?u32 = null, |
| 68 | | 73 | |
| ... | @@ -109,6 +114,11 @@ relocs: RelocTable = .{}, | ... | @@ -109,6 +114,11 @@ relocs: RelocTable = .{}, |
| 109 | /// this will be a table indexed by index into the list of Atoms. | 114 | /// this will be a table indexed by index into the list of Atoms. |
| 110 | base_relocs: BaseRelocationTable = .{}, | 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 | pub const Reloc = struct { | 122 | pub const Reloc = struct { |
| 113 | @"type": enum { | 123 | @"type": enum { |
| 114 | got, | 124 | got, |
| ... | @@ -124,6 +134,7 @@ pub const Reloc = struct { | ... | @@ -124,6 +134,7 @@ pub const Reloc = struct { |
| 124 | | 134 | |
| 125 | const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Reloc)); | 135 | const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Reloc)); |
| 126 | const BaseRelocationTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(u32)); | 136 | const BaseRelocationTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(u32)); |
| | 137 | const BindingTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(SymbolWithLoc)); |
| 127 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom)); | 138 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom)); |
| 128 | | 139 | |
| 129 | const default_file_alignment: u16 = 0x200; | 140 | const default_file_alignment: u16 = 0x200; |
| ... | @@ -269,10 +280,13 @@ pub fn deinit(self: *Coff) void { | ... | @@ -269,10 +280,13 @@ pub fn deinit(self: *Coff) void { |
| 269 | | 280 | |
| 270 | self.locals.deinit(gpa); | 281 | self.locals.deinit(gpa); |
| 271 | self.globals.deinit(gpa); | 282 | self.globals.deinit(gpa); |
| | 283 | self.unresolved.deinit(gpa); |
| 272 | self.locals_free_list.deinit(gpa); | 284 | self.locals_free_list.deinit(gpa); |
| 273 | self.strtab.deinit(gpa); | 285 | self.strtab.deinit(gpa); |
| 274 | self.got_entries.deinit(gpa); | 286 | self.got_entries.deinit(gpa); |
| 275 | self.got_entries_free_list.deinit(gpa); | 287 | self.got_entries_free_list.deinit(gpa); |
| | 288 | self.imports_table.deinit(gpa); |
| | 289 | self.imports_table_free_list.deinit(gpa); |
| 276 | self.decls.deinit(gpa); | 290 | self.decls.deinit(gpa); |
| 277 | self.atom_by_index_table.deinit(gpa); | 291 | self.atom_by_index_table.deinit(gpa); |
| 278 | | 292 | |
| ... | @@ -299,6 +313,14 @@ pub fn deinit(self: *Coff) void { | ... | @@ -299,6 +313,14 @@ pub fn deinit(self: *Coff) void { |
| 299 | } | 313 | } |
| 300 | self.base_relocs.deinit(gpa); | 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 | fn populateMissingMetadata(self: *Coff) !void { | 326 | fn populateMissingMetadata(self: *Coff) !void { |
| ... | @@ -420,7 +442,7 @@ fn populateMissingMetadata(self: *Coff) !void { | ... | @@ -420,7 +442,7 @@ fn populateMissingMetadata(self: *Coff) !void { |
| 420 | .number_of_linenumbers = 0, | 442 | .number_of_linenumbers = 0, |
| 421 | .flags = .{ | 443 | .flags = .{ |
| 422 | .CNT_INITIALIZED_DATA = 1, | 444 | .CNT_INITIALIZED_DATA = 1, |
| 423 | .MEM_PURGEABLE = 1, | 445 | .MEM_DISCARDABLE = 1, |
| 424 | .MEM_READ = 1, | 446 | .MEM_READ = 1, |
| 425 | }, | 447 | }, |
| 426 | }; | 448 | }; |
| ... | @@ -428,6 +450,30 @@ fn populateMissingMetadata(self: *Coff) !void { | ... | @@ -428,6 +450,30 @@ fn populateMissingMetadata(self: *Coff) !void { |
| 428 | try self.sections.append(gpa, .{ .header = header }); | 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 | if (self.strtab_offset == null) { | 477 | if (self.strtab_offset == null) { |
| 432 | try self.strtab.buffer.append(gpa, 0); | 478 | try self.strtab.buffer.append(gpa, 0); |
| 433 | self.strtab_offset = self.findFreeSpace(@intCast(u32, self.strtab.len()), 1); | 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,6 +672,27 @@ pub fn allocateGotEntry(self: *Coff, target: SymbolWithLoc) !u32 { |
| 626 | return index; | 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 | fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { | 696 | fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { |
| 630 | const gpa = self.base.allocator; | 697 | const gpa = self.base.allocator; |
| 631 | const atom = try gpa.create(Atom); | 698 | const atom = try gpa.create(Atom); |
| ... | @@ -666,6 +733,32 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { | ... | @@ -666,6 +733,32 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { |
| 666 | return atom; | 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 | fn growAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u32 { | 762 | fn growAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u32 { |
| 670 | const sym = atom.getSymbol(self); | 763 | const sym = atom.getSymbol(self); |
| 671 | const align_ok = mem.alignBackwardGeneric(u32, sym.value, alignment) == sym.value; | 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,7 +784,7 @@ fn writeAtom(self: *Coff, atom: *Atom, code: []const u8) !void { |
| 691 | try self.resolveRelocs(atom); | 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 | switch (self.ptr_width) { | 788 | switch (self.ptr_width) { |
| 696 | .p32 => { | 789 | .p32 => { |
| 697 | var buffer: [@sizeOf(u32)]u8 = [_]u8{0} ** @sizeOf(u32); | 790 | var buffer: [@sizeOf(u32)]u8 = [_]u8{0} ** @sizeOf(u32); |
| ... | @@ -718,7 +811,12 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { | ... | @@ -718,7 +811,12 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { |
| 718 | const got_atom = self.getGotAtomForSymbol(reloc.target) orelse continue; | 811 | const got_atom = self.getGotAtomForSymbol(reloc.target) orelse continue; |
| 719 | break :blk got_atom.getSymbol(self).value; | 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 | const target_vaddr_with_addend = target_vaddr + reloc.addend; | 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,7 +1069,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, |
| 971 | sym.value = vaddr; | 1069 | sym.value = vaddr; |
| 972 | log.debug(" (updating GOT entry)", .{}); | 1070 | log.debug(" (updating GOT entry)", .{}); |
| 973 | const got_atom = self.getGotAtomForSymbol(.{ .sym_index = atom.sym_index, .file = null }).?; | 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 | } else if (code_len < atom.size) { | 1074 | } else if (code_len < atom.size) { |
| 977 | self.shrinkAtom(atom, code_len); | 1075 | self.shrinkAtom(atom, code_len); |
| ... | @@ -992,7 +1090,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, | ... | @@ -992,7 +1090,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, |
| 992 | const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null }; | 1090 | const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null }; |
| 993 | _ = try self.allocateGotEntry(got_target); | 1091 | _ = try self.allocateGotEntry(got_target); |
| 994 | const got_atom = try self.createGotAtom(got_target); | 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 | try self.writeAtom(atom, code); | 1096 | try self.writeAtom(atom, code); |
| ... | @@ -1227,6 +1325,16 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -1227,6 +1325,16 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1227 | sub_prog_node.activate(); | 1325 | sub_prog_node.activate(); |
| 1228 | defer sub_prog_node.end(); | 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 | if (build_options.enable_logging) { | 1338 | if (build_options.enable_logging) { |
| 1231 | self.logSymtab(); | 1339 | self.logSymtab(); |
| 1232 | } | 1340 | } |
| ... | @@ -1272,7 +1380,6 @@ pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 { | ... | @@ -1272,7 +1380,6 @@ pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 { |
| 1272 | const gpa = self.base.allocator; | 1380 | const gpa = self.base.allocator; |
| 1273 | const sym_name = try gpa.dupe(u8, name); | 1381 | const sym_name = try gpa.dupe(u8, name); |
| 1274 | const global_index = @intCast(u32, self.globals.values().len); | 1382 | const global_index = @intCast(u32, self.globals.values().len); |
| 1275 | _ = global_index; | | |
| 1276 | const gop = try self.globals.getOrPut(gpa, sym_name); | 1383 | const gop = try self.globals.getOrPut(gpa, sym_name); |
| 1277 | defer if (gop.found_existing) gpa.free(sym_name); | 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,6 +1395,7 @@ pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 { |
| 1288 | try self.setSymbolName(sym, sym_name); | 1395 | try self.setSymbolName(sym, sym_name); |
| 1289 | sym.storage_class = .EXTERNAL; | 1396 | sym.storage_class = .EXTERNAL; |
| 1290 | gop.value_ptr.* = sym_loc; | 1397 | gop.value_ptr.* = sym_loc; |
| | 1398 | try self.unresolved.putNoClobber(gpa, global_index, true); |
| 1291 | | 1399 | |
| 1292 | return sym_index; | 1400 | return sym_index; |
| 1293 | } | 1401 | } |
| ... | @@ -1676,6 +1784,13 @@ pub fn getGotAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom { | ... | @@ -1676,6 +1784,13 @@ pub fn getGotAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom { |
| 1676 | return self.atom_by_index_table.get(got_index); | 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 | fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !void { | 1794 | fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !void { |
| 1680 | if (name.len <= 8) { | 1795 | if (name.len <= 8) { |
| 1681 | mem.copy(u8, &header.name, name); | 1796 | mem.copy(u8, &header.name, name); |