Commit 43b55ea9f4

Luuk de Gram <luuk@degram.dev>
2022-10-01 15:33:15
wasm-linker: generate 'producers' section
The `producers` section contains meta data of the binary and/or object file. It *can* contain the source language, the tool it was processed by, and/or the SDK that was used to produce the file. For now, we always set the language and processed-by fields to Zig. In the future we will parse linked object files to detect their producers sections and append (if different) their language, SDK and processed-by fields.
1 parent 11dce78
Changed files (1)
src
src/link/Wasm.zig
@@ -2556,6 +2556,10 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
             try wasm.emitDataRelocations(&binary_bytes, data_index, symbol_table);
         }
     } else if (!wasm.base.options.strip) {
+        try wasm.emitNameSection(&binary_bytes, arena);
+    }
+
+    if (!wasm.base.options.strip) {
         if (wasm.dwarf) |*dwarf| {
             const mod = wasm.base.options.module.?;
             try dwarf.writeDbgAbbrev(&wasm.base);
@@ -2597,7 +2601,8 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
                 debug_bytes.clearRetainingCapacity();
             }
         }
-        try wasm.emitNameSection(&binary_bytes, arena);
+
+        try emitProducerSection(&binary_bytes);
     }
 
     // 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: []
     );
 }
 
+fn emitProducerSection(binary_bytes: *std.ArrayList(u8)) !void {
+    const header_offset = try reserveCustomSectionHeader(binary_bytes);
+
+    const writer = binary_bytes.writer();
+    const producers = "producers";
+    try leb.writeULEB128(writer, @intCast(u32, producers.len));
+    try writer.writeAll(producers);
+
+    try leb.writeULEB128(writer, @as(u32, 2)); // 2 fields: Language + processed-by
+
+    // used for the Zig version
+    var version_buf: [100]u8 = undefined;
+    const version = try std.fmt.bufPrint(&version_buf, "{}", .{build_options.semver});
+
+    // language field
+    {
+        const language = "language";
+        try leb.writeULEB128(writer, @intCast(u32, language.len));
+        try writer.writeAll(language);
+
+        // field_value_count (TODO: Parse object files for producer sections to detect their language)
+        try leb.writeULEB128(writer, @as(u32, 1));
+
+        // versioned name
+        {
+            try leb.writeULEB128(writer, @as(u32, 3)); // len of "Zig"
+            try writer.writeAll("Zig");
+
+            try leb.writeULEB128(writer, @intCast(u32, version.len));
+            try writer.writeAll(version);
+        }
+    }
+
+    // processed-by field
+    {
+        const processed_by = "processed_by";
+        try leb.writeULEB128(writer, @intCast(u32, processed_by.len));
+        try writer.writeAll(processed_by);
+
+        // field_value_count (TODO: Parse object files for producer sections to detect other used tools)
+        try leb.writeULEB128(writer, @as(u32, 1));
+
+        // versioned name
+        {
+            try leb.writeULEB128(writer, @as(u32, 3)); // len of "Zig"
+            try writer.writeAll("Zig");
+
+            try leb.writeULEB128(writer, @intCast(u32, version.len));
+            try writer.writeAll(version);
+        }
+    }
+
+    try writeCustomSectionHeader(
+        binary_bytes.items,
+        header_offset,
+        @intCast(u32, binary_bytes.items.len - header_offset - 6),
+    );
+}
+
 fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem.Allocator) !void {
     const Name = struct {
         index: u32,