authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-11 16:41:11-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:35-08:00
log26c38b2d42ca3d68a8964c83a86a7e69f0990019
tree8f8b7246fbcd6997b3f23ff2b86dd47b7229eabc
parent031c84c8cb29e9b22cd5a131c147d3910c5ba345

wasm linker: support export section as implicit symbols


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

src/link/Wasm.zig+13-1
...@@ -894,6 +894,15 @@ pub const ObjectGlobalIndex = enum(u32) {...@@ -894,6 +894,15 @@ pub const ObjectGlobalIndex = enum(u32) {
894 _,894 _,
895};895};
896896
897/// Index into `Wasm.object_memories`.
898pub const ObjectMemoryIndex = enum(u32) {
899 _,
900
901 pub fn ptr(index: ObjectMemoryIndex, wasm: *const Wasm) *std.wasm.Memory {
902 return &wasm.object_memories.items[@intFromEnum(index)];
903 }
904};
905
897/// Index into `object_functions`.906/// Index into `object_functions`.
898pub const ObjectFunctionIndex = enum(u32) {907pub const ObjectFunctionIndex = enum(u32) {
899 _,908 _,
...@@ -2609,7 +2618,10 @@ pub fn addExpr(wasm: *Wasm, bytes: []const u8) Allocator.Error!Expr {...@@ -2609,7 +2618,10 @@ pub fn addExpr(wasm: *Wasm, bytes: []const u8) Allocator.Error!Expr {
2609pub fn addRelocatableDataPayload(wasm: *Wasm, bytes: []const u8) Allocator.Error!DataSegment.Payload {2618pub fn addRelocatableDataPayload(wasm: *Wasm, bytes: []const u8) Allocator.Error!DataSegment.Payload {
2610 const gpa = wasm.base.comp.gpa;2619 const gpa = wasm.base.comp.gpa;
2611 try wasm.string_bytes.appendSlice(gpa, bytes);2620 try wasm.string_bytes.appendSlice(gpa, bytes);
2612 return @enumFromInt(wasm.string_bytes.items.len - bytes.len);2621 return .{
2622 .off = @intCast(wasm.string_bytes.items.len - bytes.len),
2623 .len = @intCast(bytes.len),
2624 };
2613}2625}
26142626
2615pub fn uavSymbolIndex(wasm: *Wasm, ip_index: InternPool.Index) Allocator.Error!SymbolTableIndex {2627pub fn uavSymbolIndex(wasm: *Wasm, ip_index: InternPool.Index) Allocator.Error!SymbolTableIndex {
src/link/Wasm/Object.zig+40-12
...@@ -122,6 +122,19 @@ pub const ScratchSpace = struct {...@@ -122,6 +122,19 @@ pub const ScratchSpace = struct {
122 func_imports: std.ArrayListUnmanaged(FunctionImport) = .empty,122 func_imports: std.ArrayListUnmanaged(FunctionImport) = .empty,
123 symbol_table: std.ArrayListUnmanaged(Symbol) = .empty,123 symbol_table: std.ArrayListUnmanaged(Symbol) = .empty,
124 segment_info: std.ArrayListUnmanaged(SegmentInfo) = .empty,124 segment_info: std.ArrayListUnmanaged(SegmentInfo) = .empty,
125 exports: std.ArrayListUnmanaged(Export) = .empty,
126
127 const Export = struct {
128 name: Wasm.String,
129 pointee: Pointee,
130
131 const Pointee = union(std.wasm.ExternalKind) {
132 function: Wasm.ObjectFunctionIndex,
133 table: Wasm.ObjectTableIndex,
134 memory: Wasm.ObjectMemoryIndex,
135 global: Wasm.ObjectGlobalIndex,
136 };
137 };
125138
126 /// Index into `func_imports`.139 /// Index into `func_imports`.
127 const FuncImportIndex = enum(u32) {140 const FuncImportIndex = enum(u32) {
...@@ -142,6 +155,7 @@ pub const ScratchSpace = struct {...@@ -142,6 +155,7 @@ pub const ScratchSpace = struct {
142 };155 };
143156
144 pub fn deinit(ss: *ScratchSpace, gpa: Allocator) void {157 pub fn deinit(ss: *ScratchSpace, gpa: Allocator) void {
158 ss.exports.deinit(gpa);
145 ss.func_types.deinit(gpa);159 ss.func_types.deinit(gpa);
146 ss.func_type_indexes.deinit(gpa);160 ss.func_type_indexes.deinit(gpa);
147 ss.func_imports.deinit(gpa);161 ss.func_imports.deinit(gpa);
...@@ -151,6 +165,7 @@ pub const ScratchSpace = struct {...@@ -151,6 +165,7 @@ pub const ScratchSpace = struct {
151 }165 }
152166
153 fn clear(ss: *ScratchSpace) void {167 fn clear(ss: *ScratchSpace) void {
168 ss.exports.clearRetainingCapacity();
154 ss.func_types.clearRetainingCapacity();169 ss.func_types.clearRetainingCapacity();
155 ss.func_type_indexes.clearRetainingCapacity();170 ss.func_type_indexes.clearRetainingCapacity();
156 ss.func_imports.clearRetainingCapacity();171 ss.func_imports.clearRetainingCapacity();
...@@ -622,24 +637,22 @@ pub fn parse(...@@ -622,24 +637,22 @@ pub fn parse(
622 },637 },
623 .@"export" => {638 .@"export" => {
624 const exports_len, pos = readLeb(u32, bytes, pos);639 const exports_len, pos = readLeb(u32, bytes, pos);
625 // TODO: instead, read into scratch space, and then later640 // Read into scratch space, and then later add this data as if
626 // add this data as if it were extra symbol table entries,641 // it were extra symbol table entries, but allow merging with
627 // but allow merging with existing symbol table data if the name matches.642 // existing symbol table data if the name matches.
628 for (try wasm.object_exports.addManyAsSlice(gpa, exports_len)) |*exp| {643 for (try ss.exports.addManyAsSlice(gpa, exports_len)) |*exp| {
629 const name, pos = readBytes(bytes, pos);644 const name, pos = readBytes(bytes, pos);
630 const kind: std.wasm.ExternalKind = @enumFromInt(bytes[pos]);645 const kind: std.wasm.ExternalKind = @enumFromInt(bytes[pos]);
631 pos += 1;646 pos += 1;
632 const index, pos = readLeb(u32, bytes, pos);647 const index, pos = readLeb(u32, bytes, pos);
633 const rebased_index = index + switch (kind) {
634 .function => functions_start,
635 .table => tables_start,
636 .memory => memories_start,
637 .global => globals_start,
638 };
639 exp.* = .{648 exp.* = .{
640 .name = try wasm.internString(name),649 .name = try wasm.internString(name),
641 .kind = kind,650 .pointee = switch (kind) {
642 .index = rebased_index,651 .function => .{ .function = @enumFromInt(functions_start + index) },
652 .table => .{ .table = @enumFromInt(tables_start + index) },
653 .memory => .{ .memory = @enumFromInt(memories_start + index) },
654 .global => .{ .global = @enumFromInt(globals_start + index) },
655 },
643 };656 };
644 }657 }
645 },658 },
...@@ -828,6 +841,21 @@ pub fn parse(...@@ -828,6 +841,21 @@ pub fn parse(
828 },841 },
829 };842 };
830843
844 // Apply export section info. This is done after the symbol table above so
845 // that the symbol table can take precedence, overriding the export name.
846 for (ss.exports.items) |*exp| {
847 switch (exp.pointee) {
848 inline .function, .table, .memory, .global => |index| {
849 const ptr = index.ptr(wasm);
850 if (ptr.name == .none) {
851 // Missng symbol table entry; use defaults for exported things.
852 ptr.name = exp.name.toOptional();
853 ptr.flags.exported = true;
854 }
855 },
856 }
857 }
858
831 // Apply segment_info.859 // Apply segment_info.
832 for (wasm.object_data_segments.items[data_segment_start..], ss.segment_info.items) |*data, info| {860 for (wasm.object_data_segments.items[data_segment_start..], ss.segment_info.items) |*data, info| {
833 data.name = info.name.toOptional();861 data.name = info.name.toOptional();