Люди, а возможно ли вообще модифицировать данные в кэше? т.е в кэше одно в ОЗУ другое, а проц юзал то че в кэше?
Да, для этого нужно отключить кеширование в регистре CR0, не очищая содержимого кеша. В этом случае процессор будет только читать из кеша, но не писать. Но тормоза будут приличные.
Stamerlan Не понятно, что ты имеешь в виду, т.к. обычно процессор так и работает с памятью в режиме write back - сначала читает данные из ОЗУ в кэш и затем модифицирует данные в кэше, помечая соответствующие линейки как модифицированные. Пока эти линейки не будут записаны обратно в ОЗУ (write back) как раз и будет "в кэше одно, в ОЗУ другое".
Вобщем идея такая: в кэше происходит модификация кода, а в ОЗУ нет. Если программа будет остановленна отладчиком, то в кэше стопудова будет что-то другое и будет выполнена другая команда. Ну а если все в живую то в кэше будет то что надо. 2Mika0x65 Дай почитать про эта где-нибудь, а то книг по теме нету, а на компе я читаю тока статейки(угадай почему)
Stamerlan Наивняк Если не брать в расчет режим DMA, то все обращения к ОЗУ происходят через процессор, который полностью отвечает за синхронность данных в кэше и ОЗУ. Если ты изменяешь код или данные, загруженные в кэш, то при их последующем чтении (хоть напрямую через mov в твоей программе, хоть через ReadProcessMemory в отладчике) процессор "видит", что соответствующие адреса находятся в кэше и выдает модифицированные данные из кэша, а не из ОЗУ. Более того в современных процах, начиная с первого пентиума, проц следит за модификацией кода и сбрасывает конвеер, если обнаруживает запись в текущую линейку кэша инструкций (в P6), а в P4 и атлонах так и вовсе отслеживается запись в текущий килобайт кода (т.к.они используют преддекодирование команд). Поэтому фокус с самомодификацией рулил только на i486 и связан он был не с различием данных в кэше и ОЗУ, а с тем, что проц не сбрасывал команды уже загруженные в конвеер - в итоге сразу после записи в кэше была новая команда, а в конвеер успевала загрузиться старая. С современными процами такие фокусы не проходят PS: Чтобы не изобретать велосипеды, почитай раздельчики про self-modifying code в официальных манах Intel и AMD, которые гарантируют корректную работу проца при модификации кода, но не рекомендуют этого делать только из соображений производительности (особенно на P4 и K7+)
2leoКонцепция сброса кэша при SMC сейчас не валидна? Всё уже укра... изменено до нас /автоматически/? Такой "болезнью" только допнёвые семейства процессоров страдали? А API остались: FlushInstructionCache, NtFlushInstructionCache. Но ответ таки там дан: сбрасывать кэш инструкциями jmp/cpuid только вот не всякий джамп вроде бы сбрасывает кэш, только безусловный(?).
а какое отношение имеют инструкции сериализации (например CPUID) к сбросу кэша? с безусловными переходами аналогично
asmfan Во-первых, глянь в раздельчик 10.6 volume 3A, там все достаточно конкретно сказано и про P1\P6, и про P4, и про 486. А также в амд-шый 7.5.1 volume 2. Во-вторых, не путай кэш инструкций с конвеером (prefetched queue - очередью загруженных\декодированных команд). Jmp\cpuid могут сбрасывать только конвеер, но никак не кэш. Для сброса кэша есть команды invd\wbinvd, но к SMC они отношения не имеют. Современные процы сами отслеживают модификацию кода, т.к. 1) у них кэши L1 разные для данных (DC) и для инструкций (IC), 2) команды mov m,r работают только с кэшем данных (или с L2), поэтому для поддержки SMC проц просто вынужден при кажой записи в память проверять не затрагивает ли она адреса, представленные в кэше инструкций - если да, то соотв.линейка IC или весь кэш IC объявляются инвалидными и впоследствии грузятся заново из L2 с измененным кодом. Разумеется при таком "ЧП" не составляет никакого труда "заодно" сбросить очередь команд в конвеере после инструкции mov m,r. Поэтому рекомендации о необходимости софтварной сериализации после записи в код по моему являются страшилками "на всякий пожарный"
Пнёвость/допнёвость тут ни при чём - на всём семействе x86 эти APIлки ничего не делают, они для других архитектур предназначены, а на x86 влезли только для переносимости сишного кода.
Только что оттуда) имелся ввиду кэш команд, Trace Cache пней 4х. Неужели его эти инструкции не сбрасывают?
Какие эти ? jmp/cpuid ? Конечно нет, с какой стати сбрасывать 12К "с большим трудом" декодированных и увязанных в трассы мопов, да еще по обычной популярной команде jmp ?!! Вот как раз команда записи в текущий килобайт относительно адреса исполняемой команды и приводит к автоматическому сбросу всего T-кэша, т.к. его "нестандартная" реализация (в отличие от P6 и атлонов) не позволяет быстро определить наличие произвольного адреса в кэше. А jmp, непредсказанные jcc и серийные команды просто сбрасывают конвеер, т.е. все команды (мопы) которые уже считаны из T-кэша и находятся в конвеере PS: никаких спецкоманд для сброса кэша инструкций нет, есть только команды общего сброса invd\wbinvd, которые махом сбрасывают кэши всех уровней (включая внешние, если есть)
Спасибо. Мой тугой рассудок разделил таки теперь понятия instruction prefetch unit/prefetch queue/ и кэш команд.
разве обычный прямой (или косвенный) JMP сбрасывает конвеер? c Jcc все понятно: переход может быть предсказан неверно и поэтому может потребоваться откат но JMP то выполняется всегда да, операнд может быть не известен (в случае косвенного JMP) априорно но out-of-order выполнение этого и не требует соответствующая микрооперация будет выполнена, когда операнд будет известен
Когда прямой переход выполняется в первый раз, то сбрасывает. В современных компах одно только декодирование команд растягивается на 4-5 стадий (тактов) и на каждой стадии декодер может выдавать в среднем по 3 мопа (= простых команды). Поэтому когда наконец JMP будет декодирован и станет известен адрес прыжка, за этим JMP уже может выстроиться очередь из десятка других команд, которые ес-но придется выбросить и начать декодировать команды по новому адресу. Адрес косвенного перехода при первом проходе вообще становится известным только на этапе исполнения, т.е. через 10-20-30 стадий в завис-ти от проца. Поэтому за JMP может выстроиться очередь из нескольких десятков неверных команд, которые также будут сброшены. При повторных проходах косвенные переходы ведут почти также как условные - если адрес не меняется, то все ОК, если меняется, то сброс конвеера и переход по новому адресу PS: поэтому кстати не рекомендуется мешать код с данными, т.к. декодер, проскакивая "по инерции" JMP может начать декодировать всякий мусор, например "Hello, World!"
leo "сброс конвеера" затрагивает весь ROB? при выполнении микрооперации, которая реализует JMP в ROB могут быть микрооперации, которые были помещены в него до нее, но не выполненные полностью
rei3er Нет конечно, только те команды\мопы, которые идут "после" JMP, а те которые "до" разумеется завершаются и уходят в отставку как им и положено asmlamo Да есть, и я уже дважды о них упомянул Но к самомодификации кода они отношения не имеют, т.к. сбрасывают вообще все кэши и предназначены только для системных "штучек", особенно invd которая не сохраняет измененные данные в ОЗУ и поэтому в "неумелых руках" может привести к непредсказуемым последствиям