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 {...@@ -644,6 +644,8 @@ const WasmDumper = struct {
644644
645 if (mem.eql(u8, name, "name")) {645 if (mem.eql(u8, name, "name")) {
646 try parseDumpNames(reader, writer, data);646 try parseDumpNames(reader, writer, data);
647 } else if (mem.eql(u8, name, "producers")) {
648 try parseDumpProducers(reader, writer, data);
647 }649 }
648 // TODO: Implement parsing and dumping other custom sections (such as relocations)650 // TODO: Implement parsing and dumping other custom sections (such as relocations)
649 },651 },
...@@ -863,4 +865,38 @@ const WasmDumper = struct {...@@ -863,4 +865,38 @@ const WasmDumper = struct {
863 }865 }
864 }866 }
865 }867 }
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 }
866};902};
src/link/Wasm.zig+65-1
...@@ -2556,6 +2556,10 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2556,6 +2556,10 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2556 try wasm.emitDataRelocations(&binary_bytes, data_index, symbol_table);2556 try wasm.emitDataRelocations(&binary_bytes, data_index, symbol_table);
2557 }2557 }
2558 } else if (!wasm.base.options.strip) {2558 } else if (!wasm.base.options.strip) {
2559 try wasm.emitNameSection(&binary_bytes, arena);
2560 }
2561
2562 if (!wasm.base.options.strip) {
2559 if (wasm.dwarf) |*dwarf| {2563 if (wasm.dwarf) |*dwarf| {
2560 const mod = wasm.base.options.module.?;2564 const mod = wasm.base.options.module.?;
2561 try dwarf.writeDbgAbbrev(&wasm.base);2565 try dwarf.writeDbgAbbrev(&wasm.base);
...@@ -2597,7 +2601,8 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2597,7 +2601,8 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2597 debug_bytes.clearRetainingCapacity();2601 debug_bytes.clearRetainingCapacity();
2598 }2602 }
2599 }2603 }
2600 try wasm.emitNameSection(&binary_bytes, arena);2604
2605 try emitProducerSection(&binary_bytes);
2601 }2606 }
26022607
2603 // Only when writing all sections executed properly we write the magic2608 // 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: []...@@ -2631,6 +2636,65 @@ fn emitDebugSection(binary_bytes: *std.ArrayList(u8), data: []const u8, name: []
2631 );2636 );
2632}2637}
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
2634fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem.Allocator) !void {2698fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem.Allocator) !void {
2635 const Name = struct {2699 const Name = struct {
2636 index: u32,2700 index: u32,
test/link.zig+6-1
...@@ -34,7 +34,7 @@ fn addWasmCases(cases: *tests.StandaloneContext) void {...@@ -34,7 +34,7 @@ fn addWasmCases(cases: *tests.StandaloneContext) void {
34 });34 });
3535
36 cases.addBuildFile("test/link/wasm/bss/build.zig", .{36 cases.addBuildFile("test/link/wasm/bss/build.zig", .{
37 .build_modes = true,37 .build_modes = false,
38 .requires_stage2 = true,38 .requires_stage2 = true,
39 });39 });
4040
...@@ -44,6 +44,11 @@ fn addWasmCases(cases: *tests.StandaloneContext) void {...@@ -44,6 +44,11 @@ fn addWasmCases(cases: *tests.StandaloneContext) void {
44 .use_emulation = true,44 .use_emulation = true,
45 });45 });
4646
47 cases.addBuildFile("test/link/wasm/producers/build.zig", .{
48 .build_modes = true,
49 .requires_stage2 = true,
50 });
51
47 cases.addBuildFile("test/link/wasm/segments/build.zig", .{52 cases.addBuildFile("test/link/wasm/segments/build.zig", .{
48 .build_modes = true,53 .build_modes = true,
49 .requires_stage2 = true,54 .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 {}