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.
This commit is contained in:
Luuk de Gram 2022-10-01 15:33:15 +02:00
parent 11dce78944
commit 43b55ea9f4
No known key found for this signature in database
GPG Key ID: A8CFE58E4DC7D664

View File

@ -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,