کد خودتغییردهنده

زبان اسمبلی

کد خود تغییر دهندگی برای پیاده‌سازی در هنگام استفاده از زبان اسمبلی بسیار ساده است. دستورالعمل‌ها می‌توانند به‌طور پویا در حافظه ایجاد شوند (یا در موارد دیگر بر روی کدهای موجود در ذخیره‌سازی برنامه‌های محافظت نشده)، در توالی معادل با آن‌هایی که کامپایلر استاندارد ممکن است به عنوان کد هدف تولید کند. با پردازنده‌های مدرن، ممکن است عوارض جانبی ناخواسته بر روی حافظه نهان CPU وجود داشته باشد که باید در نظر گرفته شود. این روش اغلب برای آزمایش شرایط «اولین بار» مورد استفاده قرار می‌گیرد، همان‌طور که در این نمونه زبان اسمبلی مناسب IBM / 360 توضیح داده شده‌است. این روش با استفاده از پوشش دستور برای کاهش طول مسیر دستورالعمل به N × 1) -1) که در آن N که تعداد رکوردها در فایل است.
(-۱ سرباری برای انجام پوشش است)، استفاده می‌شود.
SUBRTN NOP OPENED      FIRST TIME HERE?
 * The NOP is x'4700'<Address_of_opened>
        OI    SUBRTN+1,X'F0'  YES, CHANGE NOP TO UNCONDITIONAL BRANCH (47F0...)
        OPEN   INPUT               AND  OPEN THE INPUT FILE SINCE IT'S THE FIRST TIME THRU
 OPENED GET    INPUT        NORMAL PROCESSING RESUMES HERE
       ...
کد جایگزین ممکن است شامل هر بار آزمودن «پرچم» باشد. دستور پرش بدون قید و شرط کمی سریعتر از دستور مقایسه ای است، و همچنین باعث کاهش طول مسیر کلی می‌شود. در سیستم عامل‌های بعدی برای برنامه‌هایی که در حافظه محافظت شده قرار دارند، این تکنیک نمی‌تواند مورد استفاده قرار گیرد و به جای آن از تغییر اشاره گر به زیر برنامه استفاده خواهد شد. اشاره گر در حافظه پویا قرار دارد و می‌تواند پس از گذراندن اولین مرحله برای دور زدن OPEN تغییر یابد (ابتدا باید یک اشاره گر به جای یک پرش مستقیم بارگذاری شود و به زیر برنامه ارتباط پیدا کند که N دستورالعمل را به طول مسیر اضافه می‌کند - اما یک کاهش متناظر با N برای پرش بدون قید و شرط وجود دارد که دیگر لازم نیست).

در زیر نمونه ای از زبان اسمبلی Zilog Z80 است. این کد ثبات B را از مقدار ۰ به ۵ افزایش می‌دهد. دستور مقایسه ای "CP" در هر حلقه تغییر می‌کند. 
;====================================================================  ==ORG 0HCALL FUNC00HALT;====================================================================  ==FUNC00:LD A,6LD HL,label01+1LD B,(HL)label00:INC BLD (HL),Blabel01:CP $0JP NZ,label00RET;====================================================================  ==
کد خود تغییر دهنده گاهی اوقات برای غلبه بر محدودیت‌های مجموعه دستورها ماشین مورد استفاده قرار می‌گیرد. به عنوان مثال، در مجموعه دستورها Intel 8080، نمی‌توان یک بایت را از یک پورت ورودی که توسط یک ثبات مشخص شده‌است را وارد کرد. پورت ورودی به صورت استاتیکی در خود دستور، به عنوان بایت دوم دستور دو بایتی رمزگذاری می‌شود. با استفاده از کد خود تغییر دهنده، می‌توان محتویات ثبات را در بایت دوم دستور ذخیره کرد، سپس دستور اصلاح شده را برای رسیدن به اثر مورد نظر، اجرا می‌کند.

زبانهای سطح بالا

برخی از زبان‌های کامپایل شده به صراحت اجازه می‌دهند کد خود را تغییر دهید. به عنوان مثال، فعل ALTER در COBOL ممکن است به عنوان دستور پرشی اجرا شود که در حین اجرای برنامه اصلاح می‌شود. یکی از روش‌های برنامه‌ریزی دسته ای استفاده از کد خودمحور است. Clipper و SPITBOL نیز امکانات را برای تغییر صریح خود فراهم می‌کنند. کامپایلر Algol در سیستم‌های B6700 یک رابط را برای سیستم عامل ارائه داد که در آن اجرای کد می‌تواند یک رشته متن یا یک فایل دیسک نام‌گذاری شده را به کامپایلر Algol منتقل کند و سپس قادر به فراخوانی نسخه جدیدی از یک روش بود.

