authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-29 20:21:26-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:36-08:00
log7d224516c4414015186bc1497ca6641b7390bf92
treeaa703daf59107ff10601ad1c626ff9c18ea11a0c
parentc5822879a1da97e6c381c6684f4b9281400e5de0

wasm linker: chase relocations for references


5 files changed, 601 insertions(+), 353 deletions(-)

src/arch/wasm/Emit.zig+8-8
...@@ -108,7 +108,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -108,7 +108,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
108 try wasm.out_relocs.append(gpa, .{108 try wasm.out_relocs.append(gpa, .{
109 .offset = @intCast(code.items.len),109 .offset = @intCast(code.items.len),
110 .pointee = .{ .symbol_index = try wasm.errorNameTableSymbolIndex() },110 .pointee = .{ .symbol_index = try wasm.errorNameTableSymbolIndex() },
111 .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64,111 .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64,
112 .addend = 0,112 .addend = 0,
113 });113 });
114 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);114 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);
...@@ -162,7 +162,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -162,7 +162,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
162 try wasm.out_relocs.append(gpa, .{162 try wasm.out_relocs.append(gpa, .{
163 .offset = @intCast(code.items.len),163 .offset = @intCast(code.items.len),
164 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(datas[inst].nav_index) },164 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(datas[inst].nav_index) },
165 .tag = .FUNCTION_INDEX_LEB,165 .tag = .function_index_leb,
166 .addend = 0,166 .addend = 0,
167 });167 });
168 code.appendNTimesAssumeCapacity(0, 5);168 code.appendNTimesAssumeCapacity(0, 5);
...@@ -182,7 +182,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -182,7 +182,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
182 try wasm.out_relocs.append(gpa, .{182 try wasm.out_relocs.append(gpa, .{
183 .offset = @intCast(code.items.len),183 .offset = @intCast(code.items.len),
184 .pointee = .{ .type_index = func_ty_index },184 .pointee = .{ .type_index = func_ty_index },
185 .tag = .TYPE_INDEX_LEB,185 .tag = .type_index_leb,
186 .addend = 0,186 .addend = 0,
187 });187 });
188 code.appendNTimesAssumeCapacity(0, 5);188 code.appendNTimesAssumeCapacity(0, 5);
...@@ -202,7 +202,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -202,7 +202,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
202 try wasm.out_relocs.append(gpa, .{202 try wasm.out_relocs.append(gpa, .{
203 .offset = @intCast(code.items.len),203 .offset = @intCast(code.items.len),
204 .pointee = .{ .symbol_index = try wasm.tagNameSymbolIndex(datas[inst].ip_index) },204 .pointee = .{ .symbol_index = try wasm.tagNameSymbolIndex(datas[inst].ip_index) },
205 .tag = .FUNCTION_INDEX_LEB,205 .tag = .function_index_leb,
206 .addend = 0,206 .addend = 0,
207 });207 });
208 code.appendNTimesAssumeCapacity(0, 5);208 code.appendNTimesAssumeCapacity(0, 5);
...@@ -226,7 +226,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -226,7 +226,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
226 try wasm.out_relocs.append(gpa, .{226 try wasm.out_relocs.append(gpa, .{
227 .offset = @intCast(code.items.len),227 .offset = @intCast(code.items.len),
228 .pointee = .{ .symbol_index = try wasm.symbolNameIndex(symbol_name) },228 .pointee = .{ .symbol_index = try wasm.symbolNameIndex(symbol_name) },
229 .tag = .FUNCTION_INDEX_LEB,229 .tag = .function_index_leb,
230 .addend = 0,230 .addend = 0,
231 });231 });
232 code.appendNTimesAssumeCapacity(0, 5);232 code.appendNTimesAssumeCapacity(0, 5);
...@@ -245,7 +245,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -245,7 +245,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
245 try wasm.out_relocs.append(gpa, .{245 try wasm.out_relocs.append(gpa, .{
246 .offset = @intCast(code.items.len),246 .offset = @intCast(code.items.len),
247 .pointee = .{ .symbol_index = try wasm.stackPointerSymbolIndex() },247 .pointee = .{ .symbol_index = try wasm.stackPointerSymbolIndex() },
248 .tag = .GLOBAL_INDEX_LEB,248 .tag = .global_index_leb,
249 .addend = 0,249 .addend = 0,
250 });250 });
251 code.appendNTimesAssumeCapacity(0, 5);251 code.appendNTimesAssumeCapacity(0, 5);
...@@ -922,7 +922,7 @@ fn uavRefOffObj(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.UavRef...@@ -922,7 +922,7 @@ fn uavRefOffObj(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.UavRef
922 try wasm.out_relocs.append(gpa, .{922 try wasm.out_relocs.append(gpa, .{
923 .offset = @intCast(code.items.len),923 .offset = @intCast(code.items.len),
924 .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(data.uav_obj.key(wasm).*) },924 .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(data.uav_obj.key(wasm).*) },
925 .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64,925 .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64,
926 .addend = data.offset,926 .addend = data.offset,
927 });927 });
928 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);928 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);
...@@ -957,7 +957,7 @@ fn navRefOff(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.NavRefOff...@@ -957,7 +957,7 @@ fn navRefOff(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.NavRefOff
957 try wasm.out_relocs.append(gpa, .{957 try wasm.out_relocs.append(gpa, .{
958 .offset = @intCast(code.items.len),958 .offset = @intCast(code.items.len),
959 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(data.nav_index) },959 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(data.nav_index) },
960 .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64,960 .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64,
961 .addend = data.offset,961 .addend = data.offset,
962 });962 });
963 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);963 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);
src/codegen.zig+2-2
...@@ -670,7 +670,7 @@ fn lowerUavRef(...@@ -670,7 +670,7 @@ fn lowerUavRef(
670 try wasm.out_relocs.append(gpa, .{670 try wasm.out_relocs.append(gpa, .{
671 .offset = @intCast(code.items.len),671 .offset = @intCast(code.items.len),
672 .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(uav.val) },672 .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(uav.val) },
673 .tag = if (ptr_width_bytes == 4) .MEMORY_ADDR_I32 else .MEMORY_ADDR_I64,673 .tag = if (ptr_width_bytes == 4) .memory_addr_i32 else .memory_addr_i64,
674 .addend = @intCast(offset),674 .addend = @intCast(offset),
675 });675 });
676 } else {676 } else {
...@@ -742,7 +742,7 @@ fn lowerNavRef(...@@ -742,7 +742,7 @@ fn lowerNavRef(
742 try wasm.out_relocs.append(gpa, .{742 try wasm.out_relocs.append(gpa, .{
743 .offset = @intCast(code.items.len),743 .offset = @intCast(code.items.len),
744 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(nav_index) },744 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(nav_index) },
745 .tag = if (ptr_width_bytes == 4) .MEMORY_ADDR_I32 else .MEMORY_ADDR_I64,745 .tag = if (ptr_width_bytes == 4) .memory_addr_i32 else .memory_addr_i64,
746 .addend = @intCast(offset),746 .addend = @intCast(offset),
747 });747 });
748 } else {748 } else {
src/link/Wasm.zig+385-130
...@@ -93,13 +93,13 @@ func_types: std.AutoArrayHashMapUnmanaged(FunctionType, void) = .empty,...@@ -93,13 +93,13 @@ func_types: std.AutoArrayHashMapUnmanaged(FunctionType, void) = .empty,
93/// Local functions may be unnamed.93/// Local functions may be unnamed.
94object_function_imports: std.AutoArrayHashMapUnmanaged(String, FunctionImport) = .empty,94object_function_imports: std.AutoArrayHashMapUnmanaged(String, FunctionImport) = .empty,
95/// All functions for all objects.95/// All functions for all objects.
96object_functions: std.ArrayListUnmanaged(Function) = .empty,96object_functions: std.ArrayListUnmanaged(ObjectFunction) = .empty,
9797
98/// Provides a mapping of both imports and provided globals to symbol name.98/// Provides a mapping of both imports and provided globals to symbol name.
99/// Local globals may be unnamed.99/// Local globals may be unnamed.
100object_global_imports: std.AutoArrayHashMapUnmanaged(String, GlobalImport) = .empty,100object_global_imports: std.AutoArrayHashMapUnmanaged(String, GlobalImport) = .empty,
101/// All globals for all objects.101/// All globals for all objects.
102object_globals: std.ArrayListUnmanaged(Global) = .empty,102object_globals: std.ArrayListUnmanaged(ObjectGlobal) = .empty,
103103
104/// All table imports for all objects.104/// All table imports for all objects.
105object_table_imports: std.AutoArrayHashMapUnmanaged(String, TableImport) = .empty,105object_table_imports: std.AutoArrayHashMapUnmanaged(String, TableImport) = .empty,
...@@ -386,7 +386,7 @@ pub const GlobalIndex = enum(u32) {...@@ -386,7 +386,7 @@ pub const GlobalIndex = enum(u32) {
386 pub const stack_pointer: GlobalIndex = @enumFromInt(0);386 pub const stack_pointer: GlobalIndex = @enumFromInt(0);
387387
388 /// Same as `stack_pointer` but with a safety assertion.388 /// Same as `stack_pointer` but with a safety assertion.
389 pub fn stackPointer(wasm: *const Wasm) Global.Index {389 pub fn stackPointer(wasm: *const Wasm) ObjectGlobal.Index {
390 const comp = wasm.base.comp;390 const comp = wasm.base.comp;
391 assert(comp.config.output_mode != .Obj);391 assert(comp.config.output_mode != .Obj);
392 assert(comp.zcu != null);392 assert(comp.zcu != null);
...@@ -513,26 +513,19 @@ pub const SymbolFlags = packed struct(u32) {...@@ -513,26 +513,19 @@ pub const SymbolFlags = packed struct(u32) {
513513
514 // Above here matches the tooling conventions ABI.514 // Above here matches the tooling conventions ABI.
515515
516 padding1: u5 = 0,516 padding1: u13 = 0,
517 /// Zig-specific. Dead things are allowed to be garbage collected.517 /// Zig-specific. Dead things are allowed to be garbage collected.
518 alive: bool = false,518 alive: bool = false,
519 /// Zig-specific. Segments only. Signals that the segment contains only
520 /// null terminated strings allowing the linker to perform merging.
521 strings: bool = false,
522 /// Zig-specific. This symbol comes from an object that must be included in519 /// Zig-specific. This symbol comes from an object that must be included in
523 /// the final link.520 /// the final link.
524 must_link: bool = false,521 must_link: bool = false,
525 /// Zig-specific. Data segments only.522 /// Zig-specific.
526 is_passive: bool = false,
527 /// Zig-specific. Data segments only.
528 alignment: Alignment = .none,
529 /// Zig-specific. Globals only.
530 global_type: GlobalType4 = .zero,523 global_type: GlobalType4 = .zero,
531 /// Zig-specific. Tables only.524 /// Zig-specific.
532 limits_has_max: bool = false,525 limits_has_max: bool = false,
533 /// Zig-specific. Tables only.526 /// Zig-specific.
534 limits_is_shared: bool = false,527 limits_is_shared: bool = false,
535 /// Zig-specific. Tables only.528 /// Zig-specific.
536 ref_type: RefType1 = .funcref,529 ref_type: RefType1 = .funcref,
537530
538 pub const Binding = enum(u2) {531 pub const Binding = enum(u2) {
...@@ -554,10 +547,7 @@ pub const SymbolFlags = packed struct(u32) {...@@ -554,10 +547,7 @@ pub const SymbolFlags = packed struct(u32) {
554 pub fn initZigSpecific(flags: *SymbolFlags, must_link: bool, no_strip: bool) void {547 pub fn initZigSpecific(flags: *SymbolFlags, must_link: bool, no_strip: bool) void {
555 flags.no_strip = no_strip;548 flags.no_strip = no_strip;
556 flags.alive = false;549 flags.alive = false;
557 flags.strings = false;
558 flags.must_link = must_link;550 flags.must_link = must_link;
559 flags.is_passive = false;
560 flags.alignment = .none;
561 flags.global_type = .zero;551 flags.global_type = .zero;
562 flags.limits_has_max = false;552 flags.limits_has_max = false;
563 flags.limits_is_shared = false;553 flags.limits_is_shared = false;
...@@ -603,7 +593,7 @@ pub const GlobalType4 = packed struct(u4) {...@@ -603,7 +593,7 @@ pub const GlobalType4 = packed struct(u4) {
603593
604 pub const zero: GlobalType4 = @bitCast(@as(u4, 0));594 pub const zero: GlobalType4 = @bitCast(@as(u4, 0));
605595
606 pub fn to(gt: GlobalType4) Global.Type {596 pub fn to(gt: GlobalType4) ObjectGlobal.Type {
607 return .{597 return .{
608 .valtype = gt.valtype.to(),598 .valtype = gt.valtype.to(),
609 .mutable = gt.mutable,599 .mutable = gt.mutable,
...@@ -1001,18 +991,24 @@ pub const FunctionImport = extern struct {...@@ -1001,18 +991,24 @@ pub const FunctionImport = extern struct {
1001 };991 };
1002};992};
1003993
1004pub const Function = extern struct {994pub const ObjectFunction = extern struct {
1005 flags: SymbolFlags,995 flags: SymbolFlags,
1006 /// `none` if this function has no symbol describing it.996 /// `none` if this function has no symbol describing it.
1007 name: OptionalString,997 name: OptionalString,
1008 type_index: FunctionType.Index,998 type_index: FunctionType.Index,
1009 code: Code,999 code: Code,
1010 /// The offset within the section where the data starts.1000 /// The offset within the code section where the data starts.
1011 offset: u32,1001 offset: u32,
1012 section_index: ObjectSectionIndex,1002 /// The object file whose code section contains this function.
1013 source_location: SourceLocation,1003 object_index: ObjectIndex,
10141004
1015 pub const Code = DataPayload;1005 pub const Code = DataPayload;
1006
1007 fn relocations(of: *const ObjectFunction, wasm: *const Wasm) ObjectRelocation.IterableSlice {
1008 const code_section_index = of.object_index.ptr(wasm).code_section_index.?;
1009 const relocs = wasm.object_relocations_table.get(code_section_index) orelse return .empty;
1010 return .init(relocs, of.offset, of.code.len, wasm);
1011 }
1016};1012};
10171013
1018pub const GlobalImport = extern struct {1014pub const GlobalImport = extern struct {
...@@ -1101,6 +1097,10 @@ pub const GlobalImport = extern struct {...@@ -1101,6 +1097,10 @@ pub const GlobalImport = extern struct {
1101 });1097 });
1102 }1098 }
11031099
1100 fn fromObjectGlobal(wasm: *const Wasm, object_global: ObjectGlobalIndex) Resolution {
1101 return pack(wasm, .{ .object_global = object_global });
1102 }
1103
1104 pub fn name(r: Resolution, wasm: *const Wasm) ?[]const u8 {1104 pub fn name(r: Resolution, wasm: *const Wasm) ?[]const u8 {
1105 return switch (unpack(r, wasm)) {1105 return switch (unpack(r, wasm)) {
1106 .unresolved => unreachable,1106 .unresolved => unreachable,
...@@ -1137,22 +1137,32 @@ pub const GlobalImport = extern struct {...@@ -1137,22 +1137,32 @@ pub const GlobalImport = extern struct {
1137 return index.value(wasm).module_name;1137 return index.value(wasm).module_name;
1138 }1138 }
11391139
1140 pub fn globalType(index: Index, wasm: *const Wasm) Global.Type {1140 pub fn globalType(index: Index, wasm: *const Wasm) ObjectGlobal.Type {
1141 return value(index, wasm).flags.global_type.to();1141 return value(index, wasm).flags.global_type.to();
1142 }1142 }
1143 };1143 };
1144};1144};
11451145
1146pub const Global = extern struct {1146pub const ObjectGlobal = extern struct {
1147 /// `none` if this function has no symbol describing it.1147 /// `none` if this function has no symbol describing it.
1148 name: OptionalString,1148 name: OptionalString,
1149 flags: SymbolFlags,1149 flags: SymbolFlags,
1150 expr: Expr,1150 expr: Expr,
1151 /// The object file whose global section contains this global.
1152 object_index: ObjectIndex,
1153 offset: u32,
1154 size: u32,
11511155
1152 pub const Type = struct {1156 pub const Type = struct {
1153 valtype: std.wasm.Valtype,1157 valtype: std.wasm.Valtype,
1154 mutable: bool,1158 mutable: bool,
1155 };1159 };
1160
1161 fn relocations(og: *const ObjectGlobal, wasm: *const Wasm) ObjectRelocation.IterableSlice {
1162 const global_section_index = og.object_index.ptr(wasm).global_section_index.?;
1163 const relocs = wasm.object_relocations_table.get(global_section_index) orelse return .empty;
1164 return .init(relocs, og.offset, og.size, wasm);
1165 }
1156};1166};
11571167
1158pub const RefType1 = enum(u1) {1168pub const RefType1 = enum(u1) {
...@@ -1205,6 +1215,18 @@ pub const TableImport = extern struct {...@@ -1205,6 +1215,18 @@ pub const TableImport = extern struct {
1205 };1215 };
1206 }1216 }
12071217
1218 fn pack(unpacked: Unpacked) Resolution {
1219 return switch (unpacked) {
1220 .unresolved => .unresolved,
1221 .__indirect_function_table => .__indirect_function_table,
1222 .object_table => |i| @enumFromInt(first_object_table + @intFromEnum(i)),
1223 };
1224 }
1225
1226 fn fromObjectTable(object_table: ObjectTableIndex) Resolution {
1227 return pack(.{ .object_table = object_table });
1228 }
1229
1208 pub fn refType(r: Resolution, wasm: *const Wasm) std.wasm.RefType {1230 pub fn refType(r: Resolution, wasm: *const Wasm) std.wasm.RefType {
1209 return switch (unpack(r)) {1231 return switch (unpack(r)) {
1210 .unresolved => unreachable,1232 .unresolved => unreachable,
...@@ -1298,7 +1320,7 @@ pub const ObjectTableIndex = enum(u32) {...@@ -1298,7 +1320,7 @@ pub const ObjectTableIndex = enum(u32) {
1298pub const ObjectGlobalIndex = enum(u32) {1320pub const ObjectGlobalIndex = enum(u32) {
1299 _,1321 _,
13001322
1301 pub fn ptr(index: ObjectGlobalIndex, wasm: *const Wasm) *Global {1323 pub fn ptr(index: ObjectGlobalIndex, wasm: *const Wasm) *ObjectGlobal {
1302 return &wasm.object_globals.items[@intFromEnum(index)];1324 return &wasm.object_globals.items[@intFromEnum(index)];
1303 }1325 }
13041326
...@@ -1338,7 +1360,7 @@ pub const ObjectMemory = extern struct {...@@ -1338,7 +1360,7 @@ pub const ObjectMemory = extern struct {
1338pub const ObjectFunctionIndex = enum(u32) {1360pub const ObjectFunctionIndex = enum(u32) {
1339 _,1361 _,
13401362
1341 pub fn ptr(index: ObjectFunctionIndex, wasm: *const Wasm) *Function {1363 pub fn ptr(index: ObjectFunctionIndex, wasm: *const Wasm) *ObjectFunction {
1342 return &wasm.object_functions.items[@intFromEnum(index)];1364 return &wasm.object_functions.items[@intFromEnum(index)];
1343 }1365 }
13441366
...@@ -1363,8 +1385,28 @@ pub const OptionalObjectFunctionIndex = enum(u32) {...@@ -1363,8 +1385,28 @@ pub const OptionalObjectFunctionIndex = enum(u32) {
1363pub const ObjectDataSegment = extern struct {1385pub const ObjectDataSegment = extern struct {
1364 /// `none` if segment info custom subsection is missing.1386 /// `none` if segment info custom subsection is missing.
1365 name: OptionalString,1387 name: OptionalString,
1366 flags: SymbolFlags,1388 flags: Flags,
1367 payload: DataPayload,1389 payload: DataPayload,
1390 offset: u32,
1391 object_index: ObjectIndex,
1392
1393 pub const Flags = packed struct(u32) {
1394 alive: bool = false,
1395 is_passive: bool = false,
1396 alignment: Alignment = .none,
1397 /// Signals that the segment contains only null terminated strings allowing
1398 /// the linker to perform merging.
1399 strings: bool = false,
1400 /// The segment contains thread-local data. This means that a unique copy
1401 /// of this segment will be created for each thread.
1402 tls: bool = false,
1403 /// If the object file is included in the final link, the segment should be
1404 /// retained in the final output regardless of whether it is used by the
1405 /// program.
1406 retain: bool = false,
1407
1408 _: u21 = 0,
1409 };
13681410
1369 /// Index into `Wasm.object_data_segments`.1411 /// Index into `Wasm.object_data_segments`.
1370 pub const Index = enum(u32) {1412 pub const Index = enum(u32) {
...@@ -1374,6 +1416,12 @@ pub const ObjectDataSegment = extern struct {...@@ -1374,6 +1416,12 @@ pub const ObjectDataSegment = extern struct {
1374 return &wasm.object_data_segments.items[@intFromEnum(i)];1416 return &wasm.object_data_segments.items[@intFromEnum(i)];
1375 }1417 }
1376 };1418 };
1419
1420 fn relocations(ods: *const ObjectDataSegment, wasm: *const Wasm) ObjectRelocation.IterableSlice {
1421 const data_section_index = ods.object_index.ptr(wasm).data_section_index.?;
1422 const relocs = wasm.object_relocations_table.get(data_section_index) orelse return .empty;
1423 return .init(relocs, ods.offset, ods.payload.len, wasm);
1424 }
1377};1425};
13781426
1379/// A local or exported global const from an object file.1427/// A local or exported global const from an object file.
...@@ -1383,8 +1431,7 @@ pub const ObjectData = extern struct {...@@ -1383,8 +1431,7 @@ pub const ObjectData = extern struct {
1383 offset: u32,1431 offset: u32,
1384 /// May be zero. `offset + size` must be <= the segment's size.1432 /// May be zero. `offset + size` must be <= the segment's size.
1385 size: u32,1433 size: u32,
1386 /// `none` if no symbol describes it.1434 name: String,
1387 name: OptionalString,
1388 flags: SymbolFlags,1435 flags: SymbolFlags,
13891436
1390 /// Index into `Wasm.object_datas`.1437 /// Index into `Wasm.object_datas`.
...@@ -1845,7 +1892,7 @@ pub const ZcuImportIndex = enum(u32) {...@@ -1845,7 +1892,7 @@ pub const ZcuImportIndex = enum(u32) {
1845 return getExistingFunctionType(wasm, fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), target).?;1892 return getExistingFunctionType(wasm, fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), target).?;
1846 }1893 }
18471894
1848 pub fn globalType(index: ZcuImportIndex, wasm: *const Wasm) Global.Type {1895 pub fn globalType(index: ZcuImportIndex, wasm: *const Wasm) ObjectGlobal.Type {
1849 _ = index;1896 _ = index;
1850 _ = wasm;1897 _ = wasm;
1851 unreachable; // Zig has no way to create Wasm globals yet.1898 unreachable; // Zig has no way to create Wasm globals yet.
...@@ -1997,7 +2044,7 @@ pub const GlobalImportId = enum(u32) {...@@ -1997,7 +2044,7 @@ pub const GlobalImportId = enum(u32) {
1997 };2044 };
1998 }2045 }
19992046
2000 pub fn globalType(id: GlobalImportId, wasm: *Wasm) Global.Type {2047 pub fn globalType(id: GlobalImportId, wasm: *Wasm) ObjectGlobal.Type {
2001 return switch (unpack(id, wasm)) {2048 return switch (unpack(id, wasm)) {
2002 inline .object_global_import, .zcu_import => |i| i.globalType(wasm),2049 inline .object_global_import, .zcu_import => |i| i.globalType(wasm),
2003 };2050 };
...@@ -2014,7 +2061,7 @@ pub const SymbolTableIndex = enum(u32) {...@@ -2014,7 +2061,7 @@ pub const SymbolTableIndex = enum(u32) {
2014};2061};
20152062
2016pub const OutReloc = struct {2063pub const OutReloc = struct {
2017 tag: ObjectRelocation.Tag,2064 tag: Object.RelocationType,
2018 offset: u32,2065 offset: u32,
2019 pointee: Pointee,2066 pointee: Pointee,
2020 addend: i32,2067 addend: i32,
...@@ -2041,15 +2088,144 @@ pub const ObjectRelocation = struct {...@@ -2041,15 +2088,144 @@ pub const ObjectRelocation = struct {
2041 /// When `offset` is zero, its position is immediately after the id and size of the section.2088 /// When `offset` is zero, its position is immediately after the id and size of the section.
2042 offset: u32,2089 offset: u32,
2043 pointee: Pointee,2090 pointee: Pointee,
2044 /// Populated only for `MEMORY_ADDR_*`, `FUNCTION_OFFSET_I32` and `SECTION_OFFSET_I32`.2091 /// Populated only for `memory_addr_*`, `function_offset_i32` and `section_offset_i32`.
2045 addend: i32,2092 addend: i32,
20462093
2094 pub const Tag = enum(u8) {
2095 // These use `Pointee.function`.
2096 function_index_i32,
2097 function_index_leb,
2098 function_offset_i32,
2099 function_offset_i64,
2100 table_index_i32,
2101 table_index_i64,
2102 table_index_rel_sleb,
2103 table_index_rel_sleb64,
2104 table_index_sleb,
2105 table_index_sleb64,
2106 // These use `Pointee.symbol_name`.
2107 function_import_index_i32,
2108 function_import_index_leb,
2109 function_import_offset_i32,
2110 function_import_offset_i64,
2111 table_import_index_i32,
2112 table_import_index_i64,
2113 table_import_index_rel_sleb,
2114 table_import_index_rel_sleb64,
2115 table_import_index_sleb,
2116 table_import_index_sleb64,
2117 // These use `Pointee.global`.
2118 global_index_i32,
2119 global_index_leb,
2120 // These use `Pointee.symbol_name`.
2121 global_import_index_i32,
2122 global_import_index_leb,
2123 // These use `Pointee.data`.
2124 memory_addr_i32,
2125 memory_addr_i64,
2126 memory_addr_leb,
2127 memory_addr_leb64,
2128 memory_addr_locrel_i32,
2129 memory_addr_rel_sleb,
2130 memory_addr_rel_sleb64,
2131 memory_addr_sleb,
2132 memory_addr_sleb64,
2133 memory_addr_tls_sleb,
2134 memory_addr_tls_sleb64,
2135 // These use `Pointee.symbol_name`.
2136 memory_addr_import_i32,
2137 memory_addr_import_i64,
2138 memory_addr_import_leb,
2139 memory_addr_import_leb64,
2140 memory_addr_import_locrel_i32,
2141 memory_addr_import_rel_sleb,
2142 memory_addr_import_rel_sleb64,
2143 memory_addr_import_sleb,
2144 memory_addr_import_sleb64,
2145 memory_addr_import_tls_sleb,
2146 memory_addr_import_tls_sleb64,
2147 /// Uses `Pointee.section`.
2148 section_offset_i32,
2149 /// Uses `Pointee.table`.
2150 table_number_leb,
2151 /// Uses `Pointee.symbol_name`.
2152 table_import_number_leb,
2153 /// Uses `Pointee.type_index`.
2154 type_index_leb,
2155
2156 pub fn fromType(t: Object.RelocationType) Tag {
2157 return switch (t) {
2158 .event_index_leb => unreachable,
2159 .function_index_i32 => .function_index_i32,
2160 .function_index_leb => .function_index_leb,
2161 .function_offset_i32 => .function_offset_i32,
2162 .function_offset_i64 => .function_offset_i64,
2163 .global_index_i32 => .global_index_i32,
2164 .global_index_leb => .global_index_leb,
2165 .memory_addr_i32 => .memory_addr_i32,
2166 .memory_addr_i64 => .memory_addr_i64,
2167 .memory_addr_leb => .memory_addr_leb,
2168 .memory_addr_leb64 => .memory_addr_leb64,
2169 .memory_addr_locrel_i32 => .memory_addr_locrel_i32,
2170 .memory_addr_rel_sleb => .memory_addr_rel_sleb,
2171 .memory_addr_rel_sleb64 => .memory_addr_rel_sleb64,
2172 .memory_addr_sleb => .memory_addr_sleb,
2173 .memory_addr_sleb64 => .memory_addr_sleb64,
2174 .memory_addr_tls_sleb => .memory_addr_tls_sleb,
2175 .memory_addr_tls_sleb64 => .memory_addr_tls_sleb64,
2176 .section_offset_i32 => .section_offset_i32,
2177 .table_index_i32 => .table_index_i32,
2178 .table_index_i64 => .table_index_i64,
2179 .table_index_rel_sleb => .table_index_rel_sleb,
2180 .table_index_rel_sleb64 => .table_index_rel_sleb64,
2181 .table_index_sleb => .table_index_sleb,
2182 .table_index_sleb64 => .table_index_sleb64,
2183 .table_number_leb => .table_number_leb,
2184 .type_index_leb => .type_index_leb,
2185 };
2186 }
2187
2188 pub fn fromTypeImport(t: Object.RelocationType) Tag {
2189 return switch (t) {
2190 .event_index_leb => unreachable,
2191 .function_index_i32 => .function_import_index_i32,
2192 .function_index_leb => .function_import_index_leb,
2193 .function_offset_i32 => .function_import_offset_i32,
2194 .function_offset_i64 => .function_import_offset_i64,
2195 .global_index_i32 => .global_import_index_i32,
2196 .global_index_leb => .global_import_index_leb,
2197 .memory_addr_i32 => .memory_addr_import_i32,
2198 .memory_addr_i64 => .memory_addr_import_i64,
2199 .memory_addr_leb => .memory_addr_import_leb,
2200 .memory_addr_leb64 => .memory_addr_import_leb64,
2201 .memory_addr_locrel_i32 => .memory_addr_import_locrel_i32,
2202 .memory_addr_rel_sleb => .memory_addr_import_rel_sleb,
2203 .memory_addr_rel_sleb64 => .memory_addr_import_rel_sleb64,
2204 .memory_addr_sleb => .memory_addr_import_sleb,
2205 .memory_addr_sleb64 => .memory_addr_import_sleb64,
2206 .memory_addr_tls_sleb => .memory_addr_import_tls_sleb,
2207 .memory_addr_tls_sleb64 => .memory_addr_import_tls_sleb64,
2208 .section_offset_i32 => unreachable,
2209 .table_index_i32 => .table_import_index_i32,
2210 .table_index_i64 => .table_import_index_i64,
2211 .table_index_rel_sleb => .table_import_index_rel_sleb,
2212 .table_index_rel_sleb64 => .table_import_index_rel_sleb64,
2213 .table_index_sleb => .table_import_index_sleb,
2214 .table_index_sleb64 => .table_import_index_sleb64,
2215 .table_number_leb => .table_import_number_leb,
2216 .type_index_leb => unreachable,
2217 };
2218 }
2219 };
2220
2047 pub const Pointee = union {2221 pub const Pointee = union {
2048 symbol_name: String,2222 symbol_name: String,
2223 data: ObjectData.Index,
2049 type_index: FunctionType.Index,2224 type_index: FunctionType.Index,
2050 section: ObjectSectionIndex,2225 section: ObjectSectionIndex,
2051 data: ObjectData.Index,2226 function: ObjectFunctionIndex,
2052 function: Wasm.ObjectFunctionIndex,2227 global: ObjectGlobalIndex,
2228 table: ObjectTableIndex,
2053 };2229 };
20542230
2055 pub const Slice = extern struct {2231 pub const Slice = extern struct {
...@@ -2057,63 +2233,47 @@ pub const ObjectRelocation = struct {...@@ -2057,63 +2233,47 @@ pub const ObjectRelocation = struct {
2057 off: u32,2233 off: u32,
2058 len: u32,2234 len: u32,
20592235
2060 pub fn slice(s: Slice, wasm: *const Wasm) []ObjectRelocation {2236 const empty: Slice = .{ .off = 0, .len = 0 };
2061 return wasm.relocations.items[s.off..][0..s.len];2237
2238 fn tags(s: Slice, wasm: *const Wasm) []const ObjectRelocation.Tag {
2239 return wasm.object_relocations.items(.tag)[s.off..][0..s.len];
2240 }
2241
2242 fn offsets(s: Slice, wasm: *const Wasm) []const u32 {
2243 return wasm.object_relocations.items(.offset)[s.off..][0..s.len];
2244 }
2245
2246 fn pointees(s: Slice, wasm: *const Wasm) []const Pointee {
2247 return wasm.object_relocations.items(.pointee)[s.off..][0..s.len];
2248 }
2249
2250 fn addends(s: Slice, wasm: *const Wasm) []const i32 {
2251 return wasm.object_relocations.items(.addend)[s.off..][0..s.len];
2062 }2252 }
2063 };2253 };
20642254
2065 pub const Tag = enum(u8) {2255 pub const IterableSlice = struct {
2066 /// Uses `function`.2256 slice: Slice,
2067 FUNCTION_INDEX_LEB = 0,2257 /// Offset at which point to stop iterating.
2068 /// Uses `table_index`.2258 end: u32,
2069 TABLE_INDEX_SLEB = 1,2259
2070 /// Uses `table_index`.2260 const empty: IterableSlice = .{ .slice = .empty, .end = 0 };
2071 TABLE_INDEX_I32 = 2,2261
2072 /// Uses `data_segment`.2262 fn init(relocs: Slice, offset: u32, size: u32, wasm: *const Wasm) IterableSlice {
2073 MEMORY_ADDR_LEB = 3,2263 const offsets = relocs.offsets(wasm);
2074 /// Uses `data_segment`.2264 const start = std.sort.lowerBound(u32, offsets, offset, order);
2075 MEMORY_ADDR_SLEB = 4,2265 return .{
2076 /// Uses `data_segment`.2266 .slice = .{
2077 MEMORY_ADDR_I32 = 5,2267 .off = @intCast(relocs.off + start),
2078 /// Uses `type_index`.2268 .len = @intCast(relocs.len - start),
2079 TYPE_INDEX_LEB = 6,2269 },
2080 /// Uses `symbol_name`.2270 .end = offset + size,
2081 GLOBAL_INDEX_LEB = 7,2271 };
2082 FUNCTION_OFFSET_I32 = 8,2272 }
2083 SECTION_OFFSET_I32 = 9,2273
2084 TAG_INDEX_LEB = 10,2274 fn order(lhs: u32, rhs: u32) std.math.Order {
2085 /// Uses `data_segment`.2275 return std.math.order(lhs, rhs);
2086 MEMORY_ADDR_REL_SLEB = 11,2276 }
2087 TABLE_INDEX_REL_SLEB = 12,
2088 /// Uses `symbol_name`.
2089 GLOBAL_INDEX_I32 = 13,
2090 /// Uses `data_segment`.
2091 MEMORY_ADDR_LEB64 = 14,
2092 /// Uses `data_segment`.
2093 MEMORY_ADDR_SLEB64 = 15,
2094 /// Uses `data_segment`.
2095 MEMORY_ADDR_I64 = 16,
2096 /// Uses `data_segment`.
2097 MEMORY_ADDR_REL_SLEB64 = 17,
2098 /// Uses `table_index`.
2099 TABLE_INDEX_SLEB64 = 18,
2100 /// Uses `table_index`.
2101 TABLE_INDEX_I64 = 19,
2102 TABLE_NUMBER_LEB = 20,
2103 /// Uses `data_segment`.
2104 MEMORY_ADDR_TLS_SLEB = 21,
2105 FUNCTION_OFFSET_I64 = 22,
2106 /// Uses `data_segment`.
2107 MEMORY_ADDR_LOCREL_I32 = 23,
2108 TABLE_INDEX_REL_SLEB64 = 24,
2109 /// Uses `data_segment`.
2110 MEMORY_ADDR_TLS_SLEB64 = 25,
2111 /// Uses `symbol_name`.
2112 FUNCTION_INDEX_I32 = 26,
2113
2114 // Above here, the tags correspond to symbol table ABI described in
2115 // https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md
2116 // Below, the tags are compiler-internal.
2117 };2277 };
2118};2278};
21192279
...@@ -2781,7 +2941,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v...@@ -2781,7 +2941,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
2781 // At the end, output functions and globals will be populated.2941 // At the end, output functions and globals will be populated.
2782 for (wasm.object_function_imports.keys(), wasm.object_function_imports.values(), 0..) |name, *import, i| {2942 for (wasm.object_function_imports.keys(), wasm.object_function_imports.values(), 0..) |name, *import, i| {
2783 if (import.flags.isIncluded(rdynamic)) {2943 if (import.flags.isIncluded(rdynamic)) {
2784 try markFunction(wasm, name, import, @enumFromInt(i));2944 try markFunctionImport(wasm, name, import, @enumFromInt(i));
2785 }2945 }
2786 }2946 }
2787 wasm.functions_end_prelink = @intCast(wasm.functions.entries.len);2947 wasm.functions_end_prelink = @intCast(wasm.functions.entries.len);
...@@ -2789,7 +2949,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v...@@ -2789,7 +2949,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
27892949
2790 for (wasm.object_global_imports.keys(), wasm.object_global_imports.values(), 0..) |name, *import, i| {2950 for (wasm.object_global_imports.keys(), wasm.object_global_imports.values(), 0..) |name, *import, i| {
2791 if (import.flags.isIncluded(rdynamic)) {2951 if (import.flags.isIncluded(rdynamic)) {
2792 try markGlobal(wasm, name, import, @enumFromInt(i));2952 try markGlobalImport(wasm, name, import, @enumFromInt(i));
2793 }2953 }
2794 }2954 }
2795 wasm.globals_end_prelink = @intCast(wasm.globals.entries.len);2955 wasm.globals_end_prelink = @intCast(wasm.globals.entries.len);
...@@ -2797,13 +2957,12 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v...@@ -2797,13 +2957,12 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
27972957
2798 for (wasm.object_table_imports.keys(), wasm.object_table_imports.values(), 0..) |name, *import, i| {2958 for (wasm.object_table_imports.keys(), wasm.object_table_imports.values(), 0..) |name, *import, i| {
2799 if (import.flags.isIncluded(rdynamic)) {2959 if (import.flags.isIncluded(rdynamic)) {
2800 try markTable(wasm, name, import, @enumFromInt(i));2960 try markTableImport(wasm, name, import, @enumFromInt(i));
2801 }2961 }
2802 }2962 }
2803}2963}
28042964
2805/// Recursively mark alive everything referenced by the function.2965fn markFunctionImport(
2806fn markFunction(
2807 wasm: *Wasm,2966 wasm: *Wasm,
2808 name: String,2967 name: String,
2809 import: *FunctionImport,2968 import: *FunctionImport,
...@@ -2814,8 +2973,6 @@ fn markFunction(...@@ -2814,8 +2973,6 @@ fn markFunction(
28142973
2815 const comp = wasm.base.comp;2974 const comp = wasm.base.comp;
2816 const gpa = comp.gpa;2975 const gpa = comp.gpa;
2817 const rdynamic = comp.config.rdynamic;
2818 const is_obj = comp.config.output_mode == .Obj;
28192976
2820 try wasm.functions.ensureUnusedCapacity(gpa, 1);2977 try wasm.functions.ensureUnusedCapacity(gpa, 1);
28212978
...@@ -2836,20 +2993,31 @@ fn markFunction(...@@ -2836,20 +2993,31 @@ fn markFunction(
2836 try wasm.function_imports.put(gpa, name, .fromObject(func_index, wasm));2993 try wasm.function_imports.put(gpa, name, .fromObject(func_index, wasm));
2837 }2994 }
2838 } else {2995 } else {
2839 const gop = wasm.functions.getOrPutAssumeCapacity(import.resolution);2996 try markFunction(wasm, import.resolution.unpack(wasm).object_function);
2997 }
2998}
28402999
2841 if (!is_obj and import.flags.isExported(rdynamic)) try wasm.function_exports.append(gpa, .{3000/// Recursively mark alive everything referenced by the function.
2842 .name = name,3001fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex) Allocator.Error!void {
2843 .function_index = @enumFromInt(gop.index),3002 const comp = wasm.base.comp;
2844 });3003 const gpa = comp.gpa;
3004 const gop = try wasm.functions.getOrPut(gpa, .fromObjectFunction(wasm, i));
3005 if (gop.found_existing) return;
28453006
2846 for (try wasm.functionResolutionRelocSlice(import.resolution)) |reloc|3007 const rdynamic = comp.config.rdynamic;
2847 try wasm.markReloc(reloc);3008 const is_obj = comp.config.output_mode == .Obj;
2848 }3009 const function = i.ptr(wasm);
3010
3011 if (!is_obj and function.flags.isExported(rdynamic)) try wasm.function_exports.append(gpa, .{
3012 .name = function.name.unwrap().?,
3013 .function_index = @enumFromInt(gop.index),
3014 });
3015
3016 try wasm.markRelocations(function.relocations(wasm));
2849}3017}
28503018
2851/// Recursively mark alive everything referenced by the global.3019/// Recursively mark alive everything referenced by the global.
2852fn markGlobal(3020fn markGlobalImport(
2853 wasm: *Wasm,3021 wasm: *Wasm,
2854 name: String,3022 name: String,
2855 import: *GlobalImport,3023 import: *GlobalImport,
...@@ -2860,8 +3028,6 @@ fn markGlobal(...@@ -2860,8 +3028,6 @@ fn markGlobal(
28603028
2861 const comp = wasm.base.comp;3029 const comp = wasm.base.comp;
2862 const gpa = comp.gpa;3030 const gpa = comp.gpa;
2863 const rdynamic = comp.config.rdynamic;
2864 const is_obj = comp.config.output_mode == .Obj;
28653031
2866 try wasm.globals.ensureUnusedCapacity(gpa, 1);3032 try wasm.globals.ensureUnusedCapacity(gpa, 1);
28673033
...@@ -2888,19 +3054,29 @@ fn markGlobal(...@@ -2888,19 +3054,29 @@ fn markGlobal(
2888 try wasm.global_imports.put(gpa, name, .fromObject(global_index, wasm));3054 try wasm.global_imports.put(gpa, name, .fromObject(global_index, wasm));
2889 }3055 }
2890 } else {3056 } else {
2891 const gop = wasm.globals.getOrPutAssumeCapacity(import.resolution);3057 try markGlobal(wasm, import.resolution.unpack(wasm).object_global);
3058 }
3059}
28923060
2893 if (!is_obj and import.flags.isExported(rdynamic)) try wasm.global_exports.append(gpa, .{3061fn markGlobal(wasm: *Wasm, i: ObjectGlobalIndex) Allocator.Error!void {
2894 .name = name,3062 const comp = wasm.base.comp;
2895 .global_index = @enumFromInt(gop.index),3063 const gpa = comp.gpa;
2896 });3064 const gop = try wasm.globals.getOrPut(gpa, .fromObjectGlobal(wasm, i));
3065 if (gop.found_existing) return;
28973066
2898 for (try wasm.globalResolutionRelocSlice(import.resolution)) |reloc|3067 const rdynamic = comp.config.rdynamic;
2899 try wasm.markReloc(reloc);3068 const is_obj = comp.config.output_mode == .Obj;
2900 }3069 const global = i.ptr(wasm);
3070
3071 if (!is_obj and global.flags.isExported(rdynamic)) try wasm.global_exports.append(gpa, .{
3072 .name = global.name.unwrap().?,
3073 .global_index = @enumFromInt(gop.index),
3074 });
3075
3076 try wasm.markRelocations(global.relocations(wasm));
2901}3077}
29023078
2903fn markTable(3079fn markTableImport(
2904 wasm: *Wasm,3080 wasm: *Wasm,
2905 name: String,3081 name: String,
2906 import: *TableImport,3082 import: *TableImport,
...@@ -2927,22 +3103,101 @@ fn markTable(...@@ -2927,22 +3103,101 @@ fn markTable(
2927 }3103 }
2928}3104}
29293105
2930fn globalResolutionRelocSlice(wasm: *Wasm, resolution: GlobalImport.Resolution) ![]const ObjectRelocation {3106fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) Allocator.Error!void {
2931 assert(resolution != .unresolved);3107 const segment = segment_index.ptr(wasm);
2932 _ = wasm;3108 if (segment.flags.alive) return;
2933 @panic("TODO");3109 segment.flags.alive = true;
2934}
29353110
2936fn functionResolutionRelocSlice(wasm: *Wasm, resolution: FunctionImport.Resolution) ![]const ObjectRelocation {3111 try wasm.markRelocations(segment.relocations(wasm));
2937 assert(resolution != .unresolved);
2938 _ = wasm;
2939 @panic("TODO");
2940}3112}
29413113
2942fn markReloc(wasm: *Wasm, reloc: ObjectRelocation) !void {3114fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) Allocator.Error!void {
2943 _ = wasm;3115 for (relocs.slice.tags(wasm), relocs.slice.pointees(wasm), relocs.slice.offsets(wasm)) |tag, *pointee, offset| {
2944 _ = reloc;3116 if (offset >= relocs.end) break;
2945 @panic("TODO");3117 switch (tag) {
3118 .function_import_index_leb,
3119 .function_import_index_i32,
3120 .function_import_offset_i32,
3121 .function_import_offset_i64,
3122 .table_import_index_sleb,
3123 .table_import_index_i32,
3124 .table_import_index_sleb64,
3125 .table_import_index_i64,
3126 .table_import_index_rel_sleb,
3127 .table_import_index_rel_sleb64,
3128 => {
3129 const name = pointee.symbol_name;
3130 const i: FunctionImport.Index = @enumFromInt(wasm.object_function_imports.getIndex(name).?);
3131 try markFunctionImport(wasm, name, i.value(wasm), i);
3132 },
3133 .global_import_index_leb, .global_import_index_i32 => {
3134 const name = pointee.symbol_name;
3135 const i: GlobalImport.Index = @enumFromInt(wasm.object_global_imports.getIndex(name).?);
3136 try markGlobalImport(wasm, name, i.value(wasm), i);
3137 },
3138 .table_import_number_leb => {
3139 const name = pointee.symbol_name;
3140 const i: TableImport.Index = @enumFromInt(wasm.object_table_imports.getIndex(name).?);
3141 try markTableImport(wasm, name, i.value(wasm), i);
3142 },
3143
3144 .function_index_leb,
3145 .function_index_i32,
3146 .function_offset_i32,
3147 .function_offset_i64,
3148 .table_index_sleb,
3149 .table_index_i32,
3150 .table_index_sleb64,
3151 .table_index_i64,
3152 .table_index_rel_sleb,
3153 .table_index_rel_sleb64,
3154 => try markFunction(wasm, pointee.function),
3155 .global_index_leb,
3156 .global_index_i32,
3157 => try markGlobal(wasm, pointee.global),
3158 .table_number_leb,
3159 => try wasm.tables.put(wasm.base.comp.gpa, .fromObjectTable(pointee.table), {}),
3160
3161 .section_offset_i32 => {
3162 log.warn("TODO: ensure section {d} is included in output", .{pointee.section});
3163 },
3164 .memory_addr_import_leb,
3165 .memory_addr_import_sleb,
3166 .memory_addr_import_i32,
3167 .memory_addr_import_rel_sleb,
3168 .memory_addr_import_leb64,
3169 .memory_addr_import_sleb64,
3170 .memory_addr_import_i64,
3171 .memory_addr_import_rel_sleb64,
3172 .memory_addr_import_tls_sleb,
3173 .memory_addr_import_locrel_i32,
3174 .memory_addr_import_tls_sleb64,
3175 => {
3176 const name = pointee.symbol_name;
3177 if (name == wasm.preloaded_strings.__heap_end or
3178 name == wasm.preloaded_strings.__heap_base)
3179 {
3180 continue;
3181 }
3182 log.warn("TODO: ensure data symbol {s} is included in output", .{name.slice(wasm)});
3183 },
3184
3185 .memory_addr_leb,
3186 .memory_addr_sleb,
3187 .memory_addr_i32,
3188 .memory_addr_rel_sleb,
3189 .memory_addr_leb64,
3190 .memory_addr_sleb64,
3191 .memory_addr_i64,
3192 .memory_addr_rel_sleb64,
3193 .memory_addr_tls_sleb,
3194 .memory_addr_locrel_i32,
3195 .memory_addr_tls_sleb64,
3196 => try markDataSegment(wasm, pointee.data.ptr(wasm).segment),
3197
3198 .type_index_leb => continue,
3199 }
3200 }
2946}3201}
29473202
2948pub fn flushModule(3203pub fn flushModule(
src/link/Wasm/Flush.zig-142
...@@ -1398,148 +1398,6 @@ fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void {...@@ -1398,148 +1398,6 @@ fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void {
1398// try binary_bytes.insertSlice(table_offset, &buf);1398// try binary_bytes.insertSlice(table_offset, &buf);
1399//}1399//}
14001400
1401///// Resolves the relocations within the atom, writing the new value
1402///// at the calculated offset.
1403//fn resolveAtomRelocs(wasm: *const Wasm, atom: *Atom) void {
1404// const symbol_name = wasm.symbolLocName(atom.symbolLoc());
1405// log.debug("resolving {d} relocs in atom '{s}'", .{ atom.relocs.len, symbol_name });
1406//
1407// for (atom.relocSlice(wasm)) |reloc| {
1408// const value = atomRelocationValue(wasm, atom, reloc);
1409// log.debug("relocating '{s}' referenced in '{s}' offset=0x{x:0>8} value={d}", .{
1410// wasm.symbolLocName(.{
1411// .file = atom.file,
1412// .index = @enumFromInt(reloc.index),
1413// }),
1414// symbol_name,
1415// reloc.offset,
1416// value,
1417// });
1418//
1419// switch (reloc.tag) {
1420// .TABLE_INDEX_I32,
1421// .FUNCTION_OFFSET_I32,
1422// .GLOBAL_INDEX_I32,
1423// .MEMORY_ADDR_I32,
1424// .SECTION_OFFSET_I32,
1425// => mem.writeInt(u32, atom.code.slice(wasm)[reloc.offset - atom.original_offset ..][0..4], @as(u32, @truncate(value)), .little),
1426//
1427// .TABLE_INDEX_I64,
1428// .MEMORY_ADDR_I64,
1429// => mem.writeInt(u64, atom.code.slice(wasm)[reloc.offset - atom.original_offset ..][0..8], value, .little),
1430//
1431// .GLOBAL_INDEX_LEB,
1432// .EVENT_INDEX_LEB,
1433// .FUNCTION_INDEX_LEB,
1434// .MEMORY_ADDR_LEB,
1435// .MEMORY_ADDR_SLEB,
1436// .TABLE_INDEX_SLEB,
1437// .TABLE_NUMBER_LEB,
1438// .TYPE_INDEX_LEB,
1439// .MEMORY_ADDR_TLS_SLEB,
1440// => leb.writeUnsignedFixed(5, atom.code.slice(wasm)[reloc.offset - atom.original_offset ..][0..5], @as(u32, @truncate(value))),
1441//
1442// .MEMORY_ADDR_LEB64,
1443// .MEMORY_ADDR_SLEB64,
1444// .TABLE_INDEX_SLEB64,
1445// .MEMORY_ADDR_TLS_SLEB64,
1446// => leb.writeUnsignedFixed(10, atom.code.slice(wasm)[reloc.offset - atom.original_offset ..][0..10], value),
1447// }
1448// }
1449//}
1450
1451///// From a given `relocation` will return the new value to be written.
1452///// All values will be represented as a `u64` as all values can fit within it.
1453///// The final value must be casted to the correct size.
1454//fn atomRelocationValue(wasm: *const Wasm, atom: *const Atom, relocation: *const Relocation) u64 {
1455// if (relocation.tag == .TYPE_INDEX_LEB) {
1456// // Eagerly resolved when parsing the object file.
1457// if (true) @panic("TODO the eager resolve when parsing");
1458// return relocation.index;
1459// }
1460// const target_loc = wasm.symbolLocFinalLoc(.{
1461// .file = atom.file,
1462// .index = @enumFromInt(relocation.index),
1463// });
1464// const symbol = wasm.finalSymbolByLoc(target_loc);
1465// if (symbol.tag != .section and !symbol.flags.alive) {
1466// const val = atom.tombstone(wasm) orelse relocation.addend;
1467// return @bitCast(val);
1468// }
1469// return switch (relocation.tag) {
1470// .FUNCTION_INDEX_LEB => if (symbol.flags.undefined)
1471// @intFromEnum(symbol.pointee.function_import)
1472// else
1473// @intFromEnum(symbol.pointee.function) + f.function_imports.items.len,
1474// .TABLE_NUMBER_LEB => if (symbol.flags.undefined)
1475// @intFromEnum(symbol.pointee.table_import)
1476// else
1477// @intFromEnum(symbol.pointee.table) + wasm.table_imports.items.len,
1478// .TABLE_INDEX_I32,
1479// .TABLE_INDEX_I64,
1480// .TABLE_INDEX_SLEB,
1481// .TABLE_INDEX_SLEB64,
1482// => wasm.indirect_function_table.get(.{ .file = atom.file, .index = @enumFromInt(relocation.index) }) orelse 0,
1483//
1484// .TYPE_INDEX_LEB => unreachable, // handled above
1485// .GLOBAL_INDEX_I32, .GLOBAL_INDEX_LEB => if (symbol.flags.undefined)
1486// @intFromEnum(symbol.pointee.global_import)
1487// else
1488// @intFromEnum(symbol.pointee.global) + f.global_imports.items.len,
1489//
1490// .MEMORY_ADDR_I32,
1491// .MEMORY_ADDR_I64,
1492// .MEMORY_ADDR_LEB,
1493// .MEMORY_ADDR_LEB64,
1494// .MEMORY_ADDR_SLEB,
1495// .MEMORY_ADDR_SLEB64,
1496// => {
1497// assert(symbol.tag == .data);
1498// if (symbol.flags.undefined) return 0;
1499// const va: i33 = symbol.virtual_address;
1500// return @intCast(va + relocation.addend);
1501// },
1502// .EVENT_INDEX_LEB => @panic("TODO: expose this as an error, events are unsupported"),
1503// .SECTION_OFFSET_I32 => {
1504// const target_atom_index = wasm.symbol_atom.get(target_loc).?;
1505// const target_atom = wasm.getAtom(target_atom_index);
1506// const rel_value: i33 = target_atom.offset;
1507// return @intCast(rel_value + relocation.addend);
1508// },
1509// .FUNCTION_OFFSET_I32 => {
1510// if (symbol.flags.undefined) {
1511// const val = atom.tombstone(wasm) orelse relocation.addend;
1512// return @bitCast(val);
1513// }
1514// const target_atom_index = wasm.symbol_atom.get(target_loc).?;
1515// const target_atom = wasm.getAtom(target_atom_index);
1516// const rel_value: i33 = target_atom.offset;
1517// return @intCast(rel_value + relocation.addend);
1518// },
1519// .MEMORY_ADDR_TLS_SLEB,
1520// .MEMORY_ADDR_TLS_SLEB64,
1521// => {
1522// const va: i33 = symbol.virtual_address;
1523// return @intCast(va + relocation.addend);
1524// },
1525// };
1526//}
1527
1528///// For a given `Atom` returns whether it has a tombstone value or not.
1529///// This defines whether we want a specific value when a section is dead.
1530//fn tombstone(atom: Atom, wasm: *const Wasm) ?i64 {
1531// const atom_name = wasm.finalSymbolByLoc(atom.symbolLoc()).name;
1532// if (atom_name == wasm.custom_sections.@".debug_ranges".name or
1533// atom_name == wasm.custom_sections.@".debug_loc".name)
1534// {
1535// return -2;
1536// } else if (mem.startsWith(u8, atom_name.slice(wasm), ".debug_")) {
1537// return -1;
1538// } else {
1539// return null;
1540// }
1541//}
1542
1543fn uleb128size(x: u32) u32 {1401fn uleb128size(x: u32) u32 {
1544 var value = x;1402 var value = x;
1545 var size: u32 = 0;1403 var size: u32 = 0;
src/link/Wasm/Object.zig+206-71
...@@ -36,12 +36,16 @@ global_imports: RelativeSlice,...@@ -36,12 +36,16 @@ global_imports: RelativeSlice,
36table_imports: RelativeSlice,36table_imports: RelativeSlice,
37/// Points into Wasm object_custom_segments37/// Points into Wasm object_custom_segments
38custom_segments: RelativeSlice,38custom_segments: RelativeSlice,
39/// For calculating local section index from `Wasm.ObjectSectionIndex`.
40local_section_index_base: u32,
41/// Points into Wasm object_init_funcs39/// Points into Wasm object_init_funcs
42init_funcs: RelativeSlice,40init_funcs: RelativeSlice,
43/// Points into Wasm object_comdats41/// Points into Wasm object_comdats
44comdats: RelativeSlice,42comdats: RelativeSlice,
43/// Guaranteed to be non-null when functions has nonzero length.
44code_section_index: ?Wasm.ObjectSectionIndex,
45/// Guaranteed to be non-null when globals has nonzero length.
46global_section_index: ?Wasm.ObjectSectionIndex,
47/// Guaranteed to be non-null when data segments has nonzero length.
48data_section_index: ?Wasm.ObjectSectionIndex,
4549
46pub const RelativeSlice = struct {50pub const RelativeSlice = struct {
47 off: u32,51 off: u32,
...@@ -52,7 +56,8 @@ pub const SegmentInfo = struct {...@@ -52,7 +56,8 @@ pub const SegmentInfo = struct {
52 name: Wasm.String,56 name: Wasm.String,
53 flags: Flags,57 flags: Flags,
5458
55 const Flags = packed struct(u32) {59 /// Matches the ABI.
60 pub const Flags = packed struct(u32) {
56 /// Signals that the segment contains only null terminated strings allowing61 /// Signals that the segment contains only null terminated strings allowing
57 /// the linker to perform merging.62 /// the linker to perform merging.
58 strings: bool,63 strings: bool,
...@@ -101,6 +106,37 @@ pub const SubsectionType = enum(u8) {...@@ -101,6 +106,37 @@ pub const SubsectionType = enum(u8) {
101 symbol_table = 8,106 symbol_table = 8,
102};107};
103108
109/// Specified by https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md
110pub const RelocationType = enum(u8) {
111 function_index_leb = 0,
112 table_index_sleb = 1,
113 table_index_i32 = 2,
114 memory_addr_leb = 3,
115 memory_addr_sleb = 4,
116 memory_addr_i32 = 5,
117 type_index_leb = 6,
118 global_index_leb = 7,
119 function_offset_i32 = 8,
120 section_offset_i32 = 9,
121 event_index_leb = 10,
122 memory_addr_rel_sleb = 11,
123 table_index_rel_sleb = 12,
124 global_index_i32 = 13,
125 memory_addr_leb64 = 14,
126 memory_addr_sleb64 = 15,
127 memory_addr_i64 = 16,
128 memory_addr_rel_sleb64 = 17,
129 table_index_sleb64 = 18,
130 table_index_i64 = 19,
131 table_number_leb = 20,
132 memory_addr_tls_sleb = 21,
133 function_offset_i64 = 22,
134 memory_addr_locrel_i32 = 23,
135 table_index_rel_sleb64 = 24,
136 memory_addr_tls_sleb64 = 25,
137 function_index_i32 = 26,
138};
139
104pub const Symbol = struct {140pub const Symbol = struct {
105 flags: Wasm.SymbolFlags,141 flags: Wasm.SymbolFlags,
106 name: Wasm.OptionalString,142 name: Wasm.OptionalString,
...@@ -245,7 +281,8 @@ pub fn parse(...@@ -245,7 +281,8 @@ pub fn parse(
245 const global_imports_start: u32 = @intCast(wasm.object_global_imports.entries.len);281 const global_imports_start: u32 = @intCast(wasm.object_global_imports.entries.len);
246 const table_imports_start: u32 = @intCast(wasm.object_table_imports.entries.len);282 const table_imports_start: u32 = @intCast(wasm.object_table_imports.entries.len);
247 const local_section_index_base = wasm.object_total_sections;283 const local_section_index_base = wasm.object_total_sections;
248 const source_location: Wasm.SourceLocation = .fromObject(@enumFromInt(wasm.objects.items.len), wasm);284 const object_index: Wasm.ObjectIndex = @enumFromInt(wasm.objects.items.len);
285 const source_location: Wasm.SourceLocation = .fromObject(object_index, wasm);
249286
250 ss.clear();287 ss.clear();
251288
...@@ -254,6 +291,9 @@ pub fn parse(...@@ -254,6 +291,9 @@ pub fn parse(
254 var saw_linking_section = false;291 var saw_linking_section = false;
255 var has_tls = false;292 var has_tls = false;
256 var table_import_symbol_count: usize = 0;293 var table_import_symbol_count: usize = 0;
294 var code_section_index: ?Wasm.ObjectSectionIndex = null;
295 var global_section_index: ?Wasm.ObjectSectionIndex = null;
296 var data_section_index: ?Wasm.ObjectSectionIndex = null;
257 while (pos < bytes.len) : (wasm.object_total_sections += 1) {297 while (pos < bytes.len) : (wasm.object_total_sections += 1) {
258 const section_index: Wasm.ObjectSectionIndex = @enumFromInt(wasm.object_total_sections);298 const section_index: Wasm.ObjectSectionIndex = @enumFromInt(wasm.object_total_sections);
259299
...@@ -365,7 +405,8 @@ pub fn parse(...@@ -365,7 +405,8 @@ pub fn parse(
365 switch (tag) {405 switch (tag) {
366 .data => {406 .data => {
367 const name, pos = readBytes(bytes, pos);407 const name, pos = readBytes(bytes, pos);
368 symbol.name = (try wasm.internString(name)).toOptional();408 const interned_name = try wasm.internString(name);
409 symbol.name = interned_name.toOptional();
369 if (symbol.flags.undefined) {410 if (symbol.flags.undefined) {
370 symbol.pointee = .data_import;411 symbol.pointee = .data_import;
371 } else {412 } else {
...@@ -376,7 +417,7 @@ pub fn parse(...@@ -376,7 +417,7 @@ pub fn parse(
376 .segment = @enumFromInt(data_segment_start + segment_index),417 .segment = @enumFromInt(data_segment_start + segment_index),
377 .offset = segment_offset,418 .offset = segment_offset,
378 .size = size,419 .size = size,
379 .name = symbol.name,420 .name = interned_name,
380 .flags = symbol.flags,421 .flags = symbol.flags,
381 });422 });
382 symbol.pointee = .{423 symbol.pointee = .{
...@@ -468,7 +509,7 @@ pub fn parse(...@@ -468,7 +509,7 @@ pub fn parse(
468 var prev_offset: u32 = 0;509 var prev_offset: u32 = 0;
469 try wasm.object_relocations.ensureUnusedCapacity(gpa, count);510 try wasm.object_relocations.ensureUnusedCapacity(gpa, count);
470 for (0..count) |_| {511 for (0..count) |_| {
471 const tag: Wasm.ObjectRelocation.Tag = @enumFromInt(bytes[pos]);512 const tag: RelocationType = @enumFromInt(bytes[pos]);
472 pos += 1;513 pos += 1;
473 const offset, pos = readLeb(u32, bytes, pos);514 const offset, pos = readLeb(u32, bytes, pos);
474 const index, pos = readLeb(u32, bytes, pos);515 const index, pos = readLeb(u32, bytes, pos);
...@@ -477,75 +518,134 @@ pub fn parse(...@@ -477,75 +518,134 @@ pub fn parse(
477 return diags.failParse(path, "relocation entries not sorted by offset", .{});518 return diags.failParse(path, "relocation entries not sorted by offset", .{});
478 prev_offset = offset;519 prev_offset = offset;
479520
521 const sym = &ss.symbol_table.items[index];
522
480 switch (tag) {523 switch (tag) {
481 .MEMORY_ADDR_LEB,524 .memory_addr_leb,
482 .MEMORY_ADDR_SLEB,525 .memory_addr_sleb,
483 .MEMORY_ADDR_I32,526 .memory_addr_i32,
484 .MEMORY_ADDR_REL_SLEB,527 .memory_addr_rel_sleb,
485 .MEMORY_ADDR_LEB64,528 .memory_addr_leb64,
486 .MEMORY_ADDR_SLEB64,529 .memory_addr_sleb64,
487 .MEMORY_ADDR_I64,530 .memory_addr_i64,
488 .MEMORY_ADDR_REL_SLEB64,531 .memory_addr_rel_sleb64,
489 .MEMORY_ADDR_TLS_SLEB,532 .memory_addr_tls_sleb,
490 .MEMORY_ADDR_LOCREL_I32,533 .memory_addr_locrel_i32,
491 .MEMORY_ADDR_TLS_SLEB64,534 .memory_addr_tls_sleb64,
492 => {535 => {
493 const addend: i32, pos = readLeb(i32, bytes, pos);536 const addend: i32, pos = readLeb(i32, bytes, pos);
494 wasm.object_relocations.appendAssumeCapacity(.{537 wasm.object_relocations.appendAssumeCapacity(switch (sym.pointee) {
495 .tag = tag,538 .data => |data| .{
496 .offset = offset,539 .tag = .fromType(tag),
497 .pointee = .{ .data = ss.symbol_table.items[index].pointee.data },540 .offset = offset,
498 .addend = addend,541 .pointee = .{ .data = data },
542 .addend = addend,
543 },
544 .data_import => .{
545 .tag = .fromTypeImport(tag),
546 .offset = offset,
547 .pointee = .{ .symbol_name = sym.name.unwrap().? },
548 .addend = addend,
549 },
550 else => unreachable,
499 });551 });
500 },552 },
501 .FUNCTION_OFFSET_I32,553 .function_offset_i32, .function_offset_i64 => {
502 .FUNCTION_OFFSET_I64,
503 => {
504 const addend: i32, pos = readLeb(i32, bytes, pos);554 const addend: i32, pos = readLeb(i32, bytes, pos);
505 wasm.object_relocations.appendAssumeCapacity(.{555 wasm.object_relocations.appendAssumeCapacity(switch (sym.pointee) {
506 .tag = tag,556 .function => .{
507 .offset = offset,557 .tag = .fromType(tag),
508 .pointee = .{ .function = ss.symbol_table.items[index].pointee.function },558 .offset = offset,
509 .addend = addend,559 .pointee = .{ .function = sym.pointee.function },
560 .addend = addend,
561 },
562 .function_import => .{
563 .tag = .fromTypeImport(tag),
564 .offset = offset,
565 .pointee = .{ .symbol_name = sym.name.unwrap().? },
566 .addend = addend,
567 },
568 else => unreachable,
510 });569 });
511 },570 },
512 .SECTION_OFFSET_I32 => {571 .section_offset_i32 => {
513 const addend: i32, pos = readLeb(i32, bytes, pos);572 const addend: i32, pos = readLeb(i32, bytes, pos);
514 wasm.object_relocations.appendAssumeCapacity(.{573 wasm.object_relocations.appendAssumeCapacity(.{
515 .tag = tag,574 .tag = .section_offset_i32,
516 .offset = offset,575 .offset = offset,
517 .pointee = .{ .section = ss.symbol_table.items[index].pointee.section },576 .pointee = .{ .section = sym.pointee.section },
518 .addend = addend,577 .addend = addend,
519 });578 });
520 },579 },
521 .TYPE_INDEX_LEB => {580 .type_index_leb => {
522 wasm.object_relocations.appendAssumeCapacity(.{581 wasm.object_relocations.appendAssumeCapacity(.{
523 .tag = tag,582 .tag = .type_index_leb,
524 .offset = offset,583 .offset = offset,
525 .pointee = .{ .type_index = ss.func_types.items[index] },584 .pointee = .{ .type_index = ss.func_types.items[index] },
526 .addend = undefined,585 .addend = undefined,
527 });586 });
528 },587 },
529 .FUNCTION_INDEX_LEB,588 .function_index_leb,
530 .FUNCTION_INDEX_I32,589 .function_index_i32,
531 .GLOBAL_INDEX_LEB,590 .table_index_sleb,
532 .GLOBAL_INDEX_I32,591 .table_index_i32,
533 .TABLE_INDEX_SLEB,592 .table_index_sleb64,
534 .TABLE_INDEX_I32,593 .table_index_i64,
535 .TABLE_INDEX_SLEB64,594 .table_index_rel_sleb,
536 .TABLE_INDEX_I64,595 .table_index_rel_sleb64,
537 .TABLE_NUMBER_LEB,
538 .TABLE_INDEX_REL_SLEB,
539 .TABLE_INDEX_REL_SLEB64,
540 .TAG_INDEX_LEB,
541 => {596 => {
542 wasm.object_relocations.appendAssumeCapacity(.{597 wasm.object_relocations.appendAssumeCapacity(switch (sym.pointee) {
543 .tag = tag,598 .function => .{
544 .offset = offset,599 .tag = .fromType(tag),
545 .pointee = .{ .symbol_name = ss.symbol_table.items[index].name.unwrap().? },600 .offset = offset,
546 .addend = undefined,601 .pointee = .{ .function = sym.pointee.function },
602 .addend = undefined,
603 },
604 .function_import => .{
605 .tag = .fromTypeImport(tag),
606 .offset = offset,
607 .pointee = .{ .symbol_name = sym.name.unwrap().? },
608 .addend = undefined,
609 },
610 else => unreachable,
611 });
612 },
613 .global_index_leb, .global_index_i32 => {
614 wasm.object_relocations.appendAssumeCapacity(switch (sym.pointee) {
615 .global => .{
616 .tag = .fromType(tag),
617 .offset = offset,
618 .pointee = .{ .global = sym.pointee.global },
619 .addend = undefined,
620 },
621 .global_import => .{
622 .tag = .fromTypeImport(tag),
623 .offset = offset,
624 .pointee = .{ .symbol_name = sym.name.unwrap().? },
625 .addend = undefined,
626 },
627 else => unreachable,
628 });
629 },
630
631 .table_number_leb => {
632 wasm.object_relocations.appendAssumeCapacity(switch (sym.pointee) {
633 .table => .{
634 .tag = .fromType(tag),
635 .offset = offset,
636 .pointee = .{ .table = sym.pointee.table },
637 .addend = undefined,
638 },
639 .table_import => .{
640 .tag = .fromTypeImport(tag),
641 .offset = offset,
642 .pointee = .{ .symbol_name = sym.name.unwrap().? },
643 .addend = undefined,
644 },
645 else => unreachable,
547 });646 });
548 },647 },
648 .event_index_leb => return diags.failParse(path, "unsupported relocation: R_WASM_EVENT_INDEX_LEB", .{}),
549 }649 }
550 }650 }
551651
...@@ -684,11 +784,17 @@ pub fn parse(...@@ -684,11 +784,17 @@ pub fn parse(
684 }784 }
685 },785 },
686 .global => {786 .global => {
787 if (global_section_index != null)
788 return diags.failParse(path, "object has more than one global section", .{});
789 global_section_index = section_index;
790
791 const section_start = pos;
687 const globals_len, pos = readLeb(u32, bytes, pos);792 const globals_len, pos = readLeb(u32, bytes, pos);
688 for (try wasm.object_globals.addManyAsSlice(gpa, globals_len)) |*global| {793 for (try wasm.object_globals.addManyAsSlice(gpa, globals_len)) |*global| {
689 const valtype, pos = readEnum(std.wasm.Valtype, bytes, pos);794 const valtype, pos = readEnum(std.wasm.Valtype, bytes, pos);
690 const mutable = bytes[pos] == 0x01;795 const mutable = bytes[pos] == 0x01;
691 pos += 1;796 pos += 1;
797 const init_start = pos;
692 const expr, pos = try readInit(wasm, bytes, pos);798 const expr, pos = try readInit(wasm, bytes, pos);
693 global.* = .{799 global.* = .{
694 .name = .none,800 .name = .none,
...@@ -699,6 +805,9 @@ pub fn parse(...@@ -699,6 +805,9 @@ pub fn parse(
699 },805 },
700 },806 },
701 .expr = expr,807 .expr = expr,
808 .object_index = object_index,
809 .offset = @intCast(init_start - section_start),
810 .size = @intCast(pos - init_start),
702 };811 };
703 }812 }
704 },813 },
...@@ -728,10 +837,14 @@ pub fn parse(...@@ -728,10 +837,14 @@ pub fn parse(
728 start_function = @enumFromInt(functions_start + index);837 start_function = @enumFromInt(functions_start + index);
729 },838 },
730 .element => {839 .element => {
731 log.warn("unimplemented: element section in {}", .{path});840 log.warn("unimplemented: element section in {} {s}", .{ path, archive_member_name.? });
732 pos = section_end;841 pos = section_end;
733 },842 },
734 .code => {843 .code => {
844 if (code_section_index != null)
845 return diags.failParse(path, "object has more than one code section", .{});
846 code_section_index = section_index;
847
735 const start = pos;848 const start = pos;
736 const count, pos = readLeb(u32, bytes, pos);849 const count, pos = readLeb(u32, bytes, pos);
737 for (try wasm.object_functions.addManyAsSlice(gpa, count)) |*elem| {850 for (try wasm.object_functions.addManyAsSlice(gpa, count)) |*elem| {
...@@ -745,12 +858,16 @@ pub fn parse(...@@ -745,12 +858,16 @@ pub fn parse(
745 .type_index = undefined, // populated from func_types858 .type_index = undefined, // populated from func_types
746 .code = payload,859 .code = payload,
747 .offset = offset,860 .offset = offset,
748 .section_index = section_index,861 .object_index = object_index,
749 .source_location = source_location,
750 };862 };
751 }863 }
752 },864 },
753 .data => {865 .data => {
866 if (data_section_index != null)
867 return diags.failParse(path, "object has more than one data section", .{});
868 data_section_index = section_index;
869
870 const section_start = pos;
754 const count, pos = readLeb(u32, bytes, pos);871 const count, pos = readLeb(u32, bytes, pos);
755 for (try wasm.object_data_segments.addManyAsSlice(gpa, count)) |*elem| {872 for (try wasm.object_data_segments.addManyAsSlice(gpa, count)) |*elem| {
756 const flags, pos = readEnum(DataSegmentFlags, bytes, pos);873 const flags, pos = readEnum(DataSegmentFlags, bytes, pos);
...@@ -761,12 +878,17 @@ pub fn parse(...@@ -761,12 +878,17 @@ pub fn parse(
761 //const expr, pos = if (flags != .passive) try readInit(wasm, bytes, pos) else .{ .none, pos };878 //const expr, pos = if (flags != .passive) try readInit(wasm, bytes, pos) else .{ .none, pos };
762 if (flags != .passive) pos = try skipInit(bytes, pos);879 if (flags != .passive) pos = try skipInit(bytes, pos);
763 const data_len, pos = readLeb(u32, bytes, pos);880 const data_len, pos = readLeb(u32, bytes, pos);
881 const segment_start = pos;
764 const payload = try wasm.addRelocatableDataPayload(bytes[pos..][0..data_len]);882 const payload = try wasm.addRelocatableDataPayload(bytes[pos..][0..data_len]);
765 pos += data_len;883 pos += data_len;
766 elem.* = .{884 elem.* = .{
767 .payload = payload,885 .payload = payload,
768 .name = .none, // Populated from symbol table886 .name = .none, // Populated from segment_info
769 .flags = .{}, // Populated from symbol table and segment_info887 .flags = .{
888 .is_passive = flags == .passive,
889 }, // Remainder populated from segment_info
890 .offset = @intCast(segment_start - section_start),
891 .object_index = object_index,
770 };892 };
771 }893 }
772 },894 },
...@@ -1033,8 +1155,10 @@ pub fn parse(...@@ -1033,8 +1155,10 @@ pub fn parse(
1033 }1155 }
1034 },1156 },
1035 .data_import => {1157 .data_import => {
1036 const name = symbol.name.unwrap().?;1158 if (symbol.flags.undefined and symbol.flags.binding == .local) {
1037 log.warn("TODO data import '{s}'", .{name.slice(wasm)});1159 const name = symbol.name.slice(wasm).?;
1160 diags.addParseError(path, "local symbol '{s}' references import", .{name});
1161 }
1038 },1162 },
1039 .data => continue, // `wasm.object_datas` has already been populated.1163 .data => continue, // `wasm.object_datas` has already been populated.
1040 };1164 };
...@@ -1055,16 +1179,21 @@ pub fn parse(...@@ -1055,16 +1179,21 @@ pub fn parse(
1055 }1179 }
10561180
1057 // Apply segment_info.1181 // Apply segment_info.
1058 for (wasm.object_data_segments.items[data_segment_start..], ss.segment_info.items) |*data, info| {1182 const data_segments = wasm.object_data_segments.items[data_segment_start..];
1183 if (data_segments.len != ss.segment_info.items.len) {
1184 return diags.failParse(path, "expected {d} segment_info entries; found {d}", .{
1185 data_segments.len, ss.segment_info.items.len,
1186 });
1187 }
1188 for (data_segments, ss.segment_info.items) |*data, info| {
1059 data.name = info.name.toOptional();1189 data.name = info.name.toOptional();
1060 data.flags.strings = info.flags.strings;1190 data.flags = .{
1061 data.flags.tls = data.flags.tls or info.flags.tls;1191 .is_passive = data.flags.is_passive,
1062 data.flags.no_strip = info.flags.retain;1192 .strings = info.flags.strings,
1063 data.flags.alignment = info.flags.alignment;1193 .tls = info.flags.tls,
1064 if (data.flags.undefined and data.flags.binding == .local) {1194 .retain = info.flags.retain,
1065 const name = info.name.slice(wasm);1195 .alignment = info.flags.alignment,
1066 diags.addParseError(path, "local symbol '{s}' references import", .{name});1196 };
1067 }
1068 }1197 }
10691198
1070 // Check for indirect function table in case of an MVP object file.1199 // Check for indirect function table in case of an MVP object file.
...@@ -1106,6 +1235,10 @@ pub fn parse(...@@ -1106,6 +1235,10 @@ pub fn parse(
1106 });1235 });
1107 }1236 }
11081237
1238 const functions_len: u32 = @intCast(wasm.object_functions.items.len - functions_start);
1239 if (functions_len > 0 and code_section_index == null)
1240 return diags.failParse(path, "code section missing ({d} functions)", .{functions_len});
1241
1109 return .{1242 return .{
1110 .version = version,1243 .version = version,
1111 .path = path,1244 .path = path,
...@@ -1114,7 +1247,7 @@ pub fn parse(...@@ -1114,7 +1247,7 @@ pub fn parse(
1114 .features = features,1247 .features = features,
1115 .functions = .{1248 .functions = .{
1116 .off = functions_start,1249 .off = functions_start,
1117 .len = @intCast(wasm.object_functions.items.len - functions_start),1250 .len = functions_len,
1118 },1251 },
1119 .function_imports = .{1252 .function_imports = .{
1120 .off = function_imports_start,1253 .off = function_imports_start,
...@@ -1140,7 +1273,9 @@ pub fn parse(...@@ -1140,7 +1273,9 @@ pub fn parse(
1140 .off = custom_segment_start,1273 .off = custom_segment_start,
1141 .len = @intCast(wasm.object_custom_segments.entries.len - custom_segment_start),1274 .len = @intCast(wasm.object_custom_segments.entries.len - custom_segment_start),
1142 },1275 },
1143 .local_section_index_base = local_section_index_base,1276 .code_section_index = code_section_index,
1277 .global_section_index = global_section_index,
1278 .data_section_index = data_section_index,
1144 };1279 };
1145}1280}
11461281