Я читал, что если можно изменить eflags бит 18 (проверка выравнивания AC), вы знаете, что процессор 486 или новее. На 386 бит сопротивляется модификации.
Я поднял следующий код сборки с этого сайта и добавил исчерпывающие комментарии (оставив нечетный синтаксис без изменений):
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'];
ЦП - это 386, если регистр al установлен в конце на 1 (при условии, что он изначально не стар), и 486 или новее в противном случае. Я понимаю эту часть.
Что я не понимаю, так это почему указатель стека должен быть обрезан до 4-байтовой границы перед выполнением теста модификации флага? Я предполагаю, что он предназначен для установки бита 18, так как в конце концов это бит выравнивания ... но xor с 0x40000 перевернет бит независимо от его значения. Другими словами, тест модификации должен иметь одинаковый результат независимо от начального значения, верно?
Если ответ «нет», мое лучшее [необразованное] предположение относительно «почему» таково: «Может быть, следующие инструкции push / pop могут вызвать выравнивание? Это выровняет ранее не выровненный указатель стека и заставит бит выравнивания переместиться из 0 к 1. Само по себе, в этом случае успешная модификация будет выглядеть неудачной, и наоборот. " (РЕДАКТИРОВАТЬ: Это определенно неверно, потому что бит выравнивания предназначен для принудительного, а не отслеживания выравнивания. Кроме того, я сомневаюсь, что pop / push в любом случае вызовет выравнивание в ранее невыровненном стеке.)
Даже если это так, какова цель выравнивания указателя стека после теста (прямо перед восстановлением исходного eflags и указателя стека)? Разве это не должно быть уже на 4-байтовой границе раньше? Если нет, то как это могло измениться от нажатия / выталкивания 4-байтовых значений?
Короче говоря, некоторые инструкции кажутся мне излишними, и я чувствую, что, должно быть, упускаю что-то важное. Может кто-нибудь здесь объяснить это?
(Дополнительный вопрос: самая первая строка копирует значение из «sx» в bx. Я никогда не видел ссылку на регистр sx. Это действительно существует или является опечаткой? Ключ «x» довольно далеко от клавиши 'p', по крайней мере на американских клавиатурах.)
РЕДАКТИРОВАТЬ: Теперь, когда на этот вопрос был дан ответ, я решил удалить неправильный комментарий из двух строк выравнивания в коде. Первоначально я сделал предположение, что выравнивание стека установит бит выравнивания, и записал это в свой комментарий (остальная часть вопроса продолжается с этой неверной логикой). Вместо этого бит проверки выравнивания на самом деле предназначен для принудительного выравнивания (а не отслеживания его), как указывает ответ flolo относительно sigbus. Я решил исправить комментарии, чтобы не путать людей с похожими вопросами.