Commit 1a4c5837fe
Changed files (10)
src
src/link/Elf/Atom.zig
@@ -523,7 +523,7 @@ fn reportUnhandledRelocError(self: Atom, rel: elf.Elf64_Rela, elf_file: *Elf) Re
relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch),
rel.r_offset,
});
- try err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
+ err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
return error.RelocFailure;
}
@@ -539,7 +539,7 @@ fn reportTextRelocError(
rel.r_offset,
symbol.name(elf_file),
});
- try err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
+ err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
return error.RelocFailure;
}
@@ -555,8 +555,8 @@ fn reportPicError(
rel.r_offset,
symbol.name(elf_file),
});
- try err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
- try err.addNote("recompile with -fPIC", .{});
+ err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
+ err.addNote("recompile with -fPIC", .{});
return error.RelocFailure;
}
@@ -572,8 +572,8 @@ fn reportNoPicError(
rel.r_offset,
symbol.name(elf_file),
});
- try err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
- try err.addNote("recompile with -fno-PIC", .{});
+ err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
+ err.addNote("recompile with -fno-PIC", .{});
return error.RelocFailure;
}
@@ -1187,7 +1187,7 @@ const x86_64 = struct {
x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]) catch {
var err = try diags.addErrorWithNotes(1);
try err.addMsg("could not relax {s}", .{@tagName(r_type)});
- try err.addNote("in {}:{s} at offset 0x{x}", .{
+ err.addNote("in {}:{s} at offset 0x{x}", .{
atom.file(elf_file).?.fmtPath(),
atom.name(elf_file),
rel.r_offset,
@@ -1332,7 +1332,7 @@ const x86_64 = struct {
relocation.fmtRelocType(rels[0].r_type(), .x86_64),
relocation.fmtRelocType(rels[1].r_type(), .x86_64),
});
- try err.addNote("in {}:{s} at offset 0x{x}", .{
+ err.addNote("in {}:{s} at offset 0x{x}", .{
self.file(elf_file).?.fmtPath(),
self.name(elf_file),
rels[0].r_offset,
@@ -1388,7 +1388,7 @@ const x86_64 = struct {
relocation.fmtRelocType(rels[0].r_type(), .x86_64),
relocation.fmtRelocType(rels[1].r_type(), .x86_64),
});
- try err.addNote("in {}:{s} at offset 0x{x}", .{
+ err.addNote("in {}:{s} at offset 0x{x}", .{
self.file(elf_file).?.fmtPath(),
self.name(elf_file),
rels[0].r_offset,
@@ -1485,7 +1485,7 @@ const x86_64 = struct {
relocation.fmtRelocType(rels[0].r_type(), .x86_64),
relocation.fmtRelocType(rels[1].r_type(), .x86_64),
});
- try err.addNote("in {}:{s} at offset 0x{x}", .{
+ err.addNote("in {}:{s} at offset 0x{x}", .{
self.file(elf_file).?.fmtPath(),
self.name(elf_file),
rels[0].r_offset,
@@ -1672,7 +1672,7 @@ const aarch64 = struct {
// TODO: relax
var err = try diags.addErrorWithNotes(1);
try err.addMsg("TODO: relax ADR_GOT_PAGE", .{});
- try err.addNote("in {}:{s} at offset 0x{x}", .{
+ err.addNote("in {}:{s} at offset 0x{x}", .{
atom.file(elf_file).?.fmtPath(),
atom.name(elf_file),
r_offset,
@@ -1959,7 +1959,7 @@ const riscv = struct {
// TODO: implement searching forward
var err = try diags.addErrorWithNotes(1);
try err.addMsg("TODO: find HI20 paired reloc scanning forward", .{});
- try err.addNote("in {}:{s} at offset 0x{x}", .{
+ err.addNote("in {}:{s} at offset 0x{x}", .{
atom.file(elf_file).?.fmtPath(),
atom.name(elf_file),
rel.r_offset,
src/link/Elf/eh_frame.zig
@@ -611,7 +611,7 @@ fn reportInvalidReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela) !void {
relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch),
rel.r_offset,
});
- try err.addNote("in {}:.eh_frame", .{elf_file.file(rec.file_index).?.fmtPath()});
+ err.addNote("in {}:.eh_frame", .{elf_file.file(rec.file_index).?.fmtPath()});
return error.RelocFailure;
}
src/link/Elf/Object.zig
@@ -797,7 +797,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {
if (!isNull(data[end .. end + sh_entsize])) {
var err = try diags.addErrorWithNotes(1);
try err.addMsg("string not null terminated", .{});
- try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
+ err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
return error.LinkFailure;
}
end += sh_entsize;
@@ -812,7 +812,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {
if (shdr.sh_size % sh_entsize != 0) {
var err = try diags.addErrorWithNotes(1);
try err.addMsg("size not a multiple of sh_entsize", .{});
- try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
+ err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
return error.LinkFailure;
}
@@ -889,8 +889,8 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{
const res = imsec.findSubsection(@intCast(esym.st_value)) orelse {
var err = try diags.addErrorWithNotes(2);
try err.addMsg("invalid symbol value: {x}", .{esym.st_value});
- try err.addNote("for symbol {s}", .{sym.name(elf_file)});
- try err.addNote("in {}", .{self.fmtPath()});
+ err.addNote("for symbol {s}", .{sym.name(elf_file)});
+ err.addNote("in {}", .{self.fmtPath()});
return error.LinkFailure;
};
@@ -915,7 +915,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{
const res = imsec.findSubsection(@intCast(@as(i64, @intCast(esym.st_value)) + rel.r_addend)) orelse {
var err = try diags.addErrorWithNotes(1);
try err.addMsg("invalid relocation at offset 0x{x}", .{rel.r_offset});
- try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
+ err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
return error.LinkFailure;
};
src/link/MachO/Atom.zig
@@ -909,8 +909,8 @@ const x86_64 = struct {
rel.offset,
rel.fmtPretty(.x86_64),
});
- try err.addNote("expected .mov instruction but found .{s}", .{@tagName(x)});
- try err.addNote("while parsing {}", .{self.getFile(macho_file).fmtPath()});
+ err.addNote("expected .mov instruction but found .{s}", .{@tagName(x)});
+ err.addNote("while parsing {}", .{self.getFile(macho_file).fmtPath()});
return error.RelaxFailUnexpectedInstruction;
},
}
src/link/Wasm/Flush.zig
@@ -22,7 +22,7 @@ const assert = std.debug.assert;
/// Ordered list of data segments that will appear in the final binary.
/// When sorted, to-be-merged segments will be made adjacent.
/// Values are virtual address.
-data_segments: std.AutoArrayHashMapUnmanaged(Wasm.DataSegment.Id, u32) = .empty,
+data_segments: std.AutoArrayHashMapUnmanaged(Wasm.DataId, u32) = .empty,
/// Each time a `data_segment` offset equals zero it indicates a new group, and
/// the next element in this array will contain the total merged segment size.
/// Value is the virtual memory address of the end of the segment.
@@ -120,7 +120,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
if (wasm.entry_resolution == .unresolved) {
var err = try diags.addErrorWithNotes(1);
try err.addMsg("entry symbol '{s}' missing", .{name.slice(wasm)});
- try err.addNote("'-fno-entry' suppresses this error", .{});
+ err.addNote("'-fno-entry' suppresses this error", .{});
}
}
}
@@ -176,10 +176,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
}), @as(u32, undefined));
for (wasm.object_data_segments.items, 0..) |*ds, i| {
if (!ds.flags.alive) continue;
- const data_segment_index: Wasm.ObjectDataSegmentIndex = @enumFromInt(i);
+ const obj_seg_index: Wasm.ObjectDataSegment.Index = @enumFromInt(i);
any_passive_inits = any_passive_inits or ds.flags.is_passive or (import_memory and !wasm.isBss(ds.name));
_ = f.data_segments.putAssumeCapacityNoClobber(.pack(wasm, .{
- .object = data_segment_index,
+ .object = obj_seg_index,
}), @as(u32, undefined));
}
if (wasm.error_name_table_ref_count > 0) {
@@ -229,7 +229,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
// For the purposes of sorting, they are implicitly all named ".data".
const Sort = struct {
wasm: *const Wasm,
- segments: []const Wasm.DataSegment.Id,
+ segments: []const Wasm.DataId,
pub fn lessThan(ctx: @This(), lhs: usize, rhs: usize) bool {
const lhs_segment = ctx.segments[lhs];
const rhs_segment = ctx.segments[rhs];
@@ -312,7 +312,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
const data_vaddr: u32 = @intCast(memory_ptr);
{
var seen_tls: enum { before, during, after } = .before;
- var category: Wasm.DataSegment.Category = undefined;
+ var category: Wasm.DataId.Category = undefined;
for (segment_ids, segment_vaddrs, 0..) |segment_id, *segment_vaddr, i| {
const alignment = segment_id.alignment(wasm);
category = segment_id.category(wasm);
@@ -707,7 +707,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
if (!is_obj) {
for (wasm.uav_fixups.items) |uav_fixup| {
- const ds_id: Wasm.DataSegment.Id = .pack(wasm, .{ .uav_exe = uav_fixup.uavs_exe_index });
+ const ds_id: Wasm.DataId = .pack(wasm, .{ .uav_exe = uav_fixup.uavs_exe_index });
const vaddr = f.data_segments.get(ds_id).?;
if (!is64) {
mem.writeInt(u32, wasm.string_bytes.items[uav_fixup.offset..][0..4], vaddr, .little);
@@ -716,7 +716,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
}
}
for (wasm.nav_fixups.items) |nav_fixup| {
- const ds_id: Wasm.DataSegment.Id = .pack(wasm, .{ .nav_exe = nav_fixup.navs_exe_index });
+ const ds_id: Wasm.DataId = .pack(wasm, .{ .nav_exe = nav_fixup.navs_exe_index });
const vaddr = f.data_segments.get(ds_id).?;
if (!is64) {
mem.writeInt(u32, wasm.string_bytes.items[nav_fixup.offset..][0..4], vaddr, .little);
@@ -862,7 +862,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
fn emitNameSection(
wasm: *Wasm,
- data_segments: *const std.AutoArrayHashMapUnmanaged(Wasm.DataSegment.Id, u32),
+ data_segments: *const std.AutoArrayHashMapUnmanaged(Wasm.DataId, u32),
binary_bytes: *std.ArrayListUnmanaged(u8),
) !void {
const f = &wasm.flush_buffer;
@@ -1137,9 +1137,9 @@ fn splitSegmentName(name: []const u8) struct { []const u8, []const u8 } {
fn wantSegmentMerge(
wasm: *const Wasm,
- a_id: Wasm.DataSegment.Id,
- b_id: Wasm.DataSegment.Id,
- b_category: Wasm.DataSegment.Category,
+ a_id: Wasm.DataId,
+ b_id: Wasm.DataId,
+ b_category: Wasm.DataId.Category,
) bool {
const a_category = a_id.category(wasm);
if (a_category != b_category) return false;
src/link/Wasm/Object.zig
@@ -102,11 +102,7 @@ pub const Symbol = struct {
const Pointee = union(enum) {
function: Wasm.ObjectFunctionIndex,
function_import: ScratchSpace.FuncImportIndex,
- data: struct {
- segment_index: Wasm.ObjectDataSegmentIndex,
- segment_offset: u32,
- size: u32,
- },
+ data: Wasm.ObjectData.Index,
data_import: void,
global: Wasm.ObjectGlobalIndex,
global_import: Wasm.GlobalImport.Index,
@@ -131,7 +127,7 @@ pub const ScratchSpace = struct {
const Pointee = union(std.wasm.ExternalKind) {
function: Wasm.ObjectFunctionIndex,
table: Wasm.ObjectTableIndex,
- memory: Wasm.ObjectMemoryIndex,
+ memory: Wasm.ObjectMemory.Index,
global: Wasm.ObjectGlobalIndex,
};
};
@@ -184,8 +180,9 @@ pub fn parse(
must_link: bool,
gc_sections: bool,
) anyerror!Object {
- const gpa = wasm.base.comp.gpa;
- const diags = &wasm.base.comp.link_diags;
+ const comp = wasm.base.comp;
+ const gpa = comp.gpa;
+ const diags = &comp.link_diags;
var pos: usize = 0;
@@ -334,12 +331,16 @@ pub fn parse(
const segment_index, pos = readLeb(u32, bytes, pos);
const segment_offset, pos = readLeb(u32, bytes, pos);
const size, pos = readLeb(u32, bytes, pos);
-
- symbol.pointee = .{ .data = .{
- .segment_index = @enumFromInt(data_segment_start + segment_index),
- .segment_offset = segment_offset,
+ try wasm.object_datas.append(gpa, .{
+ .segment = @enumFromInt(data_segment_start + segment_index),
+ .offset = segment_offset,
.size = size,
- } };
+ .name = symbol.name,
+ .flags = symbol.flags,
+ });
+ symbol.pointee = .{
+ .data = @enumFromInt(wasm.object_datas.items.len - 1),
+ };
}
},
.section => {
@@ -405,7 +406,6 @@ pub fn parse(
return error.UnrecognizedSymbolType;
},
}
- log.debug("found symbol: {}", .{symbol});
}
},
}
@@ -450,22 +450,10 @@ pub fn parse(
.MEMORY_ADDR_TLS_SLEB64,
=> {
const addend: i32, pos = readLeb(i32, bytes, pos);
- const sym_section = ss.symbol_table.items[index].pointee.data;
- if (sym_section.segment_offset != 0) {
- return diags.failParse(path, "data symbol {d} has nonzero offset {d}", .{
- index, sym_section.segment_offset,
- });
- }
- const seg_size = sym_section.segment_index.ptr(wasm).payload.len;
- if (sym_section.size != seg_size) {
- return diags.failParse(path, "data symbol {d} has size {d}, inequal to corresponding data segment {d} size {d}", .{
- index, sym_section.size, @intFromEnum(sym_section.segment_index), seg_size,
- });
- }
wasm.object_relocations.appendAssumeCapacity(.{
.tag = tag,
.offset = offset,
- .pointee = .{ .data_segment = sym_section.segment_index },
+ .pointee = .{ .data = ss.symbol_table.items[index].pointee.data },
.addend = addend,
});
},
@@ -651,7 +639,15 @@ pub fn parse(
const memories_len, pos = readLeb(u32, bytes, pos);
for (try wasm.object_memories.addManyAsSlice(gpa, memories_len)) |*memory| {
const limits, pos = readLimits(bytes, pos);
- memory.* = .{ .limits = limits };
+ memory.* = .{
+ .name = .none,
+ .flags = .{
+ .limits_has_max = limits.flags.has_max,
+ .limits_is_shared = limits.flags.is_shared,
+ },
+ .limits_min = limits.min,
+ .limits_max = limits.max,
+ };
}
},
.global => {
@@ -722,7 +718,6 @@ pub fn parse(
}
},
.data => {
- const 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);
@@ -733,13 +728,10 @@ 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_offset: u32 = @intCast(pos - start);
const payload = try wasm.addRelocatableDataPayload(bytes[pos..][0..data_len]);
pos += data_len;
elem.* = .{
.payload = payload,
- .segment_offset = segment_offset,
- .section_index = section_index,
.name = .none, // Populated from symbol table
.flags = .{}, // Populated from symbol table and segment_info
};
@@ -751,20 +743,56 @@ pub fn parse(
}
if (!saw_linking_section) return error.MissingLinkingSection;
+ const target_features = comp.root_mod.resolved_target.result.cpu.features;
+
if (has_tls) {
- const cpu_features = wasm.base.comp.root_mod.resolved_target.result.cpu.features;
- if (!std.Target.wasm.featureSetHas(cpu_features, .atomics))
+ if (!std.Target.wasm.featureSetHas(target_features, .atomics))
return diags.failParse(path, "object has TLS segment but target CPU feature atomics is disabled", .{});
- if (!std.Target.wasm.featureSetHas(cpu_features, .bulk_memory))
+ if (!std.Target.wasm.featureSetHas(target_features, .bulk_memory))
return diags.failParse(path, "object has TLS segment but target CPU feature bulk_memory is disabled", .{});
}
const features = opt_features orelse return error.MissingFeatures;
- if (true) @panic("iterate features, match against target features");
+ for (features.slice(wasm)) |feat| {
+ log.debug("feature: {s}{s}", .{ @tagName(feat.prefix), @tagName(feat.tag) });
+ switch (feat.prefix) {
+ .invalid => unreachable,
+ .@"-" => switch (feat.tag) {
+ .@"shared-mem" => if (comp.config.shared_memory) {
+ return diags.failParse(path, "object forbids shared-mem but compilation enables it", .{});
+ },
+ else => {
+ const f = feat.tag.toCpuFeature().?;
+ if (std.Target.wasm.featureSetHas(target_features, f)) {
+ return diags.failParse(
+ path,
+ "object forbids {s} but specified target features include {s}",
+ .{ @tagName(feat.tag), @tagName(f) },
+ );
+ }
+ },
+ },
+ .@"+", .@"=" => switch (feat.tag) {
+ .@"shared-mem" => if (!comp.config.shared_memory) {
+ return diags.failParse(path, "object requires shared-mem but compilation disables it", .{});
+ },
+ else => {
+ const f = feat.tag.toCpuFeature().?;
+ if (!std.Target.wasm.featureSetHas(target_features, f)) {
+ return diags.failParse(
+ path,
+ "object requires {s} but specified target features exclude {s}",
+ .{ @tagName(feat.tag), @tagName(f) },
+ );
+ }
+ },
+ },
+ }
+ }
// Apply function type information.
- for (ss.func_types.items, wasm.object_functions.items[functions_start..]) |func_type, *func| {
- func.type_index = func_type;
+ for (ss.func_type_indexes.items, wasm.object_functions.items[functions_start..]) |func_type, *func| {
+ func.type_index = func_type.ptr(ss).*;
}
// Apply symbol table information.
@@ -782,15 +810,21 @@ pub fn parse(
if (gop.value_ptr.type != fn_ty_index) {
var err = try diags.addErrorWithNotes(2);
try err.addMsg("symbol '{s}' mismatching function signatures", .{name.slice(wasm)});
- try err.addSrcNote(gop.value_ptr.source_location, "imported as {} here", .{gop.value_ptr.type.fmt(wasm)});
- try err.addSrcNote(source_location, "imported as {} here", .{fn_ty_index.fmt(wasm)});
+ gop.value_ptr.source_location.addNote(wasm, &err, "imported as {} here", .{
+ gop.value_ptr.type.fmt(wasm),
+ });
+ source_location.addNote(wasm, &err, "imported as {} here", .{fn_ty_index.fmt(wasm)});
continue;
}
- if (gop.value_ptr.module_name != ptr.module_name) {
+ if (gop.value_ptr.module_name != ptr.module_name.toOptional()) {
var err = try diags.addErrorWithNotes(2);
try err.addMsg("symbol '{s}' mismatching module names", .{name.slice(wasm)});
- try err.addSrcNote(gop.value_ptr.source_location, "module '{s}' here", .{gop.value_ptr.module_name.slice(wasm)});
- try err.addSrcNote(source_location, "module '{s}' here", .{ptr.module_name.slice(wasm)});
+ if (gop.value_ptr.module_name.slice(wasm)) |module_name| {
+ gop.value_ptr.source_location.addNote(wasm, &err, "module '{s}' here", .{module_name});
+ } else {
+ gop.value_ptr.source_location.addNote(wasm, &err, "no module here", .{});
+ }
+ source_location.addNote(wasm, &err, "module '{s}' here", .{ptr.module_name.slice(wasm)});
continue;
}
if (symbol.flags.binding == .strong) gop.value_ptr.flags.binding = .strong;
@@ -799,7 +833,7 @@ pub fn parse(
} else {
gop.value_ptr.* = .{
.flags = symbol.flags,
- .module_name = ptr.module_name,
+ .module_name = ptr.module_name.toOptional(),
.source_location = source_location,
.resolution = .unresolved,
.type = fn_ty_index,
@@ -808,7 +842,7 @@ pub fn parse(
},
.function => |index| {
assert(!symbol.flags.undefined);
- const ptr = index.ptr();
+ const ptr = index.ptr(wasm);
ptr.name = symbol.name;
ptr.flags = symbol.flags;
if (symbol.flags.binding == .local) continue; // No participation in symbol resolution.
@@ -818,35 +852,46 @@ pub fn parse(
if (gop.value_ptr.type != ptr.type_index) {
var err = try diags.addErrorWithNotes(2);
try err.addMsg("function signature mismatch: {s}", .{name.slice(wasm)});
- try err.addSrcNote(gop.value_ptr.source_location, "exported as {} here", .{ptr.type_index.fmt(wasm)});
- const word = if (gop.value_ptr.resolution == .none) "imported" else "exported";
- try err.addSrcNote(source_location, "{s} as {} here", .{ word, gop.value_ptr.type.fmt(wasm) });
+ gop.value_ptr.source_location.addNote(wasm, &err, "exported as {} here", .{
+ ptr.type_index.fmt(wasm),
+ });
+ const word = if (gop.value_ptr.resolution == .unresolved) "imported" else "exported";
+ source_location.addNote(wasm, &err, "{s} as {} here", .{ word, gop.value_ptr.type.fmt(wasm) });
continue;
}
- if (gop.value_ptr.resolution == .none or gop.value_ptr.flags.binding == .weak) {
+ if (gop.value_ptr.resolution == .unresolved or gop.value_ptr.flags.binding == .weak) {
// Intentional: if they're both weak, take the last one.
gop.value_ptr.source_location = source_location;
gop.value_ptr.module_name = host_name;
- gop.value_ptr.resolution = .fromObjectFunction(index);
+ gop.value_ptr.resolution = .fromObjectFunction(wasm, index);
continue;
}
var err = try diags.addErrorWithNotes(2);
try err.addMsg("symbol collision: {s}", .{name.slice(wasm)});
- try err.addSrcNote(gop.value_ptr.source_location, "exported as {} here", .{ptr.type_index.fmt(wasm)});
- try err.addSrcNote(source_location, "exported as {} here", .{gop.value_ptr.type.fmt(wasm)});
+ gop.value_ptr.source_location.addNote(wasm, &err, "exported as {} here", .{ptr.type_index.fmt(wasm)});
+ source_location.addNote(wasm, &err, "exported as {} here", .{gop.value_ptr.type.fmt(wasm)});
continue;
} else {
gop.value_ptr.* = .{
.flags = symbol.flags,
.module_name = host_name,
.source_location = source_location,
- .resolution = .fromObjectFunction(index),
+ .resolution = .fromObjectFunction(wasm, index),
.type = ptr.type_index,
};
}
},
- inline .global, .global_import, .table, .table_import => |i| {
+ inline .global_import, .table_import => |i| {
+ const ptr = i.value(wasm);
+ assert(i.key(wasm).toOptional() == symbol.name); // TODO
+ ptr.flags = symbol.flags;
+ if (symbol.flags.undefined and symbol.flags.binding == .local) {
+ const name = i.key(wasm).slice(wasm);
+ diags.addParseError(path, "local symbol '{s}' references import", .{name});
+ }
+ },
+ inline .global, .table => |i| {
const ptr = i.ptr(wasm);
ptr.name = symbol.name;
ptr.flags = symbol.flags;
@@ -857,10 +902,11 @@ pub fn parse(
},
.section => |i| {
// Name is provided by the section directly; symbol table does not have it.
- const ptr = i.ptr(wasm);
- ptr.flags = symbol.flags;
+ //const ptr = i.ptr(wasm);
+ //ptr.flags = symbol.flags;
+ _ = i;
if (symbol.flags.undefined and symbol.flags.binding == .local) {
- const name = ptr.name.slice(wasm);
+ const name = symbol.name.slice(wasm).?;
diags.addParseError(path, "local symbol '{s}' references import", .{name});
}
},
@@ -868,15 +914,7 @@ pub fn parse(
const name = symbol.name.unwrap().?;
log.warn("TODO data import '{s}'", .{name.slice(wasm)});
},
- .data => |data| {
- const ptr = data.ptr(wasm);
- const is_passive = ptr.flags.is_passive;
- ptr.name = symbol.name;
- ptr.flags = symbol.flags;
- ptr.flags.is_passive = is_passive;
- ptr.offset = data.segment_offset;
- ptr.size = data.size;
- },
+ .data => continue, // `wasm.object_datas` has already been populated.
};
// Apply export section info. This is done after the symbol table above so
@@ -957,18 +995,6 @@ pub fn parse(
.off = functions_start,
.len = @intCast(wasm.object_functions.items.len - functions_start),
},
- .globals = .{
- .off = globals_start,
- .len = @intCast(wasm.object_globals.items.len - globals_start),
- },
- .tables = .{
- .off = tables_start,
- .len = @intCast(wasm.object_tables.items.len - tables_start),
- },
- .memories = .{
- .off = memories_start,
- .len = @intCast(wasm.object_memories.items.len - memories_start),
- },
.function_imports = .{
.off = function_imports_start,
.len = @intCast(wasm.object_function_imports.entries.len - function_imports_start),
@@ -979,7 +1005,7 @@ pub fn parse(
},
.table_imports = .{
.off = table_imports_start,
- .len = @intCast(wasm.object_table_imports.items.len - table_imports_start),
+ .len = @intCast(wasm.object_table_imports.entries.len - table_imports_start),
},
.init_funcs = .{
.off = init_funcs_start,
src/link/Elf.zig
@@ -3394,7 +3394,7 @@ fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void {
// TODO verify `getMaxNumberOfPhdrs()` is accurate and convert this into no-op
var err = try diags.addErrorWithNotes(1);
try err.addMsg("fatal linker error: not enough space reserved for EHDR and PHDR table", .{});
- try err.addNote("required 0x{x}, available 0x{x}", .{ needed_size, available_space });
+ err.addNote("required 0x{x}, available 0x{x}", .{ needed_size, available_space });
}
phdr_table_load.p_filesz = needed_size + ehsize;
@@ -4545,12 +4545,12 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {
for (refs.items[0..nrefs]) |ref| {
const atom_ptr = self.atom(ref).?;
const file_ptr = atom_ptr.file(self).?;
- try err.addNote("referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) });
+ err.addNote("referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) });
}
if (refs.items.len > max_notes) {
const remaining = refs.items.len - max_notes;
- try err.addNote("referenced {d} more times", .{remaining});
+ err.addNote("referenced {d} more times", .{remaining});
}
}
}
@@ -4567,17 +4567,17 @@ fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemor
var err = try diags.addErrorWithNotes(nnotes + 1);
try err.addMsg("duplicate symbol definition: {s}", .{sym.name(self)});
- try err.addNote("defined by {}", .{sym.file(self).?.fmtPath()});
+ err.addNote("defined by {}", .{sym.file(self).?.fmtPath()});
var inote: usize = 0;
while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {
const file_ptr = self.file(notes.items[inote]).?;
- try err.addNote("defined by {}", .{file_ptr.fmtPath()});
+ err.addNote("defined by {}", .{file_ptr.fmtPath()});
}
if (notes.items.len > max_notes) {
const remaining = notes.items.len - max_notes;
- try err.addNote("defined {d} more times", .{remaining});
+ err.addNote("defined {d} more times", .{remaining});
}
}
@@ -4601,7 +4601,7 @@ pub fn addFileError(
const diags = &self.base.comp.link_diags;
var err = try diags.addErrorWithNotes(1);
try err.addMsg(format, args);
- try err.addNote("while parsing {}", .{self.file(file_index).?.fmtPath()});
+ err.addNote("while parsing {}", .{self.file(file_index).?.fmtPath()});
}
pub fn failFile(
src/link/MachO.zig
@@ -1572,21 +1572,21 @@ fn reportUndefs(self: *MachO) !void {
try err.addMsg("undefined symbol: {s}", .{undef_sym.getName(self)});
switch (notes) {
- .force_undefined => try err.addNote("referenced with linker flag -u", .{}),
- .entry => try err.addNote("referenced with linker flag -e", .{}),
- .dyld_stub_binder, .objc_msgsend => try err.addNote("referenced implicitly", .{}),
+ .force_undefined => err.addNote("referenced with linker flag -u", .{}),
+ .entry => err.addNote("referenced with linker flag -e", .{}),
+ .dyld_stub_binder, .objc_msgsend => err.addNote("referenced implicitly", .{}),
.refs => |refs| {
var inote: usize = 0;
while (inote < @min(refs.items.len, max_notes)) : (inote += 1) {
const ref = refs.items[inote];
const file = self.getFile(ref.file).?;
const atom = ref.getAtom(self).?;
- try err.addNote("referenced by {}:{s}", .{ file.fmtPath(), atom.getName(self) });
+ err.addNote("referenced by {}:{s}", .{ file.fmtPath(), atom.getName(self) });
}
if (refs.items.len > max_notes) {
const remaining = refs.items.len - max_notes;
- try err.addNote("referenced {d} more times", .{remaining});
+ err.addNote("referenced {d} more times", .{remaining});
}
},
}
@@ -3473,8 +3473,8 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo
seg_id,
seg.segName(),
});
- try err.addNote("TODO: emit relocations to memory locations in self-hosted backends", .{});
- try err.addNote("as a workaround, try increasing pre-allocated virtual memory of each segment", .{});
+ err.addNote("TODO: emit relocations to memory locations in self-hosted backends", .{});
+ err.addNote("as a workaround, try increasing pre-allocated virtual memory of each segment", .{});
}
seg.vmsize = needed_size;
@@ -3776,7 +3776,7 @@ pub fn reportParseError2(
const diags = &self.base.comp.link_diags;
var err = try diags.addErrorWithNotes(1);
try err.addMsg(format, args);
- try err.addNote("while parsing {}", .{self.getFile(file_index).?.fmtPath()});
+ err.addNote("while parsing {}", .{self.getFile(file_index).?.fmtPath()});
}
fn reportMissingDependencyError(
@@ -3790,10 +3790,10 @@ fn reportMissingDependencyError(
const diags = &self.base.comp.link_diags;
var err = try diags.addErrorWithNotes(2 + checked_paths.len);
try err.addMsg(format, args);
- try err.addNote("while resolving {s}", .{path});
- try err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()});
+ err.addNote("while resolving {s}", .{path});
+ err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()});
for (checked_paths) |p| {
- try err.addNote("tried {s}", .{p});
+ err.addNote("tried {s}", .{p});
}
}
@@ -3807,8 +3807,8 @@ fn reportDependencyError(
const diags = &self.base.comp.link_diags;
var err = try diags.addErrorWithNotes(2);
try err.addMsg(format, args);
- try err.addNote("while parsing {s}", .{path});
- try err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()});
+ err.addNote("while parsing {s}", .{path});
+ err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()});
}
fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {
@@ -3838,17 +3838,17 @@ fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {
var err = try diags.addErrorWithNotes(nnotes + 1);
try err.addMsg("duplicate symbol definition: {s}", .{sym.getName(self)});
- try err.addNote("defined by {}", .{sym.getFile(self).?.fmtPath()});
+ err.addNote("defined by {}", .{sym.getFile(self).?.fmtPath()});
var inote: usize = 0;
while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {
const file = self.getFile(notes.items[inote]).?;
- try err.addNote("defined by {}", .{file.fmtPath()});
+ err.addNote("defined by {}", .{file.fmtPath()});
}
if (notes.items.len > max_notes) {
const remaining = notes.items.len - max_notes;
- try err.addNote("defined {d} more times", .{remaining});
+ err.addNote("defined {d} more times", .{remaining});
}
}
return error.HasDuplicates;
src/link/Wasm.zig
@@ -109,7 +109,7 @@ object_tables: std.ArrayListUnmanaged(Table) = .empty,
/// All memory imports for all objects.
object_memory_imports: std.ArrayListUnmanaged(MemoryImport) = .empty,
/// All parsed memory sections for all objects.
-object_memories: std.ArrayListUnmanaged(std.wasm.Memory) = .empty,
+object_memories: std.ArrayListUnmanaged(ObjectMemory) = .empty,
/// All relocations from all objects concatenated. `relocs_start` marks the end
/// point of object relocations and start point of Zcu relocations.
@@ -119,8 +119,13 @@ object_relocations: std.MultiArrayList(ObjectRelocation) = .empty,
/// by the (synthetic) __wasm_call_ctors function.
object_init_funcs: std.ArrayListUnmanaged(InitFunc) = .empty,
-/// Non-synthetic section that can essentially be mem-cpy'd into place after performing relocations.
-object_data_segments: std.ArrayListUnmanaged(DataSegment) = .empty,
+/// The data section of an object has many segments. Each segment corresponds
+/// logically to an object file's .data section, or .rodata section. In
+/// the case of `-fdata-sections` there will be one segment per data symbol.
+object_data_segments: std.ArrayListUnmanaged(ObjectDataSegment) = .empty,
+/// Each segment has many data symbols. These correspond logically to global
+/// constants.
+object_datas: std.ArrayListUnmanaged(ObjectData) = .empty,
/// Non-synthetic section that can essentially be mem-cpy'd into place after performing relocations.
object_custom_segments: std.AutoArrayHashMapUnmanaged(ObjectSectionIndex, CustomSegment) = .empty,
@@ -457,6 +462,21 @@ pub const SourceLocation = enum(u32) {
.source_location_index => @panic("TODO"),
}
}
+
+ pub fn addNote(
+ sl: SourceLocation,
+ wasm: *Wasm,
+ err: *link.Diags.ErrorWithNotes,
+ comptime f: []const u8,
+ args: anytype,
+ ) void {
+ switch (sl.unpack(wasm)) {
+ .none => err.addNote(f, args),
+ .zig_object_nofile => err.addNote("zig compilation unit: " ++ f, args),
+ .object_index => |i| err.addNote("{}: " ++ f, .{i.ptr(wasm).path} ++ args),
+ .source_location_index => @panic("TODO"),
+ }
+ }
};
/// The lower bits of this ABI-match the flags here:
@@ -687,13 +707,13 @@ pub const UavsExeIndex = enum(u32) {
/// Used when emitting a relocatable object.
pub const ZcuDataObj = extern struct {
- code: DataSegment.Payload,
+ code: DataPayload,
relocs: OutReloc.Slice,
};
/// Used when not emitting a relocatable object.
pub const ZcuDataExe = extern struct {
- code: DataSegment.Payload,
+ code: DataPayload,
/// Tracks how many references there are for the purposes of sorting data segments.
count: u32,
};
@@ -917,6 +937,10 @@ pub const FunctionImport = extern struct {
return pack(wasm, .{ .zcu_func = @enumFromInt(wasm.zcu_funcs.getIndex(ip_index).?) });
}
+ pub fn fromObjectFunction(wasm: *const Wasm, object_function: ObjectFunctionIndex) Resolution {
+ return pack(wasm, .{ .object_function = object_function });
+ }
+
pub fn isNavOrUnresolved(r: Resolution, wasm: *const Wasm) bool {
return switch (r.unpack(wasm)) {
.unresolved, .zcu_func => true,
@@ -988,7 +1012,7 @@ pub const Function = extern struct {
section_index: ObjectSectionIndex,
source_location: SourceLocation,
- pub const Code = DataSegment.Payload;
+ pub const Code = DataPayload;
};
pub const GlobalImport = extern struct {
@@ -1283,12 +1307,30 @@ pub const ObjectGlobalIndex = enum(u32) {
}
};
-/// Index into `Wasm.object_memories`.
-pub const ObjectMemoryIndex = enum(u32) {
- _,
+pub const ObjectMemory = extern struct {
+ flags: SymbolFlags,
+ name: OptionalString,
+ limits_min: u32,
+ limits_max: u32,
- pub fn ptr(index: ObjectMemoryIndex, wasm: *const Wasm) *std.wasm.Memory {
- return &wasm.object_memories.items[@intFromEnum(index)];
+ /// Index into `Wasm.object_memories`.
+ pub const Index = enum(u32) {
+ _,
+
+ pub fn ptr(index: Index, wasm: *const Wasm) *ObjectMemory {
+ return &wasm.object_memories.items[@intFromEnum(index)];
+ }
+ };
+
+ pub fn limits(om: *const ObjectMemory) std.wasm.Limits {
+ return .{
+ .flags = .{
+ .has_max = om.limits_has_max,
+ .is_shared = om.limits_is_shared,
+ },
+ .min = om.limits_min,
+ .max = om.limits_max,
+ };
}
};
@@ -1318,14 +1360,74 @@ pub const OptionalObjectFunctionIndex = enum(u32) {
}
};
-pub const DataSegment = extern struct {
+pub const ObjectDataSegment = extern struct {
+ /// `none` if segment info custom subsection is missing.
+ name: OptionalString,
+ flags: SymbolFlags,
+ payload: DataPayload,
+
+ /// Index into `Wasm.object_data_segments`.
+ pub const Index = enum(u32) {
+ _,
+
+ pub fn ptr(i: Index, wasm: *const Wasm) *ObjectDataSegment {
+ return &wasm.object_data_segments.items[@intFromEnum(i)];
+ }
+ };
+};
+
+/// A local or exported global const from an object file.
+pub const ObjectData = extern struct {
+ segment: ObjectDataSegment.Index,
+ /// Index into the object segment payload. Must be <= the segment's size.
+ offset: u32,
+ /// May be zero. `offset + size` must be <= the segment's size.
+ size: u32,
/// `none` if no symbol describes it.
name: OptionalString,
flags: SymbolFlags,
- payload: Payload,
- /// From the data segment start to the first byte of payload.
- segment_offset: u32,
- section_index: ObjectSectionIndex,
+
+ /// Index into `Wasm.object_datas`.
+ pub const Index = enum(u32) {
+ _,
+
+ pub fn ptr(i: Index, wasm: *const Wasm) *ObjectData {
+ return &wasm.object_datas.items[@intFromEnum(i)];
+ }
+ };
+};
+
+pub const DataPayload = extern struct {
+ off: Off,
+ /// The size in bytes of the data representing the segment within the section.
+ len: u32,
+
+ pub const Off = enum(u32) {
+ /// The payload is all zeroes (bss section).
+ none = std.math.maxInt(u32),
+ /// Points into string_bytes. No corresponding string_table entry.
+ _,
+
+ pub fn unwrap(off: Off) ?u32 {
+ return if (off == .none) null else @intFromEnum(off);
+ }
+ };
+
+ pub fn slice(p: DataPayload, wasm: *const Wasm) []const u8 {
+ return wasm.string_bytes.items[p.off.unwrap().?..][0..p.len];
+ }
+};
+
+/// A reference to a local or exported global const.
+pub const DataId = enum(u32) {
+ __zig_error_names,
+ __zig_error_name_table,
+ /// First, an `ObjectDataSegment.Index`.
+ /// Next, index into `uavs_obj` or `uavs_exe` depending on whether emitting an object.
+ /// Next, index into `navs_obj` or `navs_exe` depending on whether emitting an object.
+ _,
+
+ const first_object = @intFromEnum(DataId.__zig_error_name_table) + 1;
pub const Category = enum {
/// Thread-local variables.
@@ -1337,221 +1439,180 @@ pub const DataSegment = extern struct {
zero,
};
- pub const Payload = extern struct {
- off: Off,
- /// The size in bytes of the data representing the segment within the section.
- len: u32,
-
- pub const Off = enum(u32) {
- /// The payload is all zeroes (bss section).
- none = std.math.maxInt(u32),
- /// Points into string_bytes. No corresponding string_table entry.
- _,
-
- pub fn unwrap(off: Off) ?u32 {
- return if (off == .none) null else @intFromEnum(off);
- }
- };
-
- pub fn slice(p: DataSegment.Payload, wasm: *const Wasm) []const u8 {
- return wasm.string_bytes.items[p.off.unwrap().?..][0..p.len];
- }
- };
-
- pub const Id = enum(u32) {
+ pub const Unpacked = union(enum) {
__zig_error_names,
__zig_error_name_table,
- /// First, an `ObjectDataSegmentIndex`.
- /// Next, index into `uavs_obj` or `uavs_exe` depending on whether emitting an object.
- /// Next, index into `navs_obj` or `navs_exe` depending on whether emitting an object.
- _,
-
- const first_object = @intFromEnum(Id.__zig_error_name_table) + 1;
+ object: ObjectDataSegment.Index,
+ uav_exe: UavsExeIndex,
+ uav_obj: UavsObjIndex,
+ nav_exe: NavsExeIndex,
+ nav_obj: NavsObjIndex,
+ };
- pub const Unpacked = union(enum) {
- __zig_error_names,
- __zig_error_name_table,
- object: ObjectDataSegmentIndex,
- uav_exe: UavsExeIndex,
- uav_obj: UavsObjIndex,
- nav_exe: NavsExeIndex,
- nav_obj: NavsObjIndex,
+ pub fn pack(wasm: *const Wasm, unpacked: Unpacked) DataId {
+ return switch (unpacked) {
+ .__zig_error_names => .__zig_error_names,
+ .__zig_error_name_table => .__zig_error_name_table,
+ .object => |i| @enumFromInt(first_object + @intFromEnum(i)),
+ inline .uav_exe, .uav_obj => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + @intFromEnum(i)),
+ .nav_exe => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + wasm.uavs_exe.entries.len + @intFromEnum(i)),
+ .nav_obj => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + wasm.uavs_obj.entries.len + @intFromEnum(i)),
};
+ }
- pub fn pack(wasm: *const Wasm, unpacked: Unpacked) Id {
- return switch (unpacked) {
- .__zig_error_names => .__zig_error_names,
- .__zig_error_name_table => .__zig_error_name_table,
- .object => |i| @enumFromInt(first_object + @intFromEnum(i)),
- inline .uav_exe, .uav_obj => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + @intFromEnum(i)),
- .nav_exe => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + wasm.uavs_exe.entries.len + @intFromEnum(i)),
- .nav_obj => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + wasm.uavs_obj.entries.len + @intFromEnum(i)),
- };
- }
-
- pub fn unpack(id: Id, wasm: *const Wasm) Unpacked {
- return switch (id) {
- .__zig_error_names => .__zig_error_names,
- .__zig_error_name_table => .__zig_error_name_table,
- _ => {
- const object_index = @intFromEnum(id) - first_object;
-
- const uav_index = if (object_index < wasm.object_data_segments.items.len)
- return .{ .object = @enumFromInt(object_index) }
+ pub fn unpack(id: DataId, wasm: *const Wasm) Unpacked {
+ return switch (id) {
+ .__zig_error_names => .__zig_error_names,
+ .__zig_error_name_table => .__zig_error_name_table,
+ _ => {
+ const object_index = @intFromEnum(id) - first_object;
+
+ const uav_index = if (object_index < wasm.object_data_segments.items.len)
+ return .{ .object = @enumFromInt(object_index) }
+ else
+ object_index - wasm.object_data_segments.items.len;
+
+ const comp = wasm.base.comp;
+ const is_obj = comp.config.output_mode == .Obj;
+ if (is_obj) {
+ const nav_index = if (uav_index < wasm.uavs_obj.entries.len)
+ return .{ .uav_obj = @enumFromInt(uav_index) }
else
- object_index - wasm.object_data_segments.items.len;
-
- const comp = wasm.base.comp;
- const is_obj = comp.config.output_mode == .Obj;
- if (is_obj) {
- const nav_index = if (uav_index < wasm.uavs_obj.entries.len)
- return .{ .uav_obj = @enumFromInt(uav_index) }
- else
- uav_index - wasm.uavs_obj.entries.len;
-
- return .{ .nav_obj = @enumFromInt(nav_index) };
- } else {
- const nav_index = if (uav_index < wasm.uavs_exe.entries.len)
- return .{ .uav_exe = @enumFromInt(uav_index) }
- else
- uav_index - wasm.uavs_exe.entries.len;
-
- return .{ .nav_exe = @enumFromInt(nav_index) };
- }
- },
- };
- }
+ uav_index - wasm.uavs_obj.entries.len;
- pub fn category(id: Id, wasm: *const Wasm) Category {
- return switch (unpack(id, wasm)) {
- .__zig_error_names, .__zig_error_name_table => .data,
- .object => |i| {
- const ptr = i.ptr(wasm);
- if (ptr.flags.tls) return .tls;
- if (wasm.isBss(ptr.name)) return .zero;
- return .data;
- },
- inline .uav_exe, .uav_obj => |i| if (i.value(wasm).code.off == .none) .zero else .data,
- inline .nav_exe, .nav_obj => |i| {
- const zcu = wasm.base.comp.zcu.?;
- const ip = &zcu.intern_pool;
- const nav = ip.getNav(i.key(wasm).*);
- if (nav.isThreadLocal(ip)) return .tls;
- const code = i.value(wasm).code;
- return if (code.off == .none) .zero else .data;
- },
- };
- }
+ return .{ .nav_obj = @enumFromInt(nav_index) };
+ } else {
+ const nav_index = if (uav_index < wasm.uavs_exe.entries.len)
+ return .{ .uav_exe = @enumFromInt(uav_index) }
+ else
+ uav_index - wasm.uavs_exe.entries.len;
- pub fn isTls(id: Id, wasm: *const Wasm) bool {
- return switch (unpack(id, wasm)) {
- .__zig_error_names, .__zig_error_name_table => false,
- .object => |i| i.ptr(wasm).flags.tls,
- .uav_exe, .uav_obj => false,
- inline .nav_exe, .nav_obj => |i| {
- const zcu = wasm.base.comp.zcu.?;
- const ip = &zcu.intern_pool;
- const nav = ip.getNav(i.key(wasm).*);
- return nav.isThreadLocal(ip);
- },
- };
- }
+ return .{ .nav_exe = @enumFromInt(nav_index) };
+ }
+ },
+ };
+ }
- pub fn isBss(id: Id, wasm: *const Wasm) bool {
- return id.category(wasm) == .zero;
- }
+ pub fn category(id: DataId, wasm: *const Wasm) Category {
+ return switch (unpack(id, wasm)) {
+ .__zig_error_names, .__zig_error_name_table => .data,
+ .object => |i| {
+ const ptr = i.ptr(wasm);
+ if (ptr.flags.tls) return .tls;
+ if (wasm.isBss(ptr.name)) return .zero;
+ return .data;
+ },
+ inline .uav_exe, .uav_obj => |i| if (i.value(wasm).code.off == .none) .zero else .data,
+ inline .nav_exe, .nav_obj => |i| {
+ const zcu = wasm.base.comp.zcu.?;
+ const ip = &zcu.intern_pool;
+ const nav = ip.getNav(i.key(wasm).*);
+ if (nav.isThreadLocal(ip)) return .tls;
+ const code = i.value(wasm).code;
+ return if (code.off == .none) .zero else .data;
+ },
+ };
+ }
- pub fn name(id: Id, wasm: *const Wasm) []const u8 {
- return switch (unpack(id, wasm)) {
- .__zig_error_names, .__zig_error_name_table, .uav_exe, .uav_obj => ".data",
- .object => |i| i.ptr(wasm).name.unwrap().?.slice(wasm),
- inline .nav_exe, .nav_obj => |i| {
- const zcu = wasm.base.comp.zcu.?;
- const ip = &zcu.intern_pool;
- const nav = ip.getNav(i.key(wasm).*);
- return nav.status.resolved.@"linksection".toSlice(ip) orelse ".data";
- },
- };
- }
+ pub fn isTls(id: DataId, wasm: *const Wasm) bool {
+ return switch (unpack(id, wasm)) {
+ .__zig_error_names, .__zig_error_name_table => false,
+ .object => |i| i.ptr(wasm).flags.tls,
+ .uav_exe, .uav_obj => false,
+ inline .nav_exe, .nav_obj => |i| {
+ const zcu = wasm.base.comp.zcu.?;
+ const ip = &zcu.intern_pool;
+ const nav = ip.getNav(i.key(wasm).*);
+ return nav.isThreadLocal(ip);
+ },
+ };
+ }
- pub fn alignment(id: Id, wasm: *const Wasm) Alignment {
- return switch (unpack(id, wasm)) {
- .__zig_error_names => .@"1",
- .__zig_error_name_table => wasm.pointerAlignment(),
- .object => |i| i.ptr(wasm).flags.alignment,
- inline .uav_exe, .uav_obj => |i| {
- const zcu = wasm.base.comp.zcu.?;
- const ip = &zcu.intern_pool;
- const ip_index = i.key(wasm).*;
- const ty: ZcuType = .fromInterned(ip.typeOf(ip_index));
- const result = ty.abiAlignment(zcu);
- assert(result != .none);
- return result;
- },
- inline .nav_exe, .nav_obj => |i| {
- const zcu = wasm.base.comp.zcu.?;
- const ip = &zcu.intern_pool;
- const nav = ip.getNav(i.key(wasm).*);
- const explicit = nav.status.resolved.alignment;
- if (explicit != .none) return explicit;
- const ty: ZcuType = .fromInterned(nav.typeOf(ip));
- const result = ty.abiAlignment(zcu);
- assert(result != .none);
- return result;
- },
- };
- }
+ pub fn isBss(id: DataId, wasm: *const Wasm) bool {
+ return id.category(wasm) == .zero;
+ }
- pub fn refCount(id: Id, wasm: *const Wasm) u32 {
- return switch (unpack(id, wasm)) {
- .__zig_error_names => @intCast(wasm.error_name_offs.items.len),
- .__zig_error_name_table => wasm.error_name_table_ref_count,
- .object, .uav_obj, .nav_obj => 0,
- inline .uav_exe, .nav_exe => |i| i.value(wasm).count,
- };
- }
+ pub fn name(id: DataId, wasm: *const Wasm) []const u8 {
+ return switch (unpack(id, wasm)) {
+ .__zig_error_names, .__zig_error_name_table, .uav_exe, .uav_obj => ".data",
+ .object => |i| i.ptr(wasm).name.unwrap().?.slice(wasm),
+ inline .nav_exe, .nav_obj => |i| {
+ const zcu = wasm.base.comp.zcu.?;
+ const ip = &zcu.intern_pool;
+ const nav = ip.getNav(i.key(wasm).*);
+ return nav.status.resolved.@"linksection".toSlice(ip) orelse ".data";
+ },
+ };
+ }
- pub fn isPassive(id: Id, wasm: *const Wasm) bool {
- const comp = wasm.base.comp;
- if (comp.config.import_memory and !id.isBss(wasm)) return true;
- return switch (unpack(id, wasm)) {
- .__zig_error_names, .__zig_error_name_table => false,
- .object => |i| i.ptr(wasm).flags.is_passive,
- .uav_exe, .uav_obj, .nav_exe, .nav_obj => false,
- };
- }
+ pub fn alignment(id: DataId, wasm: *const Wasm) Alignment {
+ return switch (unpack(id, wasm)) {
+ .__zig_error_names => .@"1",
+ .__zig_error_name_table => wasm.pointerAlignment(),
+ .object => |i| i.ptr(wasm).flags.alignment,
+ inline .uav_exe, .uav_obj => |i| {
+ const zcu = wasm.base.comp.zcu.?;
+ const ip = &zcu.intern_pool;
+ const ip_index = i.key(wasm).*;
+ const ty: ZcuType = .fromInterned(ip.typeOf(ip_index));
+ const result = ty.abiAlignment(zcu);
+ assert(result != .none);
+ return result;
+ },
+ inline .nav_exe, .nav_obj => |i| {
+ const zcu = wasm.base.comp.zcu.?;
+ const ip = &zcu.intern_pool;
+ const nav = ip.getNav(i.key(wasm).*);
+ const explicit = nav.status.resolved.alignment;
+ if (explicit != .none) return explicit;
+ const ty: ZcuType = .fromInterned(nav.typeOf(ip));
+ const result = ty.abiAlignment(zcu);
+ assert(result != .none);
+ return result;
+ },
+ };
+ }
- pub fn isEmpty(id: Id, wasm: *const Wasm) bool {
- return switch (unpack(id, wasm)) {
- .__zig_error_names, .__zig_error_name_table => false,
- .object => |i| i.ptr(wasm).payload.off == .none,
- inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.off == .none,
- };
- }
+ pub fn refCount(id: DataId, wasm: *const Wasm) u32 {
+ return switch (unpack(id, wasm)) {
+ .__zig_error_names => @intCast(wasm.error_name_offs.items.len),
+ .__zig_error_name_table => wasm.error_name_table_ref_count,
+ .object, .uav_obj, .nav_obj => 0,
+ inline .uav_exe, .nav_exe => |i| i.value(wasm).count,
+ };
+ }
- pub fn size(id: Id, wasm: *const Wasm) u32 {
- return switch (unpack(id, wasm)) {
- .__zig_error_names => @intCast(wasm.error_name_bytes.items.len),
- .__zig_error_name_table => {
- const comp = wasm.base.comp;
- const zcu = comp.zcu.?;
- const errors_len = wasm.error_name_offs.items.len;
- const elem_size = ZcuType.slice_const_u8_sentinel_0.abiSize(zcu);
- return @intCast(errors_len * elem_size);
- },
- .object => |i| i.ptr(wasm).payload.len,
- inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.len,
- };
- }
- };
-};
+ pub fn isPassive(id: DataId, wasm: *const Wasm) bool {
+ const comp = wasm.base.comp;
+ if (comp.config.import_memory and !id.isBss(wasm)) return true;
+ return switch (unpack(id, wasm)) {
+ .__zig_error_names, .__zig_error_name_table => false,
+ .object => |i| i.ptr(wasm).flags.is_passive,
+ .uav_exe, .uav_obj, .nav_exe, .nav_obj => false,
+ };
+ }
-/// Index into `Wasm.object_data_segments`.
-pub const ObjectDataSegmentIndex = enum(u32) {
- _,
+ pub fn isEmpty(id: DataId, wasm: *const Wasm) bool {
+ return switch (unpack(id, wasm)) {
+ .__zig_error_names, .__zig_error_name_table => false,
+ .object => |i| i.ptr(wasm).payload.off == .none,
+ inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.off == .none,
+ };
+ }
- pub fn ptr(i: ObjectDataSegmentIndex, wasm: *const Wasm) *DataSegment {
- return &wasm.object_data_segments.items[@intFromEnum(i)];
+ pub fn size(id: DataId, wasm: *const Wasm) u32 {
+ return switch (unpack(id, wasm)) {
+ .__zig_error_names => @intCast(wasm.error_name_bytes.items.len),
+ .__zig_error_name_table => {
+ const comp = wasm.base.comp;
+ const zcu = comp.zcu.?;
+ const errors_len = wasm.error_name_offs.items.len;
+ const elem_size = ZcuType.slice_const_u8_sentinel_0.abiSize(zcu);
+ return @intCast(errors_len * elem_size);
+ },
+ .object => |i| i.ptr(wasm).payload.len,
+ inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.len,
+ };
}
};
@@ -1565,7 +1626,7 @@ pub const CustomSegment = extern struct {
flags: SymbolFlags,
section_name: String,
- pub const Payload = DataSegment.Payload;
+ pub const Payload = DataPayload;
};
/// An index into string_bytes where a wasm expression is found.
@@ -1591,9 +1652,13 @@ pub const FunctionType = extern struct {
pub const Index = enum(u32) {
_,
- pub fn ptr(i: FunctionType.Index, wasm: *const Wasm) *FunctionType {
+ pub fn ptr(i: Index, wasm: *const Wasm) *FunctionType {
return &wasm.func_types.keys()[@intFromEnum(i)];
}
+
+ pub fn fmt(i: Index, wasm: *const Wasm) Formatter {
+ return i.ptr(wasm).fmt(wasm);
+ }
};
pub const format = @compileError("can't format without *Wasm reference");
@@ -1601,6 +1666,46 @@ pub const FunctionType = extern struct {
pub fn eql(a: FunctionType, b: FunctionType) bool {
return a.params == b.params and a.returns == b.returns;
}
+
+ pub fn fmt(ft: FunctionType, wasm: *const Wasm) Formatter {
+ return .{ .wasm = wasm, .ft = ft };
+ }
+
+ const Formatter = struct {
+ wasm: *const Wasm,
+ ft: FunctionType,
+
+ pub fn format(
+ self: Formatter,
+ comptime format_string: []const u8,
+ options: std.fmt.FormatOptions,
+ writer: anytype,
+ ) !void {
+ if (format_string.len != 0) std.fmt.invalidFmtError(format_string, self);
+ _ = options;
+ const params = self.ft.params.slice(self.wasm);
+ const returns = self.ft.returns.slice(self.wasm);
+
+ try writer.writeByte('(');
+ for (params, 0..) |param, i| {
+ try writer.print("{s}", .{@tagName(param)});
+ if (i + 1 != params.len) {
+ try writer.writeAll(", ");
+ }
+ }
+ try writer.writeAll(") -> ");
+ if (returns.len == 0) {
+ try writer.writeAll("nil");
+ } else {
+ for (returns, 0..) |return_ty, i| {
+ try writer.print("{s}", .{@tagName(return_ty)});
+ if (i + 1 != returns.len) {
+ try writer.writeAll(", ");
+ }
+ }
+ }
+ }
+ };
};
/// Represents a function entry, holding the index to its type
@@ -1955,7 +2060,7 @@ pub const ObjectRelocation = struct {
symbol_name: String,
type_index: FunctionType.Index,
section: ObjectSectionIndex,
- data_segment: ObjectDataSegmentIndex,
+ data: ObjectData.Index,
function: Wasm.ObjectFunctionIndex,
};
@@ -2096,6 +2201,8 @@ pub const Feature = packed struct(u8) {
/// Type of the feature, must be unique in the sequence of features.
tag: Tag,
+ pub const sentinel: Feature = @bitCast(@as(u8, 0));
+
/// Stored identically to `String`. The bytes are reinterpreted as `Feature`
/// elements. Elements must be sorted before string-interning.
pub const Set = enum(u32) {
@@ -2104,6 +2211,14 @@ pub const Feature = packed struct(u8) {
pub fn fromString(s: String) Set {
return @enumFromInt(@intFromEnum(s));
}
+
+ pub fn string(s: Set) String {
+ return @enumFromInt(@intFromEnum(s));
+ }
+
+ pub fn slice(s: Set, wasm: *const Wasm) [:sentinel]const Feature {
+ return @ptrCast(string(s).slice(wasm));
+ }
};
/// Unlike `std.Target.wasm.Feature` this also contains linker-features such as shared-mem.
@@ -2129,6 +2244,13 @@ pub const Feature = packed struct(u8) {
return @enumFromInt(@intFromEnum(feature));
}
+ pub fn toCpuFeature(tag: Tag) ?std.Target.wasm.Feature {
+ return if (@intFromEnum(tag) < @typeInfo(std.Target.wasm.Feature).@"enum".fields.len)
+ @enumFromInt(@intFromEnum(tag))
+ else
+ null;
+ }
+
pub const format = @compileError("use @tagName instead");
};
@@ -2136,15 +2258,14 @@ pub const Feature = packed struct(u8) {
pub const Prefix = enum(u2) {
/// Reserved so that a 0-byte Feature is invalid and therefore can be a sentinel.
invalid,
- /// '0x2b': Object uses this feature, and the link fails if feature is
- /// not in the allowed set.
+ /// Object uses this feature, and the link fails if feature is not in
+ /// the allowed set.
@"+",
- /// '0x2d': Object does not use this feature, and the link fails if
- /// this feature is in the allowed set.
+ /// Object does not use this feature, and the link fails if this
+ /// feature is in the allowed set.
@"-",
- /// '0x3d': Object uses this feature, and the link fails if this
- /// feature is not in the allowed set, or if any object does not use
- /// this feature.
+ /// Object uses this feature, and the link fails if this feature is not
+ /// in the allowed set, or if any object does not use this feature.
@"=",
};
@@ -2390,6 +2511,7 @@ pub fn deinit(wasm: *Wasm) void {
wasm.object_memories.deinit(gpa);
wasm.object_relocations.deinit(gpa);
wasm.object_data_segments.deinit(gpa);
+ wasm.object_datas.deinit(gpa);
wasm.object_custom_segments.deinit(gpa);
wasm.object_init_funcs.deinit(gpa);
wasm.object_comdats.deinit(gpa);
@@ -3412,7 +3534,7 @@ pub fn addExpr(wasm: *Wasm, bytes: []const u8) Allocator.Error!Expr {
return @enumFromInt(wasm.string_bytes.items.len - bytes.len);
}
-pub fn addRelocatableDataPayload(wasm: *Wasm, bytes: []const u8) Allocator.Error!DataSegment.Payload {
+pub fn addRelocatableDataPayload(wasm: *Wasm, bytes: []const u8) Allocator.Error!DataPayload {
const gpa = wasm.base.comp.gpa;
try wasm.string_bytes.appendSlice(gpa, bytes);
return .{
@@ -3546,7 +3668,7 @@ pub fn uavAddr(wasm: *Wasm, uav_index: UavsExeIndex) u32 {
assert(wasm.flush_buffer.memory_layout_finished);
const comp = wasm.base.comp;
assert(comp.config.output_mode != .Obj);
- const ds_id: DataSegment.Id = .pack(wasm, .{ .uav_exe = uav_index });
+ const ds_id: DataId = .pack(wasm, .{ .uav_exe = uav_index });
return wasm.flush_buffer.data_segments.get(ds_id).?;
}
@@ -3557,7 +3679,7 @@ pub fn navAddr(wasm: *Wasm, nav_index: InternPool.Nav.Index) u32 {
assert(comp.config.output_mode != .Obj);
const navs_exe_index: NavsExeIndex = @enumFromInt(wasm.navs_exe.getIndex(nav_index).?);
log.debug("navAddr {s} {}", .{ navs_exe_index.name(wasm), nav_index });
- const ds_id: DataSegment.Id = .pack(wasm, .{ .nav_exe = navs_exe_index });
+ const ds_id: DataId = .pack(wasm, .{ .nav_exe = navs_exe_index });
return wasm.flush_buffer.data_segments.get(ds_id).?;
}
@@ -3646,14 +3768,14 @@ fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Zcu
const relocs_len: u32 = @intCast(wasm.out_relocs.len - relocs_start);
wasm.string_bytes_lock.unlock();
- const naive_code: DataSegment.Payload = .{
+ const naive_code: DataPayload = .{
.off = @enumFromInt(code_start),
.len = code_len,
};
// Only nonzero init values need to take up space in the output.
const all_zeroes = std.mem.allEqual(u8, naive_code.slice(wasm), 0);
- const code: DataSegment.Payload = if (!all_zeroes) naive_code else c: {
+ const code: DataPayload = if (!all_zeroes) naive_code else c: {
wasm.string_bytes.shrinkRetainingCapacity(code_start);
// Indicate empty by making off and len the same value, however, still
// transmit the data size by using the size as that value.
src/link.zig
@@ -97,15 +97,12 @@ pub const Diags = struct {
err_msg.msg = try std.fmt.allocPrint(gpa, format, args);
}
- pub fn addNote(
- err: *ErrorWithNotes,
- comptime format: []const u8,
- args: anytype,
- ) error{OutOfMemory}!void {
+ pub fn addNote(err: *ErrorWithNotes, comptime format: []const u8, args: anytype) void {
const gpa = err.diags.gpa;
+ const msg = std.fmt.allocPrint(gpa, format, args) catch return err.diags.setAllocFailure();
const err_msg = &err.diags.msgs.items[err.index];
assert(err.note_slot < err_msg.notes.len);
- err_msg.notes[err.note_slot] = .{ .msg = try std.fmt.allocPrint(gpa, format, args) };
+ err_msg.notes[err.note_slot] = .{ .msg = msg };
err.note_slot += 1;
}
};