aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2022-02-02 00:20:41 +0100
committerJakub Konka <kubkon@jakubkonka.com>2022-02-02 13:43:41 +0100
commit15ff891f044102ba6515cb07f40805452420ea24 (patch)
tree05e00c580057290dfcfccda0a8483668322aa11f /src
parent521bd2e94a3b32382b2d1de1e6185149032b49db (diff)
downloadzig-15ff891f044102ba6515cb07f40805452420ea24.tar.gz
zig-15ff891f044102ba6515cb07f40805452420ea24.zip
stage2: pad out (non-packed) struct fields when lowering to bytes
* pad out (non-packed) struct fields when lowering to bytes to be saved in the binary - prior to this change, fields would be saved at non-aligned addresses leading to wrong accesses * add a matching test case to `behavior/struct.zig` tests * fix offset to field calculation in `struct_field_ptr` on `x86_64`
Diffstat (limited to 'src')
-rw-r--r--src/arch/x86_64/CodeGen.zig6
-rw-r--r--src/codegen.zig25
2 files changed, 27 insertions, 4 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 09b51bf59a..80b50f228b 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -1801,13 +1801,12 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));
const struct_field_ty = struct_ty.structFieldType(index);
const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*));
- const offset_to_field = struct_size - struct_field_offset - struct_field_size;
const dst_mcv: MCValue = result: {
switch (mcv) {
.stack_offset => {
const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
- .immediate = offset_to_field,
+ .immediate = struct_field_offset,
});
self.register_manager.freezeRegs(&.{offset_reg});
defer self.register_manager.unfreezeRegs(&.{offset_reg});
@@ -1817,12 +1816,13 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
break :result dst_mcv;
},
.ptr_stack_offset => |off| {
+ const offset_to_field = struct_size - struct_field_offset - struct_field_size;
const ptr_stack_offset = off + @intCast(i32, offset_to_field);
break :result MCValue{ .ptr_stack_offset = ptr_stack_offset };
},
.register => |reg| {
const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
- .immediate = offset_to_field,
+ .immediate = struct_field_offset,
});
self.register_manager.freezeRegs(&.{offset_reg});
defer self.register_manager.unfreezeRegs(&.{offset_reg});
diff --git a/src/codegen.zig b/src/codegen.zig
index faafe79c13..bcd36358b1 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -373,11 +373,24 @@ pub fn generateSymbol(
},
.Struct => {
// TODO debug info
- // TODO padding of struct members
+ const struct_obj = typed_value.ty.castTag(.@"struct").?.data;
+ if (struct_obj.layout == .Packed) {
+ return Result{
+ .fail = try ErrorMsg.create(
+ bin_file.allocator,
+ src_loc,
+ "TODO implement generateSymbol for packed struct",
+ .{},
+ ),
+ };
+ }
+
+ const struct_begin = code.items.len;
const field_vals = typed_value.val.castTag(.@"struct").?.data;
for (field_vals) |field_val, index| {
const field_ty = typed_value.ty.structFieldType(index);
if (!field_ty.hasRuntimeBits()) continue;
+
switch (try generateSymbol(bin_file, src_loc, .{
.ty = field_ty,
.val = field_val,
@@ -388,6 +401,16 @@ pub fn generateSymbol(
},
.fail => |em| return Result{ .fail = em },
}
+ const unpadded_field_end = code.items.len - struct_begin;
+
+ // Pad struct members if required
+ const target = bin_file.options.target;
+ const padded_field_end = typed_value.ty.structFieldOffset(index + 1, target);
+ const padding = try math.cast(usize, padded_field_end - unpadded_field_end);
+
+ if (padding > 0) {
+ try code.writer().writeByteNTimes(0, padding);
+ }
}
return Result{ .appended = {} };