aboutsummaryrefslogtreecommitdiff
path: root/src/link/Wasm.zig
diff options
context:
space:
mode:
authorLuuk de Gram <luuk@degram.dev>2022-10-20 16:58:00 +0200
committerLuuk de Gram <luuk@degram.dev>2022-10-25 20:48:08 +0200
commit777bcbf96871a0250664b9cabdea5dbf51e0e64d (patch)
treed32afcefc66379cebce92a2414887d6e84db7d25 /src/link/Wasm.zig
parent85b669d497641de383070353d50a6e4fd30abd49 (diff)
downloadzig-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.zig47
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,