authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-08-08 01:43:21+02:00
committergravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-08-11 20:00:12+02:00
logcce0b43270a57a884e7d7aeba25bc6953741156e
tree00be505cace3741b3ae69dd98e910302bb0a46ff
parent9d92d2ce93c52083fe405716a6cf05151384b76e

wasm: change symbol name for function if it uses library name

Fixes bug when `fn "js" log(...)` collide with compiler-rt `log` symbol, to fix I reuse logic/idea from llvm backend.

2 files changed, 28 insertions(+), 13 deletions(-)

src/link/Wasm.zig+24-11
...@@ -187,7 +187,7 @@ overaligned_uavs: std.array_hash_map.Auto(InternPool.Index, Alignment) = .empty,...@@ -187,7 +187,7 @@ overaligned_uavs: std.array_hash_map.Auto(InternPool.Index, Alignment) = .empty,
187zcu_funcs: std.array_hash_map.Auto(InternPool.Index, ZcuFunc) = .empty,187zcu_funcs: std.array_hash_map.Auto(InternPool.Index, ZcuFunc) = .empty,
188nav_exports: std.array_hash_map.Auto(NavExport, Zcu.Export.Index) = .empty,188nav_exports: std.array_hash_map.Auto(NavExport, Zcu.Export.Index) = .empty,
189uav_exports: std.array_hash_map.Auto(UavExport, Zcu.Export.Index) = .empty,189uav_exports: std.array_hash_map.Auto(UavExport, Zcu.Export.Index) = .empty,
190imports: std.array_hash_map.Auto(InternPool.Nav.Index, void) = .empty,190imports: std.array_hash_map.Auto(InternPool.Nav.Index, String) = .empty,
191191
192dwarf: ?Dwarf = null,192dwarf: ?Dwarf = null,
193193
...@@ -409,7 +409,7 @@ pub const OutputFunctionIndex = enum(u32) {...@@ -409,7 +409,7 @@ pub const OutputFunctionIndex = enum(u32) {
409 const ip = &zcu.intern_pool;409 const ip = &zcu.intern_pool;
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.imports.get(ext.owner_nav).?;
413 return fromSymbolName(wasm, name);413 return fromSymbolName(wasm, name);
414 },414 },
415 else => fromResolution(wasm, .fromIpIndex(wasm, ip_index)).?,415 else => fromResolution(wasm, .fromIpIndex(wasm, ip_index)).?,
...@@ -479,8 +479,8 @@ pub const OutputDataIndex = enum(u32) {...@@ -479,8 +479,8 @@ pub const OutputDataIndex = enum(u32) {
479 const zcu = wasm.base.comp.zcu.?;479 const zcu = wasm.base.comp.zcu.?;
480 const ip = &zcu.intern_pool;480 const ip = &zcu.intern_pool;
481 const nav = ip.getNav(nav_index);481 const nav = ip.getNav(nav_index);
482 if (nav.getExtern(ip)) |ext| {482 if (nav.getExtern(ip) != null) {
483 return fromSymbolName(wasm, wasm.getExistingString(ext.name.toSlice(ip)).?);483 return fromSymbolName(wasm, wasm.imports.get(nav_index).?);
484 }484 }
485 const resolution: ObjectDataImport.Resolution = if (wasm.base.comp.config.output_mode == .Obj)485 const resolution: ObjectDataImport.Resolution = if (wasm.base.comp.config.output_mode == .Obj)
486 .pack(wasm, .{ .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(nav_index).?)) })486 .pack(wasm, .{ .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(nav_index).?)) })
...@@ -2592,6 +2592,10 @@ pub const ZcuImportIndex = enum(u32) {...@@ -2592,6 +2592,10 @@ pub const ZcuImportIndex = enum(u32) {
2592 return &wasm.imports.keys()[@backingInt(index)];2592 return &wasm.imports.keys()[@backingInt(index)];
2593 }2593 }
25942594
2595 pub fn symbolName(index: ZcuImportIndex, wasm: *const Wasm) String {
2596 return wasm.imports.values()[@backingInt(index)];
2597 }
2598
2595 pub fn flags(index: ZcuImportIndex, wasm: *const Wasm) SymbolFlags {2599 pub fn flags(index: ZcuImportIndex, wasm: *const Wasm) SymbolFlags {
2596 const zcu = wasm.base.comp.zcu.?;2600 const zcu = wasm.base.comp.zcu.?;
2597 const ip = &zcu.intern_pool;2601 const ip = &zcu.intern_pool;
...@@ -2613,7 +2617,7 @@ pub const ZcuImportIndex = enum(u32) {...@@ -2613,7 +2617,7 @@ pub const ZcuImportIndex = enum(u32) {
2613 },2617 },
2614 .undefined = true,2618 .undefined = true,
2615 .exported = wasm.missing_exports.contains(name_string),2619 .exported = wasm.missing_exports.contains(name_string),
2616 .explicit_name = false,2620 .explicit_name = index.symbolName(wasm) != name_string,
2617 .no_strip = false,2621 .no_strip = false,
2618 .tls = ext.is_threadlocal,2622 .tls = ext.is_threadlocal,
2619 .absolute = false,2623 .absolute = false,
...@@ -3683,14 +3687,23 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index...@@ -3683,14 +3687,23 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
3683 } else {3687 } else {
3684 assert(!wasm.navs_exe.contains(ext.owner_nav));3688 assert(!wasm.navs_exe.contains(ext.owner_nav));
3685 }3689 }
3686 const name = try wasm.internString(ext.name.toSlice(ip));3690 const name_slice = ext.name.toSlice(ip);
3687 if (ext.lib_name.toSlice(ip)) |ext_name| _ = try wasm.internString(ext_name);3691 const name = try wasm.internString(name_slice);
3692 const symbol_name = if (ip.isFunctionType(nav.resolved.?.type)) symbol_name: {
3693 const lib_name = ext.lib_name.toSlice(ip) orelse break :symbol_name name;
3694 _ = try wasm.internString(lib_name);
3695 // match llvm backend behavior
3696 if (mem.eql(u8, lib_name, "c")) break :symbol_name name;
3697 const qualified_name = try std.fmt.allocPrint(gpa, "{s}|{s}", .{ name_slice, lib_name });
3698 defer gpa.free(qualified_name);
3699 break :symbol_name try wasm.internString(qualified_name);
3700 } else name;
3688 try wasm.imports.ensureUnusedCapacity(gpa, 1);3701 try wasm.imports.ensureUnusedCapacity(gpa, 1);
3689 try wasm.function_imports.ensureUnusedCapacity(gpa, 1);3702 try wasm.function_imports.ensureUnusedCapacity(gpa, 1);
3690 try wasm.data_imports.ensureUnusedCapacity(gpa, 1);3703 try wasm.data_imports.ensureUnusedCapacity(gpa, 1);
3691 const zcu_import = wasm.addZcuImportReserved(ext.owner_nav);3704 const zcu_import = wasm.addZcuImportReserved(ext.owner_nav, symbol_name);
3692 if (ip.isFunctionType(nav.resolved.?.type)) {3705 if (ip.isFunctionType(nav.resolved.?.type)) {
3693 wasm.function_imports.putAssumeCapacity(name, .fromZcuImport(zcu_import, wasm));3706 wasm.function_imports.putAssumeCapacity(symbol_name, .fromZcuImport(zcu_import, wasm));
3694 // Ensure there is a corresponding function type table entry.3707 // Ensure there is a corresponding function type table entry.
3695 const fn_info = zcu.typeToFunc(.fromInterned(ext.ty)).?;3708 const fn_info = zcu.typeToFunc(.fromInterned(ext.ty)).?;
3696 _ = try internFunctionType(wasm, fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), fn_info.is_var_args, target);3709 _ = try internFunctionType(wasm, fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), fn_info.is_var_args, target);
...@@ -5073,9 +5086,9 @@ fn pointerSize(wasm: *const Wasm) u32 {...@@ -5073,9 +5086,9 @@ fn pointerSize(wasm: *const Wasm) u32 {
5073 };5086 };
5074}5087}
50755088
5076fn addZcuImportReserved(wasm: *Wasm, nav_index: InternPool.Nav.Index) ZcuImportIndex {5089fn addZcuImportReserved(wasm: *Wasm, nav_index: InternPool.Nav.Index, symbol_name: String) ZcuImportIndex {
5077 const gop = wasm.imports.getOrPutAssumeCapacity(nav_index);5090 const gop = wasm.imports.getOrPutAssumeCapacity(nav_index);
5078 gop.value_ptr.* = {};5091 gop.value_ptr.* = symbol_name;
5079 return @fromBackingInt(@intCast(gop.index));5092 return @fromBackingInt(@intCast(gop.index));
5080}5093}
50815094
src/link/Wasm/Flush.zig+4-2
...@@ -1472,14 +1472,16 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -1472,14 +1472,16 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
1472 // SYMTAB_FUNCTION1472 // SYMTAB_FUNCTION
1473 {1473 {
1474 symbol_table_offsets.function = symbol_count;1474 symbol_table_offsets.function = symbol_count;
1475 for (f.function_imports.values(), 0..) |i, function_index| {1475 for (f.function_imports.keys(), f.function_imports.values(), 0..) |symbol_name, i, function_index| {
1476 try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.function));1476 try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.function));
1477 const flags = i.flags(wasm);1477 const flags = i.flags(wasm);
1478 assert(flags.undefined);1478 assert(flags.undefined);
1479 try appendLeb128(gpa, binary_bytes, flags.toAbiInteger());1479 try appendLeb128(gpa, binary_bytes, flags.toAbiInteger());
1480 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index)));1480 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index)));
1481 if (flags.explicit_name) {1481 if (flags.explicit_name) {
1482 unreachable; // never set1482 const name = symbol_name.slice(wasm);
1483 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1484 try binary_bytes.appendSlice(gpa, name);
1483 }1485 }
1484 symbol_count += 1;1486 symbol_count += 1;
1485 }1487 }