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) {
894894 _,
895895};
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
897906/// Index into `object_functions`.
898907pub const ObjectFunctionIndex = enum(u32) {
899908 _,
......@@ -2609,7 +2618,10 @@ pub fn addExpr(wasm: *Wasm, bytes: []const u8) Allocator.Error!Expr {
26092618pub fn addRelocatableDataPayload(wasm: *Wasm, bytes: []const u8) Allocator.Error!DataSegment.Payload {
26102619 const gpa = wasm.base.comp.gpa;
26112620 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 };
26132625}
26142626
26152627pub 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 {
122122 func_imports: std.ArrayListUnmanaged(FunctionImport) = .empty,
123123 symbol_table: std.ArrayListUnmanaged(Symbol) = .empty,
124124 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
126139 /// Index into `func_imports`.
127140 const FuncImportIndex = enum(u32) {
......@@ -142,6 +155,7 @@ pub const ScratchSpace = struct {
142155 };
143156
144157 pub fn deinit(ss: *ScratchSpace, gpa: Allocator) void {
158 ss.exports.deinit(gpa);
145159 ss.func_types.deinit(gpa);
146160 ss.func_type_indexes.deinit(gpa);
147161 ss.func_imports.deinit(gpa);
......@@ -151,6 +165,7 @@ pub const ScratchSpace = struct {
151165 }
152166
153167 fn clear(ss: *ScratchSpace) void {
168 ss.exports.clearRetainingCapacity();
154169 ss.func_types.clearRetainingCapacity();
155170 ss.func_type_indexes.clearRetainingCapacity();
156171 ss.func_imports.clearRetainingCapacity();
......@@ -622,24 +637,22 @@ pub fn parse(
622637 },
623638 .@"export" => {
624639 const exports_len, pos = readLeb(u32, bytes, pos);
625 // TODO: instead, read into scratch space, and then later
626 // add this data as if it were extra symbol table entries,
627 // but allow merging with existing symbol table data if the name matches.
628 for (try wasm.object_exports.addManyAsSlice(gpa, exports_len)) |*exp| {
640 // Read into scratch space, and then later add this data as if
641 // it were extra symbol table entries, but allow merging with
642 // existing symbol table data if the name matches.
643 for (try ss.exports.addManyAsSlice(gpa, exports_len)) |*exp| {
629644 const name, pos = readBytes(bytes, pos);
630645 const kind: std.wasm.ExternalKind = @enumFromInt(bytes[pos]);
631646 pos += 1;
632647 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 };
639648 exp.* = .{
640649 .name = try wasm.internString(name),
641 .kind = kind,
642 .index = rebased_index,
650 .pointee = switch (kind) {
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 },
643656 };
644657 }
645658 },
......@@ -828,6 +841,21 @@ pub fn parse(
828841 },
829842 };
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
831859 // Apply segment_info.
832860 for (wasm.object_data_segments.items[data_segment_start..], ss.segment_info.items) |*data, info| {
833861 data.name = info.name.toOptional();