| ... | @@ -653,6 +653,8 @@ fn resolveSymbolsInArchives(self: *Wasm) !void { | ... | @@ -653,6 +653,8 @@ fn resolveSymbolsInArchives(self: *Wasm) !void { |
| 653 | } | 653 | } |
| 654 | | 654 | |
| 655 | fn checkUndefinedSymbols(self: *const Wasm) !void { | 655 | fn checkUndefinedSymbols(self: *const Wasm) !void { |
| | 656 | if (self.base.options.output_mode == .Obj) return; |
| | 657 | |
| 656 | var found_undefined_symbols = false; | 658 | var found_undefined_symbols = false; |
| 657 | for (self.undefs.values()) |undef| { | 659 | for (self.undefs.values()) |undef| { |
| 658 | const symbol = undef.getSymbol(self); | 660 | const symbol = undef.getSymbol(self); |
| ... | @@ -2207,33 +2209,38 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2207,33 +2209,38 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2207 | try self.mergeTypes(); | 2209 | try self.mergeTypes(); |
| 2208 | try self.setupExports(); | 2210 | try self.setupExports(); |
| 2209 | | 2211 | |
| 2210 | const file = self.base.file.?; | | |
| 2211 | const header_size = 5 + 1; | 2212 | const header_size = 5 + 1; |
| 2212 | const is_obj = self.base.options.output_mode == .Obj; | 2213 | const is_obj = self.base.options.output_mode == .Obj; |
| 2213 | | 2214 | |
| | 2215 | var binary_bytes = std.ArrayList(u8).init(self.base.allocator); |
| | 2216 | defer binary_bytes.deinit(); |
| | 2217 | const binary_writer = binary_bytes.writer(); |
| | 2218 | |
| 2214 | // We write the magic bytes at the end so they will only be written | 2219 | // We write the magic bytes at the end so they will only be written |
| 2215 | // if everything succeeded as expected. | 2220 | // if everything succeeded as expected. So populate with 0's for now. |
| 2216 | try file.setEndPos(@sizeOf(@TypeOf(wasm.magic ++ wasm.version))); | 2221 | try binary_writer.writeAll(&[_]u8{0} ** 8); |
| 2217 | try file.seekTo(@sizeOf(@TypeOf(wasm.magic ++ wasm.version))); | | |
| 2218 | | 2222 | |
| 2219 | // Type section | 2223 | // Type section |
| 2220 | if (self.func_types.items.len != 0) { | 2224 | if (self.func_types.items.len != 0) { |
| 2221 | const header_offset = try reserveVecSectionHeader(file); | 2225 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2222 | const writer = file.writer(); | | |
| 2223 | log.debug("Writing type section. Count: ({d})", .{self.func_types.items.len}); | 2226 | log.debug("Writing type section. Count: ({d})", .{self.func_types.items.len}); |
| 2224 | for (self.func_types.items) |func_type| { | 2227 | for (self.func_types.items) |func_type| { |
| 2225 | try leb.writeULEB128(writer, wasm.function_type); | 2228 | try leb.writeULEB128(binary_writer, wasm.function_type); |
| 2226 | try leb.writeULEB128(writer, @intCast(u32, func_type.params.len)); | 2229 | try leb.writeULEB128(binary_writer, @intCast(u32, func_type.params.len)); |
| 2227 | for (func_type.params) |param_ty| try leb.writeULEB128(writer, wasm.valtype(param_ty)); | 2230 | for (func_type.params) |param_ty| { |
| 2228 | try leb.writeULEB128(writer, @intCast(u32, func_type.returns.len)); | 2231 | try leb.writeULEB128(binary_writer, wasm.valtype(param_ty)); |
| 2229 | for (func_type.returns) |ret_ty| try leb.writeULEB128(writer, wasm.valtype(ret_ty)); | 2232 | } |
| | 2233 | try leb.writeULEB128(binary_writer, @intCast(u32, func_type.returns.len)); |
| | 2234 | for (func_type.returns) |ret_ty| { |
| | 2235 | try leb.writeULEB128(binary_writer, wasm.valtype(ret_ty)); |
| | 2236 | } |
| 2230 | } | 2237 | } |
| 2231 | | 2238 | |
| 2232 | try writeVecSectionHeader( | 2239 | try writeVecSectionHeader( |
| 2233 | file, | 2240 | binary_bytes.items, |
| 2234 | header_offset, | 2241 | header_offset, |
| 2235 | .type, | 2242 | .type, |
| 2236 | @intCast(u32, (try file.getPos()) - header_offset - header_size), | 2243 | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2237 | @intCast(u32, self.func_types.items.len), | 2244 | @intCast(u32, self.func_types.items.len), |
| 2238 | ); | 2245 | ); |
| 2239 | section_count += 1; | 2246 | section_count += 1; |
| ... | @@ -2243,8 +2250,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2243,8 +2250,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2243 | const import_memory = self.base.options.import_memory or is_obj; | 2250 | const import_memory = self.base.options.import_memory or is_obj; |
| 2244 | const import_table = self.base.options.import_table or is_obj; | 2251 | const import_table = self.base.options.import_table or is_obj; |
| 2245 | if (self.imports.count() != 0 or import_memory or import_table) { | 2252 | if (self.imports.count() != 0 or import_memory or import_table) { |
| 2246 | const header_offset = try reserveVecSectionHeader(file); | 2253 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2247 | const writer = file.writer(); | | |
| 2248 | | 2254 | |
| 2249 | // import table is always first table so emit that first | 2255 | // import table is always first table so emit that first |
| 2250 | if (import_table) { | 2256 | if (import_table) { |
| ... | @@ -2261,14 +2267,14 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2261,14 +2267,14 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2261 | }, | 2267 | }, |
| 2262 | }, | 2268 | }, |
| 2263 | }; | 2269 | }; |
| 2264 | try self.emitImport(writer, table_imp); | 2270 | try self.emitImport(binary_writer, table_imp); |
| 2265 | } | 2271 | } |
| 2266 | | 2272 | |
| 2267 | var it = self.imports.iterator(); | 2273 | var it = self.imports.iterator(); |
| 2268 | while (it.next()) |entry| { | 2274 | while (it.next()) |entry| { |
| 2269 | assert(entry.key_ptr.*.getSymbol(self).isUndefined()); | 2275 | assert(entry.key_ptr.*.getSymbol(self).isUndefined()); |
| 2270 | const import = entry.value_ptr.*; | 2276 | const import = entry.value_ptr.*; |
| 2271 | try self.emitImport(writer, import); | 2277 | try self.emitImport(binary_writer, import); |
| 2272 | } | 2278 | } |
| 2273 | | 2279 | |
| 2274 | if (import_memory) { | 2280 | if (import_memory) { |
| ... | @@ -2278,14 +2284,14 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2278,14 +2284,14 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2278 | .name = try self.string_table.put(self.base.allocator, mem_name), | 2284 | .name = try self.string_table.put(self.base.allocator, mem_name), |
| 2279 | .kind = .{ .memory = self.memories.limits }, | 2285 | .kind = .{ .memory = self.memories.limits }, |
| 2280 | }; | 2286 | }; |
| 2281 | try self.emitImport(writer, mem_imp); | 2287 | try self.emitImport(binary_writer, mem_imp); |
| 2282 | } | 2288 | } |
| 2283 | | 2289 | |
| 2284 | try writeVecSectionHeader( | 2290 | try writeVecSectionHeader( |
| 2285 | file, | 2291 | binary_bytes.items, |
| 2286 | header_offset, | 2292 | header_offset, |
| 2287 | .import, | 2293 | .import, |
| 2288 | @intCast(u32, (try file.getPos()) - header_offset - header_size), | 2294 | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2289 | @intCast(u32, self.imports.count() + @boolToInt(import_memory) + @boolToInt(import_table)), | 2295 | @intCast(u32, self.imports.count() + @boolToInt(import_memory) + @boolToInt(import_table)), |
| 2290 | ); | 2296 | ); |
| 2291 | section_count += 1; | 2297 | section_count += 1; |
| ... | @@ -2293,17 +2299,16 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2293,17 +2299,16 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2293 | | 2299 | |
| 2294 | // Function section | 2300 | // Function section |
| 2295 | if (self.functions.count() != 0) { | 2301 | if (self.functions.count() != 0) { |
| 2296 | const header_offset = try reserveVecSectionHeader(file); | 2302 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2297 | const writer = file.writer(); | | |
| 2298 | for (self.functions.values()) |function| { | 2303 | for (self.functions.values()) |function| { |
| 2299 | try leb.writeULEB128(writer, function.type_index); | 2304 | try leb.writeULEB128(binary_writer, function.type_index); |
| 2300 | } | 2305 | } |
| 2301 | | 2306 | |
| 2302 | try writeVecSectionHeader( | 2307 | try writeVecSectionHeader( |
| 2303 | file, | 2308 | binary_bytes.items, |
| 2304 | header_offset, | 2309 | header_offset, |
| 2305 | .function, | 2310 | .function, |
| 2306 | @intCast(u32, (try file.getPos()) - header_offset - header_size), | 2311 | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2307 | @intCast(u32, self.functions.count()), | 2312 | @intCast(u32, self.functions.count()), |
| 2308 | ); | 2313 | ); |
| 2309 | section_count += 1; | 2314 | section_count += 1; |
| ... | @@ -2312,20 +2317,19 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2312,20 +2317,19 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2312 | // Table section | 2317 | // Table section |
| 2313 | const export_table = self.base.options.export_table; | 2318 | const export_table = self.base.options.export_table; |
| 2314 | if (!import_table and self.function_table.count() != 0) { | 2319 | if (!import_table and self.function_table.count() != 0) { |
| 2315 | const header_offset = try reserveVecSectionHeader(file); | 2320 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2316 | const writer = file.writer(); | | |
| 2317 | | 2321 | |
| 2318 | try leb.writeULEB128(writer, wasm.reftype(.funcref)); | 2322 | try leb.writeULEB128(binary_writer, wasm.reftype(.funcref)); |
| 2319 | try emitLimits(writer, .{ | 2323 | try emitLimits(binary_writer, .{ |
| 2320 | .min = @intCast(u32, self.function_table.count()) + 1, | 2324 | .min = @intCast(u32, self.function_table.count()) + 1, |
| 2321 | .max = null, | 2325 | .max = null, |
| 2322 | }); | 2326 | }); |
| 2323 | | 2327 | |
| 2324 | try writeVecSectionHeader( | 2328 | try writeVecSectionHeader( |
| 2325 | file, | 2329 | binary_bytes.items, |
| 2326 | header_offset, | 2330 | header_offset, |
| 2327 | .table, | 2331 | .table, |
| 2328 | @intCast(u32, (try file.getPos()) - header_offset - header_size), | 2332 | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2329 | @as(u32, 1), | 2333 | @as(u32, 1), |
| 2330 | ); | 2334 | ); |
| 2331 | section_count += 1; | 2335 | section_count += 1; |
| ... | @@ -2333,15 +2337,14 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2333,15 +2337,14 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2333 | | 2337 | |
| 2334 | // Memory section | 2338 | // Memory section |
| 2335 | if (!import_memory) { | 2339 | if (!import_memory) { |
| 2336 | const header_offset = try reserveVecSectionHeader(file); | 2340 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2337 | const writer = file.writer(); | | |
| 2338 | | 2341 | |
| 2339 | try emitLimits(writer, self.memories.limits); | 2342 | try emitLimits(binary_writer, self.memories.limits); |
| 2340 | try writeVecSectionHeader( | 2343 | try writeVecSectionHeader( |
| 2341 | file, | 2344 | binary_bytes.items, |
| 2342 | header_offset, | 2345 | header_offset, |
| 2343 | .memory, | 2346 | .memory, |
| 2344 | @intCast(u32, (try file.getPos()) - header_offset - header_size), | 2347 | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2345 | @as(u32, 1), // wasm currently only supports 1 linear memory segment | 2348 | @as(u32, 1), // wasm currently only supports 1 linear memory segment |
| 2346 | ); | 2349 | ); |
| 2347 | section_count += 1; | 2350 | section_count += 1; |
| ... | @@ -2349,20 +2352,19 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2349,20 +2352,19 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2349 | | 2352 | |
| 2350 | // Global section (used to emit stack pointer) | 2353 | // Global section (used to emit stack pointer) |
| 2351 | if (self.wasm_globals.items.len > 0) { | 2354 | if (self.wasm_globals.items.len > 0) { |
| 2352 | const header_offset = try reserveVecSectionHeader(file); | 2355 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2353 | const writer = file.writer(); | | |
| 2354 | | 2356 | |
| 2355 | for (self.wasm_globals.items) |global| { | 2357 | for (self.wasm_globals.items) |global| { |
| 2356 | try writer.writeByte(wasm.valtype(global.global_type.valtype)); | 2358 | try binary_writer.writeByte(wasm.valtype(global.global_type.valtype)); |
| 2357 | try writer.writeByte(@boolToInt(global.global_type.mutable)); | 2359 | try binary_writer.writeByte(@boolToInt(global.global_type.mutable)); |
| 2358 | try emitInit(writer, global.init); | 2360 | try emitInit(binary_writer, global.init); |
| 2359 | } | 2361 | } |
| 2360 | | 2362 | |
| 2361 | try writeVecSectionHeader( | 2363 | try writeVecSectionHeader( |
| 2362 | file, | 2364 | binary_bytes.items, |
| 2363 | header_offset, | 2365 | header_offset, |
| 2364 | .global, | 2366 | .global, |
| 2365 | @intCast(u32, (try file.getPos()) - header_offset - header_size), | 2367 | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2366 | @intCast(u32, self.wasm_globals.items.len), | 2368 | @intCast(u32, self.wasm_globals.items.len), |
| 2367 | ); | 2369 | ); |
| 2368 | section_count += 1; | 2370 | section_count += 1; |
| ... | @@ -2370,35 +2372,35 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2370,35 +2372,35 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2370 | | 2372 | |
| 2371 | // Export section | 2373 | // Export section |
| 2372 | if (self.exports.items.len != 0 or export_table or !import_memory) { | 2374 | if (self.exports.items.len != 0 or export_table or !import_memory) { |
| 2373 | const header_offset = try reserveVecSectionHeader(file); | 2375 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2374 | const writer = file.writer(); | 2376 | |
| 2375 | for (self.exports.items) |exp| { | 2377 | for (self.exports.items) |exp| { |
| 2376 | const name = self.string_table.get(exp.name); | 2378 | const name = self.string_table.get(exp.name); |
| 2377 | try leb.writeULEB128(writer, @intCast(u32, name.len)); | 2379 | try leb.writeULEB128(binary_writer, @intCast(u32, name.len)); |
| 2378 | try writer.writeAll(name); | 2380 | try binary_writer.writeAll(name); |
| 2379 | try leb.writeULEB128(writer, @enumToInt(exp.kind)); | 2381 | try leb.writeULEB128(binary_writer, @enumToInt(exp.kind)); |
| 2380 | try leb.writeULEB128(writer, exp.index); | 2382 | try leb.writeULEB128(binary_writer, exp.index); |
| 2381 | } | 2383 | } |
| 2382 | | 2384 | |
| 2383 | if (export_table) { | 2385 | if (export_table) { |
| 2384 | try leb.writeULEB128(writer, @intCast(u32, "__indirect_function_table".len)); | 2386 | try leb.writeULEB128(binary_writer, @intCast(u32, "__indirect_function_table".len)); |
| 2385 | try writer.writeAll("__indirect_function_table"); | 2387 | try binary_writer.writeAll("__indirect_function_table"); |
| 2386 | try writer.writeByte(wasm.externalKind(.table)); | 2388 | try binary_writer.writeByte(wasm.externalKind(.table)); |
| 2387 | try leb.writeULEB128(writer, @as(u32, 0)); // function table is always the first table | 2389 | try leb.writeULEB128(binary_writer, @as(u32, 0)); // function table is always the first table |
| 2388 | } | 2390 | } |
| 2389 | | 2391 | |
| 2390 | if (!import_memory) { | 2392 | if (!import_memory) { |
| 2391 | try leb.writeULEB128(writer, @intCast(u32, "memory".len)); | 2393 | try leb.writeULEB128(binary_writer, @intCast(u32, "memory".len)); |
| 2392 | try writer.writeAll("memory"); | 2394 | try binary_writer.writeAll("memory"); |
| 2393 | try writer.writeByte(wasm.externalKind(.memory)); | 2395 | try binary_writer.writeByte(wasm.externalKind(.memory)); |
| 2394 | try leb.writeULEB128(writer, @as(u32, 0)); | 2396 | try leb.writeULEB128(binary_writer, @as(u32, 0)); |
| 2395 | } | 2397 | } |
| 2396 | | 2398 | |
| 2397 | try writeVecSectionHeader( | 2399 | try writeVecSectionHeader( |
| 2398 | file, | 2400 | binary_bytes.items, |
| 2399 | header_offset, | 2401 | header_offset, |
| 2400 | .@"export", | 2402 | .@"export", |
| 2401 | @intCast(u32, (try file.getPos()) - header_offset - header_size), | 2403 | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2402 | @intCast(u32, self.exports.items.len) + @boolToInt(export_table) + @boolToInt(!import_memory), | 2404 | @intCast(u32, self.exports.items.len) + @boolToInt(export_table) + @boolToInt(!import_memory), |
| 2403 | ); | 2405 | ); |
| 2404 | section_count += 1; | 2406 | section_count += 1; |
| ... | @@ -2406,25 +2408,24 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2406,25 +2408,24 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2406 | | 2408 | |
| 2407 | // element section (function table) | 2409 | // element section (function table) |
| 2408 | if (self.function_table.count() > 0) { | 2410 | if (self.function_table.count() > 0) { |
| 2409 | const header_offset = try reserveVecSectionHeader(file); | 2411 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2410 | const writer = file.writer(); | | |
| 2411 | | 2412 | |
| 2412 | var flags: u32 = 0x2; // Yes we have a table | 2413 | var flags: u32 = 0x2; // Yes we have a table |
| 2413 | try leb.writeULEB128(writer, flags); | 2414 | try leb.writeULEB128(binary_writer, flags); |
| 2414 | try leb.writeULEB128(writer, @as(u32, 0)); // index of that table. TODO: Store synthetic symbols | 2415 | try leb.writeULEB128(binary_writer, @as(u32, 0)); // index of that table. TODO: Store synthetic symbols |
| 2415 | try emitInit(writer, .{ .i32_const = 1 }); // We start at index 1, so unresolved function pointers are invalid | 2416 | try emitInit(binary_writer, .{ .i32_const = 1 }); // We start at index 1, so unresolved function pointers are invalid |
| 2416 | try leb.writeULEB128(writer, @as(u8, 0)); | 2417 | try leb.writeULEB128(binary_writer, @as(u8, 0)); |
| 2417 | try leb.writeULEB128(writer, @intCast(u32, self.function_table.count())); | 2418 | try leb.writeULEB128(binary_writer, @intCast(u32, self.function_table.count())); |
| 2418 | var symbol_it = self.function_table.keyIterator(); | 2419 | var symbol_it = self.function_table.keyIterator(); |
| 2419 | while (symbol_it.next()) |symbol_loc_ptr| { | 2420 | while (symbol_it.next()) |symbol_loc_ptr| { |
| 2420 | try leb.writeULEB128(writer, symbol_loc_ptr.*.getSymbol(self).index); | 2421 | try leb.writeULEB128(binary_writer, symbol_loc_ptr.*.getSymbol(self).index); |
| 2421 | } | 2422 | } |
| 2422 | | 2423 | |
| 2423 | try writeVecSectionHeader( | 2424 | try writeVecSectionHeader( |
| 2424 | file, | 2425 | binary_bytes.items, |
| 2425 | header_offset, | 2426 | header_offset, |
| 2426 | .element, | 2427 | .element, |
| 2427 | @intCast(u32, (try file.getPos()) - header_offset - header_size), | 2428 | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2428 | @as(u32, 1), | 2429 | @as(u32, 1), |
| 2429 | ); | 2430 | ); |
| 2430 | section_count += 1; | 2431 | section_count += 1; |
| ... | @@ -2433,8 +2434,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2433,8 +2434,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2433 | // Code section | 2434 | // Code section |
| 2434 | var code_section_size: u32 = 0; | 2435 | var code_section_size: u32 = 0; |
| 2435 | if (self.code_section_index) |code_index| { | 2436 | if (self.code_section_index) |code_index| { |
| 2436 | const header_offset = try reserveVecSectionHeader(file); | 2437 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2437 | const writer = file.writer(); | | |
| 2438 | var atom: *Atom = self.atoms.get(code_index).?.getFirst(); | 2438 | var atom: *Atom = self.atoms.get(code_index).?.getFirst(); |
| 2439 | | 2439 | |
| 2440 | // The code section must be sorted in line with the function order. | 2440 | // The code section must be sorted in line with the function order. |
| ... | @@ -2460,13 +2460,13 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2460,13 +2460,13 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2460 | std.sort.sort(*Atom, sorted_atoms.items, self, atom_sort_fn); | 2460 | std.sort.sort(*Atom, sorted_atoms.items, self, atom_sort_fn); |
| 2461 | | 2461 | |
| 2462 | for (sorted_atoms.items) |sorted_atom| { | 2462 | for (sorted_atoms.items) |sorted_atom| { |
| 2463 | try leb.writeULEB128(writer, sorted_atom.size); | 2463 | try leb.writeULEB128(binary_writer, sorted_atom.size); |
| 2464 | try writer.writeAll(sorted_atom.code.items); | 2464 | try binary_writer.writeAll(sorted_atom.code.items); |
| 2465 | } | 2465 | } |
| 2466 | | 2466 | |
| 2467 | code_section_size = @intCast(u32, (try file.getPos()) - header_offset - header_size); | 2467 | code_section_size = @intCast(u32, binary_bytes.items.len - header_offset - header_size); |
| 2468 | try writeVecSectionHeader( | 2468 | try writeVecSectionHeader( |
| 2469 | file, | 2469 | binary_bytes.items, |
| 2470 | header_offset, | 2470 | header_offset, |
| 2471 | .code, | 2471 | .code, |
| 2472 | code_section_size, | 2472 | code_section_size, |
| ... | @@ -2478,8 +2478,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2478,8 +2478,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2478 | | 2478 | |
| 2479 | // Data section | 2479 | // Data section |
| 2480 | if (self.data_segments.count() != 0) { | 2480 | if (self.data_segments.count() != 0) { |
| 2481 | const header_offset = try reserveVecSectionHeader(file); | 2481 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2482 | const writer = file.writer(); | | |
| 2483 | | 2482 | |
| 2484 | var it = self.data_segments.iterator(); | 2483 | var it = self.data_segments.iterator(); |
| 2485 | var segment_count: u32 = 0; | 2484 | var segment_count: u32 = 0; |
| ... | @@ -2493,10 +2492,10 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2493,10 +2492,10 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2493 | const segment = self.segments.items[atom_index]; | 2492 | const segment = self.segments.items[atom_index]; |
| 2494 | | 2493 | |
| 2495 | // flag and index to memory section (currently, there can only be 1 memory section in wasm) | 2494 | // flag and index to memory section (currently, there can only be 1 memory section in wasm) |
| 2496 | try leb.writeULEB128(writer, @as(u32, 0)); | 2495 | try leb.writeULEB128(binary_writer, @as(u32, 0)); |
| 2497 | // offset into data section | 2496 | // offset into data section |
| 2498 | try emitInit(writer, .{ .i32_const = @bitCast(i32, segment.offset) }); | 2497 | try emitInit(binary_writer, .{ .i32_const = @bitCast(i32, segment.offset) }); |
| 2499 | try leb.writeULEB128(writer, segment.size); | 2498 | try leb.writeULEB128(binary_writer, segment.size); |
| 2500 | | 2499 | |
| 2501 | // fill in the offset table and the data segments | 2500 | // fill in the offset table and the data segments |
| 2502 | var current_offset: u32 = 0; | 2501 | var current_offset: u32 = 0; |
| ... | @@ -2508,12 +2507,12 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2508,12 +2507,12 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2508 | // Pad with zeroes to ensure all segments are aligned | 2507 | // Pad with zeroes to ensure all segments are aligned |
| 2509 | if (current_offset != atom.offset) { | 2508 | if (current_offset != atom.offset) { |
| 2510 | const diff = atom.offset - current_offset; | 2509 | const diff = atom.offset - current_offset; |
| 2511 | try writer.writeByteNTimes(0, diff); | 2510 | try binary_writer.writeByteNTimes(0, diff); |
| 2512 | current_offset += diff; | 2511 | current_offset += diff; |
| 2513 | } | 2512 | } |
| 2514 | assert(current_offset == atom.offset); | 2513 | assert(current_offset == atom.offset); |
| 2515 | assert(atom.code.items.len == atom.size); | 2514 | assert(atom.code.items.len == atom.size); |
| 2516 | try writer.writeAll(atom.code.items); | 2515 | try binary_writer.writeAll(atom.code.items); |
| 2517 | | 2516 | |
| 2518 | current_offset += atom.size; | 2517 | current_offset += atom.size; |
| 2519 | if (atom.next) |next| { | 2518 | if (atom.next) |next| { |
| ... | @@ -2522,7 +2521,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2522,7 +2521,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2522 | // also pad with zeroes when last atom to ensure | 2521 | // also pad with zeroes when last atom to ensure |
| 2523 | // segments are aligned. | 2522 | // segments are aligned. |
| 2524 | if (current_offset != segment.size) { | 2523 | if (current_offset != segment.size) { |
| 2525 | try writer.writeByteNTimes(0, segment.size - current_offset); | 2524 | try binary_writer.writeByteNTimes(0, segment.size - current_offset); |
| 2526 | current_offset += segment.size - current_offset; | 2525 | current_offset += segment.size - current_offset; |
| 2527 | } | 2526 | } |
| 2528 | break; | 2527 | break; |
| ... | @@ -2532,10 +2531,10 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2532,10 +2531,10 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2532 | } | 2531 | } |
| 2533 | | 2532 | |
| 2534 | try writeVecSectionHeader( | 2533 | try writeVecSectionHeader( |
| 2535 | file, | 2534 | binary_bytes.items, |
| 2536 | header_offset, | 2535 | header_offset, |
| 2537 | .data, | 2536 | .data, |
| 2538 | @intCast(u32, (try file.getPos()) - header_offset - header_size), | 2537 | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2539 | @intCast(u32, segment_count), | 2538 | @intCast(u32, segment_count), |
| 2540 | ); | 2539 | ); |
| 2541 | data_section_index = section_count; | 2540 | data_section_index = section_count; |
| ... | @@ -2547,12 +2546,12 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2547,12 +2546,12 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2547 | // we never store all symbols in a single table, but store a location reference instead. | 2546 | // we never store all symbols in a single table, but store a location reference instead. |
| 2548 | // This means that for a relocatable object file, we need to generate one and provide it to the relocation sections. | 2547 | // This means that for a relocatable object file, we need to generate one and provide it to the relocation sections. |
| 2549 | var symbol_table = std.AutoArrayHashMap(SymbolLoc, u32).init(arena); | 2548 | var symbol_table = std.AutoArrayHashMap(SymbolLoc, u32).init(arena); |
| 2550 | try self.emitLinkSection(file, arena, &symbol_table); | 2549 | try self.emitLinkSection(&binary_bytes, &symbol_table); |
| 2551 | if (code_section_index) |code_index| { | 2550 | if (code_section_index) |code_index| { |
| 2552 | try self.emitCodeRelocations(file, arena, code_index, symbol_table); | 2551 | try self.emitCodeRelocations(&binary_bytes, code_index, symbol_table); |
| 2553 | } | 2552 | } |
| 2554 | if (data_section_index) |data_index| { | 2553 | if (data_section_index) |data_index| { |
| 2555 | try self.emitDataRelocations(file, arena, data_index, symbol_table); | 2554 | try self.emitDataRelocations(&binary_bytes, data_index, symbol_table); |
| 2556 | } | 2555 | } |
| 2557 | } else if (!self.base.options.strip) { | 2556 | } else if (!self.base.options.strip) { |
| 2558 | if (self.dwarf) |*dwarf| { | 2557 | if (self.dwarf) |*dwarf| { |
| ... | @@ -2592,41 +2591,45 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2592,41 +2591,45 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2592 | try debug_bytes.appendSlice(atom.code.items); | 2591 | try debug_bytes.appendSlice(atom.code.items); |
| 2593 | atom = atom.next orelse break; | 2592 | atom = atom.next orelse break; |
| 2594 | } | 2593 | } |
| 2595 | try emitDebugSection(file, debug_bytes.items, item.name); | 2594 | try emitDebugSection(&binary_bytes, debug_bytes.items, item.name); |
| 2596 | debug_bytes.clearRetainingCapacity(); | 2595 | debug_bytes.clearRetainingCapacity(); |
| 2597 | } | 2596 | } |
| 2598 | } | 2597 | } |
| 2599 | try self.emitNameSection(file, arena); | 2598 | try self.emitNameSection(&binary_bytes, arena); |
| 2600 | } | 2599 | } |
| 2601 | | 2600 | |
| 2602 | // Only when writing all sections executed properly we write the magic | 2601 | // Only when writing all sections executed properly we write the magic |
| 2603 | // bytes. This allows us to easily detect what went wrong while generating | 2602 | // bytes. This allows us to easily detect what went wrong while generating |
| 2604 | // the final binary. | 2603 | // the final binary. |
| 2605 | try file.pwriteAll(&(wasm.magic ++ wasm.version), 0); | 2604 | mem.copy(u8, binary_bytes.items, &(wasm.magic ++ wasm.version)); |
| | 2605 | |
| | 2606 | // finally, write the entire binary into the file. |
| | 2607 | var iovec = [_]std.os.iovec_const{.{ |
| | 2608 | .iov_base = binary_bytes.items.ptr, |
| | 2609 | .iov_len = binary_bytes.items.len, |
| | 2610 | }}; |
| | 2611 | try self.base.file.?.writevAll(&iovec); |
| 2606 | } | 2612 | } |
| 2607 | | 2613 | |
| 2608 | fn emitDebugSection(file: fs.File, data: []const u8, name: []const u8) !void { | 2614 | fn emitDebugSection(binary_bytes: *std.ArrayList(u8), data: []const u8, name: []const u8) !void { |
| 2609 | if (data.len == 0) return; | 2615 | if (data.len == 0) return; |
| 2610 | const header_offset = try reserveCustomSectionHeader(file); | 2616 | const header_offset = try reserveCustomSectionHeader(binary_bytes); |
| 2611 | const writer = file.writer(); | 2617 | const writer = binary_bytes.writer(); |
| 2612 | try leb.writeULEB128(writer, @intCast(u32, name.len)); | 2618 | try leb.writeULEB128(writer, @intCast(u32, name.len)); |
| 2613 | try writer.writeAll(name); | 2619 | try writer.writeAll(name); |
| 2614 | | 2620 | |
| 2615 | try file.writevAll(&[_]std.os.iovec_const{.{ | 2621 | const start = binary_bytes.items.len - header_offset; |
| 2616 | .iov_base = data.ptr, | | |
| 2617 | .iov_len = data.len, | | |
| 2618 | }}); | | |
| 2619 | const start = header_offset + 6 + name.len + getULEB128Size(@intCast(u32, name.len)); | | |
| 2620 | log.debug("Emit debug section: '{s}' start=0x{x:0>8} end=0x{x:0>8}", .{ name, start, start + data.len }); | 2622 | log.debug("Emit debug section: '{s}' start=0x{x:0>8} end=0x{x:0>8}", .{ name, start, start + data.len }); |
| | 2623 | try writer.writeAll(data); |
| 2621 | | 2624 | |
| 2622 | try writeCustomSectionHeader( | 2625 | try writeCustomSectionHeader( |
| 2623 | file, | 2626 | binary_bytes.items, |
| 2624 | header_offset, | 2627 | header_offset, |
| 2625 | @intCast(u32, (try file.getPos()) - header_offset - 6), | 2628 | @intCast(u32, binary_bytes.items.len - header_offset - 6), |
| 2626 | ); | 2629 | ); |
| 2627 | } | 2630 | } |
| 2628 | | 2631 | |
| 2629 | fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void { | 2632 | fn emitNameSection(self: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem.Allocator) !void { |
| 2630 | const Name = struct { | 2633 | const Name = struct { |
| 2631 | index: u32, | 2634 | index: u32, |
| 2632 | name: []const u8, | 2635 | name: []const u8, |
| ... | @@ -2672,8 +2675,8 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void { | ... | @@ -2672,8 +2675,8 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void { |
| 2672 | std.sort.sort(Name, funcs.values(), {}, Name.lessThan); | 2675 | std.sort.sort(Name, funcs.values(), {}, Name.lessThan); |
| 2673 | std.sort.sort(Name, globals.items, {}, Name.lessThan); | 2676 | std.sort.sort(Name, globals.items, {}, Name.lessThan); |
| 2674 | | 2677 | |
| 2675 | const header_offset = try reserveCustomSectionHeader(file); | 2678 | const header_offset = try reserveCustomSectionHeader(binary_bytes); |
| 2676 | const writer = file.writer(); | 2679 | const writer = binary_bytes.writer(); |
| 2677 | try leb.writeULEB128(writer, @intCast(u32, "name".len)); | 2680 | try leb.writeULEB128(writer, @intCast(u32, "name".len)); |
| 2678 | try writer.writeAll("name"); | 2681 | try writer.writeAll("name"); |
| 2679 | | 2682 | |
| ... | @@ -2682,9 +2685,9 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void { | ... | @@ -2682,9 +2685,9 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void { |
| 2682 | try self.emitNameSubsection(.data_segment, segments.items, writer); | 2685 | try self.emitNameSubsection(.data_segment, segments.items, writer); |
| 2683 | | 2686 | |
| 2684 | try writeCustomSectionHeader( | 2687 | try writeCustomSectionHeader( |
| 2685 | file, | 2688 | binary_bytes.items, |
| 2686 | header_offset, | 2689 | header_offset, |
| 2687 | @intCast(u32, (try file.getPos()) - header_offset - 6), | 2690 | @intCast(u32, binary_bytes.items.len - header_offset - 6), |
| 2688 | ); | 2691 | ); |
| 2689 | } | 2692 | } |
| 2690 | | 2693 | |
| ... | @@ -3197,54 +3200,40 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! | ... | @@ -3197,54 +3200,40 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! |
| 3197 | } | 3200 | } |
| 3198 | } | 3201 | } |
| 3199 | | 3202 | |
| 3200 | fn reserveVecSectionHeader(file: fs.File) !u64 { | 3203 | fn reserveVecSectionHeader(bytes: *std.ArrayList(u8)) !u32 { |
| 3201 | // section id + fixed leb contents size + fixed leb vector length | 3204 | // section id + fixed leb contents size + fixed leb vector length |
| 3202 | const header_size = 1 + 5 + 5; | 3205 | const header_size = 1 + 5 + 5; |
| 3203 | // TODO: this should be a single lseek(2) call, but fs.File does not | 3206 | const offset = @intCast(u32, bytes.items.len); |
| 3204 | // currently provide a way to do this. | 3207 | try bytes.appendSlice(&[_]u8{0} ** header_size); |
| 3205 | try file.seekBy(header_size); | 3208 | return offset; |
| 3206 | return (try file.getPos()) - header_size; | | |
| 3207 | } | 3209 | } |
| 3208 | | 3210 | |
| 3209 | fn reserveCustomSectionHeader(file: fs.File) !u64 { | 3211 | fn reserveCustomSectionHeader(bytes: *std.ArrayList(u8)) !u64 { |
| 3210 | // unlike regular section, we don't emit the count | 3212 | // unlike regular section, we don't emit the count |
| 3211 | const header_size = 1 + 5; | 3213 | const header_size = 1 + 5; |
| 3212 | // TODO: this should be a single lseek(2) call, but fs.File does not | 3214 | const offset = @intCast(u32, bytes.items.len); |
| 3213 | // currently provide a way to do this. | 3215 | try bytes.appendSlice(&[_]u8{0} ** header_size); |
| 3214 | try file.seekBy(header_size); | 3216 | return offset; |
| 3215 | return (try file.getPos()) - header_size; | | |
| 3216 | } | 3217 | } |
| 3217 | | 3218 | |
| 3218 | fn writeVecSectionHeader(file: fs.File, offset: u64, section: wasm.Section, size: u32, items: u32) !void { | 3219 | fn writeVecSectionHeader(buffer: []u8, offset: u32, section: wasm.Section, size: u32, items: u32) !void { |
| 3219 | var buf: [1 + 5 + 5]u8 = undefined; | 3220 | var buf: [1 + 5 + 5]u8 = undefined; |
| 3220 | buf[0] = @enumToInt(section); | 3221 | buf[0] = @enumToInt(section); |
| 3221 | leb.writeUnsignedFixed(5, buf[1..6], size); | 3222 | leb.writeUnsignedFixed(5, buf[1..6], size); |
| 3222 | leb.writeUnsignedFixed(5, buf[6..], items); | 3223 | leb.writeUnsignedFixed(5, buf[6..], items); |
| 3223 | | 3224 | mem.copy(u8, buffer[offset..], &buf); |
| 3224 | if (builtin.target.os.tag == .windows) { | | |
| 3225 | // https://github.com/ziglang/zig/issues/12783 | | |
| 3226 | const curr_pos = try file.getPos(); | | |
| 3227 | try file.pwriteAll(&buf, offset); | | |
| 3228 | try file.seekTo(curr_pos); | | |
| 3229 | } else try file.pwriteAll(&buf, offset); | | |
| 3230 | } | 3225 | } |
| 3231 | | 3226 | |
| 3232 | fn writeCustomSectionHeader(file: fs.File, offset: u64, size: u32) !void { | 3227 | fn writeCustomSectionHeader(buffer: []u8, offset: u64, size: u32) !void { |
| 3233 | var buf: [1 + 5]u8 = undefined; | 3228 | var buf: [1 + 5]u8 = undefined; |
| 3234 | buf[0] = 0; // 0 = 'custom' section | 3229 | buf[0] = 0; // 0 = 'custom' section |
| 3235 | leb.writeUnsignedFixed(5, buf[1..6], size); | 3230 | leb.writeUnsignedFixed(5, buf[1..6], size); |
| 3236 | | 3231 | mem.copy(u8, buffer[offset..], &buf); |
| 3237 | if (builtin.target.os.tag == .windows) { | | |
| 3238 | // https://github.com/ziglang/zig/issues/12783 | | |
| 3239 | const curr_pos = try file.getPos(); | | |
| 3240 | try file.pwriteAll(&buf, offset); | | |
| 3241 | try file.seekTo(curr_pos); | | |
| 3242 | } else try file.pwriteAll(&buf, offset); | | |
| 3243 | } | 3232 | } |
| 3244 | | 3233 | |
| 3245 | fn emitLinkSection(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *std.AutoArrayHashMap(SymbolLoc, u32)) !void { | 3234 | fn emitLinkSection(self: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: *std.AutoArrayHashMap(SymbolLoc, u32)) !void { |
| 3246 | const offset = try reserveCustomSectionHeader(file); | 3235 | const offset = try reserveCustomSectionHeader(binary_bytes); |
| 3247 | const writer = file.writer(); | 3236 | const writer = binary_bytes.writer(); |
| 3248 | // emit "linking" custom section name | 3237 | // emit "linking" custom section name |
| 3249 | const section_name = "linking"; | 3238 | const section_name = "linking"; |
| 3250 | try leb.writeULEB128(writer, section_name.len); | 3239 | try leb.writeULEB128(writer, section_name.len); |
| ... | @@ -3255,21 +3244,18 @@ fn emitLinkSection(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: * | ... | @@ -3255,21 +3244,18 @@ fn emitLinkSection(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: * |
| 3255 | | 3244 | |
| 3256 | // For each subsection type (found in types.Subsection) we can emit a section. | 3245 | // For each subsection type (found in types.Subsection) we can emit a section. |
| 3257 | // Currently, we only support emitting segment info and the symbol table. | 3246 | // Currently, we only support emitting segment info and the symbol table. |
| 3258 | try self.emitSymbolTable(file, arena, symbol_table); | 3247 | try self.emitSymbolTable(binary_bytes, symbol_table); |
| 3259 | try self.emitSegmentInfo(file, arena); | 3248 | try self.emitSegmentInfo(binary_bytes); |
| 3260 | | 3249 | |
| 3261 | const size = @intCast(u32, (try file.getPos()) - offset - 6); | 3250 | const size = @intCast(u32, binary_bytes.items.len - offset - 6); |
| 3262 | try writeCustomSectionHeader(file, offset, size); | 3251 | try writeCustomSectionHeader(binary_bytes.items, offset, size); |
| 3263 | } | 3252 | } |
| 3264 | | 3253 | |
| 3265 | fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *std.AutoArrayHashMap(SymbolLoc, u32)) !void { | 3254 | fn emitSymbolTable(self: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: *std.AutoArrayHashMap(SymbolLoc, u32)) !void { |
| 3266 | // After emitting the subtype, we must emit the subsection's length | 3255 | const writer = binary_bytes.writer(); |
| 3267 | // so first write it to a temporary arraylist to calculate the length | | |
| 3268 | // and then write all data at once. | | |
| 3269 | var payload = std.ArrayList(u8).init(arena); | | |
| 3270 | const writer = payload.writer(); | | |
| 3271 | | 3256 | |
| 3272 | try leb.writeULEB128(file.writer(), @enumToInt(types.SubsectionType.WASM_SYMBOL_TABLE)); | 3257 | try leb.writeULEB128(writer, @enumToInt(types.SubsectionType.WASM_SYMBOL_TABLE)); |
| | 3258 | const table_offset = binary_bytes.items.len; |
| 3273 | | 3259 | |
| 3274 | var symbol_count: u32 = 0; | 3260 | var symbol_count: u32 = 0; |
| 3275 | for (self.resolved_symbols.keys()) |sym_loc| { | 3261 | for (self.resolved_symbols.keys()) |sym_loc| { |
| ... | @@ -3307,23 +3293,17 @@ fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: * | ... | @@ -3307,23 +3293,17 @@ fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: * |
| 3307 | } | 3293 | } |
| 3308 | } | 3294 | } |
| 3309 | | 3295 | |
| 3310 | var buf: [5]u8 = undefined; | 3296 | var buf: [10]u8 = undefined; |
| 3311 | leb.writeUnsignedFixed(5, &buf, symbol_count); | 3297 | leb.writeUnsignedFixed(5, buf[0..5], @intCast(u32, binary_bytes.items.len - table_offset + 5)); |
| 3312 | try payload.insertSlice(0, &buf); | 3298 | leb.writeUnsignedFixed(5, buf[5..], symbol_count); |
| 3313 | try leb.writeULEB128(file.writer(), @intCast(u32, payload.items.len)); | 3299 | try binary_bytes.insertSlice(table_offset, &buf); |
| 3314 | | | |
| 3315 | const iovec: std.os.iovec_const = .{ | | |
| 3316 | .iov_base = payload.items.ptr, | | |
| 3317 | .iov_len = payload.items.len, | | |
| 3318 | }; | | |
| 3319 | var iovecs = [_]std.os.iovec_const{iovec}; | | |
| 3320 | try file.writevAll(&iovecs); | | |
| 3321 | } | 3300 | } |
| 3322 | | 3301 | |
| 3323 | fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void { | 3302 | fn emitSegmentInfo(self: *Wasm, binary_bytes: *std.ArrayList(u8)) !void { |
| 3324 | var payload = std.ArrayList(u8).init(arena); | 3303 | const writer = binary_bytes.writer(); |
| 3325 | const writer = payload.writer(); | 3304 | try leb.writeULEB128(writer, @enumToInt(types.SubsectionType.WASM_SEGMENT_INFO)); |
| 3326 | try leb.writeULEB128(file.writer(), @enumToInt(types.SubsectionType.WASM_SEGMENT_INFO)); | 3305 | const segment_offset = binary_bytes.items.len; |
| | 3306 | |
| 3327 | try leb.writeULEB128(writer, @intCast(u32, self.segment_info.count())); | 3307 | try leb.writeULEB128(writer, @intCast(u32, self.segment_info.count())); |
| 3328 | for (self.segment_info.values()) |segment_info| { | 3308 | for (self.segment_info.values()) |segment_info| { |
| 3329 | log.debug("Emit segment: {s} align({d}) flags({b})", .{ | 3309 | log.debug("Emit segment: {s} align({d}) flags({b})", .{ |
| ... | @@ -3337,13 +3317,9 @@ fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void { | ... | @@ -3337,13 +3317,9 @@ fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void { |
| 3337 | try leb.writeULEB128(writer, segment_info.flags); | 3317 | try leb.writeULEB128(writer, segment_info.flags); |
| 3338 | } | 3318 | } |
| 3339 | | 3319 | |
| 3340 | try leb.writeULEB128(file.writer(), @intCast(u32, payload.items.len)); | 3320 | var buf: [5]u8 = undefined; |
| 3341 | const iovec: std.os.iovec_const = .{ | 3321 | leb.writeUnsignedFixed(5, &buf, @intCast(u32, binary_bytes.items.len - segment_offset)); |
| 3342 | .iov_base = payload.items.ptr, | 3322 | try binary_bytes.insertSlice(segment_offset, &buf); |
| 3343 | .iov_len = payload.items.len, | | |
| 3344 | }; | | |
| 3345 | var iovecs = [_]std.os.iovec_const{iovec}; | | |
| 3346 | try file.writevAll(&iovecs); | | |
| 3347 | } | 3323 | } |
| 3348 | | 3324 | |
| 3349 | pub fn getULEB128Size(uint_value: anytype) u32 { | 3325 | pub fn getULEB128Size(uint_value: anytype) u32 { |
| ... | @@ -3361,21 +3337,20 @@ pub fn getULEB128Size(uint_value: anytype) u32 { | ... | @@ -3361,21 +3337,20 @@ pub fn getULEB128Size(uint_value: anytype) u32 { |
| 3361 | /// For each relocatable section, emits a custom "relocation.<section_name>" section | 3337 | /// For each relocatable section, emits a custom "relocation.<section_name>" section |
| 3362 | fn emitCodeRelocations( | 3338 | fn emitCodeRelocations( |
| 3363 | self: *Wasm, | 3339 | self: *Wasm, |
| 3364 | file: fs.File, | 3340 | binary_bytes: *std.ArrayList(u8), |
| 3365 | arena: Allocator, | | |
| 3366 | section_index: u32, | 3341 | section_index: u32, |
| 3367 | symbol_table: std.AutoArrayHashMap(SymbolLoc, u32), | 3342 | symbol_table: std.AutoArrayHashMap(SymbolLoc, u32), |
| 3368 | ) !void { | 3343 | ) !void { |
| 3369 | const code_index = self.code_section_index orelse return; | 3344 | const code_index = self.code_section_index orelse return; |
| 3370 | var payload = std.ArrayList(u8).init(arena); | 3345 | const writer = binary_bytes.writer(); |
| 3371 | const writer = payload.writer(); | 3346 | const header_offset = try reserveCustomSectionHeader(binary_bytes); |
| 3372 | | 3347 | |
| 3373 | // write custom section information | 3348 | // write custom section information |
| 3374 | const name = "reloc.CODE"; | 3349 | const name = "reloc.CODE"; |
| 3375 | try leb.writeULEB128(writer, @intCast(u32, name.len)); | 3350 | try leb.writeULEB128(writer, @intCast(u32, name.len)); |
| 3376 | try writer.writeAll(name); | 3351 | try writer.writeAll(name); |
| 3377 | try leb.writeULEB128(writer, section_index); | 3352 | try leb.writeULEB128(writer, section_index); |
| 3378 | const reloc_start = payload.items.len; | 3353 | const reloc_start = binary_bytes.items.len; |
| 3379 | | 3354 | |
| 3380 | var count: u32 = 0; | 3355 | var count: u32 = 0; |
| 3381 | var atom: *Atom = self.atoms.get(code_index).?.getFirst(); | 3356 | var atom: *Atom = self.atoms.get(code_index).?.getFirst(); |
| ... | @@ -3401,36 +3376,27 @@ fn emitCodeRelocations( | ... | @@ -3401,36 +3376,27 @@ fn emitCodeRelocations( |
| 3401 | if (count == 0) return; | 3376 | if (count == 0) return; |
| 3402 | var buf: [5]u8 = undefined; | 3377 | var buf: [5]u8 = undefined; |
| 3403 | leb.writeUnsignedFixed(5, &buf, count); | 3378 | leb.writeUnsignedFixed(5, &buf, count); |
| 3404 | try payload.insertSlice(reloc_start, &buf); | 3379 | try binary_bytes.insertSlice(reloc_start, &buf); |
| 3405 | var iovecs = [_]std.os.iovec_const{ | 3380 | const size = @intCast(u32, binary_bytes.items.len - header_offset - 6); |
| 3406 | .{ | 3381 | try writeCustomSectionHeader(binary_bytes.items, header_offset, size); |
| 3407 | .iov_base = payload.items.ptr, | | |
| 3408 | .iov_len = payload.items.len, | | |
| 3409 | }, | | |
| 3410 | }; | | |
| 3411 | const header_offset = try reserveCustomSectionHeader(file); | | |
| 3412 | try file.writevAll(&iovecs); | | |
| 3413 | const size = @intCast(u32, payload.items.len); | | |
| 3414 | try writeCustomSectionHeader(file, header_offset, size); | | |
| 3415 | } | 3382 | } |
| 3416 | | 3383 | |
| 3417 | fn emitDataRelocations( | 3384 | fn emitDataRelocations( |
| 3418 | self: *Wasm, | 3385 | self: *Wasm, |
| 3419 | file: fs.File, | 3386 | binary_bytes: *std.ArrayList(u8), |
| 3420 | arena: Allocator, | | |
| 3421 | section_index: u32, | 3387 | section_index: u32, |
| 3422 | symbol_table: std.AutoArrayHashMap(SymbolLoc, u32), | 3388 | symbol_table: std.AutoArrayHashMap(SymbolLoc, u32), |
| 3423 | ) !void { | 3389 | ) !void { |
| 3424 | if (self.data_segments.count() == 0) return; | 3390 | if (self.data_segments.count() == 0) return; |
| 3425 | var payload = std.ArrayList(u8).init(arena); | 3391 | const writer = binary_bytes.writer(); |
| 3426 | const writer = payload.writer(); | 3392 | const header_offset = try reserveCustomSectionHeader(binary_bytes); |
| 3427 | | 3393 | |
| 3428 | // write custom section information | 3394 | // write custom section information |
| 3429 | const name = "reloc.DATA"; | 3395 | const name = "reloc.DATA"; |
| 3430 | try leb.writeULEB128(writer, @intCast(u32, name.len)); | 3396 | try leb.writeULEB128(writer, @intCast(u32, name.len)); |
| 3431 | try writer.writeAll(name); | 3397 | try writer.writeAll(name); |
| 3432 | try leb.writeULEB128(writer, section_index); | 3398 | try leb.writeULEB128(writer, section_index); |
| 3433 | const reloc_start = payload.items.len; | 3399 | const reloc_start = binary_bytes.items.len; |
| 3434 | | 3400 | |
| 3435 | var count: u32 = 0; | 3401 | var count: u32 = 0; |
| 3436 | // for each atom, we calculate the uleb size and append that | 3402 | // for each atom, we calculate the uleb size and append that |
| ... | @@ -3462,17 +3428,9 @@ fn emitDataRelocations( | ... | @@ -3462,17 +3428,9 @@ fn emitDataRelocations( |
| 3462 | | 3428 | |
| 3463 | var buf: [5]u8 = undefined; | 3429 | var buf: [5]u8 = undefined; |
| 3464 | leb.writeUnsignedFixed(5, &buf, count); | 3430 | leb.writeUnsignedFixed(5, &buf, count); |
| 3465 | try payload.insertSlice(reloc_start, &buf); | 3431 | try binary_bytes.insertSlice(reloc_start, &buf); |
| 3466 | var iovecs = [_]std.os.iovec_const{ | 3432 | const size = @intCast(u32, binary_bytes.items.len - header_offset - 6); |
| 3467 | .{ | 3433 | try writeCustomSectionHeader(binary_bytes.items, header_offset, size); |
| 3468 | .iov_base = payload.items.ptr, | | |
| 3469 | .iov_len = payload.items.len, | | |
| 3470 | }, | | |
| 3471 | }; | | |
| 3472 | const header_offset = try reserveCustomSectionHeader(file); | | |
| 3473 | try file.writevAll(&iovecs); | | |
| 3474 | const size = @intCast(u32, payload.items.len); | | |
| 3475 | try writeCustomSectionHeader(file, header_offset, size); | | |
| 3476 | } | 3434 | } |
| 3477 | | 3435 | |
| 3478 | /// Searches for an a matching function signature, when not found | 3436 | /// Searches for an a matching function signature, when not found |