Мы сломаем все ваши эмуляторы
2020-09-05 08:52 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
При реверсировании микрокода процессоров Intel 8086/8088 обнаружилась интересная недокументированная особенность: префикс REP/REPNE перед инструкциями целочисленного умножения и деления со знаком (MUL, IMUL, IDIV) обращает знак результата (произведения или частного):
https://www.reenigne.org/blog/8086-microcode-disassembled/
Перед тем, как процессор начнёт исполнять микрокод для инструкции умножения или деления, отрицательные операнды этих инструкций преобразуются в положительные, а их изначальный знак попутно XOR-ится на некий 1-битный внутренний регистр, состояние которого используется микропрограммой умножения или деления как флаг отрицательного результата. Поскольку у инструкций умножения и деления сложные и длинные микропрограммы с десятками микроопераций, которые портят состояние всех внутренних временных регистров процессора, проектировщиками из Intel для хранения знака результата операции умножения/деления было решено переиспользовать тот же самый 1-битный флаг, который взводится инструкционным префиксом REP/REPNE и сбрасывается на каждой новой инструкции (и который официально предназначен совсем для других целей: для повторения строковых инструкций типа MOVS/CMPS/SCAS, и соответственно не определён для инструкций умножения и деления). Таким образом, если у инструкций умножения или деления есть этот префикс, тогда начальное состояние флага знака результата равно 1 (–), а не 0 (+), как обычно.
Логично, не правда ли?
Жаль только, что трюк не работает, начиная с Intel 80286.
https://www.reenigne.org/blog/8086-microcode-disassembled/
Перед тем, как процессор начнёт исполнять микрокод для инструкции умножения или деления, отрицательные операнды этих инструкций преобразуются в положительные, а их изначальный знак попутно XOR-ится на некий 1-битный внутренний регистр, состояние которого используется микропрограммой умножения или деления как флаг отрицательного результата. Поскольку у инструкций умножения и деления сложные и длинные микропрограммы с десятками микроопераций, которые портят состояние всех внутренних временных регистров процессора, проектировщиками из Intel для хранения знака результата операции умножения/деления было решено переиспользовать тот же самый 1-битный флаг, который взводится инструкционным префиксом REP/REPNE и сбрасывается на каждой новой инструкции (и который официально предназначен совсем для других целей: для повторения строковых инструкций типа MOVS/CMPS/SCAS, и соответственно не определён для инструкций умножения и деления). Таким образом, если у инструкций умножения или деления есть этот префикс, тогда начальное состояние флага знака результата равно 1 (–), а не 0 (+), как обычно.
Логично, не правда ли?
Жаль только, что трюк не работает, начиная с Intel 80286.