motiejus/zig

fork of https://codeberg.org/ziglang/zig
git clone https://git.jakstys.lt/motiejus/zig.git
Log | Tree | Refs | README | LICENSE

commit 777bcbf96871a0250664b9cabdea5dbf51e0e64d (tree)
parent 85b669d497641de383070353d50a6e4fd30abd49
Author: Luuk de Gram <luuk@degram.dev>
Date:   Thu, 20 Oct 2022 16:58:00 +0200

wasm-linker: emit `target_features` section

When the result is not being stripped, we emit the `target_features`
section based on all the used features. This includes features
inferred from linked object files.
Considering we know all possible features upfront, we can use an
array and therefore do not have to dynamically allocate memory.
Using this trick we can also easily order all features based
the same ordering as found in `std.Target.wasm` which is the same
ordering used by LLVM and the like.

Diffstat:
Msrc/link/Wasm.zig | 47+++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 45 insertions(+), 2 deletions(-)

diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig @@ -651,7 +651,12 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void { } } -fn validateFeatures(wasm: *const Wasm, arena: Allocator) !void { +fn validateFeatures( + wasm: *const Wasm, + arena: Allocator, + to_emit: *[@typeInfo(std.Target.wasm.Feature).Enum.fields.len]bool, + emit_features_count: *u32, +) !void { const cpu_features = wasm.base.options.target.cpu.features; const infer = cpu_features.isEmpty(); // when the user did not define any features, we infer them from linked objects. var allowed = std.AutoHashMap(std.Target.wasm.Feature, void).init(arena); @@ -755,6 +760,13 @@ fn validateFeatures(wasm: *const Wasm, arena: Allocator) !void { if (!valid_feature_set) { return error.InvalidFeatureSet; } + + if (allowed.count() > 0) { + emit_features_count.* = allowed.count(); + for (to_emit) |*feature_enabled, feature_index| { + feature_enabled.* = allowed.contains(@intToEnum(std.Target.wasm.Feature, feature_index)); + } + } } fn checkUndefinedSymbols(wasm: *const Wasm) !void { @@ -2264,7 +2276,9 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod try wasm.resolveSymbolsInObject(@intCast(u16, object_index)); } - try wasm.validateFeatures(arena); + var emit_features_count: u32 = 0; + var enabled_features: [@typeInfo(std.Target.wasm.Feature).Enum.fields.len]bool = undefined; + try wasm.validateFeatures(arena, &enabled_features, &emit_features_count); try wasm.resolveSymbolsInArchives(); try wasm.checkUndefinedSymbols(); @@ -2710,6 +2724,9 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod } try emitProducerSection(&binary_bytes); + if (emit_features_count > 0) { + try emitFeaturesSection(&binary_bytes, &enabled_features, emit_features_count); + } } // Only when writing all sections executed properly we write the magic @@ -2802,6 +2819,32 @@ fn emitProducerSection(binary_bytes: *std.ArrayList(u8)) !void { ); } +fn emitFeaturesSection(binary_bytes: *std.ArrayList(u8), enabled_features: []const bool, features_count: u32) !void { + const header_offset = try reserveCustomSectionHeader(binary_bytes); + + const writer = binary_bytes.writer(); + const target_features = "target_features"; + try leb.writeULEB128(writer, @intCast(u32, target_features.len)); + try writer.writeAll(target_features); + + try leb.writeULEB128(writer, features_count); + for (enabled_features) |enabled, feature_index| { + if (enabled) { + const feature: types.Feature = .{ .prefix = .used, .tag = @intToEnum(types.Feature.Tag, feature_index) }; + try leb.writeULEB128(writer, @enumToInt(feature.prefix)); + const string = feature.toString(); + try leb.writeULEB128(writer, @intCast(u32, string.len)); + try writer.writeAll(string); + } + } + + 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,