authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-09-10 19:38:19+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-09-12 21:19:16+02:00
log6dbf5f1d8686c1f5b31f3dfce9b1ac0944f8e3a5
tree47480b99b6c92dd133a177f60be140d47b4c1d56
parenta01b1448e2927146cde9f7861605585f96b5084d
signaturelock-open Commit is signed but in an unrecognized format.

wasm-linker: write to file at once

Rather than writing to the file using a writer, we now first write to an arraylist and store the binary in memory. Once the full binary data was written, we write all data to disk at once. This reduces the amount of syscalls tremendously, increasing the performance of the linker in exchange for increased memory usage during flush.

1 files changed, 158 insertions(+), 200 deletions(-)

src/link/Wasm.zig+158-200
...@@ -653,6 +653,8 @@ fn resolveSymbolsInArchives(self: *Wasm) !void {...@@ -653,6 +653,8 @@ fn resolveSymbolsInArchives(self: *Wasm) !void {
653}653}
654654
655fn checkUndefinedSymbols(self: *const Wasm) !void {655fn 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();
22092211
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;
22132214
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 written2219 // 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)));
22182222
2219 // Type section2223 // 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 }
22312238
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();
22482254
2249 // import table is always first table so emit that first2255 // 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 }
22662272
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 }
22732279
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 }
22832289
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
22932299
2294 // Function section2300 // 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 }
23012306
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 section2317 // 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();
23172321
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 });
23232327
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
23332337
2334 // Memory section2338 // 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();
23382341
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 segment2348 @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
23492352
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();
23542356
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 }
23602362
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
23702372
2371 // Export section2373 // 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 }
23822384
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 table2389 try leb.writeULEB128(binary_writer, @as(u32, 0)); // function table is always the first table
2388 }2390 }
23892391
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 }
23962398
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
24062408
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();
24112412
2412 var flags: u32 = 0x2; // Yes we have a table2413 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 symbols2415 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 invalid2416 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 }
24222423
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 section2434 // 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();
24392439
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);
24612461
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 }
24662466
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
24782478
2479 // Data section2479 // 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();
24832482
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];
24942493
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 section2496 // 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);
25002499
2501 // fill in the offset table and the data segments2500 // 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 aligned2507 // 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);
25172516
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 ensure2521 // 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 }
25332532
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 }
26012600
2602 // Only when writing all sections executed properly we write the magic2601 // Only when writing all sections executed properly we write the magic
2603 // bytes. This allows us to easily detect what went wrong while generating2602 // 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}
26072613
2608fn emitDebugSection(file: fs.File, data: []const u8, name: []const u8) !void {2614fn 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);
26142620
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);
26212624
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}
26282631
2629fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void {2632fn 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);
26742677
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");
26792682
...@@ -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);
26832686
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}
26902693
...@@ -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}
31993202
3200fn reserveVecSectionHeader(file: fs.File) !u64 {3203fn reserveVecSectionHeader(bytes: *std.ArrayList(u8)) !u32 {
3201 // section id + fixed leb contents size + fixed leb vector length3204 // 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 not3206 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}
32083210
3209fn reserveCustomSectionHeader(file: fs.File) !u64 {3211fn reserveCustomSectionHeader(bytes: *std.ArrayList(u8)) !u64 {
3210 // unlike regular section, we don't emit the count3212 // 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 not3214 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}
32173218
3218fn writeVecSectionHeader(file: fs.File, offset: u64, section: wasm.Section, size: u32, items: u32) !void {3219fn 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);
32233224 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}
32313226
3232fn writeCustomSectionHeader(file: fs.File, offset: u64, size: u32) !void {3227fn 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' section3229 buf[0] = 0; // 0 = 'custom' section
3235 leb.writeUnsignedFixed(5, buf[1..6], size);3230 leb.writeUnsignedFixed(5, buf[1..6], size);
32363231 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}
32443233
3245fn emitLinkSection(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *std.AutoArrayHashMap(SymbolLoc, u32)) !void {3234fn 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 name3237 // 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: *
32553244
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);
32603249
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}
32643253
3265fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *std.AutoArrayHashMap(SymbolLoc, u32)) !void {3254fn 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 length3255 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();
32713256
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;
32733259
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 }
33093295
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}
33223301
3323fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void {3302fn 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 }
33393319
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}
33483324
3349pub fn getULEB128Size(uint_value: anytype) u32 {3325pub 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>" section3337/// For each relocatable section, emits a custom "relocation.<section_name>" section
3362fn emitCodeRelocations(3338fn 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);
33723347
3373 // write custom section information3348 // 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;
33793354
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}
34163383
3417fn emitDataRelocations(3384fn 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);
34273393
3428 // write custom section information3394 // 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;
34343400
3435 var count: u32 = 0;3401 var count: u32 = 0;
3436 // for each atom, we calculate the uleb size and append that3402 // for each atom, we calculate the uleb size and append that
...@@ -3462,17 +3428,9 @@ fn emitDataRelocations(...@@ -3462,17 +3428,9 @@ fn emitDataRelocations(
34623428
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}
34773435
3478/// Searches for an a matching function signature, when not found3436/// Searches for an a matching function signature, when not found