Commit 7d224516c4
Changed files (5)
src
src/arch/wasm/Emit.zig
@@ -108,7 +108,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
try wasm.out_relocs.append(gpa, .{
.offset = @intCast(code.items.len),
.pointee = .{ .symbol_index = try wasm.errorNameTableSymbolIndex() },
- .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64,
+ .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64,
.addend = 0,
});
code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);
@@ -162,7 +162,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
try wasm.out_relocs.append(gpa, .{
.offset = @intCast(code.items.len),
.pointee = .{ .symbol_index = try wasm.navSymbolIndex(datas[inst].nav_index) },
- .tag = .FUNCTION_INDEX_LEB,
+ .tag = .function_index_leb,
.addend = 0,
});
code.appendNTimesAssumeCapacity(0, 5);
@@ -182,7 +182,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
try wasm.out_relocs.append(gpa, .{
.offset = @intCast(code.items.len),
.pointee = .{ .type_index = func_ty_index },
- .tag = .TYPE_INDEX_LEB,
+ .tag = .type_index_leb,
.addend = 0,
});
code.appendNTimesAssumeCapacity(0, 5);
@@ -202,7 +202,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
try wasm.out_relocs.append(gpa, .{
.offset = @intCast(code.items.len),
.pointee = .{ .symbol_index = try wasm.tagNameSymbolIndex(datas[inst].ip_index) },
- .tag = .FUNCTION_INDEX_LEB,
+ .tag = .function_index_leb,
.addend = 0,
});
code.appendNTimesAssumeCapacity(0, 5);
@@ -226,7 +226,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
try wasm.out_relocs.append(gpa, .{
.offset = @intCast(code.items.len),
.pointee = .{ .symbol_index = try wasm.symbolNameIndex(symbol_name) },
- .tag = .FUNCTION_INDEX_LEB,
+ .tag = .function_index_leb,
.addend = 0,
});
code.appendNTimesAssumeCapacity(0, 5);
@@ -245,7 +245,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
try wasm.out_relocs.append(gpa, .{
.offset = @intCast(code.items.len),
.pointee = .{ .symbol_index = try wasm.stackPointerSymbolIndex() },
- .tag = .GLOBAL_INDEX_LEB,
+ .tag = .global_index_leb,
.addend = 0,
});
code.appendNTimesAssumeCapacity(0, 5);
@@ -922,7 +922,7 @@ fn uavRefOffObj(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.UavRef
try wasm.out_relocs.append(gpa, .{
.offset = @intCast(code.items.len),
.pointee = .{ .symbol_index = try wasm.uavSymbolIndex(data.uav_obj.key(wasm).*) },
- .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64,
+ .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64,
.addend = data.offset,
});
code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);
@@ -957,7 +957,7 @@ fn navRefOff(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.NavRefOff
try wasm.out_relocs.append(gpa, .{
.offset = @intCast(code.items.len),
.pointee = .{ .symbol_index = try wasm.navSymbolIndex(data.nav_index) },
- .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64,
+ .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64,
.addend = data.offset,
});
code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);
src/link/Wasm/Flush.zig
@@ -1398,148 +1398,6 @@ fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void {
// try binary_bytes.insertSlice(table_offset, &buf);
//}
-///// Resolves the relocations within the atom, writing the new value
-///// at the calculated offset.
-//fn resolveAtomRelocs(wasm: *const Wasm, atom: *Atom) void {
-// const symbol_name = wasm.symbolLocName(atom.symbolLoc());
-// log.debug("resolving {d} relocs in atom '{s}'", .{ atom.relocs.len, symbol_name });
-//
-// for (atom.relocSlice(wasm)) |reloc| {
-// const value = atomRelocationValue(wasm, atom, reloc);
-// log.debug("relocating '{s}' referenced in '{s}' offset=0x{x:0>8} value={d}", .{
-// wasm.symbolLocName(.{
-// .file = atom.file,
-// .index = @enumFromInt(reloc.index),
-// }),
-// symbol_name,
-// reloc.offset,
-// value,
-// });
-//
-// switch (reloc.tag) {
-// .TABLE_INDEX_I32,
-// .FUNCTION_OFFSET_I32,
-// .GLOBAL_INDEX_I32,
-// .MEMORY_ADDR_I32,
-// .SECTION_OFFSET_I32,
-// => mem.writeInt(u32, atom.code.slice(wasm)[reloc.offset - atom.original_offset ..][0..4], @as(u32, @truncate(value)), .little),
-//
-// .TABLE_INDEX_I64,
-// .MEMORY_ADDR_I64,
-// => mem.writeInt(u64, atom.code.slice(wasm)[reloc.offset - atom.original_offset ..][0..8], value, .little),
-//
-// .GLOBAL_INDEX_LEB,
-// .EVENT_INDEX_LEB,
-// .FUNCTION_INDEX_LEB,
-// .MEMORY_ADDR_LEB,
-// .MEMORY_ADDR_SLEB,
-// .TABLE_INDEX_SLEB,
-// .TABLE_NUMBER_LEB,
-// .TYPE_INDEX_LEB,
-// .MEMORY_ADDR_TLS_SLEB,
-// => leb.writeUnsignedFixed(5, atom.code.slice(wasm)[reloc.offset - atom.original_offset ..][0..5], @as(u32, @truncate(value))),
-//
-// .MEMORY_ADDR_LEB64,
-// .MEMORY_ADDR_SLEB64,
-// .TABLE_INDEX_SLEB64,
-// .MEMORY_ADDR_TLS_SLEB64,
-// => leb.writeUnsignedFixed(10, atom.code.slice(wasm)[reloc.offset - atom.original_offset ..][0..10], value),
-// }
-// }
-//}
-
-///// From a given `relocation` will return the new value to be written.
-///// All values will be represented as a `u64` as all values can fit within it.
-///// The final value must be casted to the correct size.
-//fn atomRelocationValue(wasm: *const Wasm, atom: *const Atom, relocation: *const Relocation) u64 {
-// if (relocation.tag == .TYPE_INDEX_LEB) {
-// // Eagerly resolved when parsing the object file.
-// if (true) @panic("TODO the eager resolve when parsing");
-// return relocation.index;
-// }
-// const target_loc = wasm.symbolLocFinalLoc(.{
-// .file = atom.file,
-// .index = @enumFromInt(relocation.index),
-// });
-// const symbol = wasm.finalSymbolByLoc(target_loc);
-// if (symbol.tag != .section and !symbol.flags.alive) {
-// const val = atom.tombstone(wasm) orelse relocation.addend;
-// return @bitCast(val);
-// }
-// return switch (relocation.tag) {
-// .FUNCTION_INDEX_LEB => if (symbol.flags.undefined)
-// @intFromEnum(symbol.pointee.function_import)
-// else
-// @intFromEnum(symbol.pointee.function) + f.function_imports.items.len,
-// .TABLE_NUMBER_LEB => if (symbol.flags.undefined)
-// @intFromEnum(symbol.pointee.table_import)
-// else
-// @intFromEnum(symbol.pointee.table) + wasm.table_imports.items.len,
-// .TABLE_INDEX_I32,
-// .TABLE_INDEX_I64,
-// .TABLE_INDEX_SLEB,
-// .TABLE_INDEX_SLEB64,
-// => wasm.indirect_function_table.get(.{ .file = atom.file, .index = @enumFromInt(relocation.index) }) orelse 0,
-//
-// .TYPE_INDEX_LEB => unreachable, // handled above
-// .GLOBAL_INDEX_I32, .GLOBAL_INDEX_LEB => if (symbol.flags.undefined)
-// @intFromEnum(symbol.pointee.global_import)
-// else
-// @intFromEnum(symbol.pointee.global) + f.global_imports.items.len,
-//
-// .MEMORY_ADDR_I32,
-// .MEMORY_ADDR_I64,
-// .MEMORY_ADDR_LEB,
-// .MEMORY_ADDR_LEB64,
-// .MEMORY_ADDR_SLEB,
-// .MEMORY_ADDR_SLEB64,
-// => {
-// assert(symbol.tag == .data);
-// if (symbol.flags.undefined) return 0;
-// const va: i33 = symbol.virtual_address;
-// return @intCast(va + relocation.addend);
-// },
-// .EVENT_INDEX_LEB => @panic("TODO: expose this as an error, events are unsupported"),
-// .SECTION_OFFSET_I32 => {
-// const target_atom_index = wasm.symbol_atom.get(target_loc).?;
-// const target_atom = wasm.getAtom(target_atom_index);
-// const rel_value: i33 = target_atom.offset;
-// return @intCast(rel_value + relocation.addend);
-// },
-// .FUNCTION_OFFSET_I32 => {
-// if (symbol.flags.undefined) {
-// const val = atom.tombstone(wasm) orelse relocation.addend;
-// return @bitCast(val);
-// }
-// const target_atom_index = wasm.symbol_atom.get(target_loc).?;
-// const target_atom = wasm.getAtom(target_atom_index);
-// const rel_value: i33 = target_atom.offset;
-// return @intCast(rel_value + relocation.addend);
-// },
-// .MEMORY_ADDR_TLS_SLEB,
-// .MEMORY_ADDR_TLS_SLEB64,
-// => {
-// const va: i33 = symbol.virtual_address;
-// return @intCast(va + relocation.addend);
-// },
-// };
-//}
-
-///// For a given `Atom` returns whether it has a tombstone value or not.
-///// This defines whether we want a specific value when a section is dead.
-//fn tombstone(atom: Atom, wasm: *const Wasm) ?i64 {
-// const atom_name = wasm.finalSymbolByLoc(atom.symbolLoc()).name;
-// if (atom_name == wasm.custom_sections.@".debug_ranges".name or
-// atom_name == wasm.custom_sections.@".debug_loc".name)
-// {
-// return -2;
-// } else if (mem.startsWith(u8, atom_name.slice(wasm), ".debug_")) {
-// return -1;
-// } else {
-// return null;
-// }
-//}
-
fn uleb128size(x: u32) u32 {
var value = x;
var size: u32 = 0;
src/link/Wasm/Object.zig
@@ -36,12 +36,16 @@ global_imports: RelativeSlice,
table_imports: RelativeSlice,
/// Points into Wasm object_custom_segments
custom_segments: RelativeSlice,
-/// For calculating local section index from `Wasm.ObjectSectionIndex`.
-local_section_index_base: u32,
/// Points into Wasm object_init_funcs
init_funcs: RelativeSlice,
/// Points into Wasm object_comdats
comdats: RelativeSlice,
+/// Guaranteed to be non-null when functions has nonzero length.
+code_section_index: ?Wasm.ObjectSectionIndex,
+/// Guaranteed to be non-null when globals has nonzero length.
+global_section_index: ?Wasm.ObjectSectionIndex,
+/// Guaranteed to be non-null when data segments has nonzero length.
+data_section_index: ?Wasm.ObjectSectionIndex,
pub const RelativeSlice = struct {
off: u32,
@@ -52,7 +56,8 @@ pub const SegmentInfo = struct {
name: Wasm.String,
flags: Flags,
- const Flags = packed struct(u32) {
+ /// Matches the ABI.
+ pub const Flags = packed struct(u32) {
/// Signals that the segment contains only null terminated strings allowing
/// the linker to perform merging.
strings: bool,
@@ -101,6 +106,37 @@ pub const SubsectionType = enum(u8) {
symbol_table = 8,
};
+/// Specified by https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md
+pub const RelocationType = enum(u8) {
+ function_index_leb = 0,
+ table_index_sleb = 1,
+ table_index_i32 = 2,
+ memory_addr_leb = 3,
+ memory_addr_sleb = 4,
+ memory_addr_i32 = 5,
+ type_index_leb = 6,
+ global_index_leb = 7,
+ function_offset_i32 = 8,
+ section_offset_i32 = 9,
+ event_index_leb = 10,
+ memory_addr_rel_sleb = 11,
+ table_index_rel_sleb = 12,
+ global_index_i32 = 13,
+ memory_addr_leb64 = 14,
+ memory_addr_sleb64 = 15,
+ memory_addr_i64 = 16,
+ memory_addr_rel_sleb64 = 17,
+ table_index_sleb64 = 18,
+ table_index_i64 = 19,
+ table_number_leb = 20,
+ memory_addr_tls_sleb = 21,
+ function_offset_i64 = 22,
+ memory_addr_locrel_i32 = 23,
+ table_index_rel_sleb64 = 24,
+ memory_addr_tls_sleb64 = 25,
+ function_index_i32 = 26,
+};
+
pub const Symbol = struct {
flags: Wasm.SymbolFlags,
name: Wasm.OptionalString,
@@ -245,7 +281,8 @@ pub fn parse(
const global_imports_start: u32 = @intCast(wasm.object_global_imports.entries.len);
const table_imports_start: u32 = @intCast(wasm.object_table_imports.entries.len);
const local_section_index_base = wasm.object_total_sections;
- const source_location: Wasm.SourceLocation = .fromObject(@enumFromInt(wasm.objects.items.len), wasm);
+ const object_index: Wasm.ObjectIndex = @enumFromInt(wasm.objects.items.len);
+ const source_location: Wasm.SourceLocation = .fromObject(object_index, wasm);
ss.clear();
@@ -254,6 +291,9 @@ pub fn parse(
var saw_linking_section = false;
var has_tls = false;
var table_import_symbol_count: usize = 0;
+ var code_section_index: ?Wasm.ObjectSectionIndex = null;
+ var global_section_index: ?Wasm.ObjectSectionIndex = null;
+ var data_section_index: ?Wasm.ObjectSectionIndex = null;
while (pos < bytes.len) : (wasm.object_total_sections += 1) {
const section_index: Wasm.ObjectSectionIndex = @enumFromInt(wasm.object_total_sections);
@@ -365,7 +405,8 @@ pub fn parse(
switch (tag) {
.data => {
const name, pos = readBytes(bytes, pos);
- symbol.name = (try wasm.internString(name)).toOptional();
+ const interned_name = try wasm.internString(name);
+ symbol.name = interned_name.toOptional();
if (symbol.flags.undefined) {
symbol.pointee = .data_import;
} else {
@@ -376,7 +417,7 @@ pub fn parse(
.segment = @enumFromInt(data_segment_start + segment_index),
.offset = segment_offset,
.size = size,
- .name = symbol.name,
+ .name = interned_name,
.flags = symbol.flags,
});
symbol.pointee = .{
@@ -468,7 +509,7 @@ pub fn parse(
var prev_offset: u32 = 0;
try wasm.object_relocations.ensureUnusedCapacity(gpa, count);
for (0..count) |_| {
- const tag: Wasm.ObjectRelocation.Tag = @enumFromInt(bytes[pos]);
+ const tag: RelocationType = @enumFromInt(bytes[pos]);
pos += 1;
const offset, pos = readLeb(u32, bytes, pos);
const index, pos = readLeb(u32, bytes, pos);
@@ -477,75 +518,134 @@ pub fn parse(
return diags.failParse(path, "relocation entries not sorted by offset", .{});
prev_offset = offset;
+ const sym = &ss.symbol_table.items[index];
+
switch (tag) {
- .MEMORY_ADDR_LEB,
- .MEMORY_ADDR_SLEB,
- .MEMORY_ADDR_I32,
- .MEMORY_ADDR_REL_SLEB,
- .MEMORY_ADDR_LEB64,
- .MEMORY_ADDR_SLEB64,
- .MEMORY_ADDR_I64,
- .MEMORY_ADDR_REL_SLEB64,
- .MEMORY_ADDR_TLS_SLEB,
- .MEMORY_ADDR_LOCREL_I32,
- .MEMORY_ADDR_TLS_SLEB64,
+ .memory_addr_leb,
+ .memory_addr_sleb,
+ .memory_addr_i32,
+ .memory_addr_rel_sleb,
+ .memory_addr_leb64,
+ .memory_addr_sleb64,
+ .memory_addr_i64,
+ .memory_addr_rel_sleb64,
+ .memory_addr_tls_sleb,
+ .memory_addr_locrel_i32,
+ .memory_addr_tls_sleb64,
=> {
const addend: i32, pos = readLeb(i32, bytes, pos);
- wasm.object_relocations.appendAssumeCapacity(.{
- .tag = tag,
- .offset = offset,
- .pointee = .{ .data = ss.symbol_table.items[index].pointee.data },
- .addend = addend,
+ wasm.object_relocations.appendAssumeCapacity(switch (sym.pointee) {
+ .data => |data| .{
+ .tag = .fromType(tag),
+ .offset = offset,
+ .pointee = .{ .data = data },
+ .addend = addend,
+ },
+ .data_import => .{
+ .tag = .fromTypeImport(tag),
+ .offset = offset,
+ .pointee = .{ .symbol_name = sym.name.unwrap().? },
+ .addend = addend,
+ },
+ else => unreachable,
});
},
- .FUNCTION_OFFSET_I32,
- .FUNCTION_OFFSET_I64,
- => {
+ .function_offset_i32, .function_offset_i64 => {
const addend: i32, pos = readLeb(i32, bytes, pos);
- wasm.object_relocations.appendAssumeCapacity(.{
- .tag = tag,
- .offset = offset,
- .pointee = .{ .function = ss.symbol_table.items[index].pointee.function },
- .addend = addend,
+ wasm.object_relocations.appendAssumeCapacity(switch (sym.pointee) {
+ .function => .{
+ .tag = .fromType(tag),
+ .offset = offset,
+ .pointee = .{ .function = sym.pointee.function },
+ .addend = addend,
+ },
+ .function_import => .{
+ .tag = .fromTypeImport(tag),
+ .offset = offset,
+ .pointee = .{ .symbol_name = sym.name.unwrap().? },
+ .addend = addend,
+ },
+ else => unreachable,
});
},
- .SECTION_OFFSET_I32 => {
+ .section_offset_i32 => {
const addend: i32, pos = readLeb(i32, bytes, pos);
wasm.object_relocations.appendAssumeCapacity(.{
- .tag = tag,
+ .tag = .section_offset_i32,
.offset = offset,
- .pointee = .{ .section = ss.symbol_table.items[index].pointee.section },
+ .pointee = .{ .section = sym.pointee.section },
.addend = addend,
});
},
- .TYPE_INDEX_LEB => {
+ .type_index_leb => {
wasm.object_relocations.appendAssumeCapacity(.{
- .tag = tag,
+ .tag = .type_index_leb,
.offset = offset,
.pointee = .{ .type_index = ss.func_types.items[index] },
.addend = undefined,
});
},
- .FUNCTION_INDEX_LEB,
- .FUNCTION_INDEX_I32,
- .GLOBAL_INDEX_LEB,
- .GLOBAL_INDEX_I32,
- .TABLE_INDEX_SLEB,
- .TABLE_INDEX_I32,
- .TABLE_INDEX_SLEB64,
- .TABLE_INDEX_I64,
- .TABLE_NUMBER_LEB,
- .TABLE_INDEX_REL_SLEB,
- .TABLE_INDEX_REL_SLEB64,
- .TAG_INDEX_LEB,
+ .function_index_leb,
+ .function_index_i32,
+ .table_index_sleb,
+ .table_index_i32,
+ .table_index_sleb64,
+ .table_index_i64,
+ .table_index_rel_sleb,
+ .table_index_rel_sleb64,
=> {
- wasm.object_relocations.appendAssumeCapacity(.{
- .tag = tag,
- .offset = offset,
- .pointee = .{ .symbol_name = ss.symbol_table.items[index].name.unwrap().? },
- .addend = undefined,
+ wasm.object_relocations.appendAssumeCapacity(switch (sym.pointee) {
+ .function => .{
+ .tag = .fromType(tag),
+ .offset = offset,
+ .pointee = .{ .function = sym.pointee.function },
+ .addend = undefined,
+ },
+ .function_import => .{
+ .tag = .fromTypeImport(tag),
+ .offset = offset,
+ .pointee = .{ .symbol_name = sym.name.unwrap().? },
+ .addend = undefined,
+ },
+ else => unreachable,
+ });
+ },
+ .global_index_leb, .global_index_i32 => {
+ wasm.object_relocations.appendAssumeCapacity(switch (sym.pointee) {
+ .global => .{
+ .tag = .fromType(tag),
+ .offset = offset,
+ .pointee = .{ .global = sym.pointee.global },
+ .addend = undefined,
+ },
+ .global_import => .{
+ .tag = .fromTypeImport(tag),
+ .offset = offset,
+ .pointee = .{ .symbol_name = sym.name.unwrap().? },
+ .addend = undefined,
+ },
+ else => unreachable,
+ });
+ },
+
+ .table_number_leb => {
+ wasm.object_relocations.appendAssumeCapacity(switch (sym.pointee) {
+ .table => .{
+ .tag = .fromType(tag),
+ .offset = offset,
+ .pointee = .{ .table = sym.pointee.table },
+ .addend = undefined,
+ },
+ .table_import => .{
+ .tag = .fromTypeImport(tag),
+ .offset = offset,
+ .pointee = .{ .symbol_name = sym.name.unwrap().? },
+ .addend = undefined,
+ },
+ else => unreachable,
});
},
+ .event_index_leb => return diags.failParse(path, "unsupported relocation: R_WASM_EVENT_INDEX_LEB", .{}),
}
}
@@ -684,11 +784,17 @@ pub fn parse(
}
},
.global => {
+ if (global_section_index != null)
+ return diags.failParse(path, "object has more than one global section", .{});
+ global_section_index = section_index;
+
+ const section_start = pos;
const globals_len, pos = readLeb(u32, bytes, pos);
for (try wasm.object_globals.addManyAsSlice(gpa, globals_len)) |*global| {
const valtype, pos = readEnum(std.wasm.Valtype, bytes, pos);
const mutable = bytes[pos] == 0x01;
pos += 1;
+ const init_start = pos;
const expr, pos = try readInit(wasm, bytes, pos);
global.* = .{
.name = .none,
@@ -699,6 +805,9 @@ pub fn parse(
},
},
.expr = expr,
+ .object_index = object_index,
+ .offset = @intCast(init_start - section_start),
+ .size = @intCast(pos - init_start),
};
}
},
@@ -728,10 +837,14 @@ pub fn parse(
start_function = @enumFromInt(functions_start + index);
},
.element => {
- log.warn("unimplemented: element section in {}", .{path});
+ log.warn("unimplemented: element section in {} {s}", .{ path, archive_member_name.? });
pos = section_end;
},
.code => {
+ if (code_section_index != null)
+ return diags.failParse(path, "object has more than one code section", .{});
+ code_section_index = section_index;
+
const start = pos;
const count, pos = readLeb(u32, bytes, pos);
for (try wasm.object_functions.addManyAsSlice(gpa, count)) |*elem| {
@@ -745,12 +858,16 @@ pub fn parse(
.type_index = undefined, // populated from func_types
.code = payload,
.offset = offset,
- .section_index = section_index,
- .source_location = source_location,
+ .object_index = object_index,
};
}
},
.data => {
+ if (data_section_index != null)
+ return diags.failParse(path, "object has more than one data section", .{});
+ data_section_index = section_index;
+
+ const section_start = pos;
const count, pos = readLeb(u32, bytes, pos);
for (try wasm.object_data_segments.addManyAsSlice(gpa, count)) |*elem| {
const flags, pos = readEnum(DataSegmentFlags, bytes, pos);
@@ -761,12 +878,17 @@ pub fn parse(
//const expr, pos = if (flags != .passive) try readInit(wasm, bytes, pos) else .{ .none, pos };
if (flags != .passive) pos = try skipInit(bytes, pos);
const data_len, pos = readLeb(u32, bytes, pos);
+ const segment_start = pos;
const payload = try wasm.addRelocatableDataPayload(bytes[pos..][0..data_len]);
pos += data_len;
elem.* = .{
.payload = payload,
- .name = .none, // Populated from symbol table
- .flags = .{}, // Populated from symbol table and segment_info
+ .name = .none, // Populated from segment_info
+ .flags = .{
+ .is_passive = flags == .passive,
+ }, // Remainder populated from segment_info
+ .offset = @intCast(segment_start - section_start),
+ .object_index = object_index,
};
}
},
@@ -1033,8 +1155,10 @@ pub fn parse(
}
},
.data_import => {
- const name = symbol.name.unwrap().?;
- log.warn("TODO data import '{s}'", .{name.slice(wasm)});
+ if (symbol.flags.undefined and symbol.flags.binding == .local) {
+ const name = symbol.name.slice(wasm).?;
+ diags.addParseError(path, "local symbol '{s}' references import", .{name});
+ }
},
.data => continue, // `wasm.object_datas` has already been populated.
};
@@ -1055,16 +1179,21 @@ pub fn parse(
}
// Apply segment_info.
- for (wasm.object_data_segments.items[data_segment_start..], ss.segment_info.items) |*data, info| {
+ const data_segments = wasm.object_data_segments.items[data_segment_start..];
+ if (data_segments.len != ss.segment_info.items.len) {
+ return diags.failParse(path, "expected {d} segment_info entries; found {d}", .{
+ data_segments.len, ss.segment_info.items.len,
+ });
+ }
+ for (data_segments, ss.segment_info.items) |*data, info| {
data.name = info.name.toOptional();
- data.flags.strings = info.flags.strings;
- data.flags.tls = data.flags.tls or info.flags.tls;
- data.flags.no_strip = info.flags.retain;
- data.flags.alignment = info.flags.alignment;
- if (data.flags.undefined and data.flags.binding == .local) {
- const name = info.name.slice(wasm);
- diags.addParseError(path, "local symbol '{s}' references import", .{name});
- }
+ data.flags = .{
+ .is_passive = data.flags.is_passive,
+ .strings = info.flags.strings,
+ .tls = info.flags.tls,
+ .retain = info.flags.retain,
+ .alignment = info.flags.alignment,
+ };
}
// Check for indirect function table in case of an MVP object file.
@@ -1106,6 +1235,10 @@ pub fn parse(
});
}
+ const functions_len: u32 = @intCast(wasm.object_functions.items.len - functions_start);
+ if (functions_len > 0 and code_section_index == null)
+ return diags.failParse(path, "code section missing ({d} functions)", .{functions_len});
+
return .{
.version = version,
.path = path,
@@ -1114,7 +1247,7 @@ pub fn parse(
.features = features,
.functions = .{
.off = functions_start,
- .len = @intCast(wasm.object_functions.items.len - functions_start),
+ .len = functions_len,
},
.function_imports = .{
.off = function_imports_start,
@@ -1140,7 +1273,9 @@ pub fn parse(
.off = custom_segment_start,
.len = @intCast(wasm.object_custom_segments.entries.len - custom_segment_start),
},
- .local_section_index_base = local_section_index_base,
+ .code_section_index = code_section_index,
+ .global_section_index = global_section_index,
+ .data_section_index = data_section_index,
};
}
src/link/Wasm.zig
@@ -93,13 +93,13 @@ func_types: std.AutoArrayHashMapUnmanaged(FunctionType, void) = .empty,
/// Local functions may be unnamed.
object_function_imports: std.AutoArrayHashMapUnmanaged(String, FunctionImport) = .empty,
/// All functions for all objects.
-object_functions: std.ArrayListUnmanaged(Function) = .empty,
+object_functions: std.ArrayListUnmanaged(ObjectFunction) = .empty,
/// Provides a mapping of both imports and provided globals to symbol name.
/// Local globals may be unnamed.
object_global_imports: std.AutoArrayHashMapUnmanaged(String, GlobalImport) = .empty,
/// All globals for all objects.
-object_globals: std.ArrayListUnmanaged(Global) = .empty,
+object_globals: std.ArrayListUnmanaged(ObjectGlobal) = .empty,
/// All table imports for all objects.
object_table_imports: std.AutoArrayHashMapUnmanaged(String, TableImport) = .empty,
@@ -386,7 +386,7 @@ pub const GlobalIndex = enum(u32) {
pub const stack_pointer: GlobalIndex = @enumFromInt(0);
/// Same as `stack_pointer` but with a safety assertion.
- pub fn stackPointer(wasm: *const Wasm) Global.Index {
+ pub fn stackPointer(wasm: *const Wasm) ObjectGlobal.Index {
const comp = wasm.base.comp;
assert(comp.config.output_mode != .Obj);
assert(comp.zcu != null);
@@ -513,26 +513,19 @@ pub const SymbolFlags = packed struct(u32) {
// Above here matches the tooling conventions ABI.
- padding1: u5 = 0,
+ padding1: u13 = 0,
/// Zig-specific. Dead things are allowed to be garbage collected.
alive: bool = false,
- /// Zig-specific. Segments only. Signals that the segment contains only
- /// null terminated strings allowing the linker to perform merging.
- strings: bool = false,
/// Zig-specific. This symbol comes from an object that must be included in
/// the final link.
must_link: bool = false,
- /// Zig-specific. Data segments only.
- is_passive: bool = false,
- /// Zig-specific. Data segments only.
- alignment: Alignment = .none,
- /// Zig-specific. Globals only.
+ /// Zig-specific.
global_type: GlobalType4 = .zero,
- /// Zig-specific. Tables only.
+ /// Zig-specific.
limits_has_max: bool = false,
- /// Zig-specific. Tables only.
+ /// Zig-specific.
limits_is_shared: bool = false,
- /// Zig-specific. Tables only.
+ /// Zig-specific.
ref_type: RefType1 = .funcref,
pub const Binding = enum(u2) {
@@ -554,10 +547,7 @@ pub const SymbolFlags = packed struct(u32) {
pub fn initZigSpecific(flags: *SymbolFlags, must_link: bool, no_strip: bool) void {
flags.no_strip = no_strip;
flags.alive = false;
- flags.strings = false;
flags.must_link = must_link;
- flags.is_passive = false;
- flags.alignment = .none;
flags.global_type = .zero;
flags.limits_has_max = false;
flags.limits_is_shared = false;
@@ -603,7 +593,7 @@ pub const GlobalType4 = packed struct(u4) {
pub const zero: GlobalType4 = @bitCast(@as(u4, 0));
- pub fn to(gt: GlobalType4) Global.Type {
+ pub fn to(gt: GlobalType4) ObjectGlobal.Type {
return .{
.valtype = gt.valtype.to(),
.mutable = gt.mutable,
@@ -1001,18 +991,24 @@ pub const FunctionImport = extern struct {
};
};
-pub const Function = extern struct {
+pub const ObjectFunction = extern struct {
flags: SymbolFlags,
/// `none` if this function has no symbol describing it.
name: OptionalString,
type_index: FunctionType.Index,
code: Code,
- /// The offset within the section where the data starts.
+ /// The offset within the code section where the data starts.
offset: u32,
- section_index: ObjectSectionIndex,
- source_location: SourceLocation,
+ /// The object file whose code section contains this function.
+ object_index: ObjectIndex,
pub const Code = DataPayload;
+
+ fn relocations(of: *const ObjectFunction, wasm: *const Wasm) ObjectRelocation.IterableSlice {
+ const code_section_index = of.object_index.ptr(wasm).code_section_index.?;
+ const relocs = wasm.object_relocations_table.get(code_section_index) orelse return .empty;
+ return .init(relocs, of.offset, of.code.len, wasm);
+ }
};
pub const GlobalImport = extern struct {
@@ -1101,6 +1097,10 @@ pub const GlobalImport = extern struct {
});
}
+ fn fromObjectGlobal(wasm: *const Wasm, object_global: ObjectGlobalIndex) Resolution {
+ return pack(wasm, .{ .object_global = object_global });
+ }
+
pub fn name(r: Resolution, wasm: *const Wasm) ?[]const u8 {
return switch (unpack(r, wasm)) {
.unresolved => unreachable,
@@ -1137,22 +1137,32 @@ pub const GlobalImport = extern struct {
return index.value(wasm).module_name;
}
- pub fn globalType(index: Index, wasm: *const Wasm) Global.Type {
+ pub fn globalType(index: Index, wasm: *const Wasm) ObjectGlobal.Type {
return value(index, wasm).flags.global_type.to();
}
};
};
-pub const Global = extern struct {
+pub const ObjectGlobal = extern struct {
/// `none` if this function has no symbol describing it.
name: OptionalString,
flags: SymbolFlags,
expr: Expr,
+ /// The object file whose global section contains this global.
+ object_index: ObjectIndex,
+ offset: u32,
+ size: u32,
pub const Type = struct {
valtype: std.wasm.Valtype,
mutable: bool,
};
+
+ fn relocations(og: *const ObjectGlobal, wasm: *const Wasm) ObjectRelocation.IterableSlice {
+ const global_section_index = og.object_index.ptr(wasm).global_section_index.?;
+ const relocs = wasm.object_relocations_table.get(global_section_index) orelse return .empty;
+ return .init(relocs, og.offset, og.size, wasm);
+ }
};
pub const RefType1 = enum(u1) {
@@ -1205,6 +1215,18 @@ pub const TableImport = extern struct {
};
}
+ fn pack(unpacked: Unpacked) Resolution {
+ return switch (unpacked) {
+ .unresolved => .unresolved,
+ .__indirect_function_table => .__indirect_function_table,
+ .object_table => |i| @enumFromInt(first_object_table + @intFromEnum(i)),
+ };
+ }
+
+ fn fromObjectTable(object_table: ObjectTableIndex) Resolution {
+ return pack(.{ .object_table = object_table });
+ }
+
pub fn refType(r: Resolution, wasm: *const Wasm) std.wasm.RefType {
return switch (unpack(r)) {
.unresolved => unreachable,
@@ -1298,7 +1320,7 @@ pub const ObjectTableIndex = enum(u32) {
pub const ObjectGlobalIndex = enum(u32) {
_,
- pub fn ptr(index: ObjectGlobalIndex, wasm: *const Wasm) *Global {
+ pub fn ptr(index: ObjectGlobalIndex, wasm: *const Wasm) *ObjectGlobal {
return &wasm.object_globals.items[@intFromEnum(index)];
}
@@ -1338,7 +1360,7 @@ pub const ObjectMemory = extern struct {
pub const ObjectFunctionIndex = enum(u32) {
_,
- pub fn ptr(index: ObjectFunctionIndex, wasm: *const Wasm) *Function {
+ pub fn ptr(index: ObjectFunctionIndex, wasm: *const Wasm) *ObjectFunction {
return &wasm.object_functions.items[@intFromEnum(index)];
}
@@ -1363,8 +1385,28 @@ pub const OptionalObjectFunctionIndex = enum(u32) {
pub const ObjectDataSegment = extern struct {
/// `none` if segment info custom subsection is missing.
name: OptionalString,
- flags: SymbolFlags,
+ flags: Flags,
payload: DataPayload,
+ offset: u32,
+ object_index: ObjectIndex,
+
+ pub const Flags = packed struct(u32) {
+ alive: bool = false,
+ is_passive: bool = false,
+ alignment: Alignment = .none,
+ /// Signals that the segment contains only null terminated strings allowing
+ /// the linker to perform merging.
+ strings: bool = false,
+ /// The segment contains thread-local data. This means that a unique copy
+ /// of this segment will be created for each thread.
+ tls: bool = false,
+ /// If the object file is included in the final link, the segment should be
+ /// retained in the final output regardless of whether it is used by the
+ /// program.
+ retain: bool = false,
+
+ _: u21 = 0,
+ };
/// Index into `Wasm.object_data_segments`.
pub const Index = enum(u32) {
@@ -1374,6 +1416,12 @@ pub const ObjectDataSegment = extern struct {
return &wasm.object_data_segments.items[@intFromEnum(i)];
}
};
+
+ fn relocations(ods: *const ObjectDataSegment, wasm: *const Wasm) ObjectRelocation.IterableSlice {
+ const data_section_index = ods.object_index.ptr(wasm).data_section_index.?;
+ const relocs = wasm.object_relocations_table.get(data_section_index) orelse return .empty;
+ return .init(relocs, ods.offset, ods.payload.len, wasm);
+ }
};
/// A local or exported global const from an object file.
@@ -1383,8 +1431,7 @@ pub const ObjectData = extern struct {
offset: u32,
/// May be zero. `offset + size` must be <= the segment's size.
size: u32,
- /// `none` if no symbol describes it.
- name: OptionalString,
+ name: String,
flags: SymbolFlags,
/// Index into `Wasm.object_datas`.
@@ -1845,7 +1892,7 @@ pub const ZcuImportIndex = enum(u32) {
return getExistingFunctionType(wasm, fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), target).?;
}
- pub fn globalType(index: ZcuImportIndex, wasm: *const Wasm) Global.Type {
+ pub fn globalType(index: ZcuImportIndex, wasm: *const Wasm) ObjectGlobal.Type {
_ = index;
_ = wasm;
unreachable; // Zig has no way to create Wasm globals yet.
@@ -1997,7 +2044,7 @@ pub const GlobalImportId = enum(u32) {
};
}
- pub fn globalType(id: GlobalImportId, wasm: *Wasm) Global.Type {
+ pub fn globalType(id: GlobalImportId, wasm: *Wasm) ObjectGlobal.Type {
return switch (unpack(id, wasm)) {
inline .object_global_import, .zcu_import => |i| i.globalType(wasm),
};
@@ -2014,7 +2061,7 @@ pub const SymbolTableIndex = enum(u32) {
};
pub const OutReloc = struct {
- tag: ObjectRelocation.Tag,
+ tag: Object.RelocationType,
offset: u32,
pointee: Pointee,
addend: i32,
@@ -2041,15 +2088,144 @@ pub const ObjectRelocation = struct {
/// When `offset` is zero, its position is immediately after the id and size of the section.
offset: u32,
pointee: Pointee,
- /// Populated only for `MEMORY_ADDR_*`, `FUNCTION_OFFSET_I32` and `SECTION_OFFSET_I32`.
+ /// Populated only for `memory_addr_*`, `function_offset_i32` and `section_offset_i32`.
addend: i32,
+ pub const Tag = enum(u8) {
+ // These use `Pointee.function`.
+ function_index_i32,
+ function_index_leb,
+ function_offset_i32,
+ function_offset_i64,
+ table_index_i32,
+ table_index_i64,
+ table_index_rel_sleb,
+ table_index_rel_sleb64,
+ table_index_sleb,
+ table_index_sleb64,
+ // These use `Pointee.symbol_name`.
+ function_import_index_i32,
+ function_import_index_leb,
+ function_import_offset_i32,
+ function_import_offset_i64,
+ table_import_index_i32,
+ table_import_index_i64,
+ table_import_index_rel_sleb,
+ table_import_index_rel_sleb64,
+ table_import_index_sleb,
+ table_import_index_sleb64,
+ // These use `Pointee.global`.
+ global_index_i32,
+ global_index_leb,
+ // These use `Pointee.symbol_name`.
+ global_import_index_i32,
+ global_import_index_leb,
+ // These use `Pointee.data`.
+ memory_addr_i32,
+ memory_addr_i64,
+ memory_addr_leb,
+ memory_addr_leb64,
+ memory_addr_locrel_i32,
+ memory_addr_rel_sleb,
+ memory_addr_rel_sleb64,
+ memory_addr_sleb,
+ memory_addr_sleb64,
+ memory_addr_tls_sleb,
+ memory_addr_tls_sleb64,
+ // These use `Pointee.symbol_name`.
+ memory_addr_import_i32,
+ memory_addr_import_i64,
+ memory_addr_import_leb,
+ memory_addr_import_leb64,
+ memory_addr_import_locrel_i32,
+ memory_addr_import_rel_sleb,
+ memory_addr_import_rel_sleb64,
+ memory_addr_import_sleb,
+ memory_addr_import_sleb64,
+ memory_addr_import_tls_sleb,
+ memory_addr_import_tls_sleb64,
+ /// Uses `Pointee.section`.
+ section_offset_i32,
+ /// Uses `Pointee.table`.
+ table_number_leb,
+ /// Uses `Pointee.symbol_name`.
+ table_import_number_leb,
+ /// Uses `Pointee.type_index`.
+ type_index_leb,
+
+ pub fn fromType(t: Object.RelocationType) Tag {
+ return switch (t) {
+ .event_index_leb => unreachable,
+ .function_index_i32 => .function_index_i32,
+ .function_index_leb => .function_index_leb,
+ .function_offset_i32 => .function_offset_i32,
+ .function_offset_i64 => .function_offset_i64,
+ .global_index_i32 => .global_index_i32,
+ .global_index_leb => .global_index_leb,
+ .memory_addr_i32 => .memory_addr_i32,
+ .memory_addr_i64 => .memory_addr_i64,
+ .memory_addr_leb => .memory_addr_leb,
+ .memory_addr_leb64 => .memory_addr_leb64,
+ .memory_addr_locrel_i32 => .memory_addr_locrel_i32,
+ .memory_addr_rel_sleb => .memory_addr_rel_sleb,
+ .memory_addr_rel_sleb64 => .memory_addr_rel_sleb64,
+ .memory_addr_sleb => .memory_addr_sleb,
+ .memory_addr_sleb64 => .memory_addr_sleb64,
+ .memory_addr_tls_sleb => .memory_addr_tls_sleb,
+ .memory_addr_tls_sleb64 => .memory_addr_tls_sleb64,
+ .section_offset_i32 => .section_offset_i32,
+ .table_index_i32 => .table_index_i32,
+ .table_index_i64 => .table_index_i64,
+ .table_index_rel_sleb => .table_index_rel_sleb,
+ .table_index_rel_sleb64 => .table_index_rel_sleb64,
+ .table_index_sleb => .table_index_sleb,
+ .table_index_sleb64 => .table_index_sleb64,
+ .table_number_leb => .table_number_leb,
+ .type_index_leb => .type_index_leb,
+ };
+ }
+
+ pub fn fromTypeImport(t: Object.RelocationType) Tag {
+ return switch (t) {
+ .event_index_leb => unreachable,
+ .function_index_i32 => .function_import_index_i32,
+ .function_index_leb => .function_import_index_leb,
+ .function_offset_i32 => .function_import_offset_i32,
+ .function_offset_i64 => .function_import_offset_i64,
+ .global_index_i32 => .global_import_index_i32,
+ .global_index_leb => .global_import_index_leb,
+ .memory_addr_i32 => .memory_addr_import_i32,
+ .memory_addr_i64 => .memory_addr_import_i64,
+ .memory_addr_leb => .memory_addr_import_leb,
+ .memory_addr_leb64 => .memory_addr_import_leb64,
+ .memory_addr_locrel_i32 => .memory_addr_import_locrel_i32,
+ .memory_addr_rel_sleb => .memory_addr_import_rel_sleb,
+ .memory_addr_rel_sleb64 => .memory_addr_import_rel_sleb64,
+ .memory_addr_sleb => .memory_addr_import_sleb,
+ .memory_addr_sleb64 => .memory_addr_import_sleb64,
+ .memory_addr_tls_sleb => .memory_addr_import_tls_sleb,
+ .memory_addr_tls_sleb64 => .memory_addr_import_tls_sleb64,
+ .section_offset_i32 => unreachable,
+ .table_index_i32 => .table_import_index_i32,
+ .table_index_i64 => .table_import_index_i64,
+ .table_index_rel_sleb => .table_import_index_rel_sleb,
+ .table_index_rel_sleb64 => .table_import_index_rel_sleb64,
+ .table_index_sleb => .table_import_index_sleb,
+ .table_index_sleb64 => .table_import_index_sleb64,
+ .table_number_leb => .table_import_number_leb,
+ .type_index_leb => unreachable,
+ };
+ }
+ };
+
pub const Pointee = union {
symbol_name: String,
+ data: ObjectData.Index,
type_index: FunctionType.Index,
section: ObjectSectionIndex,
- data: ObjectData.Index,
- function: Wasm.ObjectFunctionIndex,
+ function: ObjectFunctionIndex,
+ global: ObjectGlobalIndex,
+ table: ObjectTableIndex,
};
pub const Slice = extern struct {
@@ -2057,63 +2233,47 @@ pub const ObjectRelocation = struct {
off: u32,
len: u32,
- pub fn slice(s: Slice, wasm: *const Wasm) []ObjectRelocation {
- return wasm.relocations.items[s.off..][0..s.len];
+ const empty: Slice = .{ .off = 0, .len = 0 };
+
+ fn tags(s: Slice, wasm: *const Wasm) []const ObjectRelocation.Tag {
+ return wasm.object_relocations.items(.tag)[s.off..][0..s.len];
+ }
+
+ fn offsets(s: Slice, wasm: *const Wasm) []const u32 {
+ return wasm.object_relocations.items(.offset)[s.off..][0..s.len];
+ }
+
+ fn pointees(s: Slice, wasm: *const Wasm) []const Pointee {
+ return wasm.object_relocations.items(.pointee)[s.off..][0..s.len];
+ }
+
+ fn addends(s: Slice, wasm: *const Wasm) []const i32 {
+ return wasm.object_relocations.items(.addend)[s.off..][0..s.len];
}
};
- pub const Tag = enum(u8) {
- /// Uses `function`.
- FUNCTION_INDEX_LEB = 0,
- /// Uses `table_index`.
- TABLE_INDEX_SLEB = 1,
- /// Uses `table_index`.
- TABLE_INDEX_I32 = 2,
- /// Uses `data_segment`.
- MEMORY_ADDR_LEB = 3,
- /// Uses `data_segment`.
- MEMORY_ADDR_SLEB = 4,
- /// Uses `data_segment`.
- MEMORY_ADDR_I32 = 5,
- /// Uses `type_index`.
- TYPE_INDEX_LEB = 6,
- /// Uses `symbol_name`.
- GLOBAL_INDEX_LEB = 7,
- FUNCTION_OFFSET_I32 = 8,
- SECTION_OFFSET_I32 = 9,
- TAG_INDEX_LEB = 10,
- /// Uses `data_segment`.
- MEMORY_ADDR_REL_SLEB = 11,
- TABLE_INDEX_REL_SLEB = 12,
- /// Uses `symbol_name`.
- GLOBAL_INDEX_I32 = 13,
- /// Uses `data_segment`.
- MEMORY_ADDR_LEB64 = 14,
- /// Uses `data_segment`.
- MEMORY_ADDR_SLEB64 = 15,
- /// Uses `data_segment`.
- MEMORY_ADDR_I64 = 16,
- /// Uses `data_segment`.
- MEMORY_ADDR_REL_SLEB64 = 17,
- /// Uses `table_index`.
- TABLE_INDEX_SLEB64 = 18,
- /// Uses `table_index`.
- TABLE_INDEX_I64 = 19,
- TABLE_NUMBER_LEB = 20,
- /// Uses `data_segment`.
- MEMORY_ADDR_TLS_SLEB = 21,
- FUNCTION_OFFSET_I64 = 22,
- /// Uses `data_segment`.
- MEMORY_ADDR_LOCREL_I32 = 23,
- TABLE_INDEX_REL_SLEB64 = 24,
- /// Uses `data_segment`.
- MEMORY_ADDR_TLS_SLEB64 = 25,
- /// Uses `symbol_name`.
- FUNCTION_INDEX_I32 = 26,
-
- // Above here, the tags correspond to symbol table ABI described in
- // https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md
- // Below, the tags are compiler-internal.
+ pub const IterableSlice = struct {
+ slice: Slice,
+ /// Offset at which point to stop iterating.
+ end: u32,
+
+ const empty: IterableSlice = .{ .slice = .empty, .end = 0 };
+
+ fn init(relocs: Slice, offset: u32, size: u32, wasm: *const Wasm) IterableSlice {
+ const offsets = relocs.offsets(wasm);
+ const start = std.sort.lowerBound(u32, offsets, offset, order);
+ return .{
+ .slice = .{
+ .off = @intCast(relocs.off + start),
+ .len = @intCast(relocs.len - start),
+ },
+ .end = offset + size,
+ };
+ }
+
+ fn order(lhs: u32, rhs: u32) std.math.Order {
+ return std.math.order(lhs, rhs);
+ }
};
};
@@ -2781,7 +2941,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
// At the end, output functions and globals will be populated.
for (wasm.object_function_imports.keys(), wasm.object_function_imports.values(), 0..) |name, *import, i| {
if (import.flags.isIncluded(rdynamic)) {
- try markFunction(wasm, name, import, @enumFromInt(i));
+ try markFunctionImport(wasm, name, import, @enumFromInt(i));
}
}
wasm.functions_end_prelink = @intCast(wasm.functions.entries.len);
@@ -2789,7 +2949,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
for (wasm.object_global_imports.keys(), wasm.object_global_imports.values(), 0..) |name, *import, i| {
if (import.flags.isIncluded(rdynamic)) {
- try markGlobal(wasm, name, import, @enumFromInt(i));
+ try markGlobalImport(wasm, name, import, @enumFromInt(i));
}
}
wasm.globals_end_prelink = @intCast(wasm.globals.entries.len);
@@ -2797,13 +2957,12 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
for (wasm.object_table_imports.keys(), wasm.object_table_imports.values(), 0..) |name, *import, i| {
if (import.flags.isIncluded(rdynamic)) {
- try markTable(wasm, name, import, @enumFromInt(i));
+ try markTableImport(wasm, name, import, @enumFromInt(i));
}
}
}
-/// Recursively mark alive everything referenced by the function.
-fn markFunction(
+fn markFunctionImport(
wasm: *Wasm,
name: String,
import: *FunctionImport,
@@ -2814,8 +2973,6 @@ fn markFunction(
const comp = wasm.base.comp;
const gpa = comp.gpa;
- const rdynamic = comp.config.rdynamic;
- const is_obj = comp.config.output_mode == .Obj;
try wasm.functions.ensureUnusedCapacity(gpa, 1);
@@ -2836,20 +2993,31 @@ fn markFunction(
try wasm.function_imports.put(gpa, name, .fromObject(func_index, wasm));
}
} else {
- const gop = wasm.functions.getOrPutAssumeCapacity(import.resolution);
+ try markFunction(wasm, import.resolution.unpack(wasm).object_function);
+ }
+}
- if (!is_obj and import.flags.isExported(rdynamic)) try wasm.function_exports.append(gpa, .{
- .name = name,
- .function_index = @enumFromInt(gop.index),
- });
+/// Recursively mark alive everything referenced by the function.
+fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex) Allocator.Error!void {
+ const comp = wasm.base.comp;
+ const gpa = comp.gpa;
+ const gop = try wasm.functions.getOrPut(gpa, .fromObjectFunction(wasm, i));
+ if (gop.found_existing) return;
- for (try wasm.functionResolutionRelocSlice(import.resolution)) |reloc|
- try wasm.markReloc(reloc);
- }
+ const rdynamic = comp.config.rdynamic;
+ const is_obj = comp.config.output_mode == .Obj;
+ const function = i.ptr(wasm);
+
+ if (!is_obj and function.flags.isExported(rdynamic)) try wasm.function_exports.append(gpa, .{
+ .name = function.name.unwrap().?,
+ .function_index = @enumFromInt(gop.index),
+ });
+
+ try wasm.markRelocations(function.relocations(wasm));
}
/// Recursively mark alive everything referenced by the global.
-fn markGlobal(
+fn markGlobalImport(
wasm: *Wasm,
name: String,
import: *GlobalImport,
@@ -2860,8 +3028,6 @@ fn markGlobal(
const comp = wasm.base.comp;
const gpa = comp.gpa;
- const rdynamic = comp.config.rdynamic;
- const is_obj = comp.config.output_mode == .Obj;
try wasm.globals.ensureUnusedCapacity(gpa, 1);
@@ -2888,19 +3054,29 @@ fn markGlobal(
try wasm.global_imports.put(gpa, name, .fromObject(global_index, wasm));
}
} else {
- const gop = wasm.globals.getOrPutAssumeCapacity(import.resolution);
+ try markGlobal(wasm, import.resolution.unpack(wasm).object_global);
+ }
+}
- if (!is_obj and import.flags.isExported(rdynamic)) try wasm.global_exports.append(gpa, .{
- .name = name,
- .global_index = @enumFromInt(gop.index),
- });
+fn markGlobal(wasm: *Wasm, i: ObjectGlobalIndex) Allocator.Error!void {
+ const comp = wasm.base.comp;
+ const gpa = comp.gpa;
+ const gop = try wasm.globals.getOrPut(gpa, .fromObjectGlobal(wasm, i));
+ if (gop.found_existing) return;
- for (try wasm.globalResolutionRelocSlice(import.resolution)) |reloc|
- try wasm.markReloc(reloc);
- }
+ const rdynamic = comp.config.rdynamic;
+ const is_obj = comp.config.output_mode == .Obj;
+ const global = i.ptr(wasm);
+
+ if (!is_obj and global.flags.isExported(rdynamic)) try wasm.global_exports.append(gpa, .{
+ .name = global.name.unwrap().?,
+ .global_index = @enumFromInt(gop.index),
+ });
+
+ try wasm.markRelocations(global.relocations(wasm));
}
-fn markTable(
+fn markTableImport(
wasm: *Wasm,
name: String,
import: *TableImport,
@@ -2927,22 +3103,101 @@ fn markTable(
}
}
-fn globalResolutionRelocSlice(wasm: *Wasm, resolution: GlobalImport.Resolution) ![]const ObjectRelocation {
- assert(resolution != .unresolved);
- _ = wasm;
- @panic("TODO");
-}
+fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) Allocator.Error!void {
+ const segment = segment_index.ptr(wasm);
+ if (segment.flags.alive) return;
+ segment.flags.alive = true;
-fn functionResolutionRelocSlice(wasm: *Wasm, resolution: FunctionImport.Resolution) ![]const ObjectRelocation {
- assert(resolution != .unresolved);
- _ = wasm;
- @panic("TODO");
+ try wasm.markRelocations(segment.relocations(wasm));
}
-fn markReloc(wasm: *Wasm, reloc: ObjectRelocation) !void {
- _ = wasm;
- _ = reloc;
- @panic("TODO");
+fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) Allocator.Error!void {
+ for (relocs.slice.tags(wasm), relocs.slice.pointees(wasm), relocs.slice.offsets(wasm)) |tag, *pointee, offset| {
+ if (offset >= relocs.end) break;
+ switch (tag) {
+ .function_import_index_leb,
+ .function_import_index_i32,
+ .function_import_offset_i32,
+ .function_import_offset_i64,
+ .table_import_index_sleb,
+ .table_import_index_i32,
+ .table_import_index_sleb64,
+ .table_import_index_i64,
+ .table_import_index_rel_sleb,
+ .table_import_index_rel_sleb64,
+ => {
+ const name = pointee.symbol_name;
+ const i: FunctionImport.Index = @enumFromInt(wasm.object_function_imports.getIndex(name).?);
+ try markFunctionImport(wasm, name, i.value(wasm), i);
+ },
+ .global_import_index_leb, .global_import_index_i32 => {
+ const name = pointee.symbol_name;
+ const i: GlobalImport.Index = @enumFromInt(wasm.object_global_imports.getIndex(name).?);
+ try markGlobalImport(wasm, name, i.value(wasm), i);
+ },
+ .table_import_number_leb => {
+ const name = pointee.symbol_name;
+ const i: TableImport.Index = @enumFromInt(wasm.object_table_imports.getIndex(name).?);
+ try markTableImport(wasm, name, i.value(wasm), i);
+ },
+
+ .function_index_leb,
+ .function_index_i32,
+ .function_offset_i32,
+ .function_offset_i64,
+ .table_index_sleb,
+ .table_index_i32,
+ .table_index_sleb64,
+ .table_index_i64,
+ .table_index_rel_sleb,
+ .table_index_rel_sleb64,
+ => try markFunction(wasm, pointee.function),
+ .global_index_leb,
+ .global_index_i32,
+ => try markGlobal(wasm, pointee.global),
+ .table_number_leb,
+ => try wasm.tables.put(wasm.base.comp.gpa, .fromObjectTable(pointee.table), {}),
+
+ .section_offset_i32 => {
+ log.warn("TODO: ensure section {d} is included in output", .{pointee.section});
+ },
+ .memory_addr_import_leb,
+ .memory_addr_import_sleb,
+ .memory_addr_import_i32,
+ .memory_addr_import_rel_sleb,
+ .memory_addr_import_leb64,
+ .memory_addr_import_sleb64,
+ .memory_addr_import_i64,
+ .memory_addr_import_rel_sleb64,
+ .memory_addr_import_tls_sleb,
+ .memory_addr_import_locrel_i32,
+ .memory_addr_import_tls_sleb64,
+ => {
+ const name = pointee.symbol_name;
+ if (name == wasm.preloaded_strings.__heap_end or
+ name == wasm.preloaded_strings.__heap_base)
+ {
+ continue;
+ }
+ log.warn("TODO: ensure data symbol {s} is included in output", .{name.slice(wasm)});
+ },
+
+ .memory_addr_leb,
+ .memory_addr_sleb,
+ .memory_addr_i32,
+ .memory_addr_rel_sleb,
+ .memory_addr_leb64,
+ .memory_addr_sleb64,
+ .memory_addr_i64,
+ .memory_addr_rel_sleb64,
+ .memory_addr_tls_sleb,
+ .memory_addr_locrel_i32,
+ .memory_addr_tls_sleb64,
+ => try markDataSegment(wasm, pointee.data.ptr(wasm).segment),
+
+ .type_index_leb => continue,
+ }
+ }
}
pub fn flushModule(
src/codegen.zig
@@ -670,7 +670,7 @@ fn lowerUavRef(
try wasm.out_relocs.append(gpa, .{
.offset = @intCast(code.items.len),
.pointee = .{ .symbol_index = try wasm.uavSymbolIndex(uav.val) },
- .tag = if (ptr_width_bytes == 4) .MEMORY_ADDR_I32 else .MEMORY_ADDR_I64,
+ .tag = if (ptr_width_bytes == 4) .memory_addr_i32 else .memory_addr_i64,
.addend = @intCast(offset),
});
} else {
@@ -742,7 +742,7 @@ fn lowerNavRef(
try wasm.out_relocs.append(gpa, .{
.offset = @intCast(code.items.len),
.pointee = .{ .symbol_index = try wasm.navSymbolIndex(nav_index) },
- .tag = if (ptr_width_bytes == 4) .MEMORY_ADDR_I32 else .MEMORY_ADDR_I64,
+ .tag = if (ptr_width_bytes == 4) .memory_addr_i32 else .memory_addr_i64,
.addend = @intCast(offset),
});
} else {