| ... | ... | @@ -2341,13 +2341,6 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l |
| 2341 | 2341 | }; |
| 2342 | 2342 | } |
| 2343 | 2343 | |
| 2344 | | // The amount of sections that will be written |
| 2345 | | var section_count: u32 = 0; |
| 2346 | | // Index of the code section. Used to tell relocation table where the section lives. |
| 2347 | | var code_section_index: ?u32 = null; |
| 2348 | | // Index of the data section. Used to tell relocation table where the section lives. |
| 2349 | | var data_section_index: ?u32 = null; |
| 2350 | | |
| 2351 | 2344 | // Positional arguments to the linker such as object files and static archives. |
| 2352 | 2345 | var positionals = std.ArrayList([]const u8).init(arena); |
| 2353 | 2346 | try positionals.ensureUnusedCapacity(options.objects.len); |
| ... | ... | @@ -2406,7 +2399,6 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l |
| 2406 | 2399 | var enabled_features: [@typeInfo(types.Feature.Tag).Enum.fields.len]bool = undefined; |
| 2407 | 2400 | try wasm.validateFeatures(&enabled_features, &emit_features_count); |
| 2408 | 2401 | try wasm.resolveSymbolsInArchives(); |
| 2409 | | // try wasm.checkUndefinedSymbols(); |
| 2410 | 2402 | |
| 2411 | 2403 | try wasm.setupStart(); |
| 2412 | 2404 | try wasm.setupImports(); |
| ... | ... | @@ -2421,435 +2413,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l |
| 2421 | 2413 | try wasm.mergeSections(); |
| 2422 | 2414 | try wasm.mergeTypes(); |
| 2423 | 2415 | try wasm.setupExports(); |
| 2424 | | |
| 2425 | | const header_size = 5 + 1; |
| 2426 | | |
| 2427 | | var binary_bytes = std.ArrayList(u8).init(gpa); |
| 2428 | | defer binary_bytes.deinit(); |
| 2429 | | const binary_writer = binary_bytes.writer(); |
| 2430 | | |
| 2431 | | // We write the magic bytes at the end so they will only be written |
| 2432 | | // if everything succeeded as expected. So populate with 0's for now. |
| 2433 | | try binary_writer.writeAll(&[_]u8{0} ** 8); |
| 2434 | | // (Re)set file pointer to 0 |
| 2435 | | try wasm.base.file.?.setEndPos(0); |
| 2436 | | try wasm.base.file.?.seekTo(0); |
| 2437 | | |
| 2438 | | // Type section |
| 2439 | | if (wasm.func_types.items.len != 0) { |
| 2440 | | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2441 | | log.debug("Writing type section. Count: ({d})", .{wasm.func_types.items.len}); |
| 2442 | | for (wasm.func_types.items) |func_type| { |
| 2443 | | try leb.writeULEB128(binary_writer, std.wasm.function_type); |
| 2444 | | try leb.writeULEB128(binary_writer, @intCast(u32, func_type.params.len)); |
| 2445 | | for (func_type.params) |param_ty| { |
| 2446 | | try leb.writeULEB128(binary_writer, std.wasm.valtype(param_ty)); |
| 2447 | | } |
| 2448 | | try leb.writeULEB128(binary_writer, @intCast(u32, func_type.returns.len)); |
| 2449 | | for (func_type.returns) |ret_ty| { |
| 2450 | | try leb.writeULEB128(binary_writer, std.wasm.valtype(ret_ty)); |
| 2451 | | } |
| 2452 | | } |
| 2453 | | |
| 2454 | | try writeVecSectionHeader( |
| 2455 | | binary_bytes.items, |
| 2456 | | header_offset, |
| 2457 | | .type, |
| 2458 | | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2459 | | @intCast(u32, wasm.func_types.items.len), |
| 2460 | | ); |
| 2461 | | section_count += 1; |
| 2462 | | } |
| 2463 | | |
| 2464 | | // Import section |
| 2465 | | const import_memory = options.import_memory or is_obj; |
| 2466 | | const import_table = options.import_table or is_obj; |
| 2467 | | if (wasm.imports.count() != 0 or import_memory or import_table) { |
| 2468 | | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2469 | | |
| 2470 | | // import table is always first table so emit that first |
| 2471 | | if (import_table) { |
| 2472 | | const table_imp: types.Import = .{ |
| 2473 | | .module_name = try wasm.string_table.put(gpa, wasm.host_name), |
| 2474 | | .name = try wasm.string_table.put(gpa, "__indirect_function_table"), |
| 2475 | | .kind = .{ |
| 2476 | | .table = .{ |
| 2477 | | .limits = .{ |
| 2478 | | .min = @intCast(u32, wasm.function_table.count()), |
| 2479 | | .max = null, |
| 2480 | | }, |
| 2481 | | .reftype = .funcref, |
| 2482 | | }, |
| 2483 | | }, |
| 2484 | | }; |
| 2485 | | try wasm.emitImport(binary_writer, table_imp); |
| 2486 | | } |
| 2487 | | |
| 2488 | | var it = wasm.imports.iterator(); |
| 2489 | | while (it.next()) |entry| { |
| 2490 | | assert(entry.key_ptr.*.getSymbol(wasm).isUndefined()); |
| 2491 | | const import = entry.value_ptr.*; |
| 2492 | | try wasm.emitImport(binary_writer, import); |
| 2493 | | } |
| 2494 | | |
| 2495 | | if (import_memory) { |
| 2496 | | const mem_name = if (is_obj) "__linear_memory" else "memory"; |
| 2497 | | const mem_imp: types.Import = .{ |
| 2498 | | .module_name = try wasm.string_table.put(gpa, wasm.host_name), |
| 2499 | | .name = try wasm.string_table.put(gpa, mem_name), |
| 2500 | | .kind = .{ .memory = wasm.memories.limits }, |
| 2501 | | }; |
| 2502 | | try wasm.emitImport(binary_writer, mem_imp); |
| 2503 | | } |
| 2504 | | |
| 2505 | | try writeVecSectionHeader( |
| 2506 | | binary_bytes.items, |
| 2507 | | header_offset, |
| 2508 | | .import, |
| 2509 | | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2510 | | @intCast(u32, wasm.imports.count() + @boolToInt(import_memory) + @boolToInt(import_table)), |
| 2511 | | ); |
| 2512 | | section_count += 1; |
| 2513 | | } |
| 2514 | | |
| 2515 | | // Function section |
| 2516 | | if (wasm.functions.count() != 0) { |
| 2517 | | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2518 | | for (wasm.functions.values()) |function| { |
| 2519 | | try leb.writeULEB128(binary_writer, function.type_index); |
| 2520 | | } |
| 2521 | | |
| 2522 | | try writeVecSectionHeader( |
| 2523 | | binary_bytes.items, |
| 2524 | | header_offset, |
| 2525 | | .function, |
| 2526 | | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2527 | | @intCast(u32, wasm.functions.count()), |
| 2528 | | ); |
| 2529 | | section_count += 1; |
| 2530 | | } |
| 2531 | | |
| 2532 | | // Table section |
| 2533 | | const export_table = options.export_table; |
| 2534 | | if (!import_table and wasm.function_table.count() != 0) { |
| 2535 | | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2536 | | |
| 2537 | | try leb.writeULEB128(binary_writer, std.wasm.reftype(.funcref)); |
| 2538 | | try emitLimits(binary_writer, .{ |
| 2539 | | .min = @intCast(u32, wasm.function_table.count()) + 1, |
| 2540 | | .max = null, |
| 2541 | | }); |
| 2542 | | |
| 2543 | | try writeVecSectionHeader( |
| 2544 | | binary_bytes.items, |
| 2545 | | header_offset, |
| 2546 | | .table, |
| 2547 | | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2548 | | @as(u32, 1), |
| 2549 | | ); |
| 2550 | | section_count += 1; |
| 2551 | | } |
| 2552 | | |
| 2553 | | // Memory section |
| 2554 | | if (!import_memory) { |
| 2555 | | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2556 | | |
| 2557 | | try emitLimits(binary_writer, wasm.memories.limits); |
| 2558 | | try writeVecSectionHeader( |
| 2559 | | binary_bytes.items, |
| 2560 | | header_offset, |
| 2561 | | .memory, |
| 2562 | | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2563 | | @as(u32, 1), // wasm currently only supports 1 linear memory segment |
| 2564 | | ); |
| 2565 | | section_count += 1; |
| 2566 | | } |
| 2567 | | |
| 2568 | | // Global section (used to emit stack pointer) |
| 2569 | | if (wasm.wasm_globals.items.len > 0) { |
| 2570 | | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2571 | | |
| 2572 | | var global_count: u32 = 0; |
| 2573 | | for (wasm.wasm_globals.items) |global| { |
| 2574 | | try binary_writer.writeByte(std.wasm.valtype(global.global_type.valtype)); |
| 2575 | | try binary_writer.writeByte(@boolToInt(global.global_type.mutable)); |
| 2576 | | try emitInit(binary_writer, global.init); |
| 2577 | | global_count += 1; |
| 2578 | | } |
| 2579 | | |
| 2580 | | for (wasm.address_globals.items) |sym_loc| { |
| 2581 | | const atom = wasm.symbol_atom.get(sym_loc).?; |
| 2582 | | try binary_writer.writeByte(std.wasm.valtype(.i32)); |
| 2583 | | try binary_writer.writeByte(0); // immutable |
| 2584 | | try emitInit(binary_writer, .{ |
| 2585 | | .i32_const = @bitCast(i32, atom.offset), |
| 2586 | | }); |
| 2587 | | global_count += 1; |
| 2588 | | } |
| 2589 | | |
| 2590 | | try writeVecSectionHeader( |
| 2591 | | binary_bytes.items, |
| 2592 | | header_offset, |
| 2593 | | .global, |
| 2594 | | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2595 | | @intCast(u32, global_count), |
| 2596 | | ); |
| 2597 | | section_count += 1; |
| 2598 | | } |
| 2599 | | |
| 2600 | | // Export section |
| 2601 | | if (wasm.exports.items.len != 0 or export_table or !import_memory) { |
| 2602 | | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2603 | | |
| 2604 | | for (wasm.exports.items) |exp| { |
| 2605 | | const name = wasm.string_table.get(exp.name); |
| 2606 | | try leb.writeULEB128(binary_writer, @intCast(u32, name.len)); |
| 2607 | | try binary_writer.writeAll(name); |
| 2608 | | try leb.writeULEB128(binary_writer, @enumToInt(exp.kind)); |
| 2609 | | try leb.writeULEB128(binary_writer, exp.index); |
| 2610 | | } |
| 2611 | | |
| 2612 | | if (export_table) { |
| 2613 | | try leb.writeULEB128(binary_writer, @intCast(u32, "__indirect_function_table".len)); |
| 2614 | | try binary_writer.writeAll("__indirect_function_table"); |
| 2615 | | try binary_writer.writeByte(std.wasm.externalKind(.table)); |
| 2616 | | try leb.writeULEB128(binary_writer, @as(u32, 0)); // function table is always the first table |
| 2617 | | } |
| 2618 | | |
| 2619 | | if (!import_memory) { |
| 2620 | | try leb.writeULEB128(binary_writer, @intCast(u32, "memory".len)); |
| 2621 | | try binary_writer.writeAll("memory"); |
| 2622 | | try binary_writer.writeByte(std.wasm.externalKind(.memory)); |
| 2623 | | try leb.writeULEB128(binary_writer, @as(u32, 0)); |
| 2624 | | } |
| 2625 | | |
| 2626 | | try writeVecSectionHeader( |
| 2627 | | binary_bytes.items, |
| 2628 | | header_offset, |
| 2629 | | .@"export", |
| 2630 | | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2631 | | @intCast(u32, wasm.exports.items.len) + @boolToInt(export_table) + @boolToInt(!import_memory), |
| 2632 | | ); |
| 2633 | | section_count += 1; |
| 2634 | | } |
| 2635 | | |
| 2636 | | // element section (function table) |
| 2637 | | if (wasm.function_table.count() > 0) { |
| 2638 | | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2639 | | |
| 2640 | | var flags: u32 = 0x2; // Yes we have a table |
| 2641 | | try leb.writeULEB128(binary_writer, flags); |
| 2642 | | try leb.writeULEB128(binary_writer, @as(u32, 0)); // index of that table. TODO: Store synthetic symbols |
| 2643 | | try emitInit(binary_writer, .{ .i32_const = 1 }); // We start at index 1, so unresolved function pointers are invalid |
| 2644 | | try leb.writeULEB128(binary_writer, @as(u8, 0)); |
| 2645 | | try leb.writeULEB128(binary_writer, @intCast(u32, wasm.function_table.count())); |
| 2646 | | var symbol_it = wasm.function_table.keyIterator(); |
| 2647 | | while (symbol_it.next()) |symbol_loc_ptr| { |
| 2648 | | try leb.writeULEB128(binary_writer, symbol_loc_ptr.*.getSymbol(wasm).index); |
| 2649 | | } |
| 2650 | | |
| 2651 | | try writeVecSectionHeader( |
| 2652 | | binary_bytes.items, |
| 2653 | | header_offset, |
| 2654 | | .element, |
| 2655 | | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2656 | | @as(u32, 1), |
| 2657 | | ); |
| 2658 | | section_count += 1; |
| 2659 | | } |
| 2660 | | |
| 2661 | | // Code section |
| 2662 | | var code_section_size: u32 = 0; |
| 2663 | | if (wasm.code_section_index) |code_index| { |
| 2664 | | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2665 | | var atom: *Atom = wasm.atoms.get(code_index).?.getFirst(); |
| 2666 | | |
| 2667 | | // The code section must be sorted in line with the function order. |
| 2668 | | var sorted_atoms = try std.ArrayList(*Atom).initCapacity(gpa, wasm.functions.count()); |
| 2669 | | defer sorted_atoms.deinit(); |
| 2670 | | |
| 2671 | | while (true) { |
| 2672 | | if (wasm.resolved_symbols.contains(atom.symbolLoc())) { |
| 2673 | | if (!is_obj) { |
| 2674 | | atom.resolveRelocs(wasm); |
| 2675 | | } |
| 2676 | | sorted_atoms.appendAssumeCapacity(atom); |
| 2677 | | } |
| 2678 | | atom = atom.next orelse break; |
| 2679 | | } |
| 2680 | | |
| 2681 | | const atom_sort_fn = struct { |
| 2682 | | fn sort(ctx: *const Wasm, lhs: *const Atom, rhs: *const Atom) bool { |
| 2683 | | const lhs_sym = lhs.symbolLoc().getSymbol(ctx); |
| 2684 | | const rhs_sym = rhs.symbolLoc().getSymbol(ctx); |
| 2685 | | return lhs_sym.index < rhs_sym.index; |
| 2686 | | } |
| 2687 | | }.sort; |
| 2688 | | |
| 2689 | | std.sort.sort(*Atom, sorted_atoms.items, wasm, atom_sort_fn); |
| 2690 | | |
| 2691 | | for (sorted_atoms.items) |sorted_atom| { |
| 2692 | | try leb.writeULEB128(binary_writer, sorted_atom.size); |
| 2693 | | try binary_writer.writeAll(sorted_atom.code.items); |
| 2694 | | } |
| 2695 | | |
| 2696 | | code_section_size = @intCast(u32, binary_bytes.items.len - header_offset - header_size); |
| 2697 | | try writeVecSectionHeader( |
| 2698 | | binary_bytes.items, |
| 2699 | | header_offset, |
| 2700 | | .code, |
| 2701 | | code_section_size, |
| 2702 | | @intCast(u32, wasm.functions.count()), |
| 2703 | | ); |
| 2704 | | code_section_index = section_count; |
| 2705 | | section_count += 1; |
| 2706 | | } |
| 2707 | | |
| 2708 | | // Data section |
| 2709 | | if (wasm.data_segments.count() != 0) { |
| 2710 | | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2711 | | |
| 2712 | | var it = wasm.data_segments.iterator(); |
| 2713 | | var segment_count: u32 = 0; |
| 2714 | | while (it.next()) |entry| { |
| 2715 | | // do not output 'bss' section unless we import memory and therefore |
| 2716 | | // want to guarantee the data is zero initialized |
| 2717 | | if (!import_memory and std.mem.eql(u8, entry.key_ptr.*, ".bss")) continue; |
| 2718 | | segment_count += 1; |
| 2719 | | const atom_index = entry.value_ptr.*; |
| 2720 | | var atom: *Atom = wasm.atoms.getPtr(atom_index).?.*.getFirst(); |
| 2721 | | const segment = wasm.segments.items[atom_index]; |
| 2722 | | |
| 2723 | | // flag and index to memory section (currently, there can only be 1 memory section in wasm) |
| 2724 | | try leb.writeULEB128(binary_writer, @as(u32, 0)); |
| 2725 | | // offset into data section |
| 2726 | | try emitInit(binary_writer, .{ .i32_const = @bitCast(i32, segment.offset) }); |
| 2727 | | try leb.writeULEB128(binary_writer, segment.size); |
| 2728 | | |
| 2729 | | // fill in the offset table and the data segments |
| 2730 | | var current_offset: u32 = 0; |
| 2731 | | while (true) { |
| 2732 | | if (!wasm.resolved_symbols.contains(atom.symbolLoc())) { |
| 2733 | | atom = atom.next orelse break; |
| 2734 | | continue; |
| 2735 | | } |
| 2736 | | if (!is_obj) { |
| 2737 | | atom.resolveRelocs(wasm); |
| 2738 | | } |
| 2739 | | |
| 2740 | | // Pad with zeroes to ensure all segments are aligned |
| 2741 | | if (current_offset != atom.offset) { |
| 2742 | | const diff = atom.offset - current_offset; |
| 2743 | | try binary_writer.writeByteNTimes(0, diff); |
| 2744 | | current_offset += diff; |
| 2745 | | } |
| 2746 | | assert(current_offset == atom.offset); |
| 2747 | | assert(atom.code.items.len == atom.size); |
| 2748 | | try binary_writer.writeAll(atom.code.items); |
| 2749 | | |
| 2750 | | current_offset += atom.size; |
| 2751 | | if (atom.next) |next| { |
| 2752 | | atom = next; |
| 2753 | | } else { |
| 2754 | | // also pad with zeroes when last atom to ensure |
| 2755 | | // segments are aligned. |
| 2756 | | if (current_offset != segment.size) { |
| 2757 | | try binary_writer.writeByteNTimes(0, segment.size - current_offset); |
| 2758 | | current_offset += segment.size - current_offset; |
| 2759 | | } |
| 2760 | | break; |
| 2761 | | } |
| 2762 | | } |
| 2763 | | assert(current_offset == segment.size); |
| 2764 | | } |
| 2765 | | |
| 2766 | | try writeVecSectionHeader( |
| 2767 | | binary_bytes.items, |
| 2768 | | header_offset, |
| 2769 | | .data, |
| 2770 | | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2771 | | @intCast(u32, segment_count), |
| 2772 | | ); |
| 2773 | | data_section_index = section_count; |
| 2774 | | section_count += 1; |
| 2775 | | } |
| 2776 | | |
| 2777 | | if (is_obj) { |
| 2778 | | // relocations need to point to the index of a symbol in the final symbol table. To save memory, |
| 2779 | | // we never store all symbols in a single table, but store a location reference instead. |
| 2780 | | // This means that for a relocatable object file, we need to generate one and provide it to the relocation sections. |
| 2781 | | var symbol_table = std.AutoArrayHashMap(SymbolLoc, u32).init(arena); |
| 2782 | | try wasm.emitLinkSection(&binary_bytes, &symbol_table); |
| 2783 | | if (code_section_index) |code_index| { |
| 2784 | | try wasm.emitCodeRelocations(&binary_bytes, code_index, symbol_table); |
| 2785 | | } |
| 2786 | | if (data_section_index) |data_index| { |
| 2787 | | try wasm.emitDataRelocations(&binary_bytes, data_index, symbol_table); |
| 2788 | | } |
| 2789 | | } else if (!options.strip) { |
| 2790 | | try wasm.emitNameSection(&binary_bytes, arena); |
| 2791 | | } |
| 2792 | | |
| 2793 | | if (!options.strip) { |
| 2794 | | if (wasm.dwarf) |*dwarf| { |
| 2795 | | const mod = options.module.?; |
| 2796 | | try dwarf.writeDbgAbbrev(); |
| 2797 | | // for debug info and ranges, the address is always 0, |
| 2798 | | // as locations are always offsets relative to 'code' section. |
| 2799 | | try dwarf.writeDbgInfoHeader(mod, 0, code_section_size); |
| 2800 | | try dwarf.writeDbgAranges(0, code_section_size); |
| 2801 | | try dwarf.writeDbgLineHeader(); |
| 2802 | | } |
| 2803 | | |
| 2804 | | var debug_bytes = std.ArrayList(u8).init(gpa); |
| 2805 | | defer debug_bytes.deinit(); |
| 2806 | | |
| 2807 | | const DebugSection = struct { |
| 2808 | | name: []const u8, |
| 2809 | | index: ?u32, |
| 2810 | | }; |
| 2811 | | |
| 2812 | | const debug_sections: []const DebugSection = &.{ |
| 2813 | | .{ .name = ".debug_info", .index = wasm.debug_info_index }, |
| 2814 | | .{ .name = ".debug_pubtypes", .index = wasm.debug_pubtypes_index }, |
| 2815 | | .{ .name = ".debug_abbrev", .index = wasm.debug_abbrev_index }, |
| 2816 | | .{ .name = ".debug_line", .index = wasm.debug_line_index }, |
| 2817 | | .{ .name = ".debug_str", .index = wasm.debug_str_index }, |
| 2818 | | .{ .name = ".debug_pubnames", .index = wasm.debug_pubnames_index }, |
| 2819 | | .{ .name = ".debug_loc", .index = wasm.debug_loc_index }, |
| 2820 | | .{ .name = ".debug_ranges", .index = wasm.debug_ranges_index }, |
| 2821 | | }; |
| 2822 | | |
| 2823 | | for (debug_sections) |item| { |
| 2824 | | if (item.index) |index| { |
| 2825 | | var atom = wasm.atoms.get(index).?.getFirst(); |
| 2826 | | while (true) { |
| 2827 | | atom.resolveRelocs(wasm); |
| 2828 | | try debug_bytes.appendSlice(atom.code.items); |
| 2829 | | atom = atom.next orelse break; |
| 2830 | | } |
| 2831 | | try emitDebugSection(&binary_bytes, debug_bytes.items, item.name); |
| 2832 | | debug_bytes.clearRetainingCapacity(); |
| 2833 | | } |
| 2834 | | } |
| 2835 | | |
| 2836 | | try emitProducerSection(&binary_bytes); |
| 2837 | | if (emit_features_count > 0) { |
| 2838 | | try emitFeaturesSection(&binary_bytes, &enabled_features, emit_features_count); |
| 2839 | | } |
| 2840 | | } |
| 2841 | | |
| 2842 | | // Only when writing all sections executed properly we write the magic |
| 2843 | | // bytes. This allows us to easily detect what went wrong while generating |
| 2844 | | // the final binary. |
| 2845 | | mem.copy(u8, binary_bytes.items, &(std.wasm.magic ++ std.wasm.version)); |
| 2846 | | |
| 2847 | | // finally, write the entire binary into the file. |
| 2848 | | var iovec = [_]std.os.iovec_const{.{ |
| 2849 | | .iov_base = binary_bytes.items.ptr, |
| 2850 | | .iov_len = binary_bytes.items.len, |
| 2851 | | }}; |
| 2852 | | try wasm.base.file.?.writevAll(&iovec); |
| 2416 | try wasm.writeToFile(enabled_features, emit_features_count, arena); |
| 2853 | 2417 | |
| 2854 | 2418 | if (!wasm.base.options.disable_lld_caching) { |
| 2855 | 2419 | // Update the file with the digest. If it fails we can continue; it only |
| ... | ... | @@ -2884,13 +2448,6 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2884 | 2448 | // ensure the error names table is populated when an error name is referenced |
| 2885 | 2449 | try wasm.populateErrorNameTable(); |
| 2886 | 2450 | |
| 2887 | | // The amount of sections that will be written |
| 2888 | | var section_count: u32 = 0; |
| 2889 | | // Index of the code section. Used to tell relocation table where the section lives. |
| 2890 | | var code_section_index: ?u32 = null; |
| 2891 | | // Index of the data section. Used to tell relocation table where the section lives. |
| 2892 | | var data_section_index: ?u32 = null; |
| 2893 | | |
| 2894 | 2451 | // Used for all temporary memory allocated during flushin |
| 2895 | 2452 | var arena_instance = std.heap.ArenaAllocator.init(wasm.base.allocator); |
| 2896 | 2453 | defer arena_instance.deinit(); |
| ... | ... | @@ -2970,8 +2527,24 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2970 | 2527 | try wasm.mergeSections(); |
| 2971 | 2528 | try wasm.mergeTypes(); |
| 2972 | 2529 | try wasm.setupExports(); |
| 2530 | try wasm.writeToFile(enabled_features, emit_features_count, arena); |
| 2531 | } |
| 2973 | 2532 | |
| 2533 | /// Writes the WebAssembly in-memory module to the file |
| 2534 | fn writeToFile( |
| 2535 | wasm: *Wasm, |
| 2536 | enabled_features: [@typeInfo(types.Feature.Tag).Enum.fields.len]bool, |
| 2537 | feature_count: u32, |
| 2538 | arena: Allocator, |
| 2539 | ) !void { |
| 2540 | // Size of each section header |
| 2974 | 2541 | const header_size = 5 + 1; |
| 2542 | // The amount of sections that will be written |
| 2543 | var section_count: u32 = 0; |
| 2544 | // Index of the code section. Used to tell relocation table where the section lives. |
| 2545 | var code_section_index: ?u32 = null; |
| 2546 | // Index of the data section. Used to tell relocation table where the section lives. |
| 2547 | var data_section_index: ?u32 = null; |
| 2975 | 2548 | const is_obj = wasm.base.options.output_mode == .Obj or (!wasm.base.options.use_llvm and wasm.base.options.use_lld); |
| 2976 | 2549 | |
| 2977 | 2550 | var binary_bytes = std.ArrayList(u8).init(wasm.base.allocator); |
| ... | ... | @@ -3378,8 +2951,8 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 3378 | 2951 | } |
| 3379 | 2952 | |
| 3380 | 2953 | try emitProducerSection(&binary_bytes); |
| 3381 | | if (emit_features_count > 0) { |
| 3382 | | try emitFeaturesSection(&binary_bytes, &enabled_features, emit_features_count); |
| 2954 | if (feature_count > 0) { |
| 2955 | try emitFeaturesSection(&binary_bytes, &enabled_features, feature_count); |
| 3383 | 2956 | } |
| 3384 | 2957 | } |
| 3385 | 2958 | |