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
logc8328cb57b9b23c474ab0c55ca5caa0e90bc5f80
tree2e7b3171e2e24aa27f06127f29b0c608da3e9814
parentc5d6277ace183cf4261c13cc9b44a53ec1622199

Coff: Implement writing the export table


2 files changed, 347 insertions(+), 10 deletions(-)

lib/std/coff.zig+44
...@@ -452,6 +452,50 @@ pub const ImportHintNameEntry = extern struct {...@@ -452,6 +452,50 @@ pub const ImportHintNameEntry = extern struct {
452 name: [1]u8,452 name: [1]u8,
453};453};
454454
455pub const ExportDirectoryTable = extern struct {
456 /// Reserved
457 flags: u32,
458
459 /// Creation time of this table
460 time_date_stamp: u32,
461
462 major_version: u16,
463 minor_version: u16,
464
465 /// The address of an ASCII string that contains the name of the DLL.
466 /// This address is relative to the image base.
467 name_rva: u32,
468
469 /// The ordinal of the first export in this image
470 ordinal_base: u32,
471
472 /// Number of entries in the export address table
473 number_of_entries: u32,
474
475 /// Number of entries in the name pointer table and ordinal table
476 number_of_names: u32,
477
478 export_address_table_rva: u32,
479 name_pointer_table_rva: u32,
480 ordinal_table_rva: u32,
481};
482
483pub const ExportAddressTableEntry = extern struct {
484 /// If this address is within the export section, then this is the address of the export
485 /// Otherwise, this is the address of a string that specfies a symbol in another DLL:
486 /// <dll name>.<export name>
487 /// <dll name>.#<export ordinal>
488 export_or_forwarder_rva: u32,
489};
490
491pub const ExportNamePointerTableEntry = extern struct {
492 name_rva: u32,
493};
494
495pub const ExportOrdinalTableEntry = extern struct {
496 unbiased_ordinal: u16,
497};
498
455pub const SectionHeader = extern struct {499pub const SectionHeader = extern struct {
456 name: [8]u8,500 name: [8]u8,
457 virtual_size: u32,501 virtual_size: u32,
src/link/Coff.zig+303-10
...@@ -22,6 +22,7 @@ base: link.File,...@@ -22,6 +22,7 @@ base: link.File,
22mf: MappedFile,22mf: MappedFile,
23nodes: std.MultiArrayList(Node),23nodes: std.MultiArrayList(Node),
24import_table: ImportTable,24import_table: ImportTable,
25export_table: ExportTable,
25strings: std.HashMapUnmanaged(26strings: std.HashMapUnmanaged(
26 u32,27 u32,
27 void,28 void,
...@@ -146,6 +147,12 @@ pub const Node = union(enum) {...@@ -146,6 +147,12 @@ pub const Node = union(enum) {
146 import_address_table: ImportTable.Index,147 import_address_table: ImportTable.Index,
147 import_hint_name_table: ImportTable.Index,148 import_hint_name_table: ImportTable.Index,
148149
150 export_directory_table,
151 export_address_table,
152 export_name_pointer_table,
153 export_ordinal_table,
154 export_name_table,
155
149 pseudo_section: PseudoSectionMapIndex,156 pseudo_section: PseudoSectionMapIndex,
150 object_section: ObjectSectionMapIndex,157 object_section: ObjectSectionMapIndex,
151 global: GlobalMapIndex,158 global: GlobalMapIndex,
...@@ -270,6 +277,44 @@ pub const Node = union(enum) {...@@ -270,6 +277,44 @@ pub const Node = union(enum) {
270 }277 }
271};278};
272279
280pub const ExportTable = struct {
281 ni: MappedFile.Node.Index,
282 export_address_table_ni: MappedFile.Node.Index,
283 name_pointer_table_ni: MappedFile.Node.Index,
284 ordinal_table_ni: MappedFile.Node.Index,
285 name_table_ni: MappedFile.Node.Index,
286 entries: std.AutoArrayHashMapUnmanaged(void, Entry),
287
288 pub const Entry = struct {
289 name_index: u32,
290 name_len: u32,
291 };
292
293 const Adapter = struct {
294 coff: *Coff,
295
296 pub fn eql(adapter: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool {
297 const coff = adapter.coff;
298 const name_table_slice = coff.export_table.name_table_ni.slice(&coff.mf);
299 const rhs = coff.export_table.entries.values()[rhs_index];
300 return std.mem.eql(u8, name_table_slice[rhs.name_index..][0..rhs.name_len], lhs_key);
301 }
302
303 pub fn hash(_: Adapter, key: []const u8) u32 {
304 assert(std.mem.indexOfScalar(u8, key, 0) == null);
305 return std.array_hash_map.hashString(key);
306 }
307 };
308
309 pub const Index = enum(u32) {
310 _,
311
312 pub fn get(export_index: ExportTable.Index, coff: *Coff) *Entry {
313 return &coff.export_table.entries.values()[@intFromEnum(export_index)];
314 }
315 };
316};
317
273pub const ImportTable = struct {318pub const ImportTable = struct {
274 ni: MappedFile.Node.Index,319 ni: MappedFile.Node.Index,
275 entries: std.array_hash_map.Auto(void, Entry),320 entries: std.array_hash_map.Auto(void, Entry),
...@@ -314,6 +359,7 @@ pub const String = enum(u32) {...@@ -314,6 +359,7 @@ pub const String = enum(u32) {
314 @".rdata" = 13,359 @".rdata" = 13,
315 @".text" = 20,360 @".text" = 20,
316 @".tls$" = 26,361 @".tls$" = 26,
362 @".edata" = 32,
317 _,363 _,
318364
319 pub const Optional = enum(u32) {365 pub const Optional = enum(u32) {
...@@ -321,6 +367,7 @@ pub const String = enum(u32) {...@@ -321,6 +367,7 @@ pub const String = enum(u32) {
321 @".rdata" = @intFromEnum(String.@".rdata"),367 @".rdata" = @intFromEnum(String.@".rdata"),
322 @".text" = @intFromEnum(String.@".text"),368 @".text" = @intFromEnum(String.@".text"),
323 @".tls$" = @intFromEnum(String.@".tls$"),369 @".tls$" = @intFromEnum(String.@".tls$"),
370 @".edata" = @intFromEnum(String.@".edata"),
324 none = std.math.maxInt(u32),371 none = std.math.maxInt(u32),
325 _,372 _,
326373
...@@ -695,6 +742,14 @@ fn create(...@@ -695,6 +742,14 @@ fn create(
695 .ni = .none,742 .ni = .none,
696 .entries = .empty,743 .entries = .empty,
697 },744 },
745 .export_table = .{
746 .ni = .none,
747 .export_address_table_ni = .none,
748 .name_pointer_table_ni = .none,
749 .ordinal_table_ni = .none,
750 .name_table_ni = .none,
751 .entries = .empty,
752 },
698 .strings = .empty,753 .strings = .empty,
699 .string_bytes = .empty,754 .string_bytes = .empty,
700 .image_section_table = .empty,755 .image_section_table = .empty,
...@@ -741,6 +796,7 @@ pub fn deinit(coff: *Coff) void {...@@ -741,6 +796,7 @@ pub fn deinit(coff: *Coff) void {
741 coff.mf.deinit(gpa);796 coff.mf.deinit(gpa);
742 coff.nodes.deinit(gpa);797 coff.nodes.deinit(gpa);
743 coff.import_table.entries.deinit(gpa);798 coff.import_table.entries.deinit(gpa);
799 coff.export_table.entries.deinit(gpa);
744 coff.strings.deinit(gpa);800 coff.strings.deinit(gpa);
745 coff.string_bytes.deinit(gpa);801 coff.string_bytes.deinit(gpa);
746 coff.image_section_table.deinit(gpa);802 coff.image_section_table.deinit(gpa);
...@@ -780,7 +836,7 @@ fn initHeaders(...@@ -780,7 +836,7 @@ fn initHeaders(
780 else836 else
781 0;837 0;
782838
783 const expected_nodes_len = Node.known_count + 6 +839 const expected_nodes_len = Node.known_count + 12 +
784 @as(usize, @intFromBool(comp.config.any_non_single_threaded)) * 2;840 @as(usize, @intFromBool(comp.config.any_non_single_threaded)) * 2;
785 try coff.nodes.ensureTotalCapacity(gpa, expected_nodes_len);841 try coff.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
786 coff.nodes.appendAssumeCapacity(.file);842 coff.nodes.appendAssumeCapacity(.file);
...@@ -1005,6 +1061,67 @@ fn initHeaders(...@@ -1005,6 +1061,67 @@ fn initHeaders(
1005 );1061 );
1006 coff.nodes.appendAssumeCapacity(.import_directory_table);1062 coff.nodes.appendAssumeCapacity(.import_directory_table);
10071063
1064 {
1065 // TODO: Could create this lazily when processing the first export instead?
1066 const edata_section_ni = (try coff.pseudoSectionMapIndex(
1067 .@".edata",
1068 .of(std.coff.ExportDirectoryTable),
1069 .{ .read = true },
1070 )).symbol(coff).node(coff);
1071
1072 const name = "TODO_NAME.dll";
1073 const name_index = @sizeOf(std.coff.ExportDirectoryTable);
1074 coff.export_table.ni = try coff.mf.addLastChildNode(
1075 gpa,
1076 edata_section_ni,
1077 .{
1078 .size = @sizeOf(std.coff.ExportDirectoryTable) + name.len + 1,
1079 .alignment = .of(std.coff.ExportDirectoryTable),
1080 .fixed = true,
1081 .moved = true,
1082 },
1083 );
1084 @memcpy(coff.export_table.ni.slice(&coff.mf)[name_index..][0 .. name.len + 1], name[0 .. name.len + 1]);
1085
1086 coff.export_table.export_address_table_ni = try coff.mf.addLastChildNode(gpa, edata_section_ni, .{
1087 .alignment = .of(u32),
1088 .moved = true,
1089 });
1090 coff.export_table.name_pointer_table_ni = try coff.mf.addLastChildNode(gpa, edata_section_ni, .{
1091 .alignment = .of(u32),
1092 .moved = true,
1093 });
1094 coff.export_table.ordinal_table_ni = try coff.mf.addLastChildNode(gpa, edata_section_ni, .{
1095 .alignment = .of(u16),
1096 .moved = true,
1097 });
1098 coff.export_table.name_table_ni = try coff.mf.addLastChildNode(gpa, edata_section_ni, .{
1099 .alignment = .of(u8),
1100 .moved = true,
1101 });
1102
1103 coff.nodes.appendAssumeCapacity(.export_directory_table);
1104 coff.nodes.appendAssumeCapacity(.export_address_table);
1105 coff.nodes.appendAssumeCapacity(.export_name_pointer_table);
1106 coff.nodes.appendAssumeCapacity(.export_ordinal_table);
1107 coff.nodes.appendAssumeCapacity(.export_name_table);
1108
1109 const export_directory_table = coff.exportDirectoryTable();
1110 export_directory_table.* = .{
1111 .flags = 0,
1112 .time_date_stamp = timestamp,
1113 .major_version = 0,
1114 .minor_version = 0,
1115 .name_rva = 0,
1116 .ordinal_base = 1,
1117 .number_of_entries = 0,
1118 .number_of_names = 0,
1119 .export_address_table_rva = 0,
1120 .name_pointer_table_rva = 0,
1121 .ordinal_table_rva = 0,
1122 };
1123 }
1124
1008 // While tls variables allocated at runtime are writable, the template itself is not1125 // While tls variables allocated at runtime are writable, the template itself is not
1009 if (comp.config.any_non_single_threaded) _ = try coff.objectSectionMapIndex(1126 if (comp.config.any_non_single_threaded) _ = try coff.objectSectionMapIndex(
1010 .@".tls$",1127 .@".tls$",
...@@ -1048,6 +1165,7 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {...@@ -1048,6 +1165,7 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {
1048 .optional_header,1165 .optional_header,
1049 .data_directories,1166 .data_directories,
1050 .section_table,1167 .section_table,
1168 .export_name_table,
1051 => unreachable,1169 => unreachable,
1052 .image_section => |si| si,1170 .image_section => |si| si,
1053 .import_directory_table => break :parent_rva coff.targetLoad(1171 .import_directory_table => break :parent_rva coff.targetLoad(
...@@ -1062,6 +1180,18 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {...@@ -1062,6 +1180,18 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {
1062 .import_hint_name_table => |import_index| break :parent_rva coff.targetLoad(1180 .import_hint_name_table => |import_index| break :parent_rva coff.targetLoad(
1063 &coff.importDirectoryEntryPtr(import_index).name_rva,1181 &coff.importDirectoryEntryPtr(import_index).name_rva,
1064 ),1182 ),
1183 .export_directory_table => break :parent_rva coff.targetLoad(
1184 &coff.dataDirectoryPtr(.EXPORT).virtual_address,
1185 ),
1186 .export_address_table => break :parent_rva coff.targetLoad(
1187 &coff.exportDirectoryTable().export_address_table_rva,
1188 ),
1189 .export_name_pointer_table => break :parent_rva coff.targetLoad(
1190 &coff.exportDirectoryTable().name_pointer_table_rva,
1191 ),
1192 .export_ordinal_table => break :parent_rva coff.targetLoad(
1193 &coff.exportDirectoryTable().ordinal_table_rva,
1194 ),
1065 inline .pseudo_section,1195 inline .pseudo_section,
1066 .object_section,1196 .object_section,
1067 .global,1197 .global,
...@@ -1181,6 +1311,22 @@ pub fn importDirectoryEntryPtr(...@@ -1181,6 +1311,22 @@ pub fn importDirectoryEntryPtr(
1181 return &coff.importDirectoryTableSlice()[@intFromEnum(import_index)];1311 return &coff.importDirectoryTableSlice()[@intFromEnum(import_index)];
1182}1312}
11831313
1314pub fn exportDirectoryTable(coff: *Coff) *std.coff.ExportDirectoryTable {
1315 return @ptrCast(@alignCast(coff.export_table.ni.slice(&coff.mf)));
1316}
1317
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 {
1323 return @ptrCast(@alignCast(coff.export_table.name_pointer_table_ni.slice(&coff.mf)));
1324}
1325
1326pub fn exportOrdinalTableSlice(coff: *Coff) []std.coff.ExportOrdinalTableEntry {
1327 return @ptrCast(@alignCast(coff.export_table.ordinal_table_ni.slice(&coff.mf)));
1328}
1329
1184fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index {1330fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index {
1185 defer coff.symbol_table.addOneAssumeCapacity().* = .{1331 defer coff.symbol_table.addOneAssumeCapacity().* = .{
1186 .ni = .none,1332 .ni = .none,
...@@ -1729,6 +1875,82 @@ pub fn updateErrorData(coff: *Coff, pt: Zcu.PerThread) !void {...@@ -1729,6 +1875,82 @@ pub fn updateErrorData(coff: *Coff, pt: Zcu.PerThread) !void {
1729 };1875 };
1730}1876}
17311877
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
1732pub fn flush(1954pub fn flush(
1733 coff: *Coff,1955 coff: *Coff,
1734 arena: std.mem.Allocator,1956 arena: std.mem.Allocator,
...@@ -1739,6 +1961,9 @@ pub fn flush(...@@ -1739,6 +1961,9 @@ pub fn flush(
1739 _ = prog_node;1961 _ = prog_node;
1740 while (try coff.idle(tid)) {}1962 while (try coff.idle(tid)) {}
17411963
1964 coff.flushExports(tid) catch |err|
1965 return coff.base.comp.link_diags.fail("linker failed to flush exports: {t}", .{err});
1966
1742 // hack for stage2_x86_64 + coff1967 // hack for stage2_x86_64 + coff
1743 const comp = coff.base.comp;1968 const comp = coff.base.comp;
1744 if (comp.compiler_rt_dyn_lib) |crt_file| {1969 if (comp.compiler_rt_dyn_lib) |crt_file| {
...@@ -1932,19 +2157,20 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void {...@@ -1932,19 +2157,20 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void {
1932 const comp = zcu.comp;2157 const comp = zcu.comp;
1933 const gpa = zcu.gpa;2158 const gpa = zcu.gpa;
1934 const gn = gmi.globalName(coff);2159 const gn = gmi.globalName(coff);
2160
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);
1935 if (gn.lib_name.toSlice(coff)) |lib_name| {2170 if (gn.lib_name.toSlice(coff)) |lib_name| {
1936 const name = gn.name.toSlice(coff);
1937 try coff.nodes.ensureUnusedCapacity(gpa, 4);2171 try coff.nodes.ensureUnusedCapacity(gpa, 4);
1938 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);2172 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);
19392173
1940 const target_endian = coff.targetEndian();
1941 const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic);
1942 const addr_size: u64, const addr_align: std.mem.Alignment = switch (magic) {
1943 _ => unreachable,
1944 .PE32 => .{ 4, .@"4" },
1945 .@"PE32+" => .{ 8, .@"8" },
1946 };
1947
1948 const gop = try coff.import_table.entries.getOrPutAdapted(2174 const gop = try coff.import_table.entries.getOrPutAdapted(
1949 gpa,2175 gpa,
1950 lib_name,2176 lib_name,
...@@ -2089,6 +2315,47 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void {...@@ -2089,6 +2315,47 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void {
2089 coff.nodes.appendAssumeCapacity(.{ .global = gmi });2315 coff.nodes.appendAssumeCapacity(.{ .global = gmi });
2090 sym.rva = coff.computeNodeRva(sym.ni);2316 sym.rva = coff.computeNodeRva(sym.ni);
2091 si.applyLocationRelocs(coff);2317 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 }
2092 }2359 }
2093}2360}
20942361
...@@ -2218,6 +2485,27 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -2218,6 +2485,27 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
2218 import_hint_name_index += 2;2485 import_hint_name_index += 2;
2219 }2486 }
2220 },2487 },
2488 .export_directory_table => {
2489 const rva = coff.computeNodeRva(ni);
2490 coff.targetStore(&coff.dataDirectoryPtr(.EXPORT).virtual_address, rva);
2491 coff.targetStore(&coff.exportDirectoryTable().name_rva, rva + @sizeOf(std.coff.ExportDirectoryTable));
2492 },
2493 .export_address_table => coff.targetStore(
2494 &coff.exportDirectoryTable().export_address_table_rva,
2495 coff.computeNodeRva(ni),
2496 ),
2497 .export_name_pointer_table => coff.targetStore(
2498 &coff.exportDirectoryTable().name_pointer_table_rva,
2499 coff.computeNodeRva(ni),
2500 ),
2501 .export_ordinal_table => coff.targetStore(
2502 &coff.exportDirectoryTable().ordinal_table_rva,
2503 coff.computeNodeRva(ni),
2504 ),
2505 .export_name_table => {
2506 // .export_name_pointer_table entries are updated in flush
2507 log.warn("flushMoved export_name_table unhandled", .{});
2508 },
2221 inline .pseudo_section,2509 inline .pseudo_section,
2222 .object_section,2510 .object_section,
2223 .global,2511 .global,
...@@ -2272,6 +2560,11 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -2272,6 +2560,11 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
2272 @intCast(size),2560 @intCast(size),
2273 ),2561 ),
2274 .import_lookup_table, .import_address_table, .import_hint_name_table => {},2562 .import_lookup_table, .import_address_table, .import_hint_name_table => {},
2563 .export_directory_table => coff.targetStore(
2564 &coff.dataDirectoryPtr(.EXPORT).size,
2565 @intCast(size),
2566 ),
2567 .export_address_table, .export_name_pointer_table, .export_ordinal_table, .export_name_table => {},
2275 inline .pseudo_section,2568 inline .pseudo_section,
2276 .object_section,2569 .object_section,
2277 => |smi| smi.symbol(coff).get(coff).size = @intCast(size),2570 => |smi| smi.symbol(coff).get(coff).size = @intCast(size),