authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-13 17:03:03-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:36-08:00
logdd9a64721030cf10065e74755f0c757cb470bcf3
treea931bf3e83a178019e5879465903d1489f530f68
parent8abdebecdca3a905099fa17f2497e8bf5f918e8a

wasm linker: fix bad export index math


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

src/link/Wasm.zig+13-16
...@@ -207,7 +207,7 @@ missing_exports: std.AutoArrayHashMapUnmanaged(String, void) = .empty,...@@ -207,7 +207,7 @@ missing_exports: std.AutoArrayHashMapUnmanaged(String, void) = .empty,
207entry_resolution: FunctionImport.Resolution = .unresolved,207entry_resolution: FunctionImport.Resolution = .unresolved,
208208
209/// Empty when outputting an object.209/// Empty when outputting an object.
210function_exports: std.ArrayListUnmanaged(FunctionExport) = .empty,210function_exports: std.AutoArrayHashMapUnmanaged(String, FunctionIndex) = .empty,
211/// Tracks the value at the end of prelink.211/// Tracks the value at the end of prelink.
212function_exports_len: u32 = 0,212function_exports_len: u32 = 0,
213global_exports: std.ArrayListUnmanaged(GlobalExport) = .empty,213global_exports: std.ArrayListUnmanaged(GlobalExport) = .empty,
...@@ -353,8 +353,13 @@ pub const FunctionIndex = enum(u32) {...@@ -353,8 +353,13 @@ pub const FunctionIndex = enum(u32) {
353 }353 }
354354
355 pub fn fromSymbolName(wasm: *const Wasm, name: String) ?FunctionIndex {355 pub fn fromSymbolName(wasm: *const Wasm, name: String) ?FunctionIndex {
356 const import = wasm.object_function_imports.getPtr(name) orelse return null;356 if (wasm.object_function_imports.getPtr(name)) |import| {
357 return fromResolution(wasm, import.resolution);357 return fromResolution(wasm, import.resolution);
358 }
359 if (wasm.function_exports.get(name)) |index| {
360 return index;
361 }
362 return null;
358 }363 }
359364
360 pub fn fromResolution(wasm: *const Wasm, resolution: FunctionImport.Resolution) ?FunctionIndex {365 pub fn fromResolution(wasm: *const Wasm, resolution: FunctionImport.Resolution) ?FunctionIndex {
...@@ -363,11 +368,6 @@ pub const FunctionIndex = enum(u32) {...@@ -363,11 +368,6 @@ pub const FunctionIndex = enum(u32) {
363 }368 }
364};369};
365370
366pub const FunctionExport = extern struct {
367 name: String,
368 function_index: FunctionIndex,
369};
370
371pub const GlobalExport = extern struct {371pub const GlobalExport = extern struct {
372 name: String,372 name: String,
373 global_index: GlobalIndex,373 global_index: GlobalIndex,
...@@ -386,7 +386,7 @@ pub const OutputFunctionIndex = enum(u32) {...@@ -386,7 +386,7 @@ pub const OutputFunctionIndex = enum(u32) {
386 }386 }
387387
388 pub fn fromFunctionIndex(wasm: *const Wasm, index: FunctionIndex) OutputFunctionIndex {388 pub fn fromFunctionIndex(wasm: *const Wasm, index: FunctionIndex) OutputFunctionIndex {
389 return @enumFromInt(wasm.function_imports.entries.len + @intFromEnum(index));389 return @enumFromInt(wasm.flush_buffer.function_imports.entries.len + @intFromEnum(index));
390 }390 }
391391
392 pub fn fromObjectFunction(wasm: *const Wasm, index: ObjectFunctionIndex) OutputFunctionIndex {392 pub fn fromObjectFunction(wasm: *const Wasm, index: ObjectFunctionIndex) OutputFunctionIndex {
...@@ -410,8 +410,7 @@ pub const OutputFunctionIndex = enum(u32) {...@@ -410,8 +410,7 @@ pub const OutputFunctionIndex = enum(u32) {
410 return switch (ip.indexToKey(ip_index)) {410 return switch (ip.indexToKey(ip_index)) {
411 .@"extern" => |ext| {411 .@"extern" => |ext| {
412 const name = wasm.getExistingString(ext.name.toSlice(ip)).?;412 const name = wasm.getExistingString(ext.name.toSlice(ip)).?;
413 if (wasm.function_imports.getIndex(name)) |i| return @enumFromInt(i);413 return fromSymbolName(wasm, name);
414 return fromFunctionIndex(wasm, FunctionIndex.fromSymbolName(wasm, name).?);
415 },414 },
416 else => fromResolution(wasm, .fromIpIndex(wasm, ip_index)).?,415 else => fromResolution(wasm, .fromIpIndex(wasm, ip_index)).?,
417 };416 };
...@@ -3424,7 +3423,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v...@@ -3424,7 +3423,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
3424 }3423 }
3425 }3424 }
3426 wasm.functions_end_prelink = @intCast(wasm.functions.entries.len);3425 wasm.functions_end_prelink = @intCast(wasm.functions.entries.len);
3427 wasm.function_exports_len = @intCast(wasm.function_exports.items.len);3426 wasm.function_exports_len = @intCast(wasm.function_exports.entries.len);
34283427
3429 for (wasm.object_global_imports.keys(), wasm.object_global_imports.values(), 0..) |name, *import, i| {3428 for (wasm.object_global_imports.keys(), wasm.object_global_imports.values(), 0..) |name, *import, i| {
3430 if (import.flags.isIncluded(rdynamic)) {3429 if (import.flags.isIncluded(rdynamic)) {
...@@ -3498,10 +3497,8 @@ fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex) link.File.FlushError!void {...@@ -3498,10 +3497,8 @@ fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex) link.File.FlushError!void {
3498 const function = i.ptr(wasm);3497 const function = i.ptr(wasm);
3499 markObject(wasm, function.object_index);3498 markObject(wasm, function.object_index);
35003499
3501 if (!is_obj and function.flags.isExported(rdynamic)) try wasm.function_exports.append(gpa, .{3500 if (!is_obj and function.flags.isExported(rdynamic))
3502 .name = function.name.unwrap().?,3501 try wasm.function_exports.put(gpa, function.name.unwrap().?, @enumFromInt(gop.index));
3503 .function_index = @enumFromInt(gop.index),
3504 });
35053502
3506 try wasm.markRelocations(function.relocations(wasm));3503 try wasm.markRelocations(function.relocations(wasm));
3507}3504}
src/link/Wasm/Flush.zig+6-8
...@@ -167,10 +167,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -167,10 +167,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
167 for (wasm.nav_exports.keys()) |*nav_export| {167 for (wasm.nav_exports.keys()) |*nav_export| {
168 if (ip.isFunctionType(ip.getNav(nav_export.nav_index).typeOf(ip))) {168 if (ip.isFunctionType(ip.getNav(nav_export.nav_index).typeOf(ip))) {
169 log.debug("flush export '{s}' nav={d}", .{ nav_export.name.slice(wasm), nav_export.nav_index });169 log.debug("flush export '{s}' nav={d}", .{ nav_export.name.slice(wasm), nav_export.nav_index });
170 try wasm.function_exports.append(gpa, .{170 try wasm.function_exports.put(gpa, nav_export.name, Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?);
171 .name = nav_export.name,
172 .function_index = Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?,
173 });
174 _ = f.missing_exports.swapRemove(nav_export.name);171 _ = f.missing_exports.swapRemove(nav_export.name);
175 _ = f.function_imports.swapRemove(nav_export.name);172 _ = f.function_imports.swapRemove(nav_export.name);
176173
...@@ -671,15 +668,15 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -671,15 +668,15 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
671 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);668 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
672 var exports_len: usize = 0;669 var exports_len: usize = 0;
673670
674 for (wasm.function_exports.items) |exp| {671 for (wasm.function_exports.keys(), wasm.function_exports.values()) |exp_name, function_index| {
675 const name = exp.name.slice(wasm);672 const name = exp_name.slice(wasm);
676 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));673 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));
677 try binary_bytes.appendSlice(gpa, name);674 try binary_bytes.appendSlice(gpa, name);
678 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.function));675 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.function));
679 const func_index = Wasm.OutputFunctionIndex.fromFunctionIndex(wasm, exp.function_index);676 const func_index = Wasm.OutputFunctionIndex.fromFunctionIndex(wasm, function_index);
680 try leb.writeUleb128(binary_writer, @intFromEnum(func_index));677 try leb.writeUleb128(binary_writer, @intFromEnum(func_index));
681 }678 }
682 exports_len += wasm.function_exports.items.len;679 exports_len += wasm.function_exports.entries.len;
683680
684 // No table exports.681 // No table exports.
685682
...@@ -709,6 +706,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -709,6 +706,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
709 }706 }
710 }707 }
711708
709 // start section
712 if (Wasm.OutputFunctionIndex.fromResolution(wasm, wasm.entry_resolution)) |func_index| {710 if (Wasm.OutputFunctionIndex.fromResolution(wasm, wasm.entry_resolution)) |func_index| {
713 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);711 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
714 replaceVecSectionHeader(binary_bytes, header_offset, .start, @intFromEnum(func_index));712 replaceVecSectionHeader(binary_bytes, header_offset, .start, @intFromEnum(func_index));