diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2024-12-11 16:41:11 -0800 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2025-01-15 15:11:35 -0800 |
| commit | 26c38b2d42ca3d68a8964c83a86a7e69f0990019 (patch) | |
| tree | 8f8b7246fbcd6997b3f23ff2b86dd47b7229eabc /src | |
| parent | 031c84c8cb29e9b22cd5a131c147d3910c5ba345 (diff) | |
| download | zig-26c38b2d42ca3d68a8964c83a86a7e69f0990019.tar.gz zig-26c38b2d42ca3d68a8964c83a86a7e69f0990019.zip | |
wasm linker: support export section as implicit symbols
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/Wasm.zig | 14 | ||||
| -rw-r--r-- | src/link/Wasm/Object.zig | 52 |
2 files changed, 53 insertions, 13 deletions
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 464e2f26ef..8bca993daa 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -894,6 +894,15 @@ pub const ObjectGlobalIndex = enum(u32) { _, }; +/// Index into `Wasm.object_memories`. +pub const ObjectMemoryIndex = enum(u32) { + _, + + pub fn ptr(index: ObjectMemoryIndex, wasm: *const Wasm) *std.wasm.Memory { + return &wasm.object_memories.items[@intFromEnum(index)]; + } +}; + /// Index into `object_functions`. pub const ObjectFunctionIndex = enum(u32) { _, @@ -2609,7 +2618,10 @@ pub fn addExpr(wasm: *Wasm, bytes: []const u8) Allocator.Error!Expr { pub fn addRelocatableDataPayload(wasm: *Wasm, bytes: []const u8) Allocator.Error!DataSegment.Payload { const gpa = wasm.base.comp.gpa; try wasm.string_bytes.appendSlice(gpa, bytes); - return @enumFromInt(wasm.string_bytes.items.len - bytes.len); + return .{ + .off = @intCast(wasm.string_bytes.items.len - bytes.len), + .len = @intCast(bytes.len), + }; } pub fn uavSymbolIndex(wasm: *Wasm, ip_index: InternPool.Index) Allocator.Error!SymbolTableIndex { diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig index 15ac0ad145..d46bef6371 100644 --- a/src/link/Wasm/Object.zig +++ b/src/link/Wasm/Object.zig @@ -122,6 +122,19 @@ pub const ScratchSpace = struct { func_imports: std.ArrayListUnmanaged(FunctionImport) = .empty, symbol_table: std.ArrayListUnmanaged(Symbol) = .empty, segment_info: std.ArrayListUnmanaged(SegmentInfo) = .empty, + exports: std.ArrayListUnmanaged(Export) = .empty, + + const Export = struct { + name: Wasm.String, + pointee: Pointee, + + const Pointee = union(std.wasm.ExternalKind) { + function: Wasm.ObjectFunctionIndex, + table: Wasm.ObjectTableIndex, + memory: Wasm.ObjectMemoryIndex, + global: Wasm.ObjectGlobalIndex, + }; + }; /// Index into `func_imports`. const FuncImportIndex = enum(u32) { @@ -142,6 +155,7 @@ pub const ScratchSpace = struct { }; pub fn deinit(ss: *ScratchSpace, gpa: Allocator) void { + ss.exports.deinit(gpa); ss.func_types.deinit(gpa); ss.func_type_indexes.deinit(gpa); ss.func_imports.deinit(gpa); @@ -151,6 +165,7 @@ pub const ScratchSpace = struct { } fn clear(ss: *ScratchSpace) void { + ss.exports.clearRetainingCapacity(); ss.func_types.clearRetainingCapacity(); ss.func_type_indexes.clearRetainingCapacity(); ss.func_imports.clearRetainingCapacity(); @@ -622,24 +637,22 @@ pub fn parse( }, .@"export" => { const exports_len, pos = readLeb(u32, bytes, pos); - // TODO: instead, read into scratch space, and then later - // add this data as if it were extra symbol table entries, - // but allow merging with existing symbol table data if the name matches. - for (try wasm.object_exports.addManyAsSlice(gpa, exports_len)) |*exp| { + // Read into scratch space, and then later add this data as if + // it were extra symbol table entries, but allow merging with + // existing symbol table data if the name matches. + for (try ss.exports.addManyAsSlice(gpa, exports_len)) |*exp| { const name, pos = readBytes(bytes, pos); const kind: std.wasm.ExternalKind = @enumFromInt(bytes[pos]); pos += 1; const index, pos = readLeb(u32, bytes, pos); - const rebased_index = index + switch (kind) { - .function => functions_start, - .table => tables_start, - .memory => memories_start, - .global => globals_start, - }; exp.* = .{ .name = try wasm.internString(name), - .kind = kind, - .index = rebased_index, + .pointee = switch (kind) { + .function => .{ .function = @enumFromInt(functions_start + index) }, + .table => .{ .table = @enumFromInt(tables_start + index) }, + .memory => .{ .memory = @enumFromInt(memories_start + index) }, + .global => .{ .global = @enumFromInt(globals_start + index) }, + }, }; } }, @@ -828,6 +841,21 @@ pub fn parse( }, }; + // Apply export section info. This is done after the symbol table above so + // that the symbol table can take precedence, overriding the export name. + for (ss.exports.items) |*exp| { + switch (exp.pointee) { + inline .function, .table, .memory, .global => |index| { + const ptr = index.ptr(wasm); + if (ptr.name == .none) { + // Missng symbol table entry; use defaults for exported things. + ptr.name = exp.name.toOptional(); + ptr.flags.exported = true; + } + }, + } + } + // Apply segment_info. for (wasm.object_data_segments.items[data_segment_start..], ss.segment_info.items) |*data, info| { data.name = info.name.toOptional(); |
