| ... | ... | @@ -93,13 +93,13 @@ func_types: std.AutoArrayHashMapUnmanaged(FunctionType, void) = .empty, |
| 93 | 93 | /// Local functions may be unnamed. |
| 94 | 94 | object_function_imports: std.AutoArrayHashMapUnmanaged(String, FunctionImport) = .empty, |
| 95 | 95 | /// All functions for all objects. |
| 96 | | object_functions: std.ArrayListUnmanaged(Function) = .empty, |
| 96 | object_functions: std.ArrayListUnmanaged(ObjectFunction) = .empty, |
| 97 | 97 | |
| 98 | 98 | /// Provides a mapping of both imports and provided globals to symbol name. |
| 99 | 99 | /// Local globals may be unnamed. |
| 100 | 100 | object_global_imports: std.AutoArrayHashMapUnmanaged(String, GlobalImport) = .empty, |
| 101 | 101 | /// All globals for all objects. |
| 102 | | object_globals: std.ArrayListUnmanaged(Global) = .empty, |
| 102 | object_globals: std.ArrayListUnmanaged(ObjectGlobal) = .empty, |
| 103 | 103 | |
| 104 | 104 | /// All table imports for all objects. |
| 105 | 105 | object_table_imports: std.AutoArrayHashMapUnmanaged(String, TableImport) = .empty, |
| ... | ... | @@ -386,7 +386,7 @@ pub const GlobalIndex = enum(u32) { |
| 386 | 386 | pub const stack_pointer: GlobalIndex = @enumFromInt(0); |
| 387 | 387 | |
| 388 | 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 | 390 | const comp = wasm.base.comp; |
| 391 | 391 | assert(comp.config.output_mode != .Obj); |
| 392 | 392 | assert(comp.zcu != null); |
| ... | ... | @@ -513,26 +513,19 @@ pub const SymbolFlags = packed struct(u32) { |
| 513 | 513 | |
| 514 | 514 | // Above here matches the tooling conventions ABI. |
| 515 | 515 | |
| 516 | | padding1: u5 = 0, |
| 516 | padding1: u13 = 0, |
| 517 | 517 | /// Zig-specific. Dead things are allowed to be garbage collected. |
| 518 | 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 | 519 | /// Zig-specific. This symbol comes from an object that must be included in |
| 523 | 520 | /// the final link. |
| 524 | 521 | must_link: bool = false, |
| 525 | | /// Zig-specific. Data segments only. |
| 526 | | is_passive: bool = false, |
| 527 | | /// Zig-specific. Data segments only. |
| 528 | | alignment: Alignment = .none, |
| 529 | | /// Zig-specific. Globals only. |
| 522 | /// Zig-specific. |
| 530 | 523 | global_type: GlobalType4 = .zero, |
| 531 | | /// Zig-specific. Tables only. |
| 524 | /// Zig-specific. |
| 532 | 525 | limits_has_max: bool = false, |
| 533 | | /// Zig-specific. Tables only. |
| 526 | /// Zig-specific. |
| 534 | 527 | limits_is_shared: bool = false, |
| 535 | | /// Zig-specific. Tables only. |
| 528 | /// Zig-specific. |
| 536 | 529 | ref_type: RefType1 = .funcref, |
| 537 | 530 | |
| 538 | 531 | pub const Binding = enum(u2) { |
| ... | ... | @@ -554,10 +547,7 @@ pub const SymbolFlags = packed struct(u32) { |
| 554 | 547 | pub fn initZigSpecific(flags: *SymbolFlags, must_link: bool, no_strip: bool) void { |
| 555 | 548 | flags.no_strip = no_strip; |
| 556 | 549 | flags.alive = false; |
| 557 | | flags.strings = false; |
| 558 | 550 | flags.must_link = must_link; |
| 559 | | flags.is_passive = false; |
| 560 | | flags.alignment = .none; |
| 561 | 551 | flags.global_type = .zero; |
| 562 | 552 | flags.limits_has_max = false; |
| 563 | 553 | flags.limits_is_shared = false; |
| ... | ... | @@ -603,7 +593,7 @@ pub const GlobalType4 = packed struct(u4) { |
| 603 | 593 | |
| 604 | 594 | pub const zero: GlobalType4 = @bitCast(@as(u4, 0)); |
| 605 | 595 | |
| 606 | | pub fn to(gt: GlobalType4) Global.Type { |
| 596 | pub fn to(gt: GlobalType4) ObjectGlobal.Type { |
| 607 | 597 | return .{ |
| 608 | 598 | .valtype = gt.valtype.to(), |
| 609 | 599 | .mutable = gt.mutable, |
| ... | ... | @@ -1001,18 +991,24 @@ pub const FunctionImport = extern struct { |
| 1001 | 991 | }; |
| 1002 | 992 | }; |
| 1003 | 993 | |
| 1004 | | pub const Function = extern struct { |
| 994 | pub const ObjectFunction = extern struct { |
| 1005 | 995 | flags: SymbolFlags, |
| 1006 | 996 | /// `none` if this function has no symbol describing it. |
| 1007 | 997 | name: OptionalString, |
| 1008 | 998 | type_index: FunctionType.Index, |
| 1009 | 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 | 1001 | offset: u32, |
| 1012 | | section_index: ObjectSectionIndex, |
| 1013 | | source_location: SourceLocation, |
| 1002 | /// The object file whose code section contains this function. |
| 1003 | object_index: ObjectIndex, |
| 1014 | 1004 | |
| 1015 | 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 | }; |
| 1017 | 1013 | |
| 1018 | 1014 | pub const GlobalImport = extern struct { |
| ... | ... | @@ -1101,6 +1097,10 @@ pub const GlobalImport = extern struct { |
| 1101 | 1097 | }); |
| 1102 | 1098 | } |
| 1103 | 1099 | |
| 1100 | fn fromObjectGlobal(wasm: *const Wasm, object_global: ObjectGlobalIndex) Resolution { |
| 1101 | return pack(wasm, .{ .object_global = object_global }); |
| 1102 | } |
| 1103 | |
| 1104 | 1104 | pub fn name(r: Resolution, wasm: *const Wasm) ?[]const u8 { |
| 1105 | 1105 | return switch (unpack(r, wasm)) { |
| 1106 | 1106 | .unresolved => unreachable, |
| ... | ... | @@ -1137,22 +1137,32 @@ pub const GlobalImport = extern struct { |
| 1137 | 1137 | return index.value(wasm).module_name; |
| 1138 | 1138 | } |
| 1139 | 1139 | |
| 1140 | | pub fn globalType(index: Index, wasm: *const Wasm) Global.Type { |
| 1140 | pub fn globalType(index: Index, wasm: *const Wasm) ObjectGlobal.Type { |
| 1141 | 1141 | return value(index, wasm).flags.global_type.to(); |
| 1142 | 1142 | } |
| 1143 | 1143 | }; |
| 1144 | 1144 | }; |
| 1145 | 1145 | |
| 1146 | | pub const Global = extern struct { |
| 1146 | pub const ObjectGlobal = extern struct { |
| 1147 | 1147 | /// `none` if this function has no symbol describing it. |
| 1148 | 1148 | name: OptionalString, |
| 1149 | 1149 | flags: SymbolFlags, |
| 1150 | 1150 | expr: Expr, |
| 1151 | /// The object file whose global section contains this global. |
| 1152 | object_index: ObjectIndex, |
| 1153 | offset: u32, |
| 1154 | size: u32, |
| 1151 | 1155 | |
| 1152 | 1156 | pub const Type = struct { |
| 1153 | 1157 | valtype: std.wasm.Valtype, |
| 1154 | 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 | }; |
| 1157 | 1167 | |
| 1158 | 1168 | pub const RefType1 = enum(u1) { |
| ... | ... | @@ -1205,6 +1215,18 @@ pub const TableImport = extern struct { |
| 1205 | 1215 | }; |
| 1206 | 1216 | } |
| 1207 | 1217 | |
| 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 | 1230 | pub fn refType(r: Resolution, wasm: *const Wasm) std.wasm.RefType { |
| 1209 | 1231 | return switch (unpack(r)) { |
| 1210 | 1232 | .unresolved => unreachable, |
| ... | ... | @@ -1298,7 +1320,7 @@ pub const ObjectTableIndex = enum(u32) { |
| 1298 | 1320 | pub const ObjectGlobalIndex = enum(u32) { |
| 1299 | 1321 | _, |
| 1300 | 1322 | |
| 1301 | | pub fn ptr(index: ObjectGlobalIndex, wasm: *const Wasm) *Global { |
| 1323 | pub fn ptr(index: ObjectGlobalIndex, wasm: *const Wasm) *ObjectGlobal { |
| 1302 | 1324 | return &wasm.object_globals.items[@intFromEnum(index)]; |
| 1303 | 1325 | } |
| 1304 | 1326 | |
| ... | ... | @@ -1338,7 +1360,7 @@ pub const ObjectMemory = extern struct { |
| 1338 | 1360 | pub const ObjectFunctionIndex = enum(u32) { |
| 1339 | 1361 | _, |
| 1340 | 1362 | |
| 1341 | | pub fn ptr(index: ObjectFunctionIndex, wasm: *const Wasm) *Function { |
| 1363 | pub fn ptr(index: ObjectFunctionIndex, wasm: *const Wasm) *ObjectFunction { |
| 1342 | 1364 | return &wasm.object_functions.items[@intFromEnum(index)]; |
| 1343 | 1365 | } |
| 1344 | 1366 | |
| ... | ... | @@ -1363,8 +1385,28 @@ pub const OptionalObjectFunctionIndex = enum(u32) { |
| 1363 | 1385 | pub const ObjectDataSegment = extern struct { |
| 1364 | 1386 | /// `none` if segment info custom subsection is missing. |
| 1365 | 1387 | name: OptionalString, |
| 1366 | | flags: SymbolFlags, |
| 1388 | flags: Flags, |
| 1367 | 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 | }; |
| 1368 | 1410 | |
| 1369 | 1411 | /// Index into `Wasm.object_data_segments`. |
| 1370 | 1412 | pub const Index = enum(u32) { |
| ... | ... | @@ -1374,6 +1416,12 @@ pub const ObjectDataSegment = extern struct { |
| 1374 | 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 | }; |
| 1378 | 1426 | |
| 1379 | 1427 | /// A local or exported global const from an object file. |
| ... | ... | @@ -1383,8 +1431,7 @@ pub const ObjectData = extern struct { |
| 1383 | 1431 | offset: u32, |
| 1384 | 1432 | /// May be zero. `offset + size` must be <= the segment's size. |
| 1385 | 1433 | size: u32, |
| 1386 | | /// `none` if no symbol describes it. |
| 1387 | | name: OptionalString, |
| 1434 | name: String, |
| 1388 | 1435 | flags: SymbolFlags, |
| 1389 | 1436 | |
| 1390 | 1437 | /// Index into `Wasm.object_datas`. |
| ... | ... | @@ -1845,7 +1892,7 @@ pub const ZcuImportIndex = enum(u32) { |
| 1845 | 1892 | return getExistingFunctionType(wasm, fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), target).?; |
| 1846 | 1893 | } |
| 1847 | 1894 | |
| 1848 | | pub fn globalType(index: ZcuImportIndex, wasm: *const Wasm) Global.Type { |
| 1895 | pub fn globalType(index: ZcuImportIndex, wasm: *const Wasm) ObjectGlobal.Type { |
| 1849 | 1896 | _ = index; |
| 1850 | 1897 | _ = wasm; |
| 1851 | 1898 | unreachable; // Zig has no way to create Wasm globals yet. |
| ... | ... | @@ -1997,7 +2044,7 @@ pub const GlobalImportId = enum(u32) { |
| 1997 | 2044 | }; |
| 1998 | 2045 | } |
| 1999 | 2046 | |
| 2000 | | pub fn globalType(id: GlobalImportId, wasm: *Wasm) Global.Type { |
| 2047 | pub fn globalType(id: GlobalImportId, wasm: *Wasm) ObjectGlobal.Type { |
| 2001 | 2048 | return switch (unpack(id, wasm)) { |
| 2002 | 2049 | inline .object_global_import, .zcu_import => |i| i.globalType(wasm), |
| 2003 | 2050 | }; |
| ... | ... | @@ -2014,7 +2061,7 @@ pub const SymbolTableIndex = enum(u32) { |
| 2014 | 2061 | }; |
| 2015 | 2062 | |
| 2016 | 2063 | pub const OutReloc = struct { |
| 2017 | | tag: ObjectRelocation.Tag, |
| 2064 | tag: Object.RelocationType, |
| 2018 | 2065 | offset: u32, |
| 2019 | 2066 | pointee: Pointee, |
| 2020 | 2067 | addend: i32, |
| ... | ... | @@ -2041,15 +2088,144 @@ pub const ObjectRelocation = struct { |
| 2041 | 2088 | /// When `offset` is zero, its position is immediately after the id and size of the section. |
| 2042 | 2089 | offset: u32, |
| 2043 | 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 | 2092 | addend: i32, |
| 2046 | 2093 | |
| 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 | 2221 | pub const Pointee = union { |
| 2048 | 2222 | symbol_name: String, |
| 2223 | data: ObjectData.Index, |
| 2049 | 2224 | type_index: FunctionType.Index, |
| 2050 | 2225 | section: ObjectSectionIndex, |
| 2051 | | data: ObjectData.Index, |
| 2052 | | function: Wasm.ObjectFunctionIndex, |
| 2226 | function: ObjectFunctionIndex, |
| 2227 | global: ObjectGlobalIndex, |
| 2228 | table: ObjectTableIndex, |
| 2053 | 2229 | }; |
| 2054 | 2230 | |
| 2055 | 2231 | pub const Slice = extern struct { |
| ... | ... | @@ -2057,63 +2233,47 @@ pub const ObjectRelocation = struct { |
| 2057 | 2233 | off: u32, |
| 2058 | 2234 | len: u32, |
| 2059 | 2235 | |
| 2060 | | pub fn slice(s: Slice, wasm: *const Wasm) []ObjectRelocation { |
| 2061 | | return wasm.relocations.items[s.off..][0..s.len]; |
| 2236 | const empty: Slice = .{ .off = 0, .len = 0 }; |
| 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 | }; |
| 2064 | 2254 | |
| 2065 | | pub const Tag = enum(u8) { |
| 2066 | | /// Uses `function`. |
| 2067 | | FUNCTION_INDEX_LEB = 0, |
| 2068 | | /// Uses `table_index`. |
| 2069 | | TABLE_INDEX_SLEB = 1, |
| 2070 | | /// Uses `table_index`. |
| 2071 | | TABLE_INDEX_I32 = 2, |
| 2072 | | /// Uses `data_segment`. |
| 2073 | | MEMORY_ADDR_LEB = 3, |
| 2074 | | /// Uses `data_segment`. |
| 2075 | | MEMORY_ADDR_SLEB = 4, |
| 2076 | | /// Uses `data_segment`. |
| 2077 | | MEMORY_ADDR_I32 = 5, |
| 2078 | | /// Uses `type_index`. |
| 2079 | | TYPE_INDEX_LEB = 6, |
| 2080 | | /// Uses `symbol_name`. |
| 2081 | | GLOBAL_INDEX_LEB = 7, |
| 2082 | | FUNCTION_OFFSET_I32 = 8, |
| 2083 | | SECTION_OFFSET_I32 = 9, |
| 2084 | | TAG_INDEX_LEB = 10, |
| 2085 | | /// Uses `data_segment`. |
| 2086 | | MEMORY_ADDR_REL_SLEB = 11, |
| 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. |
| 2255 | pub const IterableSlice = struct { |
| 2256 | slice: Slice, |
| 2257 | /// Offset at which point to stop iterating. |
| 2258 | end: u32, |
| 2259 | |
| 2260 | const empty: IterableSlice = .{ .slice = .empty, .end = 0 }; |
| 2261 | |
| 2262 | fn init(relocs: Slice, offset: u32, size: u32, wasm: *const Wasm) IterableSlice { |
| 2263 | const offsets = relocs.offsets(wasm); |
| 2264 | const start = std.sort.lowerBound(u32, offsets, offset, order); |
| 2265 | return .{ |
| 2266 | .slice = .{ |
| 2267 | .off = @intCast(relocs.off + start), |
| 2268 | .len = @intCast(relocs.len - start), |
| 2269 | }, |
| 2270 | .end = offset + size, |
| 2271 | }; |
| 2272 | } |
| 2273 | |
| 2274 | fn order(lhs: u32, rhs: u32) std.math.Order { |
| 2275 | return std.math.order(lhs, rhs); |
| 2276 | } |
| 2117 | 2277 | }; |
| 2118 | 2278 | }; |
| 2119 | 2279 | |
| ... | ... | @@ -2781,7 +2941,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v |
| 2781 | 2941 | // At the end, output functions and globals will be populated. |
| 2782 | 2942 | for (wasm.object_function_imports.keys(), wasm.object_function_imports.values(), 0..) |name, *import, i| { |
| 2783 | 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 | 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 | 2949 | |
| 2790 | 2950 | for (wasm.object_global_imports.keys(), wasm.object_global_imports.values(), 0..) |name, *import, i| { |
| 2791 | 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 | 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 | 2957 | |
| 2798 | 2958 | for (wasm.object_table_imports.keys(), wasm.object_table_imports.values(), 0..) |name, *import, i| { |
| 2799 | 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 | } |
| 2804 | 2964 | |
| 2805 | | /// Recursively mark alive everything referenced by the function. |
| 2806 | | fn markFunction( |
| 2965 | fn markFunctionImport( |
| 2807 | 2966 | wasm: *Wasm, |
| 2808 | 2967 | name: String, |
| 2809 | 2968 | import: *FunctionImport, |
| ... | ... | @@ -2814,8 +2973,6 @@ fn markFunction( |
| 2814 | 2973 | |
| 2815 | 2974 | const comp = wasm.base.comp; |
| 2816 | 2975 | const gpa = comp.gpa; |
| 2817 | | const rdynamic = comp.config.rdynamic; |
| 2818 | | const is_obj = comp.config.output_mode == .Obj; |
| 2819 | 2976 | |
| 2820 | 2977 | try wasm.functions.ensureUnusedCapacity(gpa, 1); |
| 2821 | 2978 | |
| ... | ... | @@ -2836,20 +2993,31 @@ fn markFunction( |
| 2836 | 2993 | try wasm.function_imports.put(gpa, name, .fromObject(func_index, wasm)); |
| 2837 | 2994 | } |
| 2838 | 2995 | } else { |
| 2839 | | const gop = wasm.functions.getOrPutAssumeCapacity(import.resolution); |
| 2996 | try markFunction(wasm, import.resolution.unpack(wasm).object_function); |
| 2997 | } |
| 2998 | } |
| 2840 | 2999 | |
| 2841 | | if (!is_obj and import.flags.isExported(rdynamic)) try wasm.function_exports.append(gpa, .{ |
| 2842 | | .name = name, |
| 2843 | | .function_index = @enumFromInt(gop.index), |
| 2844 | | }); |
| 3000 | /// Recursively mark alive everything referenced by the function. |
| 3001 | fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex) Allocator.Error!void { |
| 3002 | const comp = wasm.base.comp; |
| 3003 | const gpa = comp.gpa; |
| 3004 | const gop = try wasm.functions.getOrPut(gpa, .fromObjectFunction(wasm, i)); |
| 3005 | if (gop.found_existing) return; |
| 2845 | 3006 | |
| 2846 | | for (try wasm.functionResolutionRelocSlice(import.resolution)) |reloc| |
| 2847 | | try wasm.markReloc(reloc); |
| 2848 | | } |
| 3007 | const rdynamic = comp.config.rdynamic; |
| 3008 | const is_obj = comp.config.output_mode == .Obj; |
| 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 | } |
| 2850 | 3018 | |
| 2851 | 3019 | /// Recursively mark alive everything referenced by the global. |
| 2852 | | fn markGlobal( |
| 3020 | fn markGlobalImport( |
| 2853 | 3021 | wasm: *Wasm, |
| 2854 | 3022 | name: String, |
| 2855 | 3023 | import: *GlobalImport, |
| ... | ... | @@ -2860,8 +3028,6 @@ fn markGlobal( |
| 2860 | 3028 | |
| 2861 | 3029 | const comp = wasm.base.comp; |
| 2862 | 3030 | const gpa = comp.gpa; |
| 2863 | | const rdynamic = comp.config.rdynamic; |
| 2864 | | const is_obj = comp.config.output_mode == .Obj; |
| 2865 | 3031 | |
| 2866 | 3032 | try wasm.globals.ensureUnusedCapacity(gpa, 1); |
| 2867 | 3033 | |
| ... | ... | @@ -2888,19 +3054,29 @@ fn markGlobal( |
| 2888 | 3054 | try wasm.global_imports.put(gpa, name, .fromObject(global_index, wasm)); |
| 2889 | 3055 | } |
| 2890 | 3056 | } else { |
| 2891 | | const gop = wasm.globals.getOrPutAssumeCapacity(import.resolution); |
| 3057 | try markGlobal(wasm, import.resolution.unpack(wasm).object_global); |
| 3058 | } |
| 3059 | } |
| 2892 | 3060 | |
| 2893 | | if (!is_obj and import.flags.isExported(rdynamic)) try wasm.global_exports.append(gpa, .{ |
| 2894 | | .name = name, |
| 2895 | | .global_index = @enumFromInt(gop.index), |
| 2896 | | }); |
| 3061 | fn markGlobal(wasm: *Wasm, i: ObjectGlobalIndex) Allocator.Error!void { |
| 3062 | const comp = wasm.base.comp; |
| 3063 | const gpa = comp.gpa; |
| 3064 | const gop = try wasm.globals.getOrPut(gpa, .fromObjectGlobal(wasm, i)); |
| 3065 | if (gop.found_existing) return; |
| 2897 | 3066 | |
| 2898 | | for (try wasm.globalResolutionRelocSlice(import.resolution)) |reloc| |
| 2899 | | try wasm.markReloc(reloc); |
| 2900 | | } |
| 3067 | const rdynamic = comp.config.rdynamic; |
| 3068 | const is_obj = comp.config.output_mode == .Obj; |
| 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 | } |
| 2902 | 3078 | |
| 2903 | | fn markTable( |
| 3079 | fn markTableImport( |
| 2904 | 3080 | wasm: *Wasm, |
| 2905 | 3081 | name: String, |
| 2906 | 3082 | import: *TableImport, |
| ... | ... | @@ -2927,22 +3103,101 @@ fn markTable( |
| 2927 | 3103 | } |
| 2928 | 3104 | } |
| 2929 | 3105 | |
| 2930 | | fn globalResolutionRelocSlice(wasm: *Wasm, resolution: GlobalImport.Resolution) ![]const ObjectRelocation { |
| 2931 | | assert(resolution != .unresolved); |
| 2932 | | _ = wasm; |
| 2933 | | @panic("TODO"); |
| 2934 | | } |
| 3106 | fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) Allocator.Error!void { |
| 3107 | const segment = segment_index.ptr(wasm); |
| 3108 | if (segment.flags.alive) return; |
| 3109 | segment.flags.alive = true; |
| 2935 | 3110 | |
| 2936 | | fn functionResolutionRelocSlice(wasm: *Wasm, resolution: FunctionImport.Resolution) ![]const ObjectRelocation { |
| 2937 | | assert(resolution != .unresolved); |
| 2938 | | _ = wasm; |
| 2939 | | @panic("TODO"); |
| 3111 | try wasm.markRelocations(segment.relocations(wasm)); |
| 2940 | 3112 | } |
| 2941 | 3113 | |
| 2942 | | fn markReloc(wasm: *Wasm, reloc: ObjectRelocation) !void { |
| 2943 | | _ = wasm; |
| 2944 | | _ = reloc; |
| 2945 | | @panic("TODO"); |
| 3114 | fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) Allocator.Error!void { |
| 3115 | for (relocs.slice.tags(wasm), relocs.slice.pointees(wasm), relocs.slice.offsets(wasm)) |tag, *pointee, offset| { |
| 3116 | if (offset >= relocs.end) break; |
| 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 | } |
| 2947 | 3202 | |
| 2948 | 3203 | pub fn flushModule( |