2011-09-23 2 views
5

Я читал, что если бит флагов 18 (проверка выравнивания AC) может быть изменен, вы знаете, что CPU - это 486 или более новый. На 386 бит поддерживает модификацию.Как работает x86 eflags бит 18 (проверка выравнивания)? (Связано с проверкой на 386 по сравнению с 486 и более поздними версиями.)

Я поднял следующий код сборки из this site и добавил исчерпывающие комментарии (оставляя нечетные синтаксис нетронутыми):

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, если аль регистр установлен в 1 в конце (считая с самого начала, что он не старше), и это 486 или новее в противном случае. Я понимаю эту часть.

Что я не понимаю, почему указатель стека должен быть усечен до 4-байтовой границы перед выполнением теста модификации флага? Я предполагаю, что он предназначен для установки бит 18, поскольку это бит выравнивания в конце концов ... но xor с 0x40000 будет переворачивать бит независимо от его значения. Другими словами, тест модификации должен иметь тот же результат независимо от начального значения, правильно?

Если ответ отрицательный, я думаю, что [лучший] [необразованный] предположил, что «почему»: «Может быть, следующие команды push/pop могут привести к выравниванию? Это приведет к выравниванию ранее не выровненного указателя стека и приведет к переводу бита выравнивания от 0 до 1. В этом случае успешная модификация окажется неудачной, и наоборот ». (EDIT: Это определенно неверно, потому что бит выравнивания - это принудительное исполнение, а не отслеживание выравнивания. Кроме того, я сомневаюсь, что pop/push в любом случае приведет к выравниванию ранее не выровненного стека).

Даже если это так, какова цель выравнивания указателя стека снова после теста (прямо перед восстановлением исходных флагов и указателя стека)? Разве это уже не должно быть на 4-байтной границе раньше? Если нет, то как это могло измениться после нажатия/выталкивания 4-байтных значений?

Короче говоря, некоторые из инструкций кажутся излишними для меня, и я чувствую, что мне не хватает чего-то важного. Может ли кто-нибудь объяснить это?

(Боковой вопрос: самая первая строка копирует значение из «sx» в bx. Я никогда не видел ссылки на регистр sx где-нибудь. Действительно ли это существует или это опечатка? ключ довольно далеко от ключа «p», по крайней мере, на американских клавиатурах.)

EDIT: Теперь, когда на этот вопрос был дан ответ, я решил удалить неверный комментарий из двух строк выравнивания в коде. Я изначально сделал предположение, что выравнивание стека установит бит выравнивания, и я написал это в свой комментарий (остальная часть вопроса продолжается с этой неправильной логикой). Вместо этого бит проверки выравнивания действительно заключается в обеспечении выравнивания (а не отслеживании), как указывает ответ flolo относительно sigbus. Я решил исправить комментарии, чтобы не путать людей с подобными вопросами.

+0

В каком музее вы ворвались, чтобы найти 386? Тебе лучше вернуть его обратно. –

+0

LOL! Насколько я знаю, я никогда не прикасался к рабочему столу 386 ... Я перепутал с старым 286 в тот же день, но я пропустил это прямо к Pentium 75. Я просто решил закрыть свои базы, прежде чем вызывать инструкцию CPUID (сначала убедитесь, что у вас нет 386, а затем проверьте бит флэш-бит 21 на наличие CPUID), в случайном случае какой-то сумасшедший когда-либо решил использовать мой код на древнем оборудовании. Наверное, я просто анал ... но по крайней мере я не проверяю 8-битные и 16-битные процессоры, поскольку современные компиляторы, по-видимому, даже не генерируют код для них. ;) –

ответ

4

Моя догадка очень проста: код не хочет сигбуса. Если выравнивание проверки не установлено, и вы установите его, вы фактически включаете проверки выравнивания (при настройке его работы). И когда указатель стека не совпадает с 4-байтной границей, что происходит? У вас есть неразмещенный доступ к памяти, что приводит к сигбусу. И если вы не хотите, чтобы этот недопустимый доступ к памяти происходил (так как вы просто хотите изменить бит для целей тестирования), вам нужно позаботиться о том, чтобы все обращения во время тестирования принимались в худшем случае (а именно: вы включили его , и ваш стек был до того, как он не был выровнен, потому что это не нужно, так как до сих пор проверки были отключены).

+0

Спасибо. Это прекрасно объясняет первую инструкцию выравнивания; Я не осознавал значение устанавливаемого бита (потенциал для сигбуса). Вы знаете, почему выравнивание установлено позже, когда кажется очевидным, что память уже должна быть выровнена? –

+1

+1 По этой причине (похоже, что это от фрагмента паскаля и, таким образом, будет работать от 16-битного стека, который не может быть 32-битным). Второе выравнивание sp действительно выглядит избыточным, вероятно, именно там следует подчеркнуть, что проверка выравнивания может быть снова включена снова командой popfl. – user786653

+0

Еще раз спасибо, ребята! Если и до тех пор, пока кто-то еще не появится и не объяснит, почему второе выравнивание действительно необходимо, я буду отмечать это как принятое и предположить, что второе выравнивание является избыточным. –

2

Нет регистра SX. Либо опечатка, либо относится к ячейке памяти.

+0

Спасибо. Я занимался этим, когда написал комментарий о сохранении указателя стека в первой строке, но хорошо иметь подтверждение, что это не какой-то неясный субрегистр. (Я думаю, это не имело бы смысла в любом случае: 16-бит sp восстанавливается из 16-битного bx, поэтому для сохранения исходного значения в bx в первую очередь потребуется не менее 16 бит.) –

 Смежные вопросы

  • Нет связанных вопросов^_^