diff options
| author | Luuk de Gram <luuk@degram.dev> | 2022-10-20 16:58:00 +0200 |
|---|---|---|
| committer | Luuk de Gram <luuk@degram.dev> | 2022-10-25 20:48:08 +0200 |
| commit | 777bcbf96871a0250664b9cabdea5dbf51e0e64d (patch) | |
| tree | d32afcefc66379cebce92a2414887d6e84db7d25 /src/link/Wasm.zig | |
| parent | 85b669d497641de383070353d50a6e4fd30abd49 (diff) | |
| download | zig-777bcbf96871a0250664b9cabdea5dbf51e0e64d.tar.gz zig-777bcbf96871a0250664b9cabdea5dbf51e0e64d.zip | |
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 (limited to 'src/link/Wasm.zig')
| -rw-r--r-- | src/link/Wasm.zig | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index ed07756345..da9a878720 100644 --- 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, |
