authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-12 15:28:05-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:35-08:00
log264a63b000021b154fffa95e6e0565c3d402706b
tree8d7cf36858ef455f736806711cfc405b92cbb5aa
parentbf880595916cad2a21fca2834e334c2b0ac09f24

wasm linker: flush export section


2 files changed, 71 insertions(+), 24 deletions(-)

src/link/Wasm.zig+25-7
...@@ -187,10 +187,10 @@ missing_exports_init: []String = &.{},...@@ -187,10 +187,10 @@ missing_exports_init: []String = &.{},
187entry_resolution: FunctionImport.Resolution = .unresolved,187entry_resolution: FunctionImport.Resolution = .unresolved,
188188
189/// Empty when outputting an object.189/// Empty when outputting an object.
190function_exports: std.ArrayListUnmanaged(FunctionIndex) = .empty,190function_exports: std.ArrayListUnmanaged(FunctionExport) = .empty,
191/// Tracks the value at the end of prelink.191/// Tracks the value at the end of prelink.
192function_exports_len: u32 = 0,192function_exports_len: u32 = 0,
193global_exports: std.ArrayListUnmanaged(GlobalIndex) = .empty,193global_exports: std.ArrayListUnmanaged(GlobalExport) = .empty,
194/// Tracks the value at the end of prelink.194/// Tracks the value at the end of prelink.
195global_exports_len: u32 = 0,195global_exports_len: u32 = 0,
196196
...@@ -262,16 +262,30 @@ pub const ObjectIndex = enum(u32) {...@@ -262,16 +262,30 @@ pub const ObjectIndex = enum(u32) {
262 }262 }
263};263};
264264
265/// Index into `functions`.265/// Index into `Wasm.functions`.
266pub const FunctionIndex = enum(u32) {266pub const FunctionIndex = enum(u32) {
267 _,267 _,
268268
269 pub fn ptr(index: FunctionIndex, wasm: *const Wasm) *FunctionImport.Resolution {
270 return &wasm.functions.keys()[@intFromEnum(index)];
271 }
272
269 pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) ?FunctionIndex {273 pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) ?FunctionIndex {
270 const i = wasm.functions.getIndex(.fromIpNav(wasm, nav_index)) orelse return null;274 const i = wasm.functions.getIndex(.fromIpNav(wasm, nav_index)) orelse return null;
271 return @enumFromInt(i);275 return @enumFromInt(i);
272 }276 }
273};277};
274278
279pub const FunctionExport = extern struct {
280 name: String,
281 function_index: FunctionIndex,
282};
283
284pub const GlobalExport = extern struct {
285 name: String,
286 global_index: GlobalIndex,
287};
288
275/// 0. Index into `function_imports`289/// 0. Index into `function_imports`
276/// 1. Index into `functions`.290/// 1. Index into `functions`.
277///291///
...@@ -2232,8 +2246,10 @@ fn markFunction(...@@ -2232,8 +2246,10 @@ fn markFunction(
2232 } else {2246 } else {
2233 const gop = wasm.functions.getOrPutAssumeCapacity(import.resolution);2247 const gop = wasm.functions.getOrPutAssumeCapacity(import.resolution);
22342248
2235 if (!is_obj and import.flags.isExported(rdynamic))2249 if (!is_obj and import.flags.isExported(rdynamic)) try wasm.function_exports.append(gpa, .{
2236 try wasm.function_exports.append(gpa, @enumFromInt(gop.index));2250 .name = name,
2251 .function_index = @enumFromInt(gop.index),
2252 });
22372253
2238 for (try wasm.functionResolutionRelocSlice(import.resolution)) |reloc|2254 for (try wasm.functionResolutionRelocSlice(import.resolution)) |reloc|
2239 try wasm.markReloc(reloc);2255 try wasm.markReloc(reloc);
...@@ -2282,8 +2298,10 @@ fn markGlobal(...@@ -2282,8 +2298,10 @@ fn markGlobal(
2282 } else {2298 } else {
2283 const gop = wasm.globals.getOrPutAssumeCapacity(import.resolution);2299 const gop = wasm.globals.getOrPutAssumeCapacity(import.resolution);
22842300
2285 if (!is_obj and import.flags.isExported(rdynamic))2301 if (!is_obj and import.flags.isExported(rdynamic)) try wasm.global_exports.append(gpa, .{
2286 try wasm.global_exports.append(gpa, @enumFromInt(gop.index));2302 .name = name,
2303 .global_index = @enumFromInt(gop.index),
2304 });
22872305
2288 for (try wasm.globalResolutionRelocSlice(import.resolution)) |reloc|2306 for (try wasm.globalResolutionRelocSlice(import.resolution)) |reloc|
2289 try wasm.markReloc(reloc);2307 try wasm.markReloc(reloc);
src/link/Wasm/Flush.zig+46-17
...@@ -79,14 +79,20 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {...@@ -79,14 +79,20 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
7979
80 for (wasm.nav_exports.keys()) |*nav_export| {80 for (wasm.nav_exports.keys()) |*nav_export| {
81 if (ip.isFunctionType(ip.getNav(nav_export.nav_index).typeOf(ip))) {81 if (ip.isFunctionType(ip.getNav(nav_export.nav_index).typeOf(ip))) {
82 try wasm.function_exports.append(gpa, Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?);82 try wasm.function_exports.append(gpa, .{
83 .name = nav_export.name,
84 .function_index = Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?,
85 });
83 _ = f.missing_exports.swapRemove(nav_export.name);86 _ = f.missing_exports.swapRemove(nav_export.name);
84 _ = wasm.function_imports.swapRemove(nav_export.name);87 _ = wasm.function_imports.swapRemove(nav_export.name);
8588
86 if (nav_export.name.toOptional() == entry_name)89 if (nav_export.name.toOptional() == entry_name)
87 wasm.entry_resolution = .fromIpNav(wasm, nav_export.nav_index);90 wasm.entry_resolution = .fromIpNav(wasm, nav_export.nav_index);
88 } else {91 } else {
89 try wasm.global_exports.append(gpa, Wasm.GlobalIndex.fromIpNav(wasm, nav_export.nav_index).?);92 try wasm.global_exports.append(gpa, .{
93 .name = nav_export.name,
94 .global_index = Wasm.GlobalIndex.fromIpNav(wasm, nav_export.nav_index).?,
95 });
90 _ = f.missing_exports.swapRemove(nav_export.name);96 _ = f.missing_exports.swapRemove(nav_export.name);
91 _ = wasm.global_imports.swapRemove(nav_export.name);97 _ = wasm.global_imports.swapRemove(nav_export.name);
92 }98 }
...@@ -437,8 +443,12 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {...@@ -437,8 +443,12 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
437 }443 }
438 total_imports += wasm.global_imports.entries.len;444 total_imports += wasm.global_imports.entries.len;
439445
440 replaceVecSectionHeader(binary_bytes, header_offset, .import, @intCast(total_imports));446 if (total_imports > 0) {
441 section_index += 1;447 replaceVecSectionHeader(binary_bytes, header_offset, .import, @intCast(total_imports));
448 section_index += 1;
449 } else {
450 binary_bytes.shrinkRetainingCapacity(header_offset);
451 }
442 }452 }
443453
444 // Function section454 // Function section
...@@ -474,7 +484,8 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {...@@ -474,7 +484,8 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
474 }484 }
475485
476 // Global section (used to emit stack pointer)486 // Global section (used to emit stack pointer)
477 if (wasm.globals.entries.len > 0) {487 const globals_len: u32 = @intCast(wasm.globals.entries.len);
488 if (globals_len > 0) {
478 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);489 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
479490
480 for (wasm.globals.keys()) |global_resolution| {491 for (wasm.globals.keys()) |global_resolution| {
...@@ -498,32 +509,50 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {...@@ -498,32 +509,50 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
498 }509 }
499 }510 }
500511
501 replaceVecSectionHeader(binary_bytes, header_offset, .global, @intCast(wasm.globals.entries.len));512 replaceVecSectionHeader(binary_bytes, header_offset, .global, globals_len);
502 section_index += 1;513 section_index += 1;
503 }514 }
504515
505 // Export section516 // Export section
506 if (wasm.exports.items.len != 0 or export_memory) {517 {
507 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);518 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
519 var exports_len: usize = 0;
508520
509 for (wasm.exports.items) |exp| {521 for (wasm.function_exports.items) |exp| {
510 const name = exp.name.slice(wasm);522 const name = exp.name.slice(wasm);
511 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));523 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));
512 try binary_writer.writeAll(name);524 try binary_bytes.appendSlice(gpa, name);
513 try leb.writeUleb128(binary_writer, @intFromEnum(exp.kind));525 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.function));
514 try leb.writeUleb128(binary_writer, exp.index);526 try leb.writeUleb128(binary_writer, @as(u32, @intCast(wasm.function_imports.entries.len + @intFromEnum(exp.function_index))));
515 }527 }
528 exports_len += wasm.function_exports.items.len;
529
530 // No table exports.
516531
517 if (export_memory) {532 if (export_memory) {
518 try leb.writeUleb128(binary_writer, @as(u32, @intCast("memory".len)));533 const name = "memory";
519 try binary_writer.writeAll("memory");534 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));
520 try binary_writer.writeByte(std.wasm.externalKind(.memory));535 try binary_bytes.appendSlice(gpa, name);
536 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.memory));
521 try leb.writeUleb128(binary_writer, @as(u32, 0));537 try leb.writeUleb128(binary_writer, @as(u32, 0));
538 exports_len += 1;
522 }539 }
523540
524 const n_items: u32 = @intCast(wasm.exports.items.len + @intFromBool(export_memory));541 for (wasm.global_exports.items) |exp| {
525 replaceVecSectionHeader(binary_bytes, header_offset, .@"export", n_items);542 const name = exp.name.slice(wasm);
526 section_index += 1;543 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));
544 try binary_bytes.appendSlice(gpa, name);
545 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.global));
546 try leb.writeUleb128(binary_writer, @as(u32, @intCast(wasm.global_imports.entries.len + @intFromEnum(exp.global_index))));
547 }
548 exports_len += wasm.global_exports.items.len;
549
550 if (exports_len > 0) {
551 replaceVecSectionHeader(binary_bytes, header_offset, .@"export", @intCast(exports_len));
552 section_index += 1;
553 } else {
554 binary_bytes.shrinkRetainingCapacity(header_offset);
555 }
527 }556 }
528557
529 if (Wasm.FunctionIndex.fromResolution(wasm.entry_resolution)) |entry_index| {558 if (Wasm.FunctionIndex.fromResolution(wasm.entry_resolution)) |entry_index| {