authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-03-22 21:56:32-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-03-23 21:40:03-04:00
logfe8bdf6f049e59cffe0033baa4d1738a64fd21cf
tree8d37291f9b748a43fb63847e861643913d6df6a9
parentc71b78eb0196cbad9fbb01ce9137d09796b48726

codegen: fix packed byte-aligned relocations

Closes #23131

8 files changed, 40 insertions(+), 32 deletions(-)

src/Zcu/PerThread.zig+2-2
......@@ -1705,7 +1705,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: Ai
17051705 lf.updateFunc(pt, func_index, air, liveness) catch |err| switch (err) {
17061706 error.OutOfMemory => return error.OutOfMemory,
17071707 error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)),
1708 error.Overflow => {
1708 error.Overflow, error.RelocationNotByteAligned => {
17091709 try zcu.failed_codegen.putNoClobber(gpa, nav_index, try Zcu.ErrorMsg.create(
17101710 gpa,
17111711 zcu.navSrcLoc(nav_index),
......@@ -3131,7 +3131,7 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error
31313131 lf.updateNav(pt, nav_index) catch |err| switch (err) {
31323132 error.OutOfMemory => return error.OutOfMemory,
31333133 error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)),
3134 error.Overflow => {
3134 error.Overflow, error.RelocationNotByteAligned => {
31353135 try zcu.failed_codegen.putNoClobber(gpa, nav_index, try Zcu.ErrorMsg.create(
31363136 gpa,
31373137 zcu.navSrcLoc(nav_index),
src/codegen.zig+15-10
......@@ -23,10 +23,7 @@ const Zir = std.zig.Zir;
2323const Alignment = InternPool.Alignment;
2424const dev = @import("dev.zig");
2525
26pub const CodeGenError = error{
27 OutOfMemory,
28 /// Compiler was asked to operate on a number larger than supported.
29 Overflow,
26pub const CodeGenError = GenerateSymbolError || error{
3027 /// Indicates the error is already stored in Zcu `failed_codegen`.
3128 CodegenFail,
3229};
......@@ -177,6 +174,8 @@ pub const GenerateSymbolError = error{
177174 OutOfMemory,
178175 /// Compiler was asked to operate on a number larger than supported.
179176 Overflow,
177 /// Compiler was asked to produce a non-byte-aligned relocation.
178 RelocationNotByteAligned,
180179};
181180
182181pub fn generateSymbol(
......@@ -481,12 +480,18 @@ pub fn generateSymbol(
481480 // pointer may point to a decl which must be marked used
482481 // but can also result in a relocation. Therefore we handle those separately.
483482 if (Type.fromInterned(field_ty).zigTypeTag(zcu) == .pointer) {
484 const field_size = math.cast(usize, Type.fromInterned(field_ty).abiSize(zcu)) orelse
485 return error.Overflow;
486 var tmp_list = try std.ArrayListUnmanaged(u8).initCapacity(gpa, field_size);
487 defer tmp_list.deinit(gpa);
488 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), &tmp_list, reloc_parent);
489 @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items);
483 const field_offset = std.math.divExact(u16, bits, 8) catch |err| switch (err) {
484 error.DivisionByZero => unreachable,
485 error.UnexpectedRemainder => return error.RelocationNotByteAligned,
486 };
487 code.items.len = current_pos + field_offset;
488 // TODO: code.lockPointers();
489 defer {
490 assert(code.items.len == current_pos + field_offset + @divExact(target.ptrBitWidth(), 8));
491 // TODO: code.unlockPointers();
492 code.items.len = current_pos + abi_size;
493 }
494 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent);
490495 } else {
491496 Value.fromInterned(field_val).writeToPackedMemory(Type.fromInterned(field_ty), pt, code.items[current_pos..], bits) catch unreachable;
492497 }
src/link.zig+3-8
......@@ -26,6 +26,7 @@ const Package = @import("Package.zig");
2626const dev = @import("dev.zig");
2727const ThreadSafeQueue = @import("ThreadSafeQueue.zig").ThreadSafeQueue;
2828const target_util = @import("target.zig");
29const codegen = @import("codegen.zig");
2930
3031pub const LdScript = @import("link/LdScript.zig");
3132
......@@ -683,13 +684,7 @@ pub const File = struct {
683684
684685 /// Note that `LinkFailure` is not a member of this error set because the error message
685686 /// must be attached to `Zcu.failed_codegen` rather than `Compilation.link_diags`.
686 pub const UpdateNavError = error{
687 Overflow,
688 OutOfMemory,
689 /// Indicates the error is already reported and stored in
690 /// `failed_codegen` on the Zcu.
691 CodegenFail,
692 };
687 pub const UpdateNavError = codegen.CodeGenError;
693688
694689 /// Called from within CodeGen to retrieve the symbol index of a global symbol.
695690 /// If no symbol exists yet with this name, a new undefined global symbol will
......@@ -920,7 +915,7 @@ pub const File = struct {
920915 decl_val: InternPool.Index,
921916 decl_align: InternPool.Alignment,
922917 src_loc: Zcu.LazySrcLoc,
923 ) !@import("codegen.zig").GenResult {
918 ) !codegen.GenResult {
924919 switch (base.tag) {
925920 .c => unreachable,
926921 .spirv => unreachable,
src/link/Coff.zig+1-1
......@@ -1134,7 +1134,7 @@ pub fn updateFunc(
11341134 ) catch |err| switch (err) {
11351135 error.CodegenFail => return error.CodegenFail,
11361136 error.OutOfMemory => return error.OutOfMemory,
1137 error.Overflow => |e| {
1137 error.Overflow, error.RelocationNotByteAligned => |e| {
11381138 try zcu.failed_codegen.putNoClobber(gpa, nav_index, try Zcu.ErrorMsg.create(
11391139 gpa,
11401140 zcu.navSrcLoc(nav_index),
src/link/Dwarf.zig+1-2
......@@ -23,12 +23,11 @@ debug_str: StringSection,
2323pub const UpdateError = error{
2424 ReinterpretDeclRef,
2525 Unimplemented,
26 OutOfMemory,
2726 EndOfStream,
28 Overflow,
2927 Underflow,
3028 UnexpectedEndOfFile,
3129} ||
30 codegen.GenerateSymbolError ||
3231 std.fs.File.OpenError ||
3332 std.fs.File.SetEndPosError ||
3433 std.fs.File.CopyRangeError ||
src/link/Plan9.zig+3-1
......@@ -1090,7 +1090,9 @@ fn updateLazySymbolAtom(
10901090 ) catch |err| switch (err) {
10911091 error.OutOfMemory => return error.OutOfMemory,
10921092 error.CodegenFail => return error.LinkFailure,
1093 error.Overflow => return diags.fail("codegen failure: encountered number too big for compiler", .{}),
1093 error.Overflow,
1094 error.RelocationNotByteAligned,
1095 => return diags.fail("unable to codegen: {s}", .{@errorName(err)}),
10941096 };
10951097 const code = code_buffer.items;
10961098 // duped_code is freed when the atom is freed
src/register_manager.zig+1-8
......@@ -14,14 +14,7 @@ const link = @import("link.zig");
1414
1515const log = std.log.scoped(.register_manager);
1616
17pub const AllocationError = error{
18 OutOfRegisters,
19 OutOfMemory,
20 /// Compiler was asked to operate on a number larger than supported.
21 Overflow,
22 /// Indicates the error is already stored in `failed_codegen` on the Zcu.
23 CodegenFail,
24};
17pub const AllocationError = @import("codegen.zig").CodeGenError || error{OutOfRegisters};
2518
2619pub fn RegisterManager(
2720 comptime Function: type,
test/behavior/packed-struct.zig+14
......@@ -1349,3 +1349,17 @@ test "assign packed struct initialized with RLS to packed struct literal field"
13491349 try expect(outer.inner.x == x);
13501350 try expect(outer.x == x);
13511351}
1352
1353test "byte-aligned packed relocation" {
1354 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1355 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
1356 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1357 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
1358
1359 const S = struct {
1360 var global: u8 align(2) = 0;
1361 var packed_value: packed struct { x: u8, y: *align(2) u8 } = .{ .x = 111, .y = &global };
1362 };
1363 try expect(S.packed_value.x == 111);
1364 try expect(S.packed_value.y == &S.global);
1365}