From: Michael Schierl <schierlm@xxxxxx> Sent: Friday, April 19, 2024 1:47 PM > Am 19.04.2024 um 18:36 schrieb Michael Kelley: > > >> I still want to understand why 32-bit Linux is taking an oops during > >> boot while 64-bit Linux does not. > > > > The difference is in this statement in dmi_save_devices(): > > > > count = (dm->length - sizeof(struct dmi_header)) / 2; > > > > On a 64-bit system, count is 0xFFFFFFFE. That's seen as a > > negative value, and the "for" loop does not do any iterations. So > > nothing bad happens. > > > > But on a 32-bit system, count is 0x7FFFFFFE. That's a big > > positive number, and the "for" loop iterates to non-existent > > memory as Michael Schierl originally described. > > > > I don't know the "C" rules for mixed signed and unsigned > > expressions, and how they differ on 32-bit and 64-bit systems. > > But that's the cause of the different behavior. > > Probably lots of implementation defined behaviour here. But when looking > at gcc 12.2 for x86/amd64 architecture (which is the version in Debian), > it is at least apparent from the assembly listing: > > https://godbolt.org/z/he7MfcWfE > > First of all (this gets me every time): sizeof(int) is 4 on both 32-and > 64-bit, unlike sizeof(uintptr_t), which is 8 on 64-bit. > > Both 32-bit and 64-bit versions zero-extend the value of dm->length from > 8 bits to 32 bits (or actually native bitlength as the upper 32 bits of > rax get set to zero whenever eax is assigned), and then the subtraction > and shifting (division) happen as native unsigend type, taking only the > lowest 32 bits of the result as value for count. In the 64-bit case one > of the extra leading 1 bits from the subtraction gets shifted into the > MSB of the result, while in the 32-bit case it remains empty. Yep -- makes sense. As you said, the sub-expression (dm->length - sizeof(struct dmi_header)) is unsigned with a size that is the size we're compiling for. When compiling for 32-bit, the right shift puts a zero in the upper bit (bit 31) because the value is treated as unsigned. But when compiling for 64-bit, bits [63:32] exist and they are all ones. The right shift puts the zero in bit 63, and bit 32 (a "1") gets shifted into bit 31. Michael