New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Packed structs: failure in assigning to struct fields #16615
Comments
Is this a duplicate of #12852? It looks like what you want is an extern struct with all fields having align(1), like this: const TssDescriptor = extern struct {
reserved1: u32 align(1) = 0,
rsp0: u64 align(1),
rsp1: u64 align(1),
rsp2: u64 align(1),
reserved2: u64 align(1) = 0,
ist1: u64 align(1),
ist2: u64 align(1),
ist3: u64 align(1),
ist4: u64 align(1),
ist5: u64 align(1),
ist6: u64 align(1),
ist7: u64 align(1),
reserved3: u32 align(1) = 0,
reserved4: u32 align(1) = 0,
reserved5: u8 align(1) = 0,
iopb: u16 align(1),
}; Instead what you have is a 824-bit integer that gets loaded and stored via bitwise operations. Proposal to make this require less syntax: #13009 |
I mean, maybe, but this happens for the GdtEntry, not the TSS |
Understood. I apologize for not reading the issue carefully. In that case this certainly looks like a miscompilation (my advice stands for the TSS struct however). |
I'll apply your advice -- I wasn't aware that I was misusing packed structs in that instance. |
Mimimalistic example to reproduce (0.11.0-dev.4315+f5239677e): const std = @import("std");
const Small = packed struct {
val: u8 = 0,
lo: u4 = 0,
hi: u4 = 0,
};
var small = Small{};
export fn val() u16 {
small = .{
.val = 0x12,
.lo = 3,
.hi = 4,
};
return @bitCast(small);
}
pub fn main() void {
std.log.info("Value: {x}", .{val()});
} Outputs: Defining the variable locally works as expected: const std = @import("std");
const Small = packed struct {
val: u8 = 0,
lo: u4 = 0,
hi: u4 = 0,
};
export fn val() u16 {
var small = Small{};
small = .{
.val = 0x12,
.lo = 3,
.hi = 4,
};
return @bitCast(small);
}
pub fn main() void {
std.log.info("Value: {x}", .{val()});
} Outputs: The asm of the buggy code indicates a wrong offset (Godbolt): mov byte ptr [example.small], 18 ; assigning val = 0x12
mov ax, word ptr [example.small+1] ; here should be no +1 offset, as we only operate on the word
and ax, -3841
or ax, 768
mov word ptr [example.small+1], ax ; here the .low value is saved one byte after the packed struct
mov ax, word ptr [example.small] ; for .hi zig correctly omits the offset, therefore it is applyed correctly
and ax, 4095
or ax, 16384
mov word ptr [example.small], ax But I'm impressed that Zig assigns each field individually, given that the whole struct is overwritten. When defining the variable locally (second working example), Zig just overrides everything in one go (Godbolt): mov word ptr [rbp - 2], 17170 |
@bibo38 Frankly, I'm surprised that that assembly doesn't cause some kind of exception, or corrupt program code. Especially if it writes one byte past the end of the packed struct -- there's no telling what that could be, so it could potentially be corrupting other data or code. |
Update: so the (proposed) fix doesn't quite work. If I localize the definitions, the results are:
According to the OSDev forums, the values are shifted by a byte (I don't know in which direction though). |
when a field was 'byte_aligned', the offset was applied once to the pointer and again when dereferencing it (because it's a ptr with a 'packed_offset') resolves ziglang#16615 and maybe ziglang#16621 ?
A field smaller that the abisize is still be accessed with a packed_offset decorated ptr, even when aligned to a byte boundary. The test was incorrect and the offset was applied once to the pointer (as if it would be used as an undecorated ptr), and again when dereferencing it (by the packed_offset decoration) resolves ziglang#16615 and maybe ziglang#16621 ?
A field smaller that the abisize is still be accessed with a packed_offset decorated ptr, even when aligned to a byte boundary. The test was incorrect and the offset was applied once to the pointer (as if it would be used as an undecorated ptr), and again when dereferencing it (by the packed_offset decoration) resolves ziglang#16615 and maybe ziglang#16621 ?
Fields smaller that the abisize, even when aligned to a byte boundary, are accessed via a packed_offset decorated ptr. This was not always considered by the code, and the offset was applied once to the pointer (as if it would be used as an undecorated ptr), and again when dereferencing it (by the packed_offset decoration) resolves ziglang#16615 and probaly ziglang#16621
Fields smaller that the abisize, even when aligned to a byte boundary, are accessed via a packed_offset decorated ptr. This was not always considered by the code, and the offset was applied once to the pointer (as if it would be used as an undecorated ptr), and again when dereferencing it (by the packed_offset decoration) resolves ziglang#16615 and probaly ziglang#16621
Fields smaller that the abisize, even when aligned to a byte boundary, are accessed via a packed_offset decorated ptr. This was not always considered by the code, and the offset was applied once to the pointer (as if it would be used as an undecorated ptr), and again when dereferencing it (by the packed_offset decoration) resolves ziglang#16615 and probaly ziglang#16621
Zig Version
0.11.0-dev.4308+417b92f08
Steps to Reproduce and Observed Behavior
I'm trying to set up the GDT. I'm using a packed struct with the alignment of u64. However, when I assign to the struct, the statically-assigned entries have all the bits on the first field set (which is correct) but no other field is set (even though I fully initialized the struct). This happens both when using packed unions to represent bitfields and when just using normal integral types.
To reproduce, all that's needed is this code:
When run, this program prints the following output:
The zeroth and seventh entries are correct (and I strongly believe the fifth and sixth are also correct).
Expected Behavior
The assignments should work fine, without any problems, and should reflect the properly assigned values.
The text was updated successfully, but these errors were encountered: