| ... | ... | @@ -279,15 +279,17 @@ pub const Node = union(enum) { |
| 279 | 279 | |
| 280 | 280 | pub const ExportTable = struct { |
| 281 | 281 | ni: MappedFile.Node.Index, |
| 282 | | export_address_table_ni: MappedFile.Node.Index, |
| 282 | export_address_table_si: Symbol.Index, |
| 283 | 283 | name_pointer_table_ni: MappedFile.Node.Index, |
| 284 | 284 | ordinal_table_ni: MappedFile.Node.Index, |
| 285 | 285 | name_table_ni: MappedFile.Node.Index, |
| 286 | 286 | entries: std.AutoArrayHashMapUnmanaged(void, Entry), |
| 287 | pending_sort: bool = false, |
| 287 | 288 | |
| 288 | 289 | pub const Entry = struct { |
| 289 | 290 | name_index: u32, |
| 290 | 291 | name_len: u32, |
| 292 | export_address_table_ri: Reloc.Index, |
| 291 | 293 | }; |
| 292 | 294 | |
| 293 | 295 | const Adapter = struct { |
| ... | ... | @@ -306,10 +308,10 @@ pub const ExportTable = struct { |
| 306 | 308 | } |
| 307 | 309 | }; |
| 308 | 310 | |
| 309 | | pub const Index = enum(u32) { |
| 311 | pub const Ordinal = enum(u16) { |
| 310 | 312 | _, |
| 311 | 313 | |
| 312 | | pub fn get(export_index: ExportTable.Index, coff: *Coff) *Entry { |
| 314 | pub fn get(export_index: ExportTable.Ordinal, coff: *Coff) *Entry { |
| 313 | 315 | return &coff.export_table.entries.values()[@intFromEnum(export_index)]; |
| 314 | 316 | } |
| 315 | 317 | }; |
| ... | ... | @@ -744,7 +746,7 @@ fn create( |
| 744 | 746 | }, |
| 745 | 747 | .export_table = .{ |
| 746 | 748 | .ni = .none, |
| 747 | | .export_address_table_ni = .none, |
| 749 | .export_address_table_si = .null, |
| 748 | 750 | .name_pointer_table_ni = .none, |
| 749 | 751 | .ordinal_table_ni = .none, |
| 750 | 752 | .name_table_ni = .none, |
| ... | ... | @@ -1083,10 +1085,21 @@ fn initHeaders( |
| 1083 | 1085 | ); |
| 1084 | 1086 | @memcpy(coff.export_table.ni.slice(&coff.mf)[name_index..][0 .. name.len + 1], name[0 .. name.len + 1]); |
| 1085 | 1087 | |
| 1086 | | coff.export_table.export_address_table_ni = try coff.mf.addLastChildNode(gpa, edata_section_ni, .{ |
| 1088 | const export_address_table_ni = try coff.mf.addLastChildNode(gpa, edata_section_ni, .{ |
| 1087 | 1089 | .alignment = .of(u32), |
| 1088 | 1090 | .moved = true, |
| 1089 | 1091 | }); |
| 1092 | |
| 1093 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); |
| 1094 | coff.export_table.export_address_table_si = coff.addSymbolAssumeCapacity(); |
| 1095 | |
| 1096 | const export_address_table_sym = coff.export_table.export_address_table_si.get(coff); |
| 1097 | export_address_table_sym.ni = export_address_table_ni; |
| 1098 | assert(export_address_table_sym.loc_relocs == .none); |
| 1099 | export_address_table_sym.loc_relocs = @enumFromInt(coff.relocs.items.len); |
| 1100 | export_address_table_sym.section_number = |
| 1101 | coff.getNode(edata_section_ni).pseudo_section.symbol(coff).get(coff).section_number; |
| 1102 | |
| 1090 | 1103 | coff.export_table.name_pointer_table_ni = try coff.mf.addLastChildNode(gpa, edata_section_ni, .{ |
| 1091 | 1104 | .alignment = .of(u32), |
| 1092 | 1105 | .moved = true, |
| ... | ... | @@ -1120,6 +1133,8 @@ fn initHeaders( |
| 1120 | 1133 | .name_pointer_table_rva = 0, |
| 1121 | 1134 | .ordinal_table_rva = 0, |
| 1122 | 1135 | }; |
| 1136 | if (target_endian != native_endian) |
| 1137 | std.mem.byteSwapAllFields(std.coff.ExportDirectoryTable, export_directory_table); |
| 1123 | 1138 | } |
| 1124 | 1139 | |
| 1125 | 1140 | // While tls variables allocated at runtime are writable, the template itself is not |
| ... | ... | @@ -1315,10 +1330,6 @@ pub fn exportDirectoryTable(coff: *Coff) *std.coff.ExportDirectoryTable { |
| 1315 | 1330 | return @ptrCast(@alignCast(coff.export_table.ni.slice(&coff.mf))); |
| 1316 | 1331 | } |
| 1317 | 1332 | |
| 1318 | | pub fn exportAddressTableSlice(coff: *Coff) []std.coff.ExportAddressTableEntry { |
| 1319 | | return @ptrCast(@alignCast(coff.export_table.export_address_table_ni.slice(&coff.mf))); |
| 1320 | | } |
| 1321 | | |
| 1322 | 1333 | pub fn exportNamePointerTableSlice(coff: *Coff) []std.coff.ExportNamePointerTableEntry { |
| 1323 | 1334 | return @ptrCast(@alignCast(coff.export_table.name_pointer_table_ni.slice(&coff.mf))); |
| 1324 | 1335 | } |
| ... | ... | @@ -1875,82 +1886,6 @@ pub fn updateErrorData(coff: *Coff, pt: Zcu.PerThread) !void { |
| 1875 | 1886 | }; |
| 1876 | 1887 | } |
| 1877 | 1888 | |
| 1878 | | fn flushExports(coff: *Coff, tid: Zcu.PerThread.Id) !void { |
| 1879 | | const export_count = coff.export_table.entries.count(); |
| 1880 | | if (export_count == 0) return; |
| 1881 | | |
| 1882 | | const gpa = coff.base.comp.zcu.?.gpa; |
| 1883 | | const edt = coff.exportDirectoryTable(); |
| 1884 | | edt.number_of_names = @intCast(export_count); |
| 1885 | | edt.number_of_entries = @intCast(export_count); |
| 1886 | | |
| 1887 | | try coff.export_table.name_pointer_table_ni.resize( |
| 1888 | | &coff.mf, |
| 1889 | | gpa, |
| 1890 | | export_count * @sizeOf(std.coff.ExportNamePointerTableEntry), |
| 1891 | | ); |
| 1892 | | |
| 1893 | | try coff.export_table.ordinal_table_ni.resize( |
| 1894 | | &coff.mf, |
| 1895 | | gpa, |
| 1896 | | export_count * @sizeOf(std.coff.ExportOrdinalTableEntry), |
| 1897 | | ); |
| 1898 | | |
| 1899 | | while (try coff.idle(tid)) {} |
| 1900 | | if (coff.targetEndian() != native_endian) |
| 1901 | | std.mem.byteSwapAllFields(std.coff.ExportDirectoryTable, edt); |
| 1902 | | |
| 1903 | | const name_table_rva = coff.computeNodeRva(coff.export_table.name_table_ni); |
| 1904 | | for ( |
| 1905 | | coff.exportNamePointerTableSlice(), |
| 1906 | | coff.exportOrdinalTableSlice(), |
| 1907 | | coff.export_table.entries.values(), |
| 1908 | | 0.., |
| 1909 | | ) |*np, *ord, entry, entry_i| { |
| 1910 | | np.name_rva = name_table_rva + entry.name_index; |
| 1911 | | if (coff.targetEndian() != native_endian) |
| 1912 | | std.mem.byteSwapAllFields(std.coff.ExportNamePointerTableEntry, np); |
| 1913 | | |
| 1914 | | ord.unbiased_ordinal = @intCast(entry_i); |
| 1915 | | if (coff.targetEndian() != native_endian) |
| 1916 | | std.mem.byteSwapAllFields(std.coff.ExportOrdinalTableEntry, &ord); |
| 1917 | | } |
| 1918 | | |
| 1919 | | const Context = struct { |
| 1920 | | np: []std.coff.ExportNamePointerTableEntry, |
| 1921 | | ord: []std.coff.ExportOrdinalTableEntry, |
| 1922 | | entries: []ExportTable.Entry, |
| 1923 | | names: []const u8, |
| 1924 | | |
| 1925 | | pub fn lessThan(ctx: @This(), lhs: usize, rhs: usize) bool { |
| 1926 | | const lhs_entry = &ctx.entries[lhs]; |
| 1927 | | const rhs_entry = &ctx.entries[rhs]; |
| 1928 | | return std.mem.lessThan( |
| 1929 | | u8, |
| 1930 | | ctx.names[lhs_entry.name_index..][0..lhs_entry.name_len], |
| 1931 | | ctx.names[rhs_entry.name_index..][0..rhs_entry.name_len], |
| 1932 | | ); |
| 1933 | | } |
| 1934 | | |
| 1935 | | pub fn swap(ctx: @This(), lhs: usize, rhs: usize) void { |
| 1936 | | std.mem.swap(std.coff.ExportNamePointerTableEntry, &ctx.np[lhs], &ctx.np[rhs]); |
| 1937 | | std.mem.swap(std.coff.ExportOrdinalTableEntry, &ctx.ord[lhs], &ctx.ord[rhs]); |
| 1938 | | std.mem.swap(ExportTable.Entry, &ctx.entries[lhs], &ctx.entries[rhs]); |
| 1939 | | } |
| 1940 | | }; |
| 1941 | | |
| 1942 | | std.sort.pdqContext(0, export_count, Context{ |
| 1943 | | .np = coff.exportNamePointerTableSlice(), |
| 1944 | | .ord = coff.exportOrdinalTableSlice(), |
| 1945 | | .entries = coff.export_table.entries.values(), |
| 1946 | | .names = coff.export_table.name_table_ni.slice(&coff.mf), |
| 1947 | | }); |
| 1948 | | |
| 1949 | | // TODO: Is there a way to know if this is the last flush? We could skip doing this if so. |
| 1950 | | // TODO: Need to reindex with adaptor? |
| 1951 | | //try coff.export_table.entries.reIndexContext(gpa, ExportTable.Adapter{ .coff = coff }); |
| 1952 | | } |
| 1953 | | |
| 1954 | 1889 | pub fn flush( |
| 1955 | 1890 | coff: *Coff, |
| 1956 | 1891 | arena: std.mem.Allocator, |
| ... | ... | @@ -1961,9 +1896,6 @@ pub fn flush( |
| 1961 | 1896 | _ = prog_node; |
| 1962 | 1897 | while (try coff.idle(tid)) {} |
| 1963 | 1898 | |
| 1964 | | coff.flushExports(tid) catch |err| |
| 1965 | | return coff.base.comp.link_diags.fail("linker failed to flush exports: {t}", .{err}); |
| 1966 | | |
| 1967 | 1899 | // hack for stage2_x86_64 + coff |
| 1968 | 1900 | const comp = coff.base.comp; |
| 1969 | 1901 | if (comp.compiler_rt_dyn_lib) |crt_file| { |
| ... | ... | @@ -2061,11 +1993,17 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 2061 | 1993 | break :task; |
| 2062 | 1994 | } else coff.mf.update_prog_node.completeOne(); |
| 2063 | 1995 | } |
| 1996 | if (coff.export_table.pending_sort) { |
| 1997 | coff.export_table.pending_sort = false; |
| 1998 | coff.flushExportsSort(); |
| 1999 | break :task; |
| 2000 | } |
| 2064 | 2001 | } |
| 2065 | 2002 | if (coff.pending_uavs.count() > 0) return true; |
| 2066 | 2003 | if (coff.globals.count() > coff.global_pending_index) return true; |
| 2067 | 2004 | for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; |
| 2068 | 2005 | if (coff.mf.updates.items.len > 0) return true; |
| 2006 | if (coff.export_table.pending_sort) return true; |
| 2069 | 2007 | return false; |
| 2070 | 2008 | } |
| 2071 | 2009 | |
| ... | ... | @@ -2158,19 +2096,19 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void { |
| 2158 | 2096 | const gpa = zcu.gpa; |
| 2159 | 2097 | const gn = gmi.globalName(coff); |
| 2160 | 2098 | |
| 2161 | | const target_endian = coff.targetEndian(); |
| 2162 | | const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic); |
| 2163 | | const addr_size: u64, const addr_align: std.mem.Alignment = switch (magic) { |
| 2164 | | _ => unreachable, |
| 2165 | | .PE32 => .{ 4, .@"4" }, |
| 2166 | | .@"PE32+" => .{ 8, .@"8" }, |
| 2167 | | }; |
| 2168 | | |
| 2169 | | const name = gn.name.toSlice(coff); |
| 2170 | 2099 | if (gn.lib_name.toSlice(coff)) |lib_name| { |
| 2100 | const name = gn.name.toSlice(coff); |
| 2171 | 2101 | try coff.nodes.ensureUnusedCapacity(gpa, 4); |
| 2172 | 2102 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); |
| 2173 | 2103 | |
| 2104 | const target_endian = coff.targetEndian(); |
| 2105 | const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic); |
| 2106 | const addr_size: u64, const addr_align: std.mem.Alignment = switch (magic) { |
| 2107 | _ => unreachable, |
| 2108 | .PE32 => .{ 4, .@"4" }, |
| 2109 | .@"PE32+" => .{ 8, .@"8" }, |
| 2110 | }; |
| 2111 | |
| 2174 | 2112 | const gop = try coff.import_table.entries.getOrPutAdapted( |
| 2175 | 2113 | gpa, |
| 2176 | 2114 | lib_name, |
| ... | ... | @@ -2315,47 +2253,6 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void { |
| 2315 | 2253 | coff.nodes.appendAssumeCapacity(.{ .global = gmi }); |
| 2316 | 2254 | sym.rva = coff.computeNodeRva(sym.ni); |
| 2317 | 2255 | si.applyLocationRelocs(coff); |
| 2318 | | } else { |
| 2319 | | const entries_ctx = ExportTable.Adapter{ .coff = coff }; |
| 2320 | | const gop = try coff.export_table.entries.getOrPutAdapted( |
| 2321 | | gpa, |
| 2322 | | name, |
| 2323 | | entries_ctx, |
| 2324 | | ); |
| 2325 | | |
| 2326 | | if (!gop.found_existing) { |
| 2327 | | errdefer _ = coff.export_table.entries.pop(); |
| 2328 | | if (coff.export_table.entries.count() > std.math.maxInt(@FieldType(std.coff.ExportDirectoryTable, "number_of_entries"))) |
| 2329 | | return coff.base.comp.link_diags.fail("exceeded maximum number of exports", .{}); |
| 2330 | | |
| 2331 | | const name_index = coff.export_table.name_table_ni.fileLocation(&coff.mf, true).size; |
| 2332 | | const new_name_table_size = name_index + name.len + 1; |
| 2333 | | if (new_name_table_size > std.math.maxInt(@FieldType(ExportTable.Entry, "name_index"))) |
| 2334 | | return coff.base.comp.link_diags.fail("exports name table limit reached", .{}); |
| 2335 | | |
| 2336 | | try coff.export_table.name_table_ni.resize(&coff.mf, gpa, new_name_table_size); |
| 2337 | | |
| 2338 | | const name_table_slice = coff.export_table.name_table_ni.slice(&coff.mf); |
| 2339 | | @memcpy(name_table_slice[name_index..][0 .. name.len + 1], name[0 .. name.len + 1]); |
| 2340 | | |
| 2341 | | gop.value_ptr.* = .{ |
| 2342 | | .name_index = @intCast(name_index), |
| 2343 | | .name_len = @intCast(name.len), |
| 2344 | | }; |
| 2345 | | |
| 2346 | | const si = gmi.symbol(coff); |
| 2347 | | const sym = si.get(coff); |
| 2348 | | |
| 2349 | | try coff.export_table.export_address_table_ni.resize( |
| 2350 | | &coff.mf, |
| 2351 | | gpa, |
| 2352 | | coff.export_table.entries.count() * @sizeOf(std.coff.ExportAddressTableEntry), |
| 2353 | | ); |
| 2354 | | const ea = &coff.exportAddressTableSlice()[gop.index]; |
| 2355 | | ea.export_or_forwarder_rva = sym.rva; |
| 2356 | | if (coff.targetEndian() != native_endian) |
| 2357 | | std.mem.byteSwapAllFields(std.coff.ExportAddressTableEntry, &ea); |
| 2358 | | } |
| 2359 | 2256 | } |
| 2360 | 2257 | } |
| 2361 | 2258 | |
| ... | ... | @@ -2490,10 +2387,19 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 2490 | 2387 | coff.targetStore(&coff.dataDirectoryPtr(.EXPORT).virtual_address, rva); |
| 2491 | 2388 | coff.targetStore(&coff.exportDirectoryTable().name_rva, rva + @sizeOf(std.coff.ExportDirectoryTable)); |
| 2492 | 2389 | }, |
| 2493 | | .export_address_table => coff.targetStore( |
| 2494 | | &coff.exportDirectoryTable().export_address_table_rva, |
| 2495 | | coff.computeNodeRva(ni), |
| 2496 | | ), |
| 2390 | .export_address_table => { |
| 2391 | coff.export_table.export_address_table_si.flushMoved(coff); |
| 2392 | |
| 2393 | // These relocs are applied directly here instead of via the above flushMoved call as |
| 2394 | // they are non-contiguous, and not tracked under export_address_table_si. |
| 2395 | for (coff.export_table.entries.values()) |entry| |
| 2396 | entry.export_address_table_ri.get(coff).apply(coff); |
| 2397 | |
| 2398 | coff.targetStore( |
| 2399 | &coff.exportDirectoryTable().export_address_table_rva, |
| 2400 | coff.computeNodeRva(ni), |
| 2401 | ); |
| 2402 | }, |
| 2497 | 2403 | .export_name_pointer_table => coff.targetStore( |
| 2498 | 2404 | &coff.exportDirectoryTable().name_pointer_table_rva, |
| 2499 | 2405 | coff.computeNodeRva(ni), |
| ... | ... | @@ -2503,8 +2409,18 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 2503 | 2409 | coff.computeNodeRva(ni), |
| 2504 | 2410 | ), |
| 2505 | 2411 | .export_name_table => { |
| 2506 | | // .export_name_pointer_table entries are updated in flush |
| 2507 | | log.warn("flushMoved export_name_table unhandled", .{}); |
| 2412 | const name_table_rva = coff.computeNodeRva(coff.export_table.name_table_ni); |
| 2413 | for ( |
| 2414 | coff.exportNamePointerTableSlice(), |
| 2415 | coff.exportOrdinalTableSlice(), |
| 2416 | ) |*np, target_ord| { |
| 2417 | const ord: ExportTable.Ordinal = @enumFromInt(coff.targetLoad(&target_ord.unbiased_ordinal)); |
| 2418 | const entry = ord.get(coff); |
| 2419 | coff.targetStore( |
| 2420 | &np.name_rva, |
| 2421 | @intCast(name_table_rva + entry.name_index), |
| 2422 | ); |
| 2423 | } |
| 2508 | 2424 | }, |
| 2509 | 2425 | inline .pseudo_section, |
| 2510 | 2426 | .object_section, |
| ... | ... | @@ -2571,6 +2487,40 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 2571 | 2487 | .global, .nav, .uav, .lazy_code, .lazy_const_data => {}, |
| 2572 | 2488 | } |
| 2573 | 2489 | } |
| 2490 | |
| 2491 | fn flushExportsSort(coff: *Coff) void { |
| 2492 | const Context = struct { |
| 2493 | coff: *Coff, |
| 2494 | np: []std.coff.ExportNamePointerTableEntry, |
| 2495 | ord: []std.coff.ExportOrdinalTableEntry, |
| 2496 | entries: []ExportTable.Entry, |
| 2497 | nt: []const u8, |
| 2498 | |
| 2499 | pub fn lessThan(ctx: @This(), lhs: usize, rhs: usize) bool { |
| 2500 | const lhs_entry = &ctx.entries[ctx.coff.targetLoad(&ctx.ord[lhs].unbiased_ordinal)]; |
| 2501 | const rhs_entry = &ctx.entries[ctx.coff.targetLoad(&ctx.ord[rhs].unbiased_ordinal)]; |
| 2502 | return std.mem.lessThan( |
| 2503 | u8, |
| 2504 | ctx.nt[lhs_entry.name_index..][0..lhs_entry.name_len], |
| 2505 | ctx.nt[rhs_entry.name_index..][0..rhs_entry.name_len], |
| 2506 | ); |
| 2507 | } |
| 2508 | |
| 2509 | pub fn swap(ctx: @This(), lhs: usize, rhs: usize) void { |
| 2510 | std.mem.swap(std.coff.ExportNamePointerTableEntry, &ctx.np[lhs], &ctx.np[rhs]); |
| 2511 | std.mem.swap(std.coff.ExportOrdinalTableEntry, &ctx.ord[lhs], &ctx.ord[rhs]); |
| 2512 | } |
| 2513 | }; |
| 2514 | |
| 2515 | std.sort.pdqContext(0, coff.export_table.entries.count(), Context{ |
| 2516 | .coff = coff, |
| 2517 | .np = coff.exportNamePointerTableSlice(), |
| 2518 | .ord = coff.exportOrdinalTableSlice(), |
| 2519 | .entries = coff.export_table.entries.values(), |
| 2520 | .nt = coff.export_table.name_table_ni.slice(&coff.mf), |
| 2521 | }); |
| 2522 | } |
| 2523 | |
| 2574 | 2524 | fn virtualSlide(coff: *Coff, start_section_index: usize, start_rva: u32) !void { |
| 2575 | 2525 | var rva = start_rva; |
| 2576 | 2526 | for ( |
| ... | ... | @@ -2596,6 +2546,17 @@ pub fn updateExports( |
| 2596 | 2546 | pt: Zcu.PerThread, |
| 2597 | 2547 | exported: Zcu.Exported, |
| 2598 | 2548 | export_indices: []const Zcu.Export.Index, |
| 2549 | ) !void { |
| 2550 | return coff.updateExportsInner(pt, exported, export_indices) catch |err| switch (err) { |
| 2551 | error.OutOfMemory => error.OutOfMemory, |
| 2552 | else => |e| coff.base.comp.link_diags.fail("updateExports failed {t}", .{e}) catch error.AnalysisFail, |
| 2553 | }; |
| 2554 | } |
| 2555 | fn updateExportsInner( |
| 2556 | coff: *Coff, |
| 2557 | pt: Zcu.PerThread, |
| 2558 | exported: Zcu.Exported, |
| 2559 | export_indices: []const Zcu.Export.Index, |
| 2599 | 2560 | ) !void { |
| 2600 | 2561 | const zcu = pt.zcu; |
| 2601 | 2562 | const gpa = zcu.gpa; |
| ... | ... | @@ -2622,7 +2583,8 @@ pub fn updateExports( |
| 2622 | 2583 | const exported_sym = exported_si.get(coff); |
| 2623 | 2584 | for (export_indices) |export_index| { |
| 2624 | 2585 | const @"export" = export_index.ptr(zcu); |
| 2625 | | const export_si = try coff.globalSymbol(@"export".opts.name.toSlice(ip), null); |
| 2586 | const name = @"export".opts.name.toSlice(ip); |
| 2587 | const export_si = try coff.globalSymbol(name, null); |
| 2626 | 2588 | const export_sym = export_si.get(coff); |
| 2627 | 2589 | export_sym.ni = exported_ni; |
| 2628 | 2590 | export_sym.rva = exported_sym.rva; |
| ... | ... | @@ -2637,6 +2599,90 @@ pub fn updateExports( |
| 2637 | 2599 | if (coff.targetEndian() != native_endian) |
| 2638 | 2600 | std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, tls_directory); |
| 2639 | 2601 | } |
| 2602 | |
| 2603 | const entries_ctx = ExportTable.Adapter{ .coff = coff }; |
| 2604 | const gop = try coff.export_table.entries.getOrPutAdapted( |
| 2605 | gpa, |
| 2606 | name, |
| 2607 | entries_ctx, |
| 2608 | ); |
| 2609 | |
| 2610 | if (!gop.found_existing) { |
| 2611 | errdefer _ = coff.export_table.entries.pop(); |
| 2612 | |
| 2613 | const export_count = coff.export_table.entries.count(); |
| 2614 | if (export_count > std.math.maxInt(@FieldType(std.coff.ExportDirectoryTable, "number_of_entries"))) |
| 2615 | return coff.base.comp.link_diags.fail("exceeded maximum number of exports", .{}); |
| 2616 | |
| 2617 | const name_index = coff.export_table.name_table_ni.fileLocation(&coff.mf, true).size; |
| 2618 | const new_name_table_size = name_index + name.len + 1; |
| 2619 | if (new_name_table_size > std.math.maxInt(@FieldType(ExportTable.Entry, "name_index"))) |
| 2620 | return coff.base.comp.link_diags.fail("exports name table limit reached", .{}); |
| 2621 | |
| 2622 | try coff.export_table.name_table_ni.resize(&coff.mf, gpa, new_name_table_size); |
| 2623 | |
| 2624 | const name_table_slice = coff.export_table.name_table_ni.slice(&coff.mf); |
| 2625 | @memcpy(name_table_slice[name_index..][0 .. name.len + 1], name[0 .. name.len + 1]); |
| 2626 | |
| 2627 | // If the new name sorts after the current tail of the sorted list, we don't need to re-sort |
| 2628 | const ordinal_table_slice = coff.exportOrdinalTableSlice(); |
| 2629 | if (ordinal_table_slice.len > 0 and !coff.export_table.pending_sort) { |
| 2630 | const tail_index: ExportTable.Ordinal = |
| 2631 | @enumFromInt(ordinal_table_slice[ordinal_table_slice.len - 1].unbiased_ordinal); |
| 2632 | const tail_entry = tail_index.get(coff); |
| 2633 | const tail_name = name_table_slice[tail_entry.name_index..][0..tail_entry.name_len]; |
| 2634 | coff.export_table.pending_sort = std.mem.lessThan(u8, name, tail_name); |
| 2635 | } |
| 2636 | |
| 2637 | const edt = coff.exportDirectoryTable(); |
| 2638 | coff.targetStore(&edt.number_of_names, @intCast(export_count)); |
| 2639 | edt.number_of_entries = edt.number_of_names; |
| 2640 | |
| 2641 | try coff.export_table.export_address_table_si.node(coff).resize( |
| 2642 | &coff.mf, |
| 2643 | gpa, |
| 2644 | export_count * @sizeOf(std.coff.ExportAddressTableEntry), |
| 2645 | ); |
| 2646 | |
| 2647 | try coff.export_table.name_pointer_table_ni.resize( |
| 2648 | &coff.mf, |
| 2649 | gpa, |
| 2650 | export_count * @sizeOf(std.coff.ExportNamePointerTableEntry), |
| 2651 | ); |
| 2652 | |
| 2653 | try coff.export_table.ordinal_table_ni.resize( |
| 2654 | &coff.mf, |
| 2655 | gpa, |
| 2656 | export_count * @sizeOf(std.coff.ExportOrdinalTableEntry), |
| 2657 | ); |
| 2658 | |
| 2659 | coff.targetStore( |
| 2660 | &coff.exportNamePointerTableSlice()[gop.index].name_rva, |
| 2661 | @intCast(coff.computeNodeRva(coff.export_table.name_table_ni) + name_index), |
| 2662 | ); |
| 2663 | coff.targetStore( |
| 2664 | &coff.exportOrdinalTableSlice()[gop.index].unbiased_ordinal, |
| 2665 | @intCast(gop.index), |
| 2666 | ); |
| 2667 | |
| 2668 | gop.value_ptr.* = .{ |
| 2669 | .name_index = @intCast(name_index), |
| 2670 | .name_len = @intCast(name.len), |
| 2671 | .export_address_table_ri = @enumFromInt(coff.relocs.items.len), |
| 2672 | }; |
| 2673 | |
| 2674 | try coff.addReloc( |
| 2675 | coff.export_table.export_address_table_si, |
| 2676 | @intCast(@sizeOf(std.coff.ExportAddressTableEntry) * gop.index), |
| 2677 | export_si, |
| 2678 | 0, |
| 2679 | .{ .AMD64 = .ADDR32NB }, |
| 2680 | ); |
| 2681 | } else { |
| 2682 | const reloc = gop.value_ptr.*.export_address_table_ri.get(coff); |
| 2683 | reloc.target = export_si; |
| 2684 | export_si.applyTargetRelocs(coff); |
| 2685 | } |
| 2640 | 2686 | } |
| 2641 | 2687 | } |
| 2642 | 2688 | |