Merge pull request #13054 from Luukdegram/wasm-producer

wasm-linker: generate 'producers' section
This commit is contained in:
Luuk de Gram 2022-10-08 15:36:15 +02:00 committed by GitHub
commit fa9327ac05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 144 additions and 2 deletions

View File

@ -644,6 +644,8 @@ const WasmDumper = struct {
if (mem.eql(u8, name, "name")) {
try parseDumpNames(reader, writer, data);
} else if (mem.eql(u8, name, "producers")) {
try parseDumpProducers(reader, writer, data);
}
// TODO: Implement parsing and dumping other custom sections (such as relocations)
},
@ -863,4 +865,38 @@ const WasmDumper = struct {
}
}
}
fn parseDumpProducers(reader: anytype, writer: anytype, data: []const u8) !void {
const field_count = try std.leb.readULEB128(u32, reader);
try writer.print("fields {d}\n", .{field_count});
var current_field: u32 = 0;
while (current_field < field_count) : (current_field += 1) {
const field_name_length = try std.leb.readULEB128(u32, reader);
const field_name = data[reader.context.pos..][0..field_name_length];
reader.context.pos += field_name_length;
const value_count = try std.leb.readULEB128(u32, reader);
try writer.print(
\\field_name {s}
\\values {d}
, .{ field_name, value_count });
try writer.writeByte('\n');
var current_value: u32 = 0;
while (current_value < value_count) : (current_value += 1) {
const value_length = try std.leb.readULEB128(u32, reader);
const value = data[reader.context.pos..][0..value_length];
reader.context.pos += value_length;
const version_length = try std.leb.readULEB128(u32, reader);
const version = data[reader.context.pos..][0..version_length];
reader.context.pos += version_length;
try writer.print(
\\value_name {s}
\\version {s}
, .{ value, version });
try writer.writeByte('\n');
}
}
}
};

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,

View File

@ -34,7 +34,7 @@ fn addWasmCases(cases: *tests.StandaloneContext) void {
});
cases.addBuildFile("test/link/wasm/bss/build.zig", .{
.build_modes = true,
.build_modes = false,
.requires_stage2 = true,
});
@ -44,6 +44,11 @@ fn addWasmCases(cases: *tests.StandaloneContext) void {
.use_emulation = true,
});
cases.addBuildFile("test/link/wasm/producers/build.zig", .{
.build_modes = true,
.requires_stage2 = true,
});
cases.addBuildFile("test/link/wasm/segments/build.zig", .{
.build_modes = true,
.requires_stage2 = true,

View File

@ -0,0 +1,36 @@
const std = @import("std");
const builtin = @import("builtin");
const Builder = std.build.Builder;
pub fn build(b: *Builder) void {
const mode = b.standardReleaseOptions();
const test_step = b.step("test", "Test");
test_step.dependOn(b.getInstallStep());
const lib = b.addSharedLibrary("lib", "lib.zig", .unversioned);
lib.setBuildMode(mode);
lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
lib.use_llvm = false;
lib.use_stage1 = false;
lib.use_lld = false;
lib.install();
const zig_version = builtin.zig_version;
var version_buf: [100]u8 = undefined;
const version_fmt = std.fmt.bufPrint(&version_buf, "version {}", .{zig_version}) catch unreachable;
const check_lib = lib.checkObject(.wasm);
check_lib.checkStart("name producers");
check_lib.checkNext("fields 2");
check_lib.checkNext("field_name language");
check_lib.checkNext("values 1");
check_lib.checkNext("value_name Zig");
check_lib.checkNext(version_fmt);
check_lib.checkNext("field_name processed-by");
check_lib.checkNext("values 1");
check_lib.checkNext("value_name Zig");
check_lib.checkNext(version_fmt);
test_step.dependOn(&check_lib.step);
}

View File

@ -0,0 +1 @@
export fn foo() void {}