Багато років тому я провів ранок, намагаючись налагодити якийсь код, що змінюється, одна інструкція змінила цільову адресу наступної інструкції, тобто я обчислював адресу філії. Він був написаний мовою асемблера і прекрасно працював, коли я переходив через програму по одній інструкції за раз. Але коли я запустив програму, це не вдалося. Врешті-решт я зрозумів, що машина отримує 2 вказівки з пам’яті і (як інструкції були викладені в пам’яті), інструкція, яку я змінював, вже була отримана, і, отже, машина виконує немодифіковану (неправильну) версію інструкції. Звичайно, коли я налагоджував, то робив лише одну інструкцію за раз.
Моя думка, самовимінюючий код може бути дуже неприємним для тестування / налагодження і часто має приховані припущення щодо поведінки машини (будь то апаратне чи віртуальне). Більше того, система ніколи не може ділитися кодовими сторінками між різними потоками / процесами, що виконуються на (тепер) багатоядерних машинах. Це позбавляє багатьох переваг віртуальної пам’яті тощо. Це також призведе до скасування оптимізації гілок, зроблених на апаратному рівні.
(Примітка - я не включаю JIT до категорії коду, що змінюється. JIT перекладається з одного представлення коду на альтернативне представлення, воно не змінює код)
Загалом, це лише погана ідея - дійсно акуратне, дійсно незрозуміле, але насправді погано.
Звичайно - якщо у вас є лише 8080 та ~ 512 байт пам'яті, можливо, вам доведеться вдатися до подібних практик.