Commit 777bcbf968
Changed files (1)
src
link
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,