diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 5823fb0f18..c537a6c921 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -1705,7 +1705,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: Ai lf.updateFunc(pt, func_index, air, liveness) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)), - error.Overflow => { + error.Overflow, error.RelocationNotByteAligned => { try zcu.failed_codegen.putNoClobber(gpa, nav_index, try Zcu.ErrorMsg.create( gpa, zcu.navSrcLoc(nav_index), @@ -3131,7 +3131,7 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error lf.updateNav(pt, nav_index) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)), - error.Overflow => { + error.Overflow, error.RelocationNotByteAligned => { try zcu.failed_codegen.putNoClobber(gpa, nav_index, try Zcu.ErrorMsg.create( gpa, zcu.navSrcLoc(nav_index), diff --git a/src/codegen.zig b/src/codegen.zig index ad241d047d..bad8a97f1c 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -23,10 +23,7 @@ const Zir = std.zig.Zir; const Alignment = InternPool.Alignment; const dev = @import("dev.zig"); -pub const CodeGenError = error{ - OutOfMemory, - /// Compiler was asked to operate on a number larger than supported. - Overflow, +pub const CodeGenError = GenerateSymbolError || error{ /// Indicates the error is already stored in Zcu `failed_codegen`. CodegenFail, }; @@ -177,6 +174,8 @@ pub const GenerateSymbolError = error{ OutOfMemory, /// Compiler was asked to operate on a number larger than supported. Overflow, + /// Compiler was asked to produce a non-byte-aligned relocation. + RelocationNotByteAligned, }; pub fn generateSymbol( @@ -481,12 +480,18 @@ pub fn generateSymbol( // pointer may point to a decl which must be marked used // but can also result in a relocation. Therefore we handle those separately. if (Type.fromInterned(field_ty).zigTypeTag(zcu) == .pointer) { - const field_size = math.cast(usize, Type.fromInterned(field_ty).abiSize(zcu)) orelse - return error.Overflow; - var tmp_list = try std.ArrayListUnmanaged(u8).initCapacity(gpa, field_size); - defer tmp_list.deinit(gpa); - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), &tmp_list, reloc_parent); - @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items); + const field_offset = std.math.divExact(u16, bits, 8) catch |err| switch (err) { + error.DivisionByZero => unreachable, + error.UnexpectedRemainder => return error.RelocationNotByteAligned, + }; + code.items.len = current_pos + field_offset; + // TODO: code.lockPointers(); + defer { + assert(code.items.len == current_pos + field_offset + @divExact(target.ptrBitWidth(), 8)); + // TODO: code.unlockPointers(); + code.items.len = current_pos + abi_size; + } + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent); } else { Value.fromInterned(field_val).writeToPackedMemory(Type.fromInterned(field_ty), pt, code.items[current_pos..], bits) catch unreachable; } diff --git a/src/link.zig b/src/link.zig index f19d63d35e..f436106aab 100644 --- a/src/link.zig +++ b/src/link.zig @@ -26,6 +26,7 @@ const Package = @import("Package.zig"); const dev = @import("dev.zig"); const ThreadSafeQueue = @import("ThreadSafeQueue.zig").ThreadSafeQueue; const target_util = @import("target.zig"); +const codegen = @import("codegen.zig"); pub const LdScript = @import("link/LdScript.zig"); @@ -683,13 +684,7 @@ pub const File = struct { /// Note that `LinkFailure` is not a member of this error set because the error message /// must be attached to `Zcu.failed_codegen` rather than `Compilation.link_diags`. - pub const UpdateNavError = error{ - Overflow, - OutOfMemory, - /// Indicates the error is already reported and stored in - /// `failed_codegen` on the Zcu. - CodegenFail, - }; + pub const UpdateNavError = codegen.CodeGenError; /// Called from within CodeGen to retrieve the symbol index of a global symbol. /// If no symbol exists yet with this name, a new undefined global symbol will @@ -920,7 +915,7 @@ pub const File = struct { decl_val: InternPool.Index, decl_align: InternPool.Alignment, src_loc: Zcu.LazySrcLoc, - ) !@import("codegen.zig").GenResult { + ) !codegen.GenResult { switch (base.tag) { .c => unreachable, .spirv => unreachable, diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 8642dea2f2..5e7d1e2655 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1134,7 +1134,7 @@ pub fn updateFunc( ) catch |err| switch (err) { error.CodegenFail => return error.CodegenFail, error.OutOfMemory => return error.OutOfMemory, - error.Overflow => |e| { + error.Overflow, error.RelocationNotByteAligned => |e| { try zcu.failed_codegen.putNoClobber(gpa, nav_index, try Zcu.ErrorMsg.create( gpa, zcu.navSrcLoc(nav_index), diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index a657667f15..0420504853 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -23,12 +23,11 @@ debug_str: StringSection, pub const UpdateError = error{ ReinterpretDeclRef, Unimplemented, - OutOfMemory, EndOfStream, - Overflow, Underflow, UnexpectedEndOfFile, } || + codegen.GenerateSymbolError || std.fs.File.OpenError || std.fs.File.SetEndPosError || std.fs.File.CopyRangeError || diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 3643166e51..c09dc17c67 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -1090,7 +1090,9 @@ fn updateLazySymbolAtom( ) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.CodegenFail => return error.LinkFailure, - error.Overflow => return diags.fail("codegen failure: encountered number too big for compiler", .{}), + error.Overflow, + error.RelocationNotByteAligned, + => return diags.fail("unable to codegen: {s}", .{@errorName(err)}), }; const code = code_buffer.items; // duped_code is freed when the atom is freed diff --git a/src/register_manager.zig b/src/register_manager.zig index 5621c8f750..90fe09980a 100644 --- a/src/register_manager.zig +++ b/src/register_manager.zig @@ -14,14 +14,7 @@ const link = @import("link.zig"); const log = std.log.scoped(.register_manager); -pub const AllocationError = error{ - OutOfRegisters, - OutOfMemory, - /// Compiler was asked to operate on a number larger than supported. - Overflow, - /// Indicates the error is already stored in `failed_codegen` on the Zcu. - CodegenFail, -}; +pub const AllocationError = @import("codegen.zig").CodeGenError || error{OutOfRegisters}; pub fn RegisterManager( comptime Function: type, diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig index 592d9fa2bd..55bd0621b0 100644 --- a/test/behavior/packed-struct.zig +++ b/test/behavior/packed-struct.zig @@ -1335,3 +1335,17 @@ test "assign packed struct initialized with RLS to packed struct literal field" try expect(outer.inner.x == x); try expect(outer.x == x); } + +test "byte-aligned packed relocation" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + + const S = struct { + var global: u8 align(2) = 0; + var packed_value: packed struct { x: u8, y: *align(2) u8 } = .{ .x = 111, .y = &global }; + }; + try expect(S.packed_value.x == 111); + try expect(S.packed_value.y == &S.global); +}