I've read that if eflags bit 18 (AC - alignment check) can be modified, you know the CPU is a 486 or newer. On the 386, the bit resists modification.
I've lifted the following assembly code from this site and added exhaustive comments (leaving the odd syntax intact):
asm
mov bx,sx ; Save the stack pointer to bx (is sx a typo or a real register?).
and sp,$fffc ; Truncate the stack pointer to a 4-byte boundary.
pushfl ; Push the eflags register to the stack.
pop eax ; Pop it into eax.
mov ecx,eax ; Save the original eflags value into ecx.
xor eax,$40000 ; Flip bit 18 in eax.
push eax ; Push eax to the stack.
popfl ; Pop modified value into eflags.
pushfl ; Push eflags back onto the stack.
pop eax ; Pop it into eax.
xor eax,ecx ; Get changed bits from the original value.
setz al ; Set al register to 1 if no bits changed (0 otherwise).
and sp,$fffc ; Truncate the stack pointer to a 4-byte boundary.
push ecx ; Push ecx (original eflags) to stack.
popfl ; Pop it into eflags to restore the original value.
mov sp,bx ; Restore the original stack pointer.
end ['eax','ebx','ecx'];
The CPU is a 386 if the al register is set to 1 at the end (assuming from the start that it's not older), and it's a 486 or newer otherwise. I understand this part.
What I don't understand is, why does the stack pointer have to be truncated to a 4-byte boundary before doing the flag modification test? I assume that it's meant to set bit 18, since it's the alignment bit after all...but the xor with 0x40000 will flip the bit regardless of its value. In other words, the modification test should have the same result regardless of the initial value, right?
If the answer is no, my best [uneducated] guess as to "why" is, "Maybe the following push/pop instructions could force alignment? This would align a previously unaligned stack pointer and cause the alignment bit to flip from 0 to 1 by itself. In that case, a successful modification would appear unsuccessful, and vice versa." (EDIT: This is definitely incorrect, because the alignment bit is about enforcing rather than tracking alignment. Plus, I doubt that pop/push would force alignment on a previously unaligned stack anyway.)
Even if that's the case though, what is the purpose of aligning the stack pointer again after the test (right before restoring the original eflags and stack pointer)? Shouldn't it already be on a 4-byte boundary from before? If not, how could that have changed from pushing/popping 4-byte values?
In short, some of the instructions seem redundant to me, and I feel that I must be missing something important. Can anyone here explain it?
(Side question: The very first line copies the value from "sx" into bx. I've never seen a reference to an sx register anywhere. Does it actually exist, or is it a typo? The 'x' key is pretty far from the 'p' key, at least on US keyboards.)
EDIT: Now that this question has been answered, I decided to remove an incorrect comment from the two alignment lines in the code. I originally made an assumption that aligning the stack would set the alignment bit, and I wrote that into my comment (the rest of the question continues with this incorrect logic). Instead, the alignment check bit really is about enforcing alignment (rather than tracking it), as flolo's answer regarding sigbus indicates. I decided to fix the comments to avoid confusing people with similar questions.