authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-05 01:55:33-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-23 00:21:00-04:00
loga87fc47bc17ae28a8a0a90da4c64751a071bac44
tree956120d93f7e0dcd5b0c24ea8ab028352c012b41
parentc8328cb57b9b23c474ab0c55ca5caa0e90bc5f80

- Move the export table logic into updateExportsInner

- Set up relocs for exported symbols in the export address table - Move the sort to `idle`, and set it up to only occur when necessary - Handle the name table being moved

1 files changed, 191 insertions(+), 145 deletions(-)

src/link/Coff.zig+191-145
...@@ -279,15 +279,17 @@ pub const Node = union(enum) {...@@ -279,15 +279,17 @@ pub const Node = union(enum) {
279279
280pub const ExportTable = struct {280pub const ExportTable = struct {
281 ni: MappedFile.Node.Index,281 ni: MappedFile.Node.Index,
282 export_address_table_ni: MappedFile.Node.Index,282 export_address_table_si: Symbol.Index,
283 name_pointer_table_ni: MappedFile.Node.Index,283 name_pointer_table_ni: MappedFile.Node.Index,
284 ordinal_table_ni: MappedFile.Node.Index,284 ordinal_table_ni: MappedFile.Node.Index,
285 name_table_ni: MappedFile.Node.Index,285 name_table_ni: MappedFile.Node.Index,
286 entries: std.AutoArrayHashMapUnmanaged(void, Entry),286 entries: std.AutoArrayHashMapUnmanaged(void, Entry),
287 pending_sort: bool = false,
287288
288 pub const Entry = struct {289 pub const Entry = struct {
289 name_index: u32,290 name_index: u32,
290 name_len: u32,291 name_len: u32,
292 export_address_table_ri: Reloc.Index,
291 };293 };
292294
293 const Adapter = struct {295 const Adapter = struct {
...@@ -306,10 +308,10 @@ pub const ExportTable = struct {...@@ -306,10 +308,10 @@ pub const ExportTable = struct {
306 }308 }
307 };309 };
308310
309 pub const Index = enum(u32) {311 pub const Ordinal = enum(u16) {
310 _,312 _,
311313
312 pub fn get(export_index: ExportTable.Index, coff: *Coff) *Entry {314 pub fn get(export_index: ExportTable.Ordinal, coff: *Coff) *Entry {
313 return &coff.export_table.entries.values()[@intFromEnum(export_index)];315 return &coff.export_table.entries.values()[@intFromEnum(export_index)];
314 }316 }
315 };317 };
...@@ -744,7 +746,7 @@ fn create(...@@ -744,7 +746,7 @@ fn create(
744 },746 },
745 .export_table = .{747 .export_table = .{
746 .ni = .none,748 .ni = .none,
747 .export_address_table_ni = .none,749 .export_address_table_si = .null,
748 .name_pointer_table_ni = .none,750 .name_pointer_table_ni = .none,
749 .ordinal_table_ni = .none,751 .ordinal_table_ni = .none,
750 .name_table_ni = .none,752 .name_table_ni = .none,
...@@ -1083,10 +1085,21 @@ fn initHeaders(...@@ -1083,10 +1085,21 @@ fn initHeaders(
1083 );1085 );
1084 @memcpy(coff.export_table.ni.slice(&coff.mf)[name_index..][0 .. name.len + 1], name[0 .. name.len + 1]);1086 @memcpy(coff.export_table.ni.slice(&coff.mf)[name_index..][0 .. name.len + 1], name[0 .. name.len + 1]);
10851087
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 .alignment = .of(u32),1089 .alignment = .of(u32),
1088 .moved = true,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 coff.export_table.name_pointer_table_ni = try coff.mf.addLastChildNode(gpa, edata_section_ni, .{1103 coff.export_table.name_pointer_table_ni = try coff.mf.addLastChildNode(gpa, edata_section_ni, .{
1091 .alignment = .of(u32),1104 .alignment = .of(u32),
1092 .moved = true,1105 .moved = true,
...@@ -1120,6 +1133,8 @@ fn initHeaders(...@@ -1120,6 +1133,8 @@ fn initHeaders(
1120 .name_pointer_table_rva = 0,1133 .name_pointer_table_rva = 0,
1121 .ordinal_table_rva = 0,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 }
11241139
1125 // While tls variables allocated at runtime are writable, the template itself is not1140 // 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,10 +1330,6 @@ pub fn exportDirectoryTable(coff: *Coff) *std.coff.ExportDirectoryTable {
1315 return @ptrCast(@alignCast(coff.export_table.ni.slice(&coff.mf)));1330 return @ptrCast(@alignCast(coff.export_table.ni.slice(&coff.mf)));
1316}1331}
13171332
1318pub fn exportAddressTableSlice(coff: *Coff) []std.coff.ExportAddressTableEntry {
1319 return @ptrCast(@alignCast(coff.export_table.export_address_table_ni.slice(&coff.mf)));
1320}
1321
1322pub fn exportNamePointerTableSlice(coff: *Coff) []std.coff.ExportNamePointerTableEntry {1333pub fn exportNamePointerTableSlice(coff: *Coff) []std.coff.ExportNamePointerTableEntry {
1323 return @ptrCast(@alignCast(coff.export_table.name_pointer_table_ni.slice(&coff.mf)));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,82 +1886,6 @@ pub fn updateErrorData(coff: *Coff, pt: Zcu.PerThread) !void {
1875 };1886 };
1876}1887}
18771888
1878fn 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
1954pub fn flush(1889pub fn flush(
1955 coff: *Coff,1890 coff: *Coff,
1956 arena: std.mem.Allocator,1891 arena: std.mem.Allocator,
...@@ -1961,9 +1896,6 @@ pub fn flush(...@@ -1961,9 +1896,6 @@ pub fn flush(
1961 _ = prog_node;1896 _ = prog_node;
1962 while (try coff.idle(tid)) {}1897 while (try coff.idle(tid)) {}
19631898
1964 coff.flushExports(tid) catch |err|
1965 return coff.base.comp.link_diags.fail("linker failed to flush exports: {t}", .{err});
1966
1967 // hack for stage2_x86_64 + coff1899 // hack for stage2_x86_64 + coff
1968 const comp = coff.base.comp;1900 const comp = coff.base.comp;
1969 if (comp.compiler_rt_dyn_lib) |crt_file| {1901 if (comp.compiler_rt_dyn_lib) |crt_file| {
...@@ -2061,11 +1993,17 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -2061,11 +1993,17 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
2061 break :task;1993 break :task;
2062 } else coff.mf.update_prog_node.completeOne();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 if (coff.pending_uavs.count() > 0) return true;2002 if (coff.pending_uavs.count() > 0) return true;
2066 if (coff.globals.count() > coff.global_pending_index) return true;2003 if (coff.globals.count() > coff.global_pending_index) return true;
2067 for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;2004 for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;
2068 if (coff.mf.updates.items.len > 0) return true;2005 if (coff.mf.updates.items.len > 0) return true;
2006 if (coff.export_table.pending_sort) return true;
2069 return false;2007 return false;
2070}2008}
20712009
...@@ -2158,19 +2096,19 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void {...@@ -2158,19 +2096,19 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void {
2158 const gpa = zcu.gpa;2096 const gpa = zcu.gpa;
2159 const gn = gmi.globalName(coff);2097 const gn = gmi.globalName(coff);
21602098
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 if (gn.lib_name.toSlice(coff)) |lib_name| {2099 if (gn.lib_name.toSlice(coff)) |lib_name| {
2100 const name = gn.name.toSlice(coff);
2171 try coff.nodes.ensureUnusedCapacity(gpa, 4);2101 try coff.nodes.ensureUnusedCapacity(gpa, 4);
2172 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);2102 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);
21732103
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 const gop = try coff.import_table.entries.getOrPutAdapted(2112 const gop = try coff.import_table.entries.getOrPutAdapted(
2175 gpa,2113 gpa,
2176 lib_name,2114 lib_name,
...@@ -2315,47 +2253,6 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void {...@@ -2315,47 +2253,6 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void {
2315 coff.nodes.appendAssumeCapacity(.{ .global = gmi });2253 coff.nodes.appendAssumeCapacity(.{ .global = gmi });
2316 sym.rva = coff.computeNodeRva(sym.ni);2254 sym.rva = coff.computeNodeRva(sym.ni);
2317 si.applyLocationRelocs(coff);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}
23612258
...@@ -2490,10 +2387,19 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -2490,10 +2387,19 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
2490 coff.targetStore(&coff.dataDirectoryPtr(.EXPORT).virtual_address, rva);2387 coff.targetStore(&coff.dataDirectoryPtr(.EXPORT).virtual_address, rva);
2491 coff.targetStore(&coff.exportDirectoryTable().name_rva, rva + @sizeOf(std.coff.ExportDirectoryTable));2388 coff.targetStore(&coff.exportDirectoryTable().name_rva, rva + @sizeOf(std.coff.ExportDirectoryTable));
2492 },2389 },
2493 .export_address_table => coff.targetStore(2390 .export_address_table => {
2494 &coff.exportDirectoryTable().export_address_table_rva,2391 coff.export_table.export_address_table_si.flushMoved(coff);
2495 coff.computeNodeRva(ni),2392
2496 ),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 .export_name_pointer_table => coff.targetStore(2403 .export_name_pointer_table => coff.targetStore(
2498 &coff.exportDirectoryTable().name_pointer_table_rva,2404 &coff.exportDirectoryTable().name_pointer_table_rva,
2499 coff.computeNodeRva(ni),2405 coff.computeNodeRva(ni),
...@@ -2503,8 +2409,18 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -2503,8 +2409,18 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
2503 coff.computeNodeRva(ni),2409 coff.computeNodeRva(ni),
2504 ),2410 ),
2505 .export_name_table => {2411 .export_name_table => {
2506 // .export_name_pointer_table entries are updated in flush2412 const name_table_rva = coff.computeNodeRva(coff.export_table.name_table_ni);
2507 log.warn("flushMoved export_name_table unhandled", .{});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 inline .pseudo_section,2425 inline .pseudo_section,
2510 .object_section,2426 .object_section,
...@@ -2571,6 +2487,40 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -2571,6 +2487,40 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
2571 .global, .nav, .uav, .lazy_code, .lazy_const_data => {},2487 .global, .nav, .uav, .lazy_code, .lazy_const_data => {},
2572 }2488 }
2573}2489}
2490
2491fn 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
2574fn virtualSlide(coff: *Coff, start_section_index: usize, start_rva: u32) !void {2524fn virtualSlide(coff: *Coff, start_section_index: usize, start_rva: u32) !void {
2575 var rva = start_rva;2525 var rva = start_rva;
2576 for (2526 for (
...@@ -2596,6 +2546,17 @@ pub fn updateExports(...@@ -2596,6 +2546,17 @@ pub fn updateExports(
2596 pt: Zcu.PerThread,2546 pt: Zcu.PerThread,
2597 exported: Zcu.Exported,2547 exported: Zcu.Exported,
2598 export_indices: []const Zcu.Export.Index,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}
2555fn updateExportsInner(
2556 coff: *Coff,
2557 pt: Zcu.PerThread,
2558 exported: Zcu.Exported,
2559 export_indices: []const Zcu.Export.Index,
2599) !void {2560) !void {
2600 const zcu = pt.zcu;2561 const zcu = pt.zcu;
2601 const gpa = zcu.gpa;2562 const gpa = zcu.gpa;
...@@ -2622,7 +2583,8 @@ pub fn updateExports(...@@ -2622,7 +2583,8 @@ pub fn updateExports(
2622 const exported_sym = exported_si.get(coff);2583 const exported_sym = exported_si.get(coff);
2623 for (export_indices) |export_index| {2584 for (export_indices) |export_index| {
2624 const @"export" = export_index.ptr(zcu);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 const export_sym = export_si.get(coff);2588 const export_sym = export_si.get(coff);
2627 export_sym.ni = exported_ni;2589 export_sym.ni = exported_ni;
2628 export_sym.rva = exported_sym.rva;2590 export_sym.rva = exported_sym.rva;
...@@ -2637,6 +2599,90 @@ pub fn updateExports(...@@ -2637,6 +2599,90 @@ pub fn updateExports(
2637 if (coff.targetEndian() != native_endian)2599 if (coff.targetEndian() != native_endian)
2638 std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, tls_directory);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}
26422688