| ... | @@ -2341,13 +2341,6 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l | ... | @@ -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 | // Positional arguments to the linker such as object files and static archives. | 2344 | // Positional arguments to the linker such as object files and static archives. |
| 2352 | var positionals = std.ArrayList([]const u8).init(arena); | 2345 | var positionals = std.ArrayList([]const u8).init(arena); |
| 2353 | try positionals.ensureUnusedCapacity(options.objects.len); | 2346 | try positionals.ensureUnusedCapacity(options.objects.len); |
| ... | @@ -2406,7 +2399,6 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l | ... | @@ -2406,7 +2399,6 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l |
| 2406 | var enabled_features: [@typeInfo(types.Feature.Tag).Enum.fields.len]bool = undefined; | 2399 | var enabled_features: [@typeInfo(types.Feature.Tag).Enum.fields.len]bool = undefined; |
| 2407 | try wasm.validateFeatures(&enabled_features, &emit_features_count); | 2400 | try wasm.validateFeatures(&enabled_features, &emit_features_count); |
| 2408 | try wasm.resolveSymbolsInArchives(); | 2401 | try wasm.resolveSymbolsInArchives(); |
| 2409 | // try wasm.checkUndefinedSymbols(); | | |
| 2410 | | 2402 | |
| 2411 | try wasm.setupStart(); | 2403 | try wasm.setupStart(); |
| 2412 | try wasm.setupImports(); | 2404 | try wasm.setupImports(); |
| ... | @@ -2421,435 +2413,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l | ... | @@ -2421,435 +2413,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l |
| 2421 | try wasm.mergeSections(); | 2413 | try wasm.mergeSections(); |
| 2422 | try wasm.mergeTypes(); | 2414 | try wasm.mergeTypes(); |
| 2423 | try wasm.setupExports(); | 2415 | try wasm.setupExports(); |
| 2424 | | 2416 | try wasm.writeToFile(enabled_features, emit_features_count, arena); |
| 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); | | |
| 2853 | | 2417 | |
| 2854 | if (!wasm.base.options.disable_lld_caching) { | 2418 | if (!wasm.base.options.disable_lld_caching) { |
| 2855 | // Update the file with the digest. If it fails we can continue; it only | 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,13 +2448,6 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2884 | // ensure the error names table is populated when an error name is referenced | 2448 | // ensure the error names table is populated when an error name is referenced |
| 2885 | try wasm.populateErrorNameTable(); | 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 | // Used for all temporary memory allocated during flushin | 2451 | // Used for all temporary memory allocated during flushin |
| 2895 | var arena_instance = std.heap.ArenaAllocator.init(wasm.base.allocator); | 2452 | var arena_instance = std.heap.ArenaAllocator.init(wasm.base.allocator); |
| 2896 | defer arena_instance.deinit(); | 2453 | defer arena_instance.deinit(); |
| ... | @@ -2970,8 +2527,24 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2970,8 +2527,24 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2970 | try wasm.mergeSections(); | 2527 | try wasm.mergeSections(); |
| 2971 | try wasm.mergeTypes(); | 2528 | try wasm.mergeTypes(); |
| 2972 | try wasm.setupExports(); | 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 | const header_size = 5 + 1; | 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 | const is_obj = wasm.base.options.output_mode == .Obj or (!wasm.base.options.use_llvm and wasm.base.options.use_lld); | 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 | var binary_bytes = std.ArrayList(u8).init(wasm.base.allocator); | 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,8 +2951,8 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 3378 | } | 2951 | } |
| 3379 | | 2952 | |
| 3380 | try emitProducerSection(&binary_bytes); | 2953 | try emitProducerSection(&binary_bytes); |
| 3381 | if (emit_features_count > 0) { | 2954 | if (feature_count > 0) { |
| 3382 | try emitFeaturesSection(&binary_bytes, &enabled_features, emit_features_count); | 2955 | try emitFeaturesSection(&binary_bytes, &enabled_features, feature_count); |
| 3383 | } | 2956 | } |
| 3384 | } | 2957 | } |
| 3385 | | 2958 | |