Вопрос
Каковы некоторые идеи для кросс-модификационного кода, которые могут вызвать неожиданное поведение в системах x86 или x86-x64, где все сделано правильно в коде кросс-модификации, за исключением выполнения команды сериализации на исполняющем процессоре ранее для выполнения измененного кода?
Как отмечено ниже, у меня есть процессор Core 2 Duo E6600 для тестирования, который явно упоминается как процессор, подверженный проблемам. Я буду тестировать любые идеи, которые есть у меня на этом компьютере, и давать обновления.
Фон
В системах x86 и x64 официальное руководство по написанию кросс-модификационного кода состоит в следующем:
; Action of Modifying Processor
Store modified code (as data) into code segment;
Memory_Flag ← 1;
; Action of Executing Processor
WHILE (Memory_Flag ≠ 1)
Wait for code to update;
ELIHW;
Execute serializing instruction; (* For example, CPUID instruction *)
Begin executing modified code;
Инструкция сериализации в явном виде упоминается в случае необходимости для некоторых процессоров. Например, у процессоров Intel Core 2 Duo E6000 есть следующие ошибки: (от http://www.mathemainzel.info/files/intelX6800andintelE6000.pdf)
Действие одного процессора или главного системного шифра, запись данных в в настоящее время выполняется сегмент кода второго процессора с намерением того, чтобы второй процессор выполнял эти данные при вызове кода кросс-модификационный код (XMC). XMC, который не заставляет второй процессор для выполнения команды синхронизации до выполнения нового кода, называется несинхронизированным XMC.
Программное обеспечение с использованием несинхронизированного XMC для изменения байта команды поток процессора может видеть неожиданное или непредсказуемое выполнение поведение от процессора, который выполняет модифицированный код.
Есть некоторые предположения о том, почему неожиданное поведение выполнения может произойти, если инструкция сериализации не используется в http://linux.kernel.narkive.com/FDc9TB0d/patch-linux-kernel-markers:
Когда i-выборка была выполнена, и микрооперации находятся в следе кеш, тогда уже нет прямой корреляции между оригиналом границы машинной инструкции и микрооперации. Это связано с оптимизация. Например (искусственный для иллюстративных целей):
mov eax, ebx
mov memory, eax
mov eax, 1
(с использованием нотации Intel не ATT - сила привычки)
В кеше трассировки не будет микроопераций для обновления eax с помощью ebx.
Изменение "mov eax, ebx" на "mov ecx, ebx" на лету делает недействительным оптимизированный тайник трассировки, следовательно, рекурсия onlhy - это GPF. Если модификация не отменяет кеш трассировки, а не GPF. вопрос заключается в следующем: "можем ли мы предсказать обстоятельства, когда кеш трассировки не было признано недействительным", и ответ в целом микроархитектура не является общедоступной. Но можно догадаться, что изменение однобайтовый код операции с инструкцией прерывания - int3 - не вызывают несогласованность, которую невозможно обработать. И то, что Intel подтверждено. Идем дальше и храним int3 без необходимости синхронизации (т.е. заставить кеш трассировки очищаться).
Там также немного больше информации на https://sourceware.org/ml/systemtap/2005-q3/msg00208.html:
Когда мы узнали об этом, я долго беседовал с Intel микроархитектуры. Оказывается, причина этого erratum (который, кстати, Intel не намерен исправлять), объясняется тем, что трассировка cache - поток микропор, полученный в результате инструкции интерпретация - не может быть гарантирована. Чтение между Я предполагаю, что эта проблема возникает из-за оптимизации, сделанной в trace cache, где уже невозможно идентифицировать оригинал границы инструкций. Если первопроходцы CPU используют кеш трассировки была признана недействительной из-за несинхронизированной перекрестной модификации, тогда выполнение команды будет прервано с помощью GPF. Дальнейшее обсуждение с Intel показало, что замена первого байта кода операции на int3 не будет подлежать этой ошибке.
Помимо того, что я разместил здесь, я не слишком много видел в Интернете по этой проблеме. Кроме того, я не нашел публичных примеров того, как люди укушены, не выполнив инструкцию по сериализации при использовании кросс-модификационного кода в системах x86 и x86-64.
У меня есть компьютер с процессором Intel Core 2 Duo E6600, который явно документирован как подверженный этой проблеме, и я не смог написать код, который вызывает эту проблему.
Написание кода для этого - личное любопытство для меня. В производственном коде я просто соблюдаю правила, но я считаю, что, возможно, что-то для меня, чтобы научиться воспроизводить это.