Masking Exceptions and Interrupts - why?!

Тема в разделе "WASM.HEAP", создана пользователем kaspersky, 20 дек 2007.

  1. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    сижу, куру интеловские манулы.
    в очередной раз перечитывая след. абзац:
    # To switch to a different stack segment, software often uses a pair
    # of instructions, for example:
    # MOV SS, AX
    # MOV ESP, StackTop
    # If an interrupt or exception occurs after the segment selector
    # has been loaded into the SS register but before the ESP register
    # has been loaded, these two parts of the logical address into
    # the stack space are inconsistent for the duration of the interrupt
    # or exception handler.
    # To prevent this situation, the processor inhibits interrupts,
    # debug exceptions, and single-step trap exceptions after either
    # a MOV to SS instruction or a POP to SS instruction, until
    # the instruction boundary following the next instruction is reached.
    # All other faults may still be generated. If the LSS instruction
    # is used to modify the contents of the SS register
    # (which is the recommended method of modifying this register),
    # this problem does not occur.

    решил посмотреть как хорошо "the processor inhibits interrupts,
    debug exceptions, and single-step trap exceptions after either"
    пишу
    mov ax,ss
    mov ss,ax
    int 03h

    по идее, исключения возникать не должно, а оно возникает!
    хорошо, делаю так.

    mov esi, offset label
    mov ax,ss
    mov ss,ax
    mov eax,[esi]

    в айсе ставою bmp на esi, надеясь, что он не сработает,
    а он собака срабатывает...

    что я делаю не так?! или исключения максируются только на время выполнения mov ss,ax?! так ведь нет!!!

    xor eax,eax
    mov ss,[eax]
    так же генерит исключение!!!
    ничего не понимаю....
     
  2. 10110111

    10110111 New Member

    Публикаций:
    0
    Регистрация:
    13 июл 2006
    Сообщения:
    319
    Адрес:
    Санкт-Петербург
    В каком кольце код?
     
  3. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    проверял в обоих. в 3 и 0.
     
  4. SII

    SII Воин против дзена

    Публикаций:
    0
    Регистрация:
    31 окт 2007
    Сообщения:
    1.483
    Адрес:
    Подмосковье
    kaspersky
    А может, блокируются прерывания только в том случае, если в первой инструкции загружается SS, а во второй -- ESP?
     
  5. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    ну сказано же ;)
    # the processor inhibits interrupts,
    # debug exceptions, and single-step trap exceptions after either
    # a MOV to SS instruction or a POP to SS instruction, until
    # the instruction boundary following the next instruction is reached.
    # All other faults may still be generated.
    трассировочное прервывание максируется это точно,
    все известные мне отладчики проскакивают MOV SS,AX/PUSHFD,
    позволяя обнаружить трассировку...

    кстати, можете меня поздравить. я виливаюсь в Syser-team
    (начну писать для него докуметацию, ну и буду на подхвате)
    и при моем участии в след. версии этот баг будет пофиксен ;)

    но все-таки, черт возьми, почему не маскируются остальные
    дебажные прерывания? например, прерывание по брякам?!
    ведь это дебажное прерывание. следовательно, оно должно
    маскироваться... проверял на живом железе под P-II, P-III,
    P-4, AMD K6 и AMD Athlon. везде все одно и то же... я тупю?
    или не догоняю?! у кого есть какие идеи?!
     
  6. 10110111

    10110111 New Member

    Публикаций:
    0
    Регистрация:
    13 июл 2006
    Сообщения:
    319
    Адрес:
    Санкт-Петербург
    Да, что ни пробовал, то же самое. Мне стало интересно. Я отправил интелам в службу поддержки этот вопрос. Буду ждать вразумительного ответа.
     
  7. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Может исключения\прерывания не игнорируются, а просто задерживаются. В мануале AMD используется не inhibit, а именно delay:
     
  8. rain

    rain New Member

    Публикаций:
    0
    Регистрация:
    22 апр 2006
    Сообщения:
    976
    leo
    да да, вы невнимательно тестили
    просто оттрейсить (через TF) оликом
    Код (Text):
    1.     mov ax, ss
    2.    
    3.     mov ss, ax
    4.     nop
    5.     nop
    первый ноп пропустится, в ядре сайсом не тестите :P

    апд:
    3-601 Vol. 2A
    апд2:
    хотя странно касательно int3 в r3 для следующего кода
    Код (Text):
    1.     mov ax, ss
    2.     mov ss, ax
    3.     int 3
    сех генерится именно на инструкции int 3 (т.е. перед ней)
     
  9. SII

    SII Воин против дзена

    Публикаций:
    0
    Регистрация:
    31 окт 2007
    Сообщения:
    1.483
    Адрес:
    Подмосковье
    kaspersky
    Ну так это блокируется действие флага TF, и не более того. Сами знаете -- приём не новый (можно ту же PDP-11 вспомнить, блокирующую трассировку при выполнении RTT). Похоже, про отладочные прерывания за счёт DR в интеле позабыли...

    Идея элементарная: банальная ошибка в документации. Обоснование могу предложить примерно такое: обычные исключения вроде деления на ноль при нормальном изменении указателя стека и сегмента стека исключены, потому что используются только команды MOV, которые не способны вызвать такие исключения; внешние прерывания маскируются флагом IF, поэтому бороться с ними не требуется -- эта задача программиста; если при попытке изменения указателя стека возникает фатальная ошибка типа недопустимого сегмента -- то программе всё равно хана (такой ошибки возникать не должно), а значит, не важно, куда стек указывает; если происходит отказ страницы из-за выгруженности -- то не страшно, поскольку ось подгрузит новую страницу, а прерывание будет обрабатываться за счёт указателя стека системы (а в нулевом кольце таких прерываний быть не должно, иначе системе хана); доступ к отладочным регистрам привилегированный -- а значит, их использовать может только система, а она не дура ставить точки останова на саму себя, а на пользователя -- не фатально по той же причине что и отказ страницы. Значит, никакие прерывания, кроме трассировки по флагу TF, отлавливать и не нужно, а его нужно отлавливать из-за совместимости с реальным режимом, поскольку там прерывание трассировки отрабатывает с использованием того же указателя стека, что меняется. Ну а идиоты (не будем показывать пальцем ;) ), которые вставляют всякую хрень между MOVами, в Интеле не предусмотрены :)

    Ну а если более кратко -- очередная ошибка в интеловских процессорах. В конце концов, они облажались ещё на инструкции NOT, которая не меняет флаги, так почему ж не допустить ошибку и в этом случае?
     
  10. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    SII
    ок, рассмотрим классический код:
    mov ss, ax
    mov esp, [ebx]

    почему на [ebx] не может быть бряка? а если возникает бряк, то разве можно генерировтаь прерывание, ведь esp еще не задан? очевидно, что нельзя. о чем мануалы и пишут.

    ситуация с

    mov ss, ax
    int 03
    mov esp, label

    конечно слегка надуманная, но... установить программную точку останова между комадами - можно. а вот как она будет обрабатываться...
     
  11. SII

    SII Воин против дзена

    Публикаций:
    0
    Регистрация:
    31 окт 2007
    Сообщения:
    1.483
    Адрес:
    Подмосковье
    kaspersky
    Рассмотрим два случая: когда ss:esp меняется в кольце 0 и в любом другом кольце.

    1) Меняется в кольце 0. В этом режиме работает ядро системы. Ошибка при смене стека в ней с точки зрения здравого смысла недопустима, ну а если она всё же возникает, то уже глубоко плевать, что происходит дальше: система всё равно падает. Так что об этом случае разработчики процессора могли просто не позаботиться, предполагая, что код ядра всегда будет загружать ss:esp корректным образом.

    2) Меняется в кольце, отличном от 0. Тут всё просто: при ошибке возникает соответствующее прерывание, ну а его обработчик будет выполняться (опять-таки с точки зрения здравого смысла) в кольце 0, почему для сохранения прерывания будет использоваться стек нулевого режима. Опять-таки заботиться не о чем: ядро (работающее в режиме 0) снимет задачу, выполнившую некорректное переключение стека.

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

    Ну и напоследок: не все прерывания можно блокировать. Та же страничная ошибка при обращении за частью нового указателя стека (например, если в Вашем примере ebx указывает на двойное слово в выгруженной странице) гарантированно приводит к невозможности корректного изменения указателя стека. В пользовательской программе это некритично: ось подгрузит новую страницу и повторит операцию, но вот в коде самой оси недопустимо, поскольку тогда не сможет корректно отработать сам процесс перехода к обработчику прерывания. С моей кочки зрения для разработчика процессора (и спецификаций к нему) наиболее правильным вариантом был бы такой: при работе процессора в защищённом режиме в кольце, отличном от нуля, а также в режиме V86 любые прерывания в процессе смены ss:esp допустимы, однако обработчик прерывания должен работать в ином кольце, в противном случае должен сразу фиксироваться двойной отказ и вылет на сброс процессора. В реальном режиме и в нулевом кольце защищённого режима никакие прерывания не блокируются, однако если они происходят при смене ss:esp, сразу фиксируется двойная ошибка. Борьба с этим: написание безошибочного кода для смены ss:esp и запрет аппаратных прерываний с помощью флажка IF.

    В моём варианте -- совершенно нормально, если только она не установлена в реальном режиме или в нулевом кольце защищённого :) Но, похоже, в Интеле руководствовались какой-то другой логикой.
     
  12. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    дык я что то не понимаю в чем проблема?
    в документации же ясно написано, что процессор задерживает прерывания, отладочные исключения сгенерированных после инструкций mov ss, XX и pop ss. до тех пор пока управление не перейдет на инструкцию после следующей за mov ss, XX или pop ss.

    Задерживает, а не отбрасывает. все таки inhibit как правило используют в значении delay, что и подтверждают доки от AMD.
     
  13. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Похоже тут никакого противоречия нет.
    Процессор может как задерживать, так и игнорировать отладочные исключения - обработка TF просто откладывается, а вот хардварный бряк на инструкции, следующей за mov ss\pop ss игнорируется (хотя интелы и тут туману напустили - типа it may not be triggered и in most situations POP SS/MOV SS will inhibit such interrupts). Int3 срабатывает по любому, т.к. это не fault, а trap, т.е. исключение генирится не перед выполнением инструкции, а после, и уже сам отладчик делает декремент EIP, передвигая его на Int3. Ну а на всякие инвлидные mov esp,[ebx] правило inhibit вообще не распространяется
     
  14. rei3er

    rei3er maxim

    Публикаций:
    0
    Регистрация:
    15 янв 2007
    Сообщения:
    917
    Адрес:
    minsk
    это програмное прерывание, точнее я бы даже так сказал, это инструкция
    на нее действие правила не распространяется
    как и на все асинхронные и процессорные события
    а точно на mov eax, [esi]?
    все верно
    на время выполнения mov ss ничего не запрещается
    а вообще
    прочитайте про VMX
    там есть такое понятие как Pending Debug Exceptions
    в контексте VMX это просто поле в VMCS
    но в контексте CPU - это регистр, куда помещается информация обо всех несработанных #DB
    при генерации #DB информация оттуда копируется в DR6 (а при VM-exit - в поле в VMCS)
    как пример
    Код (Text):
    1. ...
    2.     mov    dword [rax], 2 SHL 3 ; 2 SHL 3 - селектор сегмента стека, в rax - какой-то валидный адрес
    3.     mov    dword [rax - 4], 2 SHL 3
    4.     mov    dr0, rax
    5.     sub    rax, 4
    6.     mov    dr1, rax
    7.     mov    rdx, @F
    8.     mov    dr2, rdx
    9.     mov    edx, 0x77032A
    10.     mov    dr7, rdx
    11.     pushfq
    12.     or     dword [rsp], 0x100
    13.     popfq ; установка TF
    14. ; #DB нет по определению
    15.     mov    ss, word [rax]
    16. ; тут нет #DB как по DR0, так и по TF, также нет #DB по DR2
    17. @@:
    18.     mov    ss, word [rax + 4]
    19. ; тут нет #DB по DR1
    20.     nop
    21. ; тут генерируется #DB, причем в DR6 установлены биты B0, B1, BS
    22.     hlt
    23. ...
    то, что в DR6 нет установленного B2 легко объясняется тем, что инструкция с breakpoint все равно уже выполнилась
    и смысл от обработки теряется
     
  15. diamond

    diamond New Member

    Публикаций:
    0
    Регистрация:
    21 май 2004
    Сообщения:
    507
    Адрес:
    Russia
    Насколько я помню, если происходит какое-то исключение в 0-кольце и возникают ошибки при, например, сохранении cs/eip/eflags в стеке, то системе не хана, а генерируется исключение #DF, Double Fault. Ну а обработчик #DF обычно оформлен как шлюз задачи и его вызов возможен вообще всегда, поскольку в каждой задаче отдельный стек. Ну а как он будет разруливать ситуацию - это уже процессора не касается.
     
  16. Medstrax

    Medstrax Забанен

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    673
    Здесь идет trap, а не fault потому инструкция следующая за mov ss,... выполняется до возикновения эксепшена, соответственно после ее выполнения - дебажные эксепшны размаскируются. Если на инструкцию mov eax,[esi] поставить бряк по команде - он не срабатывает.
     
  17. Medstrax

    Medstrax Забанен

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    673
    Кстати, все не так тривиально. Действительно, если на команду, следующую за mov ss,...
    поставить брекпойнт по команде - этот брекпойнт не срабатывает. Однако, если выставить
    GD в DR7 и после mov ss,... следующей командой попытаться читать/писать DR0-7 - имеем эксепшн.
     
  18. rei3er

    rei3er maxim

    Публикаций:
    0
    Регистрация:
    15 янв 2007
    Сообщения:
    917
    Адрес:
    minsk
    это логично
    маскируются отладочные исключения
    а #DB по GD таковым не является (несмотря на то, что используется дескриптор #DB)
    это просто механизм защиты
     
  19. Medstrax

    Medstrax Забанен

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    673
    Это понятно. Непонятна логика разработчиков. В случае #DB по GD пара ss-esp может быть
    точно так же невалидна, как и в других случаях (когда эксепшены маскируются). Что в большинстве случаев приведет к краху. Почему бы тогда не обобщить маскировку на все возможные случаи исключений? Понятно, что вопрос риторический... ;)
     
  20. rei3er

    rei3er maxim

    Публикаций:
    0
    Регистрация:
    15 янв 2007
    Сообщения:
    917
    Адрес:
    minsk
    на всевозможные случаи обобщить нельзя
    тот же #PF
    что делать в этом случае?
    Код (Text):
    1. mov ss, ax
    2. mov eax, dword [eax] ; тут #PF
    продолжить выполнение - самый худший вариант: в eax будет непонятно что
    а если сгенерировать исключение - есть вариант успешного разруливания данной ситуации
    если позволить такое
    Код (Text):
    1. xor edx, edx
    2. mov ss, ax
    3. mov dr7, edx ; бит GD был установлен
    без исключения - это прямое нарушение защиты, для чего тогда GD создавался?