diff --git a/lib/compiler/Maker/Step/Run.zig b/lib/compiler/Maker/Step/Run.zig index af4819f62b2717a528ee3823aad1fee269f115c8..35bceb1754d454e89520b9a9330f2b97a00cce43 100644 --- a/lib/compiler/Maker/Step/Run.zig +++ b/lib/compiler/Maker/Step/Run.zig @@ -2126,10 +2126,16 @@ fn runCommand( defer gpa.free(snapshot_contents); const result = switch (snapshot.result) { - .stdout => generic_result.stdout.?, .stderr => generic_result.stderr.?, + .stdout => generic_result.stdout.?, }; - if (!mem.eql(u8, snapshot_contents, result)) { + if (std.mem.findDiff(u8, snapshot_contents, result)) |diff_index| { + var diff_line_number: usize = 1; + + for (snapshot_contents[0..diff_index]) |value| { + if (value == '\n') diff_line_number += 1; + } + return step.fail(maker, \\ \\========= snapshot file: ========= @@ -2138,7 +2144,21 @@ fn runCommand( \\{s} \\========= {t} output was: ======== \\{s} - , .{ snapshot.path, snapshot_contents, snapshot.result, result }); + \\================================== + \\first difference on line {d}: + \\expected: + \\{f} + \\found: + \\{f} + , .{ + snapshot.path, + snapshot_contents, + snapshot.result, + result, + diff_line_number, + fmtSnapshotIndicatorLine(snapshot_contents, diff_index), + fmtSnapshotIndicatorLine(result, diff_index), + }); } } }, @@ -2154,6 +2174,38 @@ fn runCommand( } } +const FmtIndicatorLine = struct { + buf: []const u8, + index: usize, +}; + +fn fmtSnapshotIndicatorLine(buf: []const u8, index: usize) std.fmt.Alt( + FmtIndicatorLine, + snapshotIndicatorLine, +) { + return .{ .data = .{ .buf = buf, .index = index } }; +} + +fn snapshotIndicatorLine(line: FmtIndicatorLine, w: *std.Io.Writer) std.Io.Writer.Error!void { + const line_begin_index = if (std.mem.lastIndexOfScalar(u8, line.buf[0..line.index], '\n')) |line_begin| + line_begin + 1 + else + 0; + const line_end_index = if (std.mem.findScalar(u8, line.buf[line.index..], '\n')) |line_end| + (line.index + line_end) + else + line.buf.len; + + try w.writeAll(line.buf[line_begin_index..line_end_index]); + try w.writeByte('\n'); + try w.splatByteAll(' ', line_end_index - line_begin_index); + try w.writeByte('\n'); + if (line.index >= line.buf.len) + try w.writeAll("^ (end of file)") + else + try w.print("^ ('\\x{x:0>2}')\n", .{line.buf[line.index]}); +} + const EvalGenericResult = struct { term: process.Child.Term, stdout: ?[]const u8, diff --git a/lib/compiler/objdump.zig b/lib/compiler/objdump.zig index 0ffb3295fa5834a985d1c91f693077b14bd8dc15..56746f712897835e33531511b5ad456d860c312e 100644 --- a/lib/compiler/objdump.zig +++ b/lib/compiler/objdump.zig @@ -1653,10 +1653,10 @@ const coff = struct { fn dumpFlags(w: *Io.Writer, comptime fmt: []const u8, comptime T: type, flags: *const T, cols: u32) !void { const s = @typeInfo(T).@"struct"; - inline for (s.fields) |flag_field| { - if (flag_field.type == bool and @field(flags, flag_field.name)) { + inline for (s.field_names, s.field_types) |field_name, field_type| { + if (field_type == bool and @field(flags, field_name)) { try w.splatByteAll(' ', cols); - try w.print(fmt, .{flag_field.name}); + try w.print(fmt, .{field_name}); } } } @@ -1693,25 +1693,26 @@ const coff = struct { header: *const T, Custom: type, ) !void { - inline for (@typeInfo(T).@"struct".fields) |field| { - const val = &@field(header, field.name); - if (@hasDecl(Custom, field.name)) { - try @field(Custom, field.name)(d, header); + const s = @typeInfo(T).@"struct"; + inline for (s.field_names, s.field_types) |field_name, field_type| { + const val = &@field(header, field_name); + if (@hasDecl(Custom, field_name)) { + try @field(Custom, field_name)(d, header); } else { - switch (@typeInfo(field.type)) { + switch (@typeInfo(field_type)) { .int => try d.w.print("{f} {s}\n", .{ fmtIntField(d, val.*, .{ - .kind = comptime fieldKind(field.name), + .kind = comptime fieldKind(field_name), .width = .{ .explicit = 16 }, - }), field.name }), - .@"enum" => try d.w.print("{x: >16} {s} ({t})\n", .{ val.*, field.name, val.* }), - .@"struct" => |s| { - switch (s.layout) { + }), field_name }), + .@"enum" => try d.w.print("{x: >16} {s} ({t})\n", .{ val.*, field_name, val.* }), + .@"struct" => |s_field| { + switch (s_field.layout) { .auto, .@"extern", - => try dumpHeader(d, field.type, val, Custom), + => try dumpHeader(d, field_type, val, Custom), .@"packed" => { - try d.w.print("{x: >16} {s}\n", .{ @as(s.backing_integer.?, @bitCast(val.*)), field.name }); - try dumpFlags(d.w, "| {s}\n", field.type, val, 15); + try d.w.print("{x: >16} {s}\n", .{ @as(s_field.backing_integer.?, @bitCast(val.*)), field_name }); + try dumpFlags(d.w, "| {s}\n", field_type, val, 15); }, } }, diff --git a/src/codegen/x86_64/Emit.zig b/src/codegen/x86_64/Emit.zig index d4677bfe3259fa719e54c4187ef0fb70ae98d79a..1e8e60ffb665fc70709a5291040a32a1bebcb5af 100644 --- a/src/codegen/x86_64/Emit.zig +++ b/src/codegen/x86_64/Emit.zig @@ -155,6 +155,7 @@ pub fn emitMir(emit: *Emit) Error!void { @enumFromInt(try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)) else if (emit.bin_file.cast(.elf2)) |elf| try elf.externSymbol(.{ .name = extern_func.toSlice(&emit.lower.mir).?, + .lib_name = null, .type = .FUNC, }) else if (emit.bin_file.cast(.macho)) |macho_file| @enumFromInt(try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)) @@ -254,7 +255,7 @@ pub fn emitMir(emit: *Emit) Error!void { else => unreachable, } } else if (emit.bin_file.cast(.coff2)) |_| { - if (reloc.target.is_dll_import) switch (lowered_inst.encoding.mnemonic) { + if (target.is_dll_import) switch (lowered_inst.encoding.mnemonic) { .lea => try emit.encodeInst(try .new(.none, .mov, &.{ lowered_inst.ops[0], .{ .mem = .initRip(.ptr, 0) }, diff --git a/src/link/Coff.zig b/src/link/Coff.zig index f7e859631909c81615d0d2ed4dd90a4604975e0c..fe338b3f3ac6bfc4f57d2fbd7954491fdd7a2194 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -94,6 +94,13 @@ pub const imp_prefix = "__imp_"; const header_name_max_len = @typeInfo(@FieldType(std.coff.SectionHeader, "name")).array.len; +const Error = link.Error || error{MappedFileIo}; +const LoadInputError = Error || + Io.File.SeekError || + Io.File.Reader.SizeError || + Io.Reader.Error || + MappedFile.Error; + /// This is the start of a Portable Executable (PE) file. /// It starts with a MS-DOS header followed by a MS-DOS stub program. /// This data does not change so we include it as follows in all binaries. @@ -484,7 +491,7 @@ pub const Member = struct { longnames, _, - const known_count = @typeInfo(Index).@"enum".fields.len; + const known_count = @typeInfo(Index).@"enum".field_names.len; pub fn get(member_index: Member.Index, coff: *Coff) *Member { return &coff.members.items[@intFromEnum(member_index)]; @@ -2855,7 +2862,7 @@ pub fn getNavVAddr( pt: Zcu.PerThread, nav: InternPool.Nav.Index, reloc_info: link.File.RelocInfo, -) !u64 { +) link.Error!u64 { return coff.getVAddr(reloc_info, try coff.navSymbol(pt.zcu, nav)); } @@ -2863,11 +2870,11 @@ pub fn getUavVAddr( coff: *Coff, uav: InternPool.Index, reloc_info: link.File.RelocInfo, -) !u64 { +) link.Error!u64 { return coff.getVAddr(reloc_info, try coff.uavSymbol(uav)); } -pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol.Index) !u64 { +pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol.Index) link.Error!u64 { try coff.addReloc( @enumFromInt(@intFromEnum(reloc_info.parent.atom_index)), reloc_info.offset, @@ -3524,19 +3531,13 @@ fn objectSectionMapIndex( const parent_alignment = parent_ni.alignment(&coff.mf); if (alignment.compare(.gt, parent_alignment)) { log.debug("realignParent({s}, {d}) {d}->{d}", .{ name.toSlice(coff), parent_ni, parent_alignment, alignment }); - parent_ni.realign(&coff.mf, gpa, alignment, true) catch |err| switch (err) { - error.Unimplemented => unreachable, - else => |e| return e, - }; + try parent_ni.realign(&coff.mf, gpa, alignment, true); } const old_alignment = sym.ni.alignment(&coff.mf); if (alignment.compare(.gt, old_alignment)) { log.debug("realignObject({s}) {d}->{d}", .{ name.toSlice(coff), old_alignment, alignment }); - sym.ni.realign(&coff.mf, gpa, alignment, true) catch |err| switch (err) { - error.Unimplemented => unreachable, - else => |e| return e, - }; + try sym.ni.realign(&coff.mf, gpa, alignment, true); } try coff.verifyParentSectionAttributes( @@ -3561,7 +3562,6 @@ fn verifyParentSectionAttributes( ) !void { if (parent_attrs == child_attrs) return; - const fields = std.meta.fields(ObjectSectionAttributes); const BackingT = @typeInfo(ObjectSectionAttributes).@"struct".backing_integer.?; const num_notes = @popCount(@as(BackingT, @bitCast(parent_attrs)) ^ @as(BackingT, @bitCast(child_attrs))); var err = try coff.base.comp.link_diags.addErrorWithNotes(num_notes); @@ -3571,30 +3571,67 @@ fn verifyParentSectionAttributes( parent_name.toSlice(coff), }); - inline for (fields) |field| { - if (@field(child_attrs, field.name) != @field(parent_attrs, field.name)) { + inline for (comptime std.meta.fieldNames(ObjectSectionAttributes)) |field| { + if (@field(child_attrs, field) != @field(parent_attrs, field)) { err.addNote("flags.{s} was {d} in {s}, but {d} in {s}", .{ - field.name, - @intFromBool(@field(child_attrs, field.name)), + field, + @intFromBool(@field(child_attrs, field)), child_name.toSlice(coff), - @intFromBool(@field(parent_attrs, field.name)), + @intFromBool(@field(parent_attrs, field)), parent_name.toSlice(coff), }); } } - return error.LinkFailure; + return error.AlreadyReported; } +const RelocAddend = union(enum) { + known: i64, + /// Relocs tables in input objects don't include the addend. + /// The value needs to be recovered from the reloc location. + pending: void, +}; + pub fn addReloc( coff: *Coff, loc_si: Symbol.Index, offset: u64, target_si: Symbol.Index, - addend: union(enum) { - known: i64, - pending: void, - }, + addend: RelocAddend, + @"type": Reloc.Type, +) link.Error!void { + const diags = &coff.base.comp.link_diags; + try coff.ensureUnusedRelocCapacity(loc_si, 1); + coff.addRelocAssumeCapacity(loc_si, offset, target_si, addend, @"type") catch |err| switch (err) { + error.MappedFileIo => return diags.fail( + "failed to write output file: {t}", + .{coff.mf.io_err.?}, + ), + else => |e| return e, + }; +} + +fn ensureUnusedRelocCapacity(coff: *Coff, loc_si: Symbol.Index, len: usize) !void { + const gpa = coff.base.comp.gpa; + try coff.relocs.ensureUnusedCapacity(gpa, len); + if (isImage(coff)) return; + switch (loc_si.get(coff).section_number) { + .UNDEFINED, .ABSOLUTE, .DEBUG => {}, + else => |loc_sn| { + const section = loc_sn.section(coff); + if (section.relocation_table_ni == .none) + try coff.nodes.ensureUnusedCapacity(gpa, 1); + }, + } +} + +fn addRelocAssumeCapacity( + coff: *Coff, + loc_si: Symbol.Index, + offset: u64, + target_si: Symbol.Index, + addend: RelocAddend, @"type": Reloc.Type, ) !void { const gpa = coff.base.comp.gpa; @@ -3612,8 +3649,6 @@ pub fn addReloc( ri, }); - try coff.relocs.ensureUnusedCapacity(gpa, 1); - const sri: Section.RelocationIndex = if (isImage(coff)) .none else switch (loc_si.get(coff).section_number) { @@ -3638,13 +3673,16 @@ pub fn addReloc( const new_num_relocations = old_num_relocations + 1; const new_size = new_num_relocations * std.coff.Relocation.sizeOf(); if (section.relocation_table_ni == .none) { - try coff.nodes.ensureUnusedCapacity(gpa, 1); - section.relocation_table_ni = try coff.mf.addLastChildNode(gpa, coff.sectionParent(), .{ - .size = new_size, - .alignment = .@"2", - .moved = true, - .resized = true, - }); + section.relocation_table_ni = try coff.mf.addLastChildNode( + gpa, + coff.sectionParent(), + .{ + .size = new_size, + .alignment = .@"2", + .moved = true, + .resized = true, + }, + ); coff.nodes.appendAssumeCapacity(.{ .relocation_table = loc_sn }); } else { try section.relocation_table_ni.resize(&coff.mf, gpa, new_size); @@ -3687,8 +3725,60 @@ pub fn addReloc( target.target_relocs = ri; } -pub fn loadInput(coff: *Coff, input: link.Input) (Io.File.Reader.SizeError || - Io.File.Reader.Error || MappedFile.Error || error{ WriteFailed, EndOfStream, BadMagic, LinkFailure })!void { +// pub fn loadInput(coff: *Coff, input: link.Input) link.Error!void { +// const diags = &coff.base.comp.link_diags; +// return coff.loadInputInner(input) catch |err| switch (err) { +// else => |e| return e, +// error.MappedFileIo => return diags.fail( +// "failed to write output file: {t}", +// .{coff.mf.io_err.?}, +// ), +// }; +// } + +fn failLoadInput( + coff: *Coff, + err: LoadInputError, + fr: *Io.File.Reader, + path: std.Build.Cache.Path, +) link.Error { + const diags = &coff.base.comp.link_diags; + switch (err) { + else => |e| return e, + error.MappedFileIo => return diags.fail( + "failed to write output file: {t}", + .{coff.mf.io_err.?}, + ), + error.EndOfStream => return diags.failParse( + path, + "unexpected eof", + .{}, + ), + error.AccessDenied, + error.Unexpected, + error.Unseekable, + => |e| return diags.fail( + "failed to read \"{f}\": {t}", + .{ path.fmtEscapeString(), e }, + ), + error.PermissionDenied, + error.SystemResources, + error.Streaming, + => |e| return diags.fail( + "failed to stat \"{f}\": {t}", + .{ path.fmtEscapeString(), e }, + ), + error.ReadFailed => switch (fr.err.?) { + error.Canceled => |e| return e, + else => |e| return diags.fail( + "failed to read \"{f}\": {t}", + .{ path.fmtEscapeString(), e }, + ), + }, + } +} + +pub fn loadInput(coff: *Coff, input: link.Input) link.Error!void { const comp = coff.base.comp; const io = comp.io; @@ -3703,32 +3793,24 @@ pub fn loadInput(coff: *Coff, input: link.Input) (Io.File.Reader.SizeError || var fr = object.file.reader(io, &buf); coff.loadObject(object.path, null, &fr, .{ .offset = fr.logicalPos(), - .size = try fr.getSize(), - }) catch |err| switch (err) { - error.ReadFailed => return fr.err.?, - else => |e| return e, - }; + .size = fr.getSize() catch |err| + return coff.failLoadInput(err, &fr, object.path), + }) catch |err| return coff.failLoadInput(err, &fr, object.path); }, .archive => |archive| { var fr = archive.file.reader(io, &buf); - coff.loadArchive(archive.path, &fr) catch |err| switch (err) { - error.ReadFailed => return fr.err.?, - else => |e| return e, - }; + coff.loadArchive(archive.path, &fr) catch |err| + return coff.failLoadInput(err, &fr, archive.path); }, .res => |res| { var fr = res.file.reader(io, &buf); - coff.loadRes(res.path, &fr) catch |err| switch (err) { - error.ReadFailed => return fr.err.?, - else => |e| return e, - }; + coff.loadRes(res.path, &fr) catch |err| + return coff.failLoadInput(err, &fr, res.path); }, .dso => |dso| { var fr = dso.file.reader(io, &buf); - coff.loadDll(dso.path, &fr) catch |err| switch (err) { - error.ReadFailed => return fr.err.?, - else => |e| return e, - }; + coff.loadDll(dso.path, &fr) catch |err| + return coff.failLoadInput(err, &fr, dso.path); }, .dso_exact => unreachable, } @@ -3771,7 +3853,7 @@ fn loadObject( member_name: ?[]const u8, fr: *Io.File.Reader, fl: MappedFile.Node.FileLocation, -) !void { +) LoadInputError!void { const comp = coff.base.comp; const gpa = comp.gpa; const diags = &comp.link_diags; @@ -3955,14 +4037,18 @@ fn loadObject( try member.initHeader(coff, path_str, header.time_date_stamp); { - // TODO: This should be deferred to an idle task + // TODO: This should be deferred to an idle task (but resize it here!) var nw: MappedFile.Node.Writer = undefined; member.content_ni.writer(&coff.mf, gpa, &nw); defer nw.deinit(); try fr.seekTo(fl.offset); - if (try nw.interface.sendFileAll(fr, .limited64(fl.size)) != fl.size) - return error.EndOfStream; + const written = nw.interface.sendFileAll(fr, .limited64(fl.size)) catch |err| switch (err) { + error.WriteFailed => return nw.err.?, + else => |e| return e, + }; + + if (written != fl.size) return error.EndOfStream; } break :mi mi; @@ -4816,7 +4902,7 @@ fn failMultipleDefinitions( size: struct { a: u64, b: u64 }, crc: struct { a: u32, b: u32 }, }, -) error{ LinkFailure, OutOfMemory } { +) error{ AlreadyReported, OutOfMemory } { const num_notes: usize = 2 + @as(usize, @intFromBool(comdat_reason != .none)); var err = try coff.base.comp.link_diags.addErrorWithNotes(num_notes); try err.addMsg("multiple definitions of '{s}'", .{name.toSlice(coff)}); @@ -4849,7 +4935,7 @@ fn failMultipleDefinitions( ), } - return error.LinkFailure; + return error.AlreadyReported; } const ArchiveMemberHeader = struct { @@ -4889,7 +4975,7 @@ fn parseArchiveMemberHeaderInner( }; } -fn loadArchive(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { +fn loadArchive(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) LoadInputError!void { const comp = coff.base.comp; const gpa = comp.gpa; const diags = &comp.link_diags; @@ -5164,7 +5250,7 @@ fn loadArchive(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) !vo } } -fn loadRes(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { +fn loadRes(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) LoadInputError!void { const comp = coff.base.comp; const gpa = comp.gpa; const diags = &comp.link_diags; @@ -5177,7 +5263,7 @@ fn loadRes(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { _ = r; } -fn loadDll(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { +fn loadDll(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) LoadInputError!void { const comp = coff.base.comp; const gpa = comp.gpa; const diags = &comp.link_diags; @@ -5241,7 +5327,6 @@ pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) link.Error!void { errdefer archive.file.close(comp.io); coff.loadInput(.{ .archive = archive }) catch |err| switch (err) { - error.LinkFailure => return, else => |e| return comp.link_diags.failParse( lib.ioi.path(coff), "error loading /DEFAULTLIB library '{s}': {t}", @@ -5265,10 +5350,14 @@ pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) link.Error!void { coff.exports_complete = true; } -pub fn updateNav(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { +pub fn updateNav(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) link.Error!void { coff.updateNavInner(pt, nav_index) catch |err| switch (err) { + error.MappedFileIo => return coff.base.cgFail( + nav_index, + "linker failed to update variable: {t}", + .{coff.mf.io_err.?}, + ), else => |e| return e, - error.MappedFileIo => return coff.base.cgFail(nav_index, "linker failed to update variable: {t}", .{coff.mf.io_err.?}), }; } fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { @@ -5351,7 +5440,7 @@ pub fn lowerUav( pt: Zcu.PerThread, uav_val: InternPool.Index, uav_align: InternPool.Alignment, -) !link.File.SymbolId { +) link.Error!link.File.SymbolId { const zcu = pt.zcu; const gpa = zcu.gpa; @@ -5380,7 +5469,7 @@ pub fn updateFunc( pt: Zcu.PerThread, func_index: InternPool.Index, mir: *const codegen.AnyMir, -) !void { +) link.Error!void { coff.updateFuncInner(pt, func_index, mir) catch |err| switch (err) { else => |e| return e, error.MappedFileIo => return coff.base.cgFail( @@ -5692,7 +5781,7 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void { } } - return error.LinkFailure; + return error.AlreadyReported; } pub fn flush( @@ -5700,7 +5789,7 @@ pub fn flush( arena: std.mem.Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node, -) !void { +) link.Error!void { _ = arena; _ = prog_node; const comp = coff.base.comp; @@ -5723,13 +5812,10 @@ pub fn flush( comp.gpa, number_of_symbols * std.coff.Symbol.sizeOf(), true, - ) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - else => |e| return comp.link_diags.fail( - "linker failed to compact symbol table: {t}", - .{e}, - ), - }; + ) catch |err| return comp.link_diags.fail( + "linker failed to compact symbol table: {t}", + .{err}, + ); } while (try coff.idle(tid)) {} @@ -7220,10 +7306,14 @@ pub fn updateExports( pt: Zcu.PerThread, exported: Zcu.Exported, export_indices: []const Zcu.Export.Index, -) !void { +) link.Error!void { + const diags = &coff.base.comp.link_diags; return coff.updateExportsInner(pt, exported, export_indices) catch |err| switch (err) { - error.OutOfMemory => error.OutOfMemory, - else => |e| coff.base.comp.link_diags.fail("updateExports failed {t}", .{e}) catch error.AnalysisFail, + error.MappedFileIo => return diags.fail( + "failed to write output file: {t}", + .{coff.mf.io_err.?}, + ), + else => |e| return e, }; } fn updateExportsInner( diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig index 992f36d3f616b4f4a049da28689b00ad5f13e82b..dbed210d8b3c0ae5c24bfa631fa0669fbebb485f 100644 --- a/src/link/Elf2.zig +++ b/src/link/Elf2.zig @@ -3787,7 +3787,7 @@ fn mapInputSection(elf: *Elf, opts: struct { const new_alignment: std.mem.Alignment = .fromByteUnits( std.math.ceilPowerOfTwoAssert(usize, @intCast(opts.addralign)), ); - try existing_shndx.get(elf).ni.realign(&elf.mf, gpa, new_alignment); + try existing_shndx.get(elf).ni.realign(&elf.mf, gpa, new_alignment, true); } // ...and update the shdr as needed. switch (elf.shdrPtr(existing_shndx)) { @@ -3950,7 +3950,7 @@ fn uavMapIndex( } else { const node = uav_gop.value_ptr.lsi.index().ptr(elf).node; if (resolved_align.toStdMem().order(node.alignment(&elf.mf)).compare(.gt)) { - try node.realign(&elf.mf, gpa, resolved_align.toStdMem()); + try node.realign(&elf.mf, gpa, resolved_align.toStdMem(), true); } } return umi; @@ -4679,7 +4679,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars // We have a copy relocation for this global, but the amount of space we // reserved for it could be too small or underaligned! try copied_global.node.resize(&elf.mf, gpa, gop.value_ptr.size); - try copied_global.node.realign(&elf.mf, gpa, gop.value_ptr.alignment); + try copied_global.node.realign(&elf.mf, gpa, gop.value_ptr.alignment, true); const global_ptr = elf.globalByName(name).?; switch (elf.symPtr(global_ptr.symtab_index)) { inline else => |sym_ptr| elf.targetStore(&sym_ptr.size, @intCast(gop.value_ptr.size)), @@ -6762,7 +6762,7 @@ pub fn printNode( elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf).slice(elf), }); }, - .copied_global => |name| try w.print("(copy:{s})", .{name}), + .copied_global => |name| try w.print("(copy:{s})", .{name.slice(elf)}), .nav => |nmi| { const zcu = elf.base.comp.zcu.?; const ip = &zcu.intern_pool; diff --git a/src/link/MappedFile.zig b/src/link/MappedFile.zig index a6edeb23a37e4e8a4d7fc4d2f4a82a7a7fcfcd40..3be6d0b49fb2849c231ae7cb9855e86ba6c70008 100644 --- a/src/link/MappedFile.zig +++ b/src/link/MappedFile.zig @@ -385,13 +385,14 @@ pub const Node = extern struct { /// If the new size can't contain all the children, returns error.ShrinkImpossible. /// If `shift_next` is set, then the following node is shifted backwards into /// the free space as much as alignment allows. + /// Asserts that `size` is >= the end of the last child node. pub fn shrink( ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, size: u64, shift_next: bool, - ) !void { + ) Error!void { try mf.shrinkNode(gpa, ni, size, shift_next); var writers_it = mf.writers.first; while (writers_it) |writer_node| : (writers_it = writer_node.next) { @@ -572,10 +573,7 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { else => |next_ni| { const next_offset, _ = next_ni.location(mf).resolve(mf); if (new_end > next_offset) - mf.realignNode(gpa, next_ni, opts.add_node.alignment, false, false) catch |err| switch (err) { - error.Unimplemented => unreachable, - else => |e| return e, - }; + try next_ni.realign(mf, gpa, opts.add_node.alignment, false); }, } } @@ -724,13 +722,13 @@ fn shrinkNode( const old_offset, _ = node.location().resolve(mf); // This would require unmapping first - if (ni == Node.Index.root) return error.Unimplemented; + assert(ni != Node.Index.root); defer if (std.debug.runtime_safety) mf.verify(); if (node.last != .none) { const last = node.last.get(mf); const last_offset, const last_size = last.location().resolve(mf); - if (last_offset + last_size > size) return error.ShrinkImpossible; + assert(last_offset + last_size > size); } try mf.large.ensureUnusedCapacity(gpa, 4); @@ -757,7 +755,12 @@ fn shrinkNode( node.next.setLocationAssumeCapacity(mf, new_next_offset, next_size); } -fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested_size: u64) (Allocator.Error || Io.Cancelable || IoError)!void { +fn resizeNode( + mf: *MappedFile, + gpa: std.mem.Allocator, + ni: Node.Index, + requested_size: u64, +) (Allocator.Error || Io.Cancelable || IoError)!void { mf.nodes_lock.assertUnlocked(); const io = mf.io; const node = ni.get(mf); @@ -1271,7 +1274,11 @@ fn ensureTotalCapacityPreciseInner(mf: *MappedFile, new_capacity: usize) (Alloca else => |e| return e, } - try mf.memory_map.write(io); + mf.memory_map.write(io) catch |err| switch (err) { + error.WouldBlock => return error.Unexpected, // file was not opened as non-blocking + error.NotOpenForWriting => return error.Unexpected, // we definitely opened the file for writing + else => |e| return e, + }; unmap(mf); } diff --git a/test/src/Link.zig b/test/src/Link.zig index dcb1f0eee613eb0b9d882ccca9ae7ba0051874f3..2836bb1765b49765052488d7988ea7980d28bf77 100644 --- a/test/src/Link.zig +++ b/test/src/Link.zig @@ -151,7 +151,7 @@ pub const Case = struct { const snapshot_update_path = run_step.captureStdOut(.{}); update_step.addCopyFileToSource(snapshot_update_path, snapshot_sub_path); } else { - run_step.addCheck(.{ .snapshot = .{ .file = ctx.b.path(snapshot_sub_path) } }); + run_step.addCheck(.{ .expect_stdout_snapshot = ctx.b.path(snapshot_sub_path) }); } ctx.step.dependOn(&run_step.step);