authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-10-08 15:36:15+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-10-08 15:36:15+02:00
logfa9327ac051031be21b6ccb494f31585d0b68915
treeffb6ffb6bf9a92a01c13a232dcdee9211f4be6c1
parent11dce78944ecfab1838cd678f75c354aa376a8bf
parentfda75f53fa19ed561a8fc0d7d5ed0e6a26ee3b1d
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13054 from Luukdegram/wasm-producer

wasm-linker: generate 'producers' section

5 files changed, 144 insertions(+), 2 deletions(-)

lib/std/build/CheckObjectStep.zig+36
......@@ -644,6 +644,8 @@ const WasmDumper = struct {
644644
645645 if (mem.eql(u8, name, "name")) {
646646 try parseDumpNames(reader, writer, data);
647 } else if (mem.eql(u8, name, "producers")) {
648 try parseDumpProducers(reader, writer, data);
647649 }
648650 // TODO: Implement parsing and dumping other custom sections (such as relocations)
649651 },
......@@ -863,4 +865,38 @@ const WasmDumper = struct {
863865 }
864866 }
865867 }
868
869 fn parseDumpProducers(reader: anytype, writer: anytype, data: []const u8) !void {
870 const field_count = try std.leb.readULEB128(u32, reader);
871 try writer.print("fields {d}\n", .{field_count});
872 var current_field: u32 = 0;
873 while (current_field < field_count) : (current_field += 1) {
874 const field_name_length = try std.leb.readULEB128(u32, reader);
875 const field_name = data[reader.context.pos..][0..field_name_length];
876 reader.context.pos += field_name_length;
877
878 const value_count = try std.leb.readULEB128(u32, reader);
879 try writer.print(
880 \\field_name {s}
881 \\values {d}
882 , .{ field_name, value_count });
883 try writer.writeByte('\n');
884 var current_value: u32 = 0;
885 while (current_value < value_count) : (current_value += 1) {
886 const value_length = try std.leb.readULEB128(u32, reader);
887 const value = data[reader.context.pos..][0..value_length];
888 reader.context.pos += value_length;
889
890 const version_length = try std.leb.readULEB128(u32, reader);
891 const version = data[reader.context.pos..][0..version_length];
892 reader.context.pos += version_length;
893
894 try writer.print(
895 \\value_name {s}
896 \\version {s}
897 , .{ value, version });
898 try writer.writeByte('\n');
899 }
900 }
901 }
866902};
src/link/Wasm.zig+65-1
......@@ -2556,6 +2556,10 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
25562556 try wasm.emitDataRelocations(&binary_bytes, data_index, symbol_table);
25572557 }
25582558 } else if (!wasm.base.options.strip) {
2559 try wasm.emitNameSection(&binary_bytes, arena);
2560 }
2561
2562 if (!wasm.base.options.strip) {
25592563 if (wasm.dwarf) |*dwarf| {
25602564 const mod = wasm.base.options.module.?;
25612565 try dwarf.writeDbgAbbrev(&wasm.base);
......@@ -2597,7 +2601,8 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
25972601 debug_bytes.clearRetainingCapacity();
25982602 }
25992603 }
2600 try wasm.emitNameSection(&binary_bytes, arena);
2604
2605 try emitProducerSection(&binary_bytes);
26012606 }
26022607
26032608 // Only when writing all sections executed properly we write the magic
......@@ -2631,6 +2636,65 @@ fn emitDebugSection(binary_bytes: *std.ArrayList(u8), data: []const u8, name: []
26312636 );
26322637}
26332638
2639fn emitProducerSection(binary_bytes: *std.ArrayList(u8)) !void {
2640 const header_offset = try reserveCustomSectionHeader(binary_bytes);
2641
2642 const writer = binary_bytes.writer();
2643 const producers = "producers";
2644 try leb.writeULEB128(writer, @intCast(u32, producers.len));
2645 try writer.writeAll(producers);
2646
2647 try leb.writeULEB128(writer, @as(u32, 2)); // 2 fields: Language + processed-by
2648
2649 // used for the Zig version
2650 var version_buf: [100]u8 = undefined;
2651 const version = try std.fmt.bufPrint(&version_buf, "{}", .{build_options.semver});
2652
2653 // language field
2654 {
2655 const language = "language";
2656 try leb.writeULEB128(writer, @intCast(u32, language.len));
2657 try writer.writeAll(language);
2658
2659 // field_value_count (TODO: Parse object files for producer sections to detect their language)
2660 try leb.writeULEB128(writer, @as(u32, 1));
2661
2662 // versioned name
2663 {
2664 try leb.writeULEB128(writer, @as(u32, 3)); // len of "Zig"
2665 try writer.writeAll("Zig");
2666
2667 try leb.writeULEB128(writer, @intCast(u32, version.len));
2668 try writer.writeAll(version);
2669 }
2670 }
2671
2672 // processed-by field
2673 {
2674 const processed_by = "processed-by";
2675 try leb.writeULEB128(writer, @intCast(u32, processed_by.len));
2676 try writer.writeAll(processed_by);
2677
2678 // field_value_count (TODO: Parse object files for producer sections to detect other used tools)
2679 try leb.writeULEB128(writer, @as(u32, 1));
2680
2681 // versioned name
2682 {
2683 try leb.writeULEB128(writer, @as(u32, 3)); // len of "Zig"
2684 try writer.writeAll("Zig");
2685
2686 try leb.writeULEB128(writer, @intCast(u32, version.len));
2687 try writer.writeAll(version);
2688 }
2689 }
2690
2691 try writeCustomSectionHeader(
2692 binary_bytes.items,
2693 header_offset,
2694 @intCast(u32, binary_bytes.items.len - header_offset - 6),
2695 );
2696}
2697
26342698fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem.Allocator) !void {
26352699 const Name = struct {
26362700 index: u32,
test/link.zig+6-1
......@@ -34,7 +34,7 @@ fn addWasmCases(cases: *tests.StandaloneContext) void {
3434 });
3535
3636 cases.addBuildFile("test/link/wasm/bss/build.zig", .{
37 .build_modes = true,
37 .build_modes = false,
3838 .requires_stage2 = true,
3939 });
4040
......@@ -44,6 +44,11 @@ fn addWasmCases(cases: *tests.StandaloneContext) void {
4444 .use_emulation = true,
4545 });
4646
47 cases.addBuildFile("test/link/wasm/producers/build.zig", .{
48 .build_modes = true,
49 .requires_stage2 = true,
50 });
51
4752 cases.addBuildFile("test/link/wasm/segments/build.zig", .{
4853 .build_modes = true,
4954 .requires_stage2 = true,
test/link/wasm/producers/build.zig created+36
......@@ -0,0 +1,36 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const Builder = std.build.Builder;
4
5pub fn build(b: *Builder) void {
6 const mode = b.standardReleaseOptions();
7
8 const test_step = b.step("test", "Test");
9 test_step.dependOn(b.getInstallStep());
10
11 const lib = b.addSharedLibrary("lib", "lib.zig", .unversioned);
12 lib.setBuildMode(mode);
13 lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
14 lib.use_llvm = false;
15 lib.use_stage1 = false;
16 lib.use_lld = false;
17 lib.install();
18
19 const zig_version = builtin.zig_version;
20 var version_buf: [100]u8 = undefined;
21 const version_fmt = std.fmt.bufPrint(&version_buf, "version {}", .{zig_version}) catch unreachable;
22
23 const check_lib = lib.checkObject(.wasm);
24 check_lib.checkStart("name producers");
25 check_lib.checkNext("fields 2");
26 check_lib.checkNext("field_name language");
27 check_lib.checkNext("values 1");
28 check_lib.checkNext("value_name Zig");
29 check_lib.checkNext(version_fmt);
30 check_lib.checkNext("field_name processed-by");
31 check_lib.checkNext("values 1");
32 check_lib.checkNext("value_name Zig");
33 check_lib.checkNext(version_fmt);
34
35 test_step.dependOn(&check_lib.step);
36}
test/link/wasm/producers/lib.zig created+1
......@@ -0,0 +1 @@
1export fn foo() void {}