| ... | ... | @@ -30,6 +30,7 @@ lib_string_len: u64, |
| 30 | 30 | long_names_table: LongNamesTable, |
| 31 | 31 | import_table: ImportTable, |
| 32 | 32 | export_table: ExportTable, |
| 33 | symbol_table: SymbolTable, |
| 33 | 34 | strings: std.HashMapUnmanaged( |
| 34 | 35 | u32, |
| 35 | 36 | void, |
| ... | ... | @@ -37,10 +38,10 @@ strings: std.HashMapUnmanaged( |
| 37 | 38 | std.hash_map.default_max_load_percentage, |
| 38 | 39 | ), |
| 39 | 40 | string_bytes: std.ArrayList(u8), |
| 40 | | image_section_table: std.ArrayList(Symbol.Index), |
| 41 | section_table: std.ArrayList(Symbol.Index), |
| 41 | 42 | pseudo_section_table: std.array_hash_map.Auto(String, Symbol.Index), |
| 42 | 43 | object_section_table: std.array_hash_map.Auto(String, Symbol.Index), |
| 43 | | symbol_table: std.ArrayList(Symbol), |
| 44 | symbols: std.ArrayList(Symbol), |
| 44 | 45 | globals: std.array_hash_map.Auto(GlobalName, Symbol.Index), |
| 45 | 46 | global_pending_index: u32, |
| 46 | 47 | navs: std.array_hash_map.Auto(InternPool.Nav.Index, Symbol.Index), |
| ... | ... | @@ -144,6 +145,7 @@ pub const Node = union(enum) { |
| 144 | 145 | header, |
| 145 | 146 | /// Images and archives only. |
| 146 | 147 | signature, |
| 148 | |
| 147 | 149 | /// Archives only. |
| 148 | 150 | archive_member_header: Member.Index, |
| 149 | 151 | archive_member: Member.Index, |
| ... | ... | @@ -154,15 +156,21 @@ pub const Node = union(enum) { |
| 154 | 156 | /// Image only |
| 155 | 157 | data_directories, |
| 156 | 158 | section_table, |
| 157 | | image_section: Symbol.Index, |
| 159 | // Archives and objects only |
| 160 | symbol_table, |
| 161 | symbol_table_entry, |
| 162 | // Archives and objects only |
| 163 | string_table, |
| 164 | |
| 165 | image_section: Symbol.Index, // TODO: image_section -> section |
| 158 | 166 | |
| 159 | | /// Only images contain imports |
| 167 | /// Images only |
| 160 | 168 | import_directory_table, |
| 161 | 169 | import_lookup_table: ImportTable.Index, |
| 162 | 170 | import_address_table: ImportTable.Index, |
| 163 | 171 | import_hint_name_table: ImportTable.Index, |
| 164 | 172 | |
| 165 | | /// Only images contain exports |
| 173 | /// Images only |
| 166 | 174 | export_directory_table, |
| 167 | 175 | export_address_table, |
| 168 | 176 | export_name_pointer_table, |
| ... | ... | @@ -291,6 +299,8 @@ pub const Node = union(enum) { |
| 291 | 299 | optional_header, |
| 292 | 300 | data_directories, |
| 293 | 301 | section_table, |
| 302 | symbol_table, |
| 303 | string_table, |
| 294 | 304 | }; |
| 295 | 305 | var mut_known: std.enums.EnumFieldStruct(Known, MappedFile.Node.Index, null) = undefined; |
| 296 | 306 | const info = @typeInfo(Known).@"enum"; |
| ... | ... | @@ -436,6 +446,47 @@ pub const LongNamesTable = struct { |
| 436 | 446 | }; |
| 437 | 447 | }; |
| 438 | 448 | |
| 449 | pub const SymbolTable = struct { |
| 450 | string_offsets: std.AutoArrayHashMapUnmanaged(String, StringIndex), |
| 451 | entries: std.AutoArrayHashMapUnmanaged(Symbol.Index, Entry), |
| 452 | |
| 453 | // Adding nodes to the symbol table has the result of accumulating padding |
| 454 | // between the last symbol and the string table, due to the growth factor |
| 455 | // in MappedFile. The spec requires the string table begin immediately |
| 456 | // after the last symbol, so we compact the symbol table node if needed. |
| 457 | pending_shrink: bool, |
| 458 | |
| 459 | pub const Entry = struct { |
| 460 | entry_si: Symbol.Index, |
| 461 | index: Index, |
| 462 | }; |
| 463 | |
| 464 | pub const Add = union(enum) { |
| 465 | section, |
| 466 | global: struct { |
| 467 | import: bool, |
| 468 | }, |
| 469 | }; |
| 470 | |
| 471 | pub const SymbolName = union(enum) { |
| 472 | short: []const u8, |
| 473 | long: StringIndex, |
| 474 | }; |
| 475 | |
| 476 | // Symbol.Index does not map 1:1 with SymbolTable.Index due to auxiliary entries |
| 477 | pub const Index = enum(u32) { |
| 478 | _, |
| 479 | |
| 480 | pub fn get(sti: SymbolTable.Index, coff: *Coff) *Entry { |
| 481 | return &coff.symbol_table.entries.values()[@intFromEnum(sti)]; |
| 482 | } |
| 483 | }; |
| 484 | |
| 485 | pub const StringIndex = enum(u32) { |
| 486 | _, |
| 487 | }; |
| 488 | }; |
| 489 | |
| 439 | 490 | pub const ExportTable = struct { |
| 440 | 491 | ni: MappedFile.Node.Index, |
| 441 | 492 | export_directory_table_ni: MappedFile.Node.Index, |
| ... | ... | @@ -582,7 +633,7 @@ pub const Symbol = struct { |
| 582 | 633 | } |
| 583 | 634 | |
| 584 | 635 | pub fn symbol(sn: SectionNumber, coff: *const Coff) Symbol.Index { |
| 585 | | return coff.image_section_table.items[sn.toIndex()]; |
| 636 | return coff.section_table.items[sn.toIndex()]; |
| 586 | 637 | } |
| 587 | 638 | |
| 588 | 639 | pub fn header(sn: SectionNumber, coff: *Coff) *std.coff.SectionHeader { |
| ... | ... | @@ -600,7 +651,7 @@ pub const Symbol = struct { |
| 600 | 651 | const known_count = @typeInfo(Index).@"enum".field_names.len; |
| 601 | 652 | |
| 602 | 653 | pub fn get(si: Symbol.Index, coff: *Coff) *Symbol { |
| 603 | | return &coff.symbol_table.items[@intFromEnum(si)]; |
| 654 | return &coff.symbols.items[@intFromEnum(si)]; |
| 604 | 655 | } |
| 605 | 656 | |
| 606 | 657 | pub fn node(si: Symbol.Index, coff: *Coff) MappedFile.Node.Index { |
| ... | ... | @@ -920,12 +971,17 @@ fn create( |
| 920 | 971 | .name_table_ni = .none, |
| 921 | 972 | .entries = .empty, |
| 922 | 973 | }, |
| 974 | .symbol_table = .{ |
| 975 | .string_offsets = .empty, |
| 976 | .entries = .empty, |
| 977 | .pending_shrink = false, |
| 978 | }, |
| 923 | 979 | .strings = .empty, |
| 924 | 980 | .string_bytes = .empty, |
| 925 | | .image_section_table = .empty, |
| 981 | .section_table = .empty, |
| 926 | 982 | .pseudo_section_table = .empty, |
| 927 | 983 | .object_section_table = .empty, |
| 928 | | .symbol_table = .empty, |
| 984 | .symbols = .empty, |
| 929 | 985 | .globals = .empty, |
| 930 | 986 | .global_pending_index = 0, |
| 931 | 987 | .navs = .empty, |
| ... | ... | @@ -965,15 +1021,16 @@ pub fn deinit(coff: *Coff) void { |
| 965 | 1021 | const gpa = coff.base.comp.gpa; |
| 966 | 1022 | coff.mf.deinit(gpa); |
| 967 | 1023 | coff.nodes.deinit(gpa); |
| 1024 | // TODO: Update this |
| 968 | 1025 | coff.long_names_table.entries.deinit(gpa); |
| 969 | 1026 | coff.import_table.entries.deinit(gpa); |
| 970 | 1027 | coff.export_table.entries.deinit(gpa); |
| 971 | 1028 | coff.strings.deinit(gpa); |
| 972 | 1029 | coff.string_bytes.deinit(gpa); |
| 973 | | coff.image_section_table.deinit(gpa); |
| 1030 | coff.section_table.deinit(gpa); |
| 974 | 1031 | coff.pseudo_section_table.deinit(gpa); |
| 975 | 1032 | coff.object_section_table.deinit(gpa); |
| 976 | | coff.symbol_table.deinit(gpa); |
| 1033 | coff.symbols.deinit(gpa); |
| 977 | 1034 | coff.globals.deinit(gpa); |
| 978 | 1035 | coff.navs.deinit(gpa); |
| 979 | 1036 | coff.uavs.deinit(gpa); |
| ... | ... | @@ -1035,8 +1092,13 @@ fn initHeaders( |
| 1035 | 1092 | |
| 1036 | 1093 | var expected_nodes_len: usize = Node.known_count; |
| 1037 | 1094 | if (comp.zcu != null) { |
| 1095 | // Section nodes |
| 1038 | 1096 | expected_nodes_len += 3; |
| 1097 | // Symbol table nodes |
| 1098 | if (is_archive) expected_nodes_len += 6; |
| 1099 | // Pseudo-sections and import / export table nodes |
| 1039 | 1100 | if (is_image) expected_nodes_len += 9; |
| 1101 | // TLS section nodes |
| 1040 | 1102 | expected_nodes_len += @as(usize, @intFromBool(comp.config.any_non_single_threaded)) * 2; |
| 1041 | 1103 | } |
| 1042 | 1104 | defer assert(coff.nodes.len == expected_nodes_len); |
| ... | ... | @@ -1294,10 +1356,26 @@ fn initHeaders( |
| 1294 | 1356 | })); |
| 1295 | 1357 | coff.nodes.appendAssumeCapacity(.section_table); |
| 1296 | 1358 | |
| 1359 | const symbol_table_ni = Node.known.symbol_table; |
| 1360 | assert(symbol_table_ni == try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{ |
| 1361 | .alignment = .@"4", |
| 1362 | .fixed = true, |
| 1363 | .moved = true, |
| 1364 | })); |
| 1365 | coff.nodes.appendAssumeCapacity(.symbol_table); |
| 1366 | |
| 1367 | const string_table_ni = Node.known.string_table; |
| 1368 | assert(string_table_ni == try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{ |
| 1369 | .size = @sizeOf(u32), |
| 1370 | .fixed = true, |
| 1371 | .resized = true, |
| 1372 | })); |
| 1373 | coff.nodes.appendAssumeCapacity(.string_table); |
| 1374 | |
| 1297 | 1375 | assert(coff.nodes.len == Node.known_count); |
| 1298 | 1376 | |
| 1299 | | try coff.symbol_table.ensureTotalCapacity(gpa, Symbol.Index.known_count); |
| 1300 | | coff.symbol_table.addOneAssumeCapacity().* = .{ |
| 1377 | try coff.symbols.ensureTotalCapacity(gpa, Symbol.Index.known_count); |
| 1378 | coff.symbols.addOneAssumeCapacity().* = .{ |
| 1301 | 1379 | .ni = .none, |
| 1302 | 1380 | .rva = 0, |
| 1303 | 1381 | .size = 0, |
| ... | ... | @@ -1360,7 +1438,7 @@ fn initHeaders( |
| 1360 | 1438 | }); |
| 1361 | 1439 | coff.nodes.appendAssumeCapacity(.export_address_table); |
| 1362 | 1440 | |
| 1363 | | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); |
| 1441 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| 1364 | 1442 | coff.export_table.export_address_table_si = coff.addSymbolAssumeCapacity(); |
| 1365 | 1443 | |
| 1366 | 1444 | const export_address_table_sym = coff.export_table.export_address_table_si.get(coff); |
| ... | ... | @@ -1451,6 +1529,10 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 { |
| 1451 | 1529 | .section_table, |
| 1452 | 1530 | .export_name_table, |
| 1453 | 1531 | .placeholder, |
| 1532 | |
| 1533 | .symbol_table, |
| 1534 | .symbol_table_entry, |
| 1535 | .string_table, |
| 1454 | 1536 | => unreachable, |
| 1455 | 1537 | .image_section => |si| si, |
| 1456 | 1538 | .import_directory_table => break :parent_rva coff.targetLoad( |
| ... | ... | @@ -1632,7 +1714,28 @@ pub fn dataDirectoryPtr( |
| 1632 | 1714 | } |
| 1633 | 1715 | |
| 1634 | 1716 | pub fn sectionTableSlice(coff: *Coff) []std.coff.SectionHeader { |
| 1635 | | return @ptrCast(@alignCast(Node.known.section_table.slice(&coff.mf))); |
| 1717 | return @ptrCast(@alignCast( |
| 1718 | Node.known.section_table.slice(&coff.mf)[0 .. coff.section_table.items.len * @sizeOf(std.coff.SectionHeader)], |
| 1719 | )); |
| 1720 | } |
| 1721 | |
| 1722 | pub fn symbolTableEntryPtr(coff: *Coff, sti: SymbolTable.Index) *align(2) std.coff.Symbol { |
| 1723 | return @ptrCast(@alignCast( |
| 1724 | &Node.known.symbol_table.slice(&coff.mf)[@intFromEnum(sti) * std.coff.Symbol.sizeOf()], |
| 1725 | )); |
| 1726 | } |
| 1727 | |
| 1728 | pub fn symbolAuxSectionDefinitionPtr(coff: *Coff, si: Symbol.Index) *align(2) std.coff.SectionDefinition { |
| 1729 | const sti = coff.symbol_table.entries.get(si).?.index; |
| 1730 | |
| 1731 | const symbol = coff.symbolTableEntryPtr(sti); |
| 1732 | assert(symbol.storage_class == .STATIC and symbol.number_of_aux_symbols == 1); |
| 1733 | |
| 1734 | return @ptrCast(symbolTableEntryPtr(coff, @enumFromInt(@intFromEnum(sti) + 1))); |
| 1735 | } |
| 1736 | |
| 1737 | pub fn symbolTableStringLenPtr(coff: *Coff) *align(2) u32 { |
| 1738 | return @ptrCast(@alignCast(Node.known.string_table.slice(&coff.mf)[0..@sizeOf(u32)])); |
| 1636 | 1739 | } |
| 1637 | 1740 | |
| 1638 | 1741 | pub fn importDirectoryTableSlice(coff: *Coff) []std.coff.ImportDirectoryEntry { |
| ... | ... | @@ -1662,7 +1765,7 @@ pub fn exportOrdinalTableSlice(coff: *Coff) []std.coff.ExportOrdinalTableEntry { |
| 1662 | 1765 | } |
| 1663 | 1766 | |
| 1664 | 1767 | fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index { |
| 1665 | | defer coff.symbol_table.addOneAssumeCapacity().* = .{ |
| 1768 | defer coff.symbols.addOneAssumeCapacity().* = .{ |
| 1666 | 1769 | .ni = .none, |
| 1667 | 1770 | .rva = 0, |
| 1668 | 1771 | .size = 0, |
| ... | ... | @@ -1670,7 +1773,7 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index { |
| 1670 | 1773 | .target_relocs = .none, |
| 1671 | 1774 | .section_number = .UNDEFINED, |
| 1672 | 1775 | }; |
| 1673 | | return @enumFromInt(coff.symbol_table.items.len); |
| 1776 | return @enumFromInt(coff.symbols.items.len); |
| 1674 | 1777 | } |
| 1675 | 1778 | |
| 1676 | 1779 | fn initSymbolAssumeCapacity(coff: *Coff) !Symbol.Index { |
| ... | ... | @@ -1715,7 +1818,7 @@ fn getOrPutGlobalSymbol( |
| 1715 | 1818 | lib_name: ?[]const u8, |
| 1716 | 1819 | ) !std.AutoArrayHashMapUnmanaged(GlobalName, Symbol.Index).GetOrPutResult { |
| 1717 | 1820 | const gpa = coff.base.comp.gpa; |
| 1718 | | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); |
| 1821 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| 1719 | 1822 | const sym_gop = try coff.globals.getOrPut(gpa, .{ |
| 1720 | 1823 | .name = try coff.getOrPutString(name), |
| 1721 | 1824 | .lib_name = try coff.getOrPutOptionalString(lib_name), |
| ... | ... | @@ -1724,6 +1827,7 @@ fn getOrPutGlobalSymbol( |
| 1724 | 1827 | sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity(); |
| 1725 | 1828 | coff.synth_prog_node.increaseEstimatedTotalItems(1); |
| 1726 | 1829 | } |
| 1830 | |
| 1727 | 1831 | return sym_gop; |
| 1728 | 1832 | } |
| 1729 | 1833 | |
| ... | ... | @@ -1758,7 +1862,7 @@ fn navSection( |
| 1758 | 1862 | } |
| 1759 | 1863 | fn navMapIndex(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex { |
| 1760 | 1864 | const gpa = zcu.gpa; |
| 1761 | | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); |
| 1865 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| 1762 | 1866 | const sym_gop = try coff.navs.getOrPut(gpa, nav_index); |
| 1763 | 1867 | if (!sym_gop.found_existing) sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity(); |
| 1764 | 1868 | return @enumFromInt(sym_gop.index); |
| ... | ... | @@ -1776,7 +1880,7 @@ pub fn navSymbol(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbo |
| 1776 | 1880 | |
| 1777 | 1881 | fn uavMapIndex(coff: *Coff, uav_val: InternPool.Index) !Node.UavMapIndex { |
| 1778 | 1882 | const gpa = coff.base.comp.gpa; |
| 1779 | | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); |
| 1883 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| 1780 | 1884 | const sym_gop = try coff.uavs.getOrPut(gpa, uav_val); |
| 1781 | 1885 | if (!sym_gop.found_existing) sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity(); |
| 1782 | 1886 | return @enumFromInt(sym_gop.index); |
| ... | ... | @@ -1788,7 +1892,7 @@ pub fn uavSymbol(coff: *Coff, uav_val: InternPool.Index) !Symbol.Index { |
| 1788 | 1892 | |
| 1789 | 1893 | pub fn lazySymbol(coff: *Coff, lazy: link.File.LazySymbol) !Symbol.Index { |
| 1790 | 1894 | const gpa = coff.base.comp.gpa; |
| 1791 | | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); |
| 1895 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| 1792 | 1896 | const sym_gop = try coff.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty); |
| 1793 | 1897 | if (!sym_gop.found_existing) { |
| 1794 | 1898 | sym_gop.value_ptr.* = try coff.initSymbolAssumeCapacity(); |
| ... | ... | @@ -2004,13 +2108,185 @@ fn addMemberSymbol( |
| 2004 | 2108 | coff.pending_members.putAssumeCapacity(mi, {}); |
| 2005 | 2109 | } |
| 2006 | 2110 | |
| 2111 | fn addSymbolTableEntry( |
| 2112 | coff: *Coff, |
| 2113 | name: union(enum) { |
| 2114 | bytes: []const u8, |
| 2115 | string: String, |
| 2116 | }, |
| 2117 | si: Symbol.Index, |
| 2118 | add: SymbolTable.Add, |
| 2119 | ) !void { |
| 2120 | assert(!coff.isImage()); |
| 2121 | const gpa = coff.base.comp.gpa; |
| 2122 | |
| 2123 | const string, const name_slice = switch (name) { |
| 2124 | .bytes => |bytes| .{ try coff.getOrPutString(bytes), bytes }, |
| 2125 | .string => |s| .{ s, s.toSlice(coff) }, |
| 2126 | }; |
| 2127 | |
| 2128 | const symbol_name: SymbolTable.SymbolName = if (name_slice.len > 8) index: { |
| 2129 | const string_gop = try coff.symbol_table.string_offsets.getOrPut(gpa, string); |
| 2130 | if (!string_gop.found_existing) { |
| 2131 | const string_index = Node.known.string_table.location(&coff.mf).resolve(&coff.mf)[1]; |
| 2132 | string_gop.value_ptr.* = @enumFromInt(string_index); |
| 2133 | |
| 2134 | try Node.known.string_table.resize(&coff.mf, gpa, string_index + name_slice.len + 1); |
| 2135 | const slice = Node.known.string_table.slice(&coff.mf); |
| 2136 | @memcpy(slice[string_index..][0..name_slice.len], name_slice); |
| 2137 | slice[string_index + name_slice.len] = 0; |
| 2138 | } |
| 2139 | |
| 2140 | break :index .{ .long = string_gop.value_ptr.* }; |
| 2141 | } else .{ .short = name_slice }; |
| 2142 | |
| 2143 | const symbol_index = coff.targetLoad(&coff.headerPtr().number_of_symbols); |
| 2144 | const symbols_added: u8 = switch (add) { |
| 2145 | .section => count: { |
| 2146 | const sym = si.get(coff); |
| 2147 | |
| 2148 | try coff.nodes.ensureUnusedCapacity(gpa, 2); |
| 2149 | _ = try coff.addSymbolTableEntryAssumeCapacity( |
| 2150 | symbol_name, |
| 2151 | 0, |
| 2152 | sym.section_number, |
| 2153 | .{ |
| 2154 | .complex_type = .NULL, |
| 2155 | .base_type = .NULL, |
| 2156 | }, |
| 2157 | .STATIC, |
| 2158 | 1, |
| 2159 | ); |
| 2160 | |
| 2161 | // Aux entry ields are updated by flushMoved / flushResized |
| 2162 | |
| 2163 | try coff.symbol_table.entries.put(gpa, si, .{ |
| 2164 | .entry_si = .null, |
| 2165 | .index = @enumFromInt(symbol_index), |
| 2166 | }); |
| 2167 | |
| 2168 | break :count 2; |
| 2169 | }, |
| 2170 | .global => |global| count: { |
| 2171 | const sym = si.get(coff); |
| 2172 | |
| 2173 | try coff.nodes.ensureUnusedCapacity(gpa, 1); |
| 2174 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| 2175 | |
| 2176 | const entry_ni = try coff.addSymbolTableEntryAssumeCapacity( |
| 2177 | symbol_name, |
| 2178 | if (global.import) 0 else coff.computeNodeSectionOffset(sym.ni), |
| 2179 | if (global.import) .UNDEFINED else sym.section_number, |
| 2180 | .{ |
| 2181 | .base_type = .NULL, |
| 2182 | .complex_type = if (global.import or |
| 2183 | Symbol.Index.text.get(coff).section_number == sym.section_number) |
| 2184 | .FUNCTION |
| 2185 | else |
| 2186 | .NULL, |
| 2187 | }, |
| 2188 | .EXTERNAL, |
| 2189 | 0, |
| 2190 | ); |
| 2191 | |
| 2192 | const entry_si = coff.addSymbolAssumeCapacity(); |
| 2193 | { |
| 2194 | const entry_sym = entry_si.get(coff); |
| 2195 | entry_sym.ni = entry_ni; |
| 2196 | assert(entry_sym.loc_relocs == .none); |
| 2197 | entry_sym.loc_relocs = @enumFromInt(coff.relocs.items.len); |
| 2198 | entry_sym.section_number = .UNDEFINED; |
| 2199 | } |
| 2200 | |
| 2201 | try coff.addReloc( |
| 2202 | entry_si, |
| 2203 | @offsetOf(std.coff.Symbol, "value"), |
| 2204 | si, |
| 2205 | 0, |
| 2206 | .{ .AMD64 = .SECREL }, |
| 2207 | ); |
| 2208 | |
| 2209 | try coff.symbol_table.entries.put(gpa, si, .{ |
| 2210 | .entry_si = entry_si, |
| 2211 | .index = @enumFromInt(symbol_index), |
| 2212 | }); |
| 2213 | |
| 2214 | break :count 1; |
| 2215 | }, |
| 2216 | }; |
| 2217 | |
| 2218 | const new_num_symbols = symbol_index + symbols_added; |
| 2219 | coff.targetStore(&coff.headerPtr().number_of_symbols, new_num_symbols); |
| 2220 | coff.symbol_table.pending_shrink = |
| 2221 | Node.known.symbol_table.location(&coff.mf).resolve(&coff.mf)[1] > |
| 2222 | new_num_symbols * std.coff.Symbol.sizeOf(); |
| 2223 | } |
| 2224 | |
| 2225 | /// Caller guarantees there is capacity for 1 + number_of_aux_symbols nodes. |
| 2226 | /// Auxiliary nodes are zero-initialized. |
| 2227 | fn addSymbolTableEntryAssumeCapacity( |
| 2228 | coff: *Coff, |
| 2229 | name: SymbolTable.SymbolName, |
| 2230 | value: u32, |
| 2231 | section_number: Symbol.SectionNumber, |
| 2232 | @"type": std.coff.SymType, |
| 2233 | storage_class: std.coff.StorageClass, |
| 2234 | number_of_aux_symbols: u8, |
| 2235 | ) !MappedFile.Node.Index { |
| 2236 | const gpa = coff.base.comp.gpa; |
| 2237 | |
| 2238 | const entry_ni = try coff.mf.addLastChildNode(gpa, Node.known.symbol_table, .{ |
| 2239 | .alignment = .@"2", |
| 2240 | .size = std.coff.Symbol.sizeOf(), |
| 2241 | .fixed = true, |
| 2242 | }); |
| 2243 | coff.nodes.appendAssumeCapacity(.symbol_table_entry); |
| 2244 | |
| 2245 | const entry: *align(2) std.coff.Symbol = @ptrCast(@alignCast(entry_ni.slice(&coff.mf))); |
| 2246 | entry.* = .{ |
| 2247 | .name = undefined, |
| 2248 | .value = value, |
| 2249 | .section_number = @enumFromInt(@intFromEnum(section_number)), |
| 2250 | .type = @"type", |
| 2251 | .storage_class = storage_class, |
| 2252 | .number_of_aux_symbols = number_of_aux_symbols, |
| 2253 | }; |
| 2254 | |
| 2255 | switch (name) { |
| 2256 | .short => |s| { |
| 2257 | @memcpy(entry.name[0..s.len], s); |
| 2258 | @memset(entry.name[s.len..], 0); |
| 2259 | }, |
| 2260 | .long => |l| { |
| 2261 | @memset(entry.name[0..4], 0); |
| 2262 | const offset_ptr: *align(2) u32 = @ptrCast(entry.name[4..]); |
| 2263 | coff.targetStore(offset_ptr, @intFromEnum(l)); |
| 2264 | }, |
| 2265 | } |
| 2266 | |
| 2267 | if (coff.targetEndian() != native_endian) |
| 2268 | std.mem.byteSwapAllFields(std.coff.SectionHeader, entry.*); |
| 2269 | |
| 2270 | for (0..number_of_aux_symbols) |_| { |
| 2271 | const aux_ni = try coff.mf.addLastChildNode(gpa, Node.known.symbol_table, .{ |
| 2272 | .alignment = .@"2", |
| 2273 | .size = std.coff.Symbol.sizeOf(), |
| 2274 | .fixed = true, |
| 2275 | }); |
| 2276 | coff.nodes.appendAssumeCapacity(.symbol_table_entry); |
| 2277 | @memset(aux_ni.slice(&coff.mf), 0); |
| 2278 | } |
| 2279 | |
| 2280 | return entry_ni; |
| 2281 | } |
| 2282 | |
| 2007 | 2283 | fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags) !Symbol.Index { |
| 2008 | 2284 | assert(coff.base.comp.zcu != null); |
| 2009 | 2285 | |
| 2010 | 2286 | const gpa = coff.base.comp.gpa; |
| 2011 | 2287 | try coff.nodes.ensureUnusedCapacity(gpa, 1); |
| 2012 | | try coff.image_section_table.ensureUnusedCapacity(gpa, 1); |
| 2013 | | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); |
| 2288 | try coff.section_table.ensureUnusedCapacity(gpa, 1); |
| 2289 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| 2014 | 2290 | |
| 2015 | 2291 | const coff_header = coff.headerPtr(); |
| 2016 | 2292 | const section_index = coff.targetLoad(&coff_header.number_of_sections); |
| ... | ... | @@ -2022,19 +2298,19 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags |
| 2022 | 2298 | @sizeOf(std.coff.SectionHeader) * section_table_len, |
| 2023 | 2299 | ); |
| 2024 | 2300 | |
| 2025 | | const parent_ni, const alignment = if (coff.isArchive()) |
| 2026 | | .{ Node.known.zcu_member, .@"1" } |
| 2301 | const parent_ni = if (coff.isArchive()) |
| 2302 | Node.known.zcu_member |
| 2027 | 2303 | else |
| 2028 | | .{ Node.known.file, coff.mf.flags.block_size }; |
| 2304 | Node.known.file; |
| 2029 | 2305 | |
| 2030 | 2306 | const ni = try coff.mf.addLastChildNode(gpa, parent_ni, .{ |
| 2031 | | .alignment = alignment, |
| 2307 | .alignment = coff.mf.flags.block_size, |
| 2032 | 2308 | .moved = true, |
| 2033 | 2309 | .bubbles_moved = false, |
| 2034 | 2310 | }); |
| 2035 | 2311 | |
| 2036 | 2312 | const si = coff.addSymbolAssumeCapacity(); |
| 2037 | | coff.image_section_table.appendAssumeCapacity(si); |
| 2313 | coff.section_table.appendAssumeCapacity(si); |
| 2038 | 2314 | coff.nodes.appendAssumeCapacity(.{ .image_section = si }); |
| 2039 | 2315 | const section_table = coff.sectionTableSlice(); |
| 2040 | 2316 | |
| ... | ... | @@ -2042,7 +2318,7 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags |
| 2042 | 2318 | const virtual_size = coff.optionalHeaderField(.section_alignment); |
| 2043 | 2319 | const rva: u32 = switch (section_index) { |
| 2044 | 2320 | 0 => @intCast(Node.known.header.location(&coff.mf).resolve(&coff.mf)[1]), |
| 2045 | | else => coff.image_section_table.items[section_index - 1].get(coff).rva + |
| 2321 | else => coff.section_table.items[section_index - 1].get(coff).rva + |
| 2046 | 2322 | coff.targetLoad(&section_table[section_index - 1].virtual_size), |
| 2047 | 2323 | }; |
| 2048 | 2324 | |
| ... | ... | @@ -2080,6 +2356,8 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags |
| 2080 | 2356 | @intCast(rva + virtual_size), |
| 2081 | 2357 | ), |
| 2082 | 2358 | } |
| 2359 | } else { |
| 2360 | try coff.addSymbolTableEntry(.{ .bytes = name }, si, .section); |
| 2083 | 2361 | } |
| 2084 | 2362 | |
| 2085 | 2363 | return si; |
| ... | ... | @@ -2112,7 +2390,7 @@ fn pseudoSectionMapIndex( |
| 2112 | 2390 | else |
| 2113 | 2391 | .rdata; |
| 2114 | 2392 | try coff.nodes.ensureUnusedCapacity(gpa, 1); |
| 2115 | | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); |
| 2393 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| 2116 | 2394 | const ni = try coff.mf.addLastChildNode(gpa, parent.node(coff), .{ .alignment = alignment }); |
| 2117 | 2395 | const si = coff.addSymbolAssumeCapacity(); |
| 2118 | 2396 | pseudo_section_gop.value_ptr.* = si; |
| ... | ... | @@ -2142,7 +2420,7 @@ fn objectSectionMapIndex( |
| 2142 | 2420 | name_slice[0 .. std.mem.indexOfScalar(u8, name_slice, '$') orelse name_slice.len], |
| 2143 | 2421 | ), alignment, attributes)).symbol(coff); |
| 2144 | 2422 | try coff.nodes.ensureUnusedCapacity(gpa, 1); |
| 2145 | | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); |
| 2423 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| 2146 | 2424 | const parent_ni = parent.node(coff); |
| 2147 | 2425 | var prev_ni: MappedFile.Node.Index = .none; |
| 2148 | 2426 | var next_it = parent_ni.children(&coff.mf); |
| ... | ... | @@ -2251,6 +2529,8 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde |
| 2251 | 2529 | const sym = si.get(coff); |
| 2252 | 2530 | sym.ni = ni; |
| 2253 | 2531 | sym.section_number = sec_si.get(coff).section_number; |
| 2532 | |
| 2533 | // TODO: Add symbol table entry |
| 2254 | 2534 | }, |
| 2255 | 2535 | else => si.deleteLocationRelocs(coff), |
| 2256 | 2536 | } |
| ... | ... | @@ -2506,11 +2786,6 @@ pub fn flush( |
| 2506 | 2786 | _ = prog_node; |
| 2507 | 2787 | while (try coff.idle(tid)) {} |
| 2508 | 2788 | |
| 2509 | | // TODO: Second linker member symbol tables are built here |
| 2510 | | if (isArchive(coff)) { |
| 2511 | | //Member.Index.second.get(coff).content_ni; |
| 2512 | | } |
| 2513 | | |
| 2514 | 2789 | const comp = coff.base.comp; |
| 2515 | 2790 | |
| 2516 | 2791 | // Implib generation should instead be done via building a MappedFile progressively |
| ... | ... | @@ -2634,6 +2909,26 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 2634 | 2909 | coff.flushExportsSort(); |
| 2635 | 2910 | break :task; |
| 2636 | 2911 | } |
| 2912 | // TODO: This and the above task ideally run only once, as it's wasteful otherwise |
| 2913 | if (coff.symbol_table.pending_shrink) { |
| 2914 | coff.symbol_table.pending_shrink = false; |
| 2915 | // TODO: Prog node |
| 2916 | const number_of_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols); |
| 2917 | Node.known.symbol_table.shrink( |
| 2918 | &coff.mf, |
| 2919 | comp.gpa, |
| 2920 | number_of_symbols * std.coff.Symbol.sizeOf(), |
| 2921 | true, |
| 2922 | ) catch |err| switch (err) { |
| 2923 | error.OutOfMemory => return error.OutOfMemory, |
| 2924 | else => |e| return comp.link_diags.fail( |
| 2925 | "linker failed to shrink symbol table: {t}", |
| 2926 | .{e}, |
| 2927 | ), |
| 2928 | }; |
| 2929 | |
| 2930 | break :task; |
| 2931 | } |
| 2637 | 2932 | } |
| 2638 | 2933 | if (coff.pending_uavs.count() > 0) return true; |
| 2639 | 2934 | if (coff.globals.count() > coff.global_pending_index) return true; |
| ... | ... | @@ -2641,6 +2936,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 2641 | 2936 | if (coff.mf.updates.items.len > 0) return true; |
| 2642 | 2937 | if (coff.pending_members.count() > 0) return true; |
| 2643 | 2938 | if (coff.export_table.pending_sort) return true; |
| 2939 | if (coff.symbol_table.pending_shrink) return true; |
| 2644 | 2940 | return false; |
| 2645 | 2941 | } |
| 2646 | 2942 | |
| ... | ... | @@ -2733,14 +3029,28 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void { |
| 2733 | 3029 | const gpa = zcu.gpa; |
| 2734 | 3030 | const gn = gmi.globalName(coff); |
| 2735 | 3031 | |
| 2736 | | // TODO: We still need to emit a reloc for the __imp_Name symbol? |
| 3032 | if (!coff.isImage()) { |
| 3033 | // TODO: What about data imports? |
| 3034 | |
| 3035 | // const si = gmi.symbol(coff); |
| 3036 | // const sym = si.get(coff); |
| 3037 | // sym.section_number = Symbol.Index.text.get(coff).section_number; |
| 3038 | // assert(sym.loc_relocs == .none); |
| 3039 | // sym.loc_relocs = @enumFromInt(coff.relocs.items.len); |
| 3040 | // |
| 3041 | // try coff.addSymbolTableEntry( |
| 3042 | // .{ .bytes = gn.name.toSlice(coff) }, |
| 3043 | // si, |
| 3044 | // .{ .global = .{ .import = true } }, |
| 3045 | // ); |
| 2737 | 3046 | |
| 2738 | | if (!coff.isImage()) return; |
| 3047 | return; |
| 3048 | } |
| 2739 | 3049 | |
| 2740 | 3050 | if (gn.lib_name.toSlice(coff)) |lib_name| { |
| 2741 | 3051 | const name = gn.name.toSlice(coff); |
| 2742 | 3052 | try coff.nodes.ensureUnusedCapacity(gpa, 4); |
| 2743 | | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); |
| 3053 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| 2744 | 3054 | |
| 2745 | 3055 | const target_endian = coff.targetEndian(); |
| 2746 | 3056 | const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic); |
| ... | ... | @@ -2749,7 +3059,6 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void { |
| 2749 | 3059 | .PE32 => .{ 4, .@"4" }, |
| 2750 | 3060 | .@"PE32+" => .{ 8, .@"8" }, |
| 2751 | 3061 | }; |
| 2752 | | |
| 2753 | 3062 | const gop = try coff.import_table.entries.getOrPutAdapted( |
| 2754 | 3063 | gpa, |
| 2755 | 3064 | lib_name, |
| ... | ... | @@ -2959,7 +3268,16 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 2959 | 3268 | .data_directories, |
| 2960 | 3269 | .section_table, |
| 2961 | 3270 | .placeholder, |
| 3271 | |
| 3272 | .symbol_table_entry, |
| 3273 | .string_table, |
| 2962 | 3274 | => if (!coff.isArchive()) unreachable, |
| 3275 | .symbol_table => { |
| 3276 | coff.targetStore( |
| 3277 | &coff.headerPtr().pointer_to_symbol_table, |
| 3278 | @intCast(ni.location(&coff.mf).resolve(&coff.mf)[0]), |
| 3279 | ); |
| 3280 | }, |
| 2963 | 3281 | .archive_member_header => |mi| { |
| 2964 | 3282 | const member = mi.get(coff); |
| 2965 | 3283 | switch (member.kind) { |
| ... | ... | @@ -3121,7 +3439,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 3121 | 3439 | ), |
| 3122 | 3440 | } |
| 3123 | 3441 | |
| 3124 | | if (size > coff.image_section_table.items[0].get(coff).rva) try coff.virtualSlide( |
| 3442 | if (size > coff.section_table.items[0].get(coff).rva) try coff.virtualSlide( |
| 3125 | 3443 | 0, |
| 3126 | 3444 | std.mem.alignForward( |
| 3127 | 3445 | u32, |
| ... | ... | @@ -3159,6 +3477,12 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 3159 | 3477 | .data_directories, |
| 3160 | 3478 | => unreachable, |
| 3161 | 3479 | .section_table => {}, |
| 3480 | .symbol_table => assert(!coff.isImage()), |
| 3481 | .symbol_table_entry => unreachable, |
| 3482 | .string_table => { |
| 3483 | assert(!coff.isImage()); |
| 3484 | coff.targetStore(coff.symbolTableStringLenPtr(), @intCast(size)); |
| 3485 | }, |
| 3162 | 3486 | .image_section => |si| { |
| 3163 | 3487 | const sym = si.get(coff); |
| 3164 | 3488 | const section_index = sym.section_number.toIndex(); |
| ... | ... | @@ -3173,6 +3497,13 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 3173 | 3497 | coff.targetStore(&section.virtual_size, virtual_size); |
| 3174 | 3498 | try coff.virtualSlide(section_index + 1, sym.rva + virtual_size); |
| 3175 | 3499 | } |
| 3500 | |
| 3501 | if (coff.isArchive()) { |
| 3502 | coff.targetStore( |
| 3503 | &coff.symbolAuxSectionDefinitionPtr(si).length, |
| 3504 | @intCast(size), |
| 3505 | ); |
| 3506 | } |
| 3176 | 3507 | }, |
| 3177 | 3508 | .import_directory_table => coff.targetStore( |
| 3178 | 3509 | &coff.dataDirectoryPtr(.IMPORT).size, |
| ... | ... | @@ -3298,7 +3629,7 @@ fn flushExportsSort(coff: *Coff) void { |
| 3298 | 3629 | fn virtualSlide(coff: *Coff, start_section_index: usize, start_rva: u32) !void { |
| 3299 | 3630 | var rva = start_rva; |
| 3300 | 3631 | for ( |
| 3301 | | coff.image_section_table.items[start_section_index..], |
| 3632 | coff.section_table.items[start_section_index..], |
| 3302 | 3633 | coff.sectionTableSlice()[start_section_index..], |
| 3303 | 3634 | ) |section_si, *section| { |
| 3304 | 3635 | const section_sym = section_si.get(coff); |
| ... | ... | @@ -3343,7 +3674,7 @@ fn updateExportsInner( |
| 3343 | 3674 | Value.fromInterned(uav).fmtValue(pt), |
| 3344 | 3675 | }), |
| 3345 | 3676 | } |
| 3346 | | try coff.symbol_table.ensureUnusedCapacity(gpa, export_indices.len); |
| 3677 | try coff.symbols.ensureUnusedCapacity(gpa, export_indices.len); |
| 3347 | 3678 | const exported_si: Symbol.Index = switch (exported) { |
| 3348 | 3679 | .nav => |nav| try coff.navSymbol(zcu, nav), |
| 3349 | 3680 | .uav => |uav| @enumFromInt(@intFromEnum(try coff.lowerUav( |
| ... | ... | @@ -3376,13 +3707,20 @@ fn updateExportsInner( |
| 3376 | 3707 | std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, tls_directory); |
| 3377 | 3708 | } |
| 3378 | 3709 | |
| 3379 | | if (coff.isArchive()) |
| 3710 | if (coff.isArchive()) { |
| 3380 | 3711 | try coff.addMemberSymbol( |
| 3381 | 3712 | symbol_gop.key_ptr.*.name, |
| 3382 | 3713 | coff.getNode(Node.known.zcu_member).archive_member, |
| 3383 | 3714 | export_si, |
| 3384 | 3715 | ); |
| 3385 | 3716 | |
| 3717 | try coff.addSymbolTableEntry( |
| 3718 | .{ .bytes = name }, |
| 3719 | export_si, |
| 3720 | .{ .global = .{ .import = false } }, |
| 3721 | ); |
| 3722 | } |
| 3723 | |
| 3386 | 3724 | if (coff.export_table.ni == .none) continue; |
| 3387 | 3725 | |
| 3388 | 3726 | const entries_ctx = ExportTable.Adapter{ .coff = coff }; |
| ... | ... | @@ -3425,8 +3763,7 @@ fn updateExportsInner( |
| 3425 | 3763 | coff.targetStore(&edt.number_of_names, @intCast(export_count)); |
| 3426 | 3764 | edt.number_of_entries = edt.number_of_names; |
| 3427 | 3765 | |
| 3428 | | // TODO: If we had an estimate of the total number of exports this could be a lot more efficient |
| 3429 | | |
| 3766 | // TODO: These should all be resized ahead of time to fit all exports (after https://github.com/ziglang/zig/issues/23616) |
| 3430 | 3767 | try coff.export_table.export_address_table_si.node(coff).resize( |
| 3431 | 3768 | &coff.mf, |
| 3432 | 3769 | gpa, |