dermatolog Про то, что надо сначала прочитать, что пишут, прежде чем переходить к унизительным рекомендациям. С учётом своей поправки, K10 ничего неверного не написал.
l_inc Если бы человек с самого начала называл вещи своими именами, то и унизительных рекомендаций тоже не последовало. Пойди разбери что они понимают под адресом перехода, если речь идет про сплайсинг. Если под "адресом перехода" подразумевается адрес возврата в вызывающий код, то видимо придется отправлять еще дальше (что такое стек и CALL).
dermatolog С учётом своей поправки, которую Вы, кстати, и процитириовали, и в которой своеобразное понятие "адреса перехода" уже не фигурирует, а как раз поясняется. Хм... Не согласен. Но Вам виднее.
dermatolog >Для х32 - согласен, но я в целом говорил про универсальных подход в том числе и для х64. Нет, в том месте ты не говорил про x64 – ты противопоставлял jmp и push\ret. Если бы акцент в тот момент был на универсальности подхода, то ты не стал бы после своей фразы про ограниченность jmp добавлять "в случае с PUSH аргумент принимает любое значение от 0 до 4Гиг". medstrax1 Clerk >>lock cmpxchg8b >Код изменять следует атомарно. Ok. А зачем нужен lock-префикс здесь? Есть неконтролируемые потоки, бегущие параллельно с нами, собирающиеся точно таким же образом просплайсить ту же функцию?
Sol_Ksacap Затем что например первый поток патчит код, в это время другой поток его вызывает. Если делать это побайтным копирование допустим, то первый байт изменился при записи, остальный нет. Поток исполнит не до конца изменённую инструкцию, что приведёт к краху. Если изменять атомарно, то изза захвата шины другой процессор будет ждать пока запись окончится.
Sol_Ksacap Хотя префикс не обязательный. Видимо инструкция и без него атомарно пишет, нужно в манах посмотреть. Потестил так: Первый поток: Код (Text): @@: xor eax,eax xor ecx,ecx Ip:: mov eax,12345678H cmp eax,12345678H je @b cmp ecx,87654321H je @b int 3 Изменяем инструкцию по адресу [Ip] на mov eax,12345678H и mov ecx,87654321H. Если после исполнения её значения регистров будут отличными от этих значит ошибка. При записи без cmpxchg8b возникает ошибка. При записи посредством этой инструкции без префикса Lock ошибка не возникает, тоесть изменяется атомарно: Второй поток: Код (Text): @@: ; -> mov eax,12345678H xor eax,eax xor edx,edx cmpxchg8b qword ptr [Ip] ; Edx:Eax ; [Mem64] == Edx:Eax [Mem64] <- Ecx:Ebx ; [Mem64] <> Edx:Eax Edx:Eax <- [Mem64] mov ecx,edx mov ebx,345678B8H ; Eax mov cl,12H cmpxchg8b qword ptr [Ip] ; -> mov ecx,87654321H xor eax,eax xor edx,edx cmpxchg8b qword ptr [Ip] mov ecx,edx mov ebx,654321B9H mov cl,87H cmpxchg8b qword ptr [Ip] jmp @b Хотя я всегда использовал префикс Lock, думаю он не помешает, например при изменении ссылок.
Согласно манов атомарность будет соблюдаться в следующих случаях 1)Reading or writing a quadword aligned on a 64-bit boundary 2)Unaligned 16-, 32-, and 64-bit accesses to cached memory that fit within a cache line Видимо в данном случае одно из условий соблюдено. Лучше все-таки не полагаться на случай и юзать lock
Clerk попробуй проверить соображение medstrax1 сдвинь модифицируемую инструкцию на невыровненный(некратный) адрес
Ага. Отлично. Теперь мы видим превосходство lock. Однако в манах есть такой интересный момент: Хотя тут же следует заметка: (Про более новые процессоры в том месте явно ничего не говорится, к сожалению).
Да, ситуация запутывается. Вообще фраза "Only instruction fetch and page table accesses can pass locked instructions" не совсем ясна. Идет ли речь о произвольном ядре/проце, либо только о том, которое выполняет lock. Исходя из "However, Intel recommends that developers who require the use of self-modifying code use a different synchronizing mechanism, described in the following sections", можно предположить, что речь идет только о текущем ядре, в противном случае вместо "self-modifying" было бы "сross-мodifying". Если же это не так, тогда использование lock в данном контексте излишне, на грабли можно нарваться как с ним, так и без него. Ждем leo