| ... | ... | @@ -63,11 +63,13 @@ globals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 63 | 63 | strtab: StringTable(.strtab) = .{}, |
| 64 | 64 | strtab_offset: ?u32 = null, |
| 65 | 65 | |
| 66 | | got_entries: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 66 | got_entries: std.ArrayListUnmanaged(Entry) = .{}, |
| 67 | 67 | got_entries_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 68 | got_entries_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 68 | 69 | |
| 69 | | imports_table: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 70 | | imports_table_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 70 | imports: std.ArrayListUnmanaged(Entry) = .{}, |
| 71 | imports_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 72 | imports_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 71 | 73 | |
| 72 | 74 | /// Virtual address of the entry point procedure relative to image base. |
| 73 | 75 | entry_addr: ?u32 = null, |
| ... | ... | @@ -115,6 +117,12 @@ relocs: RelocTable = .{}, |
| 115 | 117 | /// this will be a table indexed by index into the list of Atoms. |
| 116 | 118 | base_relocs: BaseRelocationTable = .{}, |
| 117 | 119 | |
| 120 | const Entry = struct { |
| 121 | target: SymbolWithLoc, |
| 122 | // Index into the synthetic symbol table (i.e., file == null). |
| 123 | sym_index: u32, |
| 124 | }; |
| 125 | |
| 118 | 126 | pub const Reloc = struct { |
| 119 | 127 | @"type": enum { |
| 120 | 128 | got, |
| ... | ... | @@ -309,8 +317,10 @@ pub fn deinit(self: *Coff) void { |
| 309 | 317 | self.strtab.deinit(gpa); |
| 310 | 318 | self.got_entries.deinit(gpa); |
| 311 | 319 | self.got_entries_free_list.deinit(gpa); |
| 320 | self.got_entries_table.deinit(gpa); |
| 321 | self.imports.deinit(gpa); |
| 322 | self.imports_free_list.deinit(gpa); |
| 312 | 323 | self.imports_table.deinit(gpa); |
| 313 | | self.imports_table_free_list.deinit(gpa); |
| 314 | 324 | self.decls.deinit(gpa); |
| 315 | 325 | self.atom_by_index_table.deinit(gpa); |
| 316 | 326 | |
| ... | ... | @@ -684,42 +694,44 @@ fn allocateGlobal(self: *Coff) !u32 { |
| 684 | 694 | pub fn allocateGotEntry(self: *Coff, target: SymbolWithLoc) !u32 { |
| 685 | 695 | const gpa = self.base.allocator; |
| 686 | 696 | try self.got_entries.ensureUnusedCapacity(gpa, 1); |
| 697 | |
| 687 | 698 | const index: u32 = blk: { |
| 688 | 699 | if (self.got_entries_free_list.popOrNull()) |index| { |
| 689 | 700 | log.debug(" (reusing GOT entry index {d})", .{index}); |
| 690 | | if (self.got_entries.getIndex(target)) |existing| { |
| 691 | | assert(existing == index); |
| 692 | | } |
| 693 | 701 | break :blk index; |
| 694 | 702 | } else { |
| 695 | | log.debug(" (allocating GOT entry at index {d})", .{self.got_entries.keys().len}); |
| 696 | | const index = @intCast(u32, self.got_entries.keys().len); |
| 697 | | self.got_entries.putAssumeCapacityNoClobber(target, 0); |
| 703 | log.debug(" (allocating GOT entry at index {d})", .{self.got_entries.items.len}); |
| 704 | const index = @intCast(u32, self.got_entries.items.len); |
| 705 | _ = self.got_entries.addOneAssumeCapacity(); |
| 698 | 706 | break :blk index; |
| 699 | 707 | } |
| 700 | 708 | }; |
| 701 | | self.got_entries.keys()[index] = target; |
| 709 | |
| 710 | self.got_entries.items[index] = .{ .target = target, .sym_index = 0 }; |
| 711 | try self.got_entries_table.putNoClobber(gpa, target, index); |
| 712 | |
| 702 | 713 | return index; |
| 703 | 714 | } |
| 704 | 715 | |
| 705 | 716 | pub fn allocateImportEntry(self: *Coff, target: SymbolWithLoc) !u32 { |
| 706 | 717 | const gpa = self.base.allocator; |
| 707 | | try self.imports_table.ensureUnusedCapacity(gpa, 1); |
| 718 | try self.imports.ensureUnusedCapacity(gpa, 1); |
| 719 | |
| 708 | 720 | const index: u32 = blk: { |
| 709 | | if (self.imports_table_free_list.popOrNull()) |index| { |
| 721 | if (self.imports_free_list.popOrNull()) |index| { |
| 710 | 722 | log.debug(" (reusing import entry index {d})", .{index}); |
| 711 | | if (self.imports_table.getIndex(target)) |existing| { |
| 712 | | assert(existing == index); |
| 713 | | } |
| 714 | 723 | break :blk index; |
| 715 | 724 | } else { |
| 716 | | log.debug(" (allocating import entry at index {d})", .{self.imports_table.keys().len}); |
| 717 | | const index = @intCast(u32, self.imports_table.keys().len); |
| 718 | | self.imports_table.putAssumeCapacityNoClobber(target, 0); |
| 725 | log.debug(" (allocating import entry at index {d})", .{self.imports.items.len}); |
| 726 | const index = @intCast(u32, self.imports.items.len); |
| 727 | _ = self.imports.addOneAssumeCapacity(); |
| 719 | 728 | break :blk index; |
| 720 | 729 | } |
| 721 | 730 | }; |
| 722 | | self.imports_table.keys()[index] = target; |
| 731 | |
| 732 | self.imports.items[index] = .{ .target = target, .sym_index = 0 }; |
| 733 | try self.imports_table.putNoClobber(gpa, target, index); |
| 734 | |
| 723 | 735 | return index; |
| 724 | 736 | } |
| 725 | 737 | |
| ... | ... | @@ -734,7 +746,6 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { |
| 734 | 746 | |
| 735 | 747 | try self.managed_atoms.append(gpa, atom); |
| 736 | 748 | try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom); |
| 737 | | self.got_entries.getPtr(target).?.* = atom.sym_index; |
| 738 | 749 | |
| 739 | 750 | const sym = atom.getSymbolPtr(self); |
| 740 | 751 | sym.section_number = @intToEnum(coff.SectionNumber, self.got_section_index.? + 1); |
| ... | ... | @@ -762,7 +773,7 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { |
| 762 | 773 | return atom; |
| 763 | 774 | } |
| 764 | 775 | |
| 765 | | fn createImportAtom(self: *Coff, target: SymbolWithLoc) !*Atom { |
| 776 | fn createImportAtom(self: *Coff) !*Atom { |
| 766 | 777 | const gpa = self.base.allocator; |
| 767 | 778 | const atom = try gpa.create(Atom); |
| 768 | 779 | errdefer gpa.destroy(atom); |
| ... | ... | @@ -773,7 +784,6 @@ fn createImportAtom(self: *Coff, target: SymbolWithLoc) !*Atom { |
| 773 | 784 | |
| 774 | 785 | try self.managed_atoms.append(gpa, atom); |
| 775 | 786 | try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom); |
| 776 | | self.imports_table.getPtr(target).?.* = atom.sym_index; |
| 777 | 787 | |
| 778 | 788 | const sym = atom.getSymbolPtr(self); |
| 779 | 789 | sym.section_number = @intToEnum(coff.SectionNumber, self.idata_section_index.? + 1); |
| ... | ... | @@ -804,7 +814,7 @@ fn writeAtom(self: *Coff, atom: *Atom, code: []const u8) !void { |
| 804 | 814 | const sym = atom.getSymbol(self); |
| 805 | 815 | const section = self.sections.get(@enumToInt(sym.section_number) - 1); |
| 806 | 816 | const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address; |
| 807 | | log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset }); |
| 817 | log.debug("writing atom for symbol {s} at file offset 0x{x} to 0x{x}", .{ atom.getName(self), file_offset, file_offset + code.len }); |
| 808 | 818 | try self.base.file.?.pwriteAll(code, file_offset); |
| 809 | 819 | try self.resolveRelocs(atom); |
| 810 | 820 | } |
| ... | ... | @@ -860,11 +870,12 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { |
| 860 | 870 | const target_vaddr = target_atom.getSymbol(self).value; |
| 861 | 871 | const target_vaddr_with_addend = target_vaddr + reloc.addend; |
| 862 | 872 | |
| 863 | | log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{ |
| 873 | log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{ |
| 864 | 874 | source_sym.value + reloc.offset, |
| 865 | 875 | target_vaddr_with_addend, |
| 866 | 876 | self.getSymbolName(reloc.target), |
| 867 | 877 | @tagName(reloc.@"type"), |
| 878 | file_offset + reloc.offset, |
| 868 | 879 | }); |
| 869 | 880 | |
| 870 | 881 | reloc.dirty = false; |
| ... | ... | @@ -901,8 +912,7 @@ fn freeAtom(self: *Coff, atom: *Atom) void { |
| 901 | 912 | log.debug("freeAtom {*}", .{atom}); |
| 902 | 913 | |
| 903 | 914 | // Remove any relocs and base relocs associated with this Atom |
| 904 | | _ = self.relocs.remove(atom); |
| 905 | | _ = self.base_relocs.remove(atom); |
| 915 | self.freeRelocationsForAtom(atom); |
| 906 | 916 | |
| 907 | 917 | const sym = atom.getSymbol(self); |
| 908 | 918 | const sect_id = @enumToInt(sym.section_number) - 1; |
| ... | ... | @@ -966,11 +976,14 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live |
| 966 | 976 | const tracy = trace(@src()); |
| 967 | 977 | defer tracy.end(); |
| 968 | 978 | |
| 979 | const decl_index = func.owner_decl; |
| 980 | const decl = module.declPtr(decl_index); |
| 981 | self.freeUnnamedConsts(decl_index); |
| 982 | self.freeRelocationsForAtom(&decl.link.coff); |
| 983 | |
| 969 | 984 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 970 | 985 | defer code_buffer.deinit(); |
| 971 | 986 | |
| 972 | | const decl_index = func.owner_decl; |
| 973 | | const decl = module.declPtr(decl_index); |
| 974 | 987 | const res = try codegen.generateFunction( |
| 975 | 988 | &self.base, |
| 976 | 989 | decl.srcLoc(), |
| ... | ... | @@ -1082,6 +1095,8 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! |
| 1082 | 1095 | } |
| 1083 | 1096 | } |
| 1084 | 1097 | |
| 1098 | self.freeRelocationsForAtom(&decl.link.coff); |
| 1099 | |
| 1085 | 1100 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 1086 | 1101 | defer code_buffer.deinit(); |
| 1087 | 1102 | |
| ... | ... | @@ -1190,8 +1205,9 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, |
| 1190 | 1205 | sym.value = vaddr; |
| 1191 | 1206 | |
| 1192 | 1207 | const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null }; |
| 1193 | | _ = try self.allocateGotEntry(got_target); |
| 1208 | const got_index = try self.allocateGotEntry(got_target); |
| 1194 | 1209 | const got_atom = try self.createGotAtom(got_target); |
| 1210 | self.got_entries.items[got_index].sym_index = got_atom.sym_index; |
| 1195 | 1211 | try self.writePtrWidthAtom(got_atom); |
| 1196 | 1212 | } |
| 1197 | 1213 | |
| ... | ... | @@ -1199,6 +1215,11 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, |
| 1199 | 1215 | try self.writeAtom(atom, code); |
| 1200 | 1216 | } |
| 1201 | 1217 | |
| 1218 | fn freeRelocationsForAtom(self: *Coff, atom: *Atom) void { |
| 1219 | _ = self.relocs.remove(atom); |
| 1220 | _ = self.base_relocs.remove(atom); |
| 1221 | } |
| 1222 | |
| 1202 | 1223 | fn freeUnnamedConsts(self: *Coff, decl_index: Module.Decl.Index) void { |
| 1203 | 1224 | const gpa = self.base.allocator; |
| 1204 | 1225 | const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return; |
| ... | ... | @@ -1237,14 +1258,20 @@ pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void { |
| 1237 | 1258 | |
| 1238 | 1259 | // Try freeing GOT atom if this decl had one |
| 1239 | 1260 | const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; |
| 1240 | | if (self.got_entries.getIndex(got_target)) |got_index| { |
| 1261 | if (self.got_entries_table.get(got_target)) |got_index| { |
| 1241 | 1262 | self.got_entries_free_list.append(gpa, @intCast(u32, got_index)) catch {}; |
| 1242 | | self.got_entries.values()[got_index] = 0; |
| 1263 | self.got_entries.items[got_index] = .{ |
| 1264 | .target = .{ .sym_index = 0, .file = null }, |
| 1265 | .sym_index = 0, |
| 1266 | }; |
| 1267 | _ = self.got_entries_table.remove(got_target); |
| 1268 | |
| 1243 | 1269 | log.debug(" adding GOT index {d} to free list (target local@{d})", .{ got_index, sym_index }); |
| 1244 | 1270 | } |
| 1245 | 1271 | |
| 1246 | 1272 | self.locals.items[sym_index].section_number = .UNDEFINED; |
| 1247 | 1273 | _ = self.atom_by_index_table.remove(sym_index); |
| 1274 | log.debug(" adding local symbol index {d} to free list", .{sym_index}); |
| 1248 | 1275 | decl.link.coff.sym_index = 0; |
| 1249 | 1276 | } |
| 1250 | 1277 | } |
| ... | ... | @@ -1453,8 +1480,9 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1453 | 1480 | const global = self.globals.items[entry.key]; |
| 1454 | 1481 | if (self.imports_table.contains(global)) continue; |
| 1455 | 1482 | |
| 1456 | | _ = try self.allocateImportEntry(global); |
| 1457 | | const import_atom = try self.createImportAtom(global); |
| 1483 | const import_index = try self.allocateImportEntry(global); |
| 1484 | const import_atom = try self.createImportAtom(); |
| 1485 | self.imports.items[import_index].sym_index = import_atom.sym_index; |
| 1458 | 1486 | try self.writePtrWidthAtom(import_atom); |
| 1459 | 1487 | } |
| 1460 | 1488 | |
| ... | ... | @@ -1668,8 +1696,8 @@ fn writeImportTable(self: *Coff) !void { |
| 1668 | 1696 | defer names_table.deinit(); |
| 1669 | 1697 | |
| 1670 | 1698 | // TODO: check if import is still valid |
| 1671 | | for (self.imports_table.keys()) |target| { |
| 1672 | | const target_name = self.getSymbolName(target); |
| 1699 | for (self.imports.items) |entry| { |
| 1700 | const target_name = self.getSymbolName(entry.target); |
| 1673 | 1701 | const start = names_table.items.len; |
| 1674 | 1702 | mem.writeIntLittle(u16, try names_table.addManyAsArray(2), 0); // TODO: currently, hint is set to 0 as we haven't yet parsed any DLL |
| 1675 | 1703 | try names_table.appendSlice(target_name); |
| ... | ... | @@ -2013,19 +2041,19 @@ pub fn getEntryPoint(self: Coff) ?SymbolWithLoc { |
| 2013 | 2041 | return self.globals.items[global_index]; |
| 2014 | 2042 | } |
| 2015 | 2043 | |
| 2016 | | /// Returns pointer-to-symbol described by `sym_with_loc` descriptor. |
| 2044 | /// Returns pointer-to-symbol described by `sym_loc` descriptor. |
| 2017 | 2045 | pub fn getSymbolPtr(self: *Coff, sym_loc: SymbolWithLoc) *coff.Symbol { |
| 2018 | 2046 | assert(sym_loc.file == null); // TODO linking object files |
| 2019 | 2047 | return &self.locals.items[sym_loc.sym_index]; |
| 2020 | 2048 | } |
| 2021 | 2049 | |
| 2022 | | /// Returns symbol described by `sym_with_loc` descriptor. |
| 2050 | /// Returns symbol described by `sym_loc` descriptor. |
| 2023 | 2051 | pub fn getSymbol(self: *const Coff, sym_loc: SymbolWithLoc) *const coff.Symbol { |
| 2024 | 2052 | assert(sym_loc.file == null); // TODO linking object files |
| 2025 | 2053 | return &self.locals.items[sym_loc.sym_index]; |
| 2026 | 2054 | } |
| 2027 | 2055 | |
| 2028 | | /// Returns name of the symbol described by `sym_with_loc` descriptor. |
| 2056 | /// Returns name of the symbol described by `sym_loc` descriptor. |
| 2029 | 2057 | pub fn getSymbolName(self: *const Coff, sym_loc: SymbolWithLoc) []const u8 { |
| 2030 | 2058 | assert(sym_loc.file == null); // TODO linking object files |
| 2031 | 2059 | const sym = self.getSymbol(sym_loc); |
| ... | ... | @@ -2033,25 +2061,27 @@ pub fn getSymbolName(self: *const Coff, sym_loc: SymbolWithLoc) []const u8 { |
| 2033 | 2061 | return self.strtab.get(offset).?; |
| 2034 | 2062 | } |
| 2035 | 2063 | |
| 2036 | | /// Returns atom if there is an atom referenced by the symbol described by `sym_with_loc` descriptor. |
| 2064 | /// Returns atom if there is an atom referenced by the symbol described by `sym_loc` descriptor. |
| 2037 | 2065 | /// Returns null on failure. |
| 2038 | 2066 | pub fn getAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom { |
| 2039 | 2067 | assert(sym_loc.file == null); // TODO linking with object files |
| 2040 | 2068 | return self.atom_by_index_table.get(sym_loc.sym_index); |
| 2041 | 2069 | } |
| 2042 | 2070 | |
| 2043 | | /// Returns GOT atom that references `sym_with_loc` if one exists. |
| 2071 | /// Returns GOT atom that references `sym_loc` if one exists. |
| 2044 | 2072 | /// Returns null otherwise. |
| 2045 | 2073 | pub fn getGotAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom { |
| 2046 | | const got_index = self.got_entries.get(sym_loc) orelse return null; |
| 2047 | | return self.atom_by_index_table.get(got_index); |
| 2074 | const got_index = self.got_entries_table.get(sym_loc) orelse return null; |
| 2075 | const got_entry = self.got_entries.items[got_index]; |
| 2076 | return self.getAtomForSymbol(.{ .sym_index = got_entry.sym_index, .file = null }); |
| 2048 | 2077 | } |
| 2049 | 2078 | |
| 2050 | | /// Returns import atom that references `sym_with_loc` if one exists. |
| 2079 | /// Returns import atom that references `sym_loc` if one exists. |
| 2051 | 2080 | /// Returns null otherwise. |
| 2052 | 2081 | pub fn getImportAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom { |
| 2053 | 2082 | const imports_index = self.imports_table.get(sym_loc) orelse return null; |
| 2054 | | return self.atom_by_index_table.get(imports_index); |
| 2083 | const imports_entry = self.imports.items[imports_index]; |
| 2084 | return self.getAtomForSymbol(.{ .sym_index = imports_entry.sym_index, .file = null }); |
| 2055 | 2085 | } |
| 2056 | 2086 | |
| 2057 | 2087 | fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !void { |
| ... | ... | @@ -2141,21 +2171,21 @@ fn logSymtab(self: *Coff) void { |
| 2141 | 2171 | } |
| 2142 | 2172 | |
| 2143 | 2173 | log.debug("GOT entries:", .{}); |
| 2144 | | for (self.got_entries.keys()) |target, i| { |
| 2145 | | const got_sym = self.getSymbol(.{ .sym_index = self.got_entries.values()[i], .file = null }); |
| 2146 | | const target_sym = self.getSymbol(target); |
| 2174 | for (self.got_entries.items) |entry, i| { |
| 2175 | const got_sym = self.getSymbol(.{ .sym_index = entry.sym_index, .file = null }); |
| 2176 | const target_sym = self.getSymbol(entry.target); |
| 2147 | 2177 | if (target_sym.section_number == .UNDEFINED) { |
| 2148 | 2178 | log.debug(" {d}@{x} => import('{s}')", .{ |
| 2149 | 2179 | i, |
| 2150 | 2180 | got_sym.value, |
| 2151 | | self.getSymbolName(target), |
| 2181 | self.getSymbolName(entry.target), |
| 2152 | 2182 | }); |
| 2153 | 2183 | } else { |
| 2154 | 2184 | log.debug(" {d}@{x} => local(%{d}) in object({?d}) {s}", .{ |
| 2155 | 2185 | i, |
| 2156 | 2186 | got_sym.value, |
| 2157 | | target.sym_index, |
| 2158 | | target.file, |
| 2187 | entry.target.sym_index, |
| 2188 | entry.target.file, |
| 2159 | 2189 | logSymAttributes(target_sym, &buf), |
| 2160 | 2190 | }); |
| 2161 | 2191 | } |