با زبان‌های تفسیر شده، "کد ماشین" متن منبع است و ممکن است حساس به ویرایش بر روی on-the-fly باشد: در SNOBOL، جملات مرجع که اجرا می‌شوند، عناصر یک آرایه متنی هستند. زبان‌های دیگر مانند Perl و Python به برنامه‌ها برای ایجاد کد جدید در زمان اجرا و اجرای آن با استفاده از یک تابع eval، اجازه می‌دهند، اما اجازه تغییر در کد فعلی قابل را نمی‌دهند. تغییر غلط (حتی اگر هر کدام از ماشین‌ها واقعاً رونویسی شوند) با تغییر اشاره گرهای تابع به دست می‌آید، همان‌طور که در این مثال جاوااسکریپت داریم: 
    var f = function (x) {return x + 1};

    // assign a new definition to f:
    f = new Function('x', 'return x + 2');
 
ماکروهای Lisp همچنین اجازه می‌دهند که کد در زمان اجرا تولید شود بدون آن که به تجزیه رشته حاوی متن برنامه نیاز باشد.
زبان برنامه‌نویسی Push یک سیستم برنامه‌نویسی ژنتیکی است که به‌طور ویژه برای ایجاد برنامه‌های خود تغییر دهنده طراحی شده‌است. در حالی که یک زبان سطح بالا نیست، زبان سطح پایینی هم در حد زبان اسمبلی نیست.

جداول کنترل

مترجم‌های جدول کنترل می‌توانند در یک معنا "خود تغییر داده شده" با مقادیر داده استخراج شده از ورودی‌های جدول (به جای اینکه به‌طور خاص دسته‌بندی شده در جمله‌های شرطی به فرم "IF inputx = 'yyy'") در نظر گرفته شود.

برنامه‌های کانال

بعضی از روش‌های دسترسی IBM به‌طور سنتی برنامه‌های کانال خود تغییر دهنده را استفاده می‌کنند، جایی که یک مقدار مانند آدرس دیسک، در یک ناحیه اشاره شده توسط برنامه کانال، که از طریق یک فرمان کانال بعدی برای دسترسی به دیسک استفاده می‌شود، خوانده می‌شود.

تاریخ

IBM SSEC در ماه ژانویه سال ۱۹۴۸ نشان داد که توانایی تغییر دستورهایش را دارد یا در غیر این صورت با آن‌ها دقیقاً مانند داده رفتار کند. با این حال، این قابلیت به ندرت در عمل کاربرد دارد. در اولین روزهای رایانه‌ها، کد خود تغییر دهنده اغلب برای کاهش استفاده از حافظه محدود یا بهبود عملکرد یا به هر دو دلیل استفاده می‌شد. همچنین گاهی اوقات برای پیاده‌سازی توابع زیر برنامه ای استفاده می‌شد و هنگامی برمی‌گشت که مجموعه دستورها تنها پرشی ساده یا رد شدن از دستورها برای تغییر دادن کنترل جریان، باشند. این کاربرد هنوز در برخی معماری معین ultra-RISC مناسب است، حداقل از لحاظ نظری؛ به عنوان مثال معماری one instruction set computer نیز از کد خود تغییر دهنده برای پیاده‌سازی توابع زیر برنامه، استفاده می‌کرد.

بهینه‌سازی یک حلقه وابستگی حالت

مثالd از Pseudocode :
repeat N times {
 if STATE is 1
 increase A by one
 else
 decrease A by one
 do something with A
}
کد خود تغییر دهنده، در این مورد، به سادگی موضوع بازنویسی حلقه مانند این است:
 repeat N times {
  ''increase'' A by one
  do something with A
  when STATE has to switch {
  replace the opcode "increase" above with the opcode to decrease, or vice versa
  }
  }
توجه داشته باشید که تعویض دو حالتی OPCode به راحتی می‌تواند به عنوان "xor var" در آدرس با مقدار" (opcodeOf (Inc) xor opcodeOf (dec " نوشته شود.
انتخاب این راه حل باید به مقدار N و فرکانس تغییر حالت بستگی داشته باشد.

تخصص

فرض کنید مجموعه ای از آمار مانند میانگین، بیشینه، موقعیت بیشینه، انحراف استاندارد و … برای برخی از مجموعه داده‌های بزرگ محاسبه می‌شود. در یک وضعیت کلی، ممکن است یک حالت مربوط به وزن با داده وجود داشته باشد، بنابراین هر x ᵢ با aw i همراه است و به جای آزمودن حضور وزن در هر مقدار شاخص، ممکن است دو نسخه از محاسبه، یکی برای استفاده با وزن و یکی برای استفاده بدون وزن، با یک آزموندن در آغاز کار، موجود باشد. حال یک گزینه دیگر را در نظر بگیرید که هر مقدار ممکن است با یک عدد بولین همراه باشد تا نشان دهد که آیا این مقدار باید حذف شود یا خیر. این روش می‌تواند با تولید چهار دسته از کد، برای هر permutation و نتایج نفوذ کد، مورد استفاده قرار گیرد. در عوض، وزن و آرایه‌های جست و جوی می‌توانند به یک آرایه موقت (با وزن صفر برای مقادیری که باید پر شوند)، با هزینه پردازش، ترکیب شوند و هنوز هم باد کردن وجود دارد. با این حال، با تغییر کد، به الگوی محاسبه آمار می‌تواند کد مورد نظر که برای پرش از مقادیر ناخواسته و برای اعمال وزن است، اضافه شود. تست‌های تکراری از گزینه‌ها وجود نخواهد داشت و به آرایه داده‌ها یک بار دسترسی انجام می‌شود، همچنین وزن و آرایه‌های جستجو می‌تواند به همین شکل باشد، اگر شامل کد باشند باشد.

استفاده به عنوان پوشش

کد خود تغییر دهنده برای مخفی کردن کپی حفاظت دستورها در برنامه‌های مبتنی بر دیسک ۱۹۸۰ برای سیستم عامل‌هایی مانند IBM PC و Apple II استفاده شده‌است. به عنوان مثال، در IBM PC (یا سازگار)، دستور دستیابی درایو فلاپی دیسک که int 0x13 می‌باشد در تصویر برنامه اجرایی نمایش داده نخواهد شد، اما بعد از اجرای برنامه، در تصویر حافظه اجرایی نوشته می‌شود.
کد خود تغییر دهنده گاهی اوقات توسط برنامه‌هایی استفاده می‌شود که نمی‌خواهند حضورشان را نشان دهند، مانند ویروس‌های کامپیوتری و برخی ازshellcodeها. ویروس‌ها و کد شل‌ها که از کد خود تغییر دهنده استفاده می‌کنند، عمدتاً این کار را با کد پلی مورفیک انجام می‌دهند. تغییر یک قطعه کد در حال اجرا نیز در حملات خاص، مانند سرریز بافر استفاده می‌شود.

سیستم یادگیری ماشین خود ارجاعی

سیستم‌های یادگیری ماشین سنتی دارای الگوریتم یادگیری ثابت و پیش برنامه‌ریزی شده برای تنظیم پارامترهایشان می باشند. با این حال، از دهه ۱۹۸۰، Jürgen Schmidhuber چند سیستم خود تغییر دهنده را با توانایی تغییر الگوریتم یادگیری خود، منتشر کرده‌است. این سیستم‌ها از خطر خودکفائی فاجعه آمیز جلوگیری می‌کنند، از این طریق اطمینان حاصل می‌کنند که خود تغییرات تنها در صورتی قابل قبول خواهند بود که با توجه به آمادگی کاربر، خطا یا عملکرد پاداش مفید باشد.

سیستم‌های عامل

به دلیل پیامدهای امنیتی کد خودمحور، تمام سیستم عامل‌های اصلی مراقب حذف چنین آسیب‌پذیری به محض شناسایی آن‌ها هستند. نگرانی معمولاً این نیست که برنامه‌ها عمداً خودشان را تغییر دهند، اما می‌توانند از طریق سوء استفاده از آنها سوءاستفاده کنند.
به عنوان نتیجهٔ مشکلاتی که می‌تواند توسط این سوء استفاده‌ها ایجاد شود، یک ویژگی OS به نام W ^ X (برای "نوشتن xor execute") توسعه داده شده‌است که به برنامه اجازه نمی‌دهد که هیچ صفحهٔ حافظه را هم قابل خواندن و هم قابل اجرا کند. بعضی از سیستم‌ها از یک صفحه که قابل نوشتن است جلوگیری می‌کنند تا به حالت قابل اجرا درآید، حتی اگر اجازه نوشتن حذف شود. سیستم‌های دیگر " درهای عقب " را ارائه می‌دهند که اجازه می‌دهد چندین صفحه بندی از یک صفحهٔ حافظه دارای مجوزهای متفاوت باشد. یک راه نسبتاً قابل حمل برای دور زدن W ^ X این است که یک پرونده با تمام مجوزها ایجاد کنید، سپس فایل را به حافظه دو بار نگاشت کنید. در لینوکس، می‌توان از یک پرچم حافظه مشترک SysV ناموجود استفاده کرد تا به حافظه مشترک قابل اجرا بدون نیاز به ایجاد یک فایل رسید. 
صرفنظر از موارد فوق، در سطح فراگیر، برنامه‌ها همچنان می‌توانند رفتار خود را با تغییر داده‌های ذخیره شده در جاهای دیگر تغییر دهند یا از طریق استفاده از پلی مورفیسم.

تعامل حافظهٔ نهان و کد خود تغییر دهنده

در معماری‌های بدون داده‌های مرتبط و حافظه پنهان دستورالعمل (برخی از هسته‌های ARM و MIPS)، هماهنگ سازی حافظه پنهان باید به وضوح توسط کد تغییر دهنده انجام شود (حافظه پنهان دادهٔ تخلیه و حافظهٔ پنهان دستورالعمل بی‌اعتبار برای محدوده حافظه تغییر داده شده).
در بعضی موارد، بخش‌های کوتاهی از کد خود تغییر دهنده به آرامی روی پردازنده‌های مدرن اجرا می‌شود. این به این دلیل است که یک پردازنده مدرن معمولاً سعی می‌کند بلوک‌های کد را در حافظه پنهان خود نگه دارد. هر بار که برنامه بخشی از خود را بازنویسی می‌کند، قسمت بازنویسی شده باید دوباره در حافظه پنهان بارگذاری شود، که باعث یک تأخیر جزئی می‌شود، اگر کدهای تغییر داده همان خط حافظهٔ پنهان را با کد تغییری به اشتراک گذارند، همانند مواردی که حافظه تغییر داده شده را آدرس درون چند بایت در یکی از کدهای تغییر داده شده‌است.
مسئله عدم اعتبار حافظهٔ پنهان در پردازنده‌های مدرن معمولاً بدین معنی است که کد خود تغییر دهنده هنوز هم سریع تر خواهد بود تنها زمانی که تغییر به ندرت رخ می‌دهد، مانند تعویض حالت درون حلقه داخلی. 
بیشتر پردازنده‌های مدرن قبل از اجرای آن، کد ماشین را بارگذاری می‌کنند، بدین معنی که اگر دستورالعملی که خیلی نزدیک اشارهگر دستورالعمل است، تغییر داده شده باشد، پردازنده متوجه نمی‌شود، بلکه کد را قبل از اینکه آن را تغییر دهد اجرا می‌کند. صف ورودی پیشفرض (PIQ) را ببینید. پردازنده‌های PC باید به کد خود تغییر دهنده را به درستی برای دلایل سازگاری عقبی انجام دهند، اما در انجام این کار بسیار دور از حالت بهینه‌اند.

هسته Synthesis Massalin

سنتز هسته ارائه شده در دکتری پایان‌نامه هنری Massalin، یک کرنل Unix کوچک است که رویکرد ساختار یافته یا حتی شی گرا را به کد خود تغییر می‌دهد، جایی که کد برای تک تک quajectsها مانند filehandles ایجاد می‌شود؛ تولید کد برای کارهای خاص اجازه می‌دهد که هسته Synthesis به (به عنوان مترجم JIT ممکن است) تعدادی از بهینه‌سازی‌ها را اعمال کند مانند حذف ثابت ثابت یا مشترک زیر بیان.
هسته Synthesis بسیار سریع بود، اما به‌طور کامل در اسمبلی نوشته شده بود. عدم وجود قابلیت حمل و نقل مانع از ایده‌های بهینه‌سازی Massalin از هر هسته تولیدی شده‌است. با این حال، ساختار تکنیک‌ها نشان می‌دهد که آن‌ها می‌توانند با یک زبان سطح بالاتری پیاده‌سازی شوند، اگرچه پیچیده‌تر از زبان‌های سطح متوسط موجود هستند. چنین زبان و کامپایلر می‌تواند اجازهٔ توسعه سریعتر سیستم عامل‌ها و برنامه‌های کاربردی را دهد.
پل هابرلی و بروس کارش با «حاشیه سازی» کد خود تغییر دهنده و بهینه‌سازی به‌طور کلی به نفع کاهش هزینه‌های توسعه مخالفت کردند.