Selbstmodifizierender Code - Self-modifying code

In der Informatik , selbst-modifizierenden Code ist Code , dass ändert seine eigenen Anweisungen , während es ausgeführt wird - in der Regel die reduzieren Anweisung Weglänge und verbessern die Leistung oder einfach sonst wiederholt einen ähnlichen Code zu verringern, wodurch die Wartung vereinfacht. Die Selbstmodifikation ist eine Alternative zur Methode des "Flag-Setzens" und der bedingten Programmverzweigung, die hauptsächlich verwendet wird, um die Anzahl der Tests zu reduzieren, die eine Bedingung benötigt. Der Begriff wird normalerweise nur auf Code angewendet, bei dem die Selbstmodifikation beabsichtigt ist, nicht in Situationen, in denen sich Code aufgrund eines Fehlers wie eines Pufferüberlaufs versehentlich selbst ändert .

Das Verfahren wird häufig zum bedingten Aufrufen von Test-/Debugging- Code verwendet, ohne dass für jeden Eingabe/Ausgabe- Zyklus ein zusätzlicher Rechenaufwand erforderlich ist .

Die Änderungen können durchgeführt werden:

  • nur während der Initialisierung - basierend auf dem Eingangsparameter (wenn der Prozess besser bekannt als Software ‚beschrieben Konfiguration ‘ und ist in etwa analog, hardwaremäßig, um die Einstellung Jumper für Leiterplatten ). Änderung der Programmeingabe Zeigers ist eine äquivalente indirekte Methode der Selbst Modifikation, aber erfordert die Koexistenz von einer oder mehrere alternativen Befehlspfaden, die Erhöhung der Programmgröße .
  • während der gesamten Ausführung („on the fly“) – basierend auf bestimmten Programmzuständen, die während der Ausführung erreicht wurden

In jedem Fall können die Modifikationen direkt an den Maschinencode- Befehlen selbst durchgeführt werden, indem neue Befehle über die vorhandenen gelegt werden (zum Beispiel: Ändern eines Vergleichs und Verzweigen zu einem unbedingten Sprung oder alternativ zu einem " NOP ").

Im IBM/360- und Z/Architecture- Befehlssatz überlagert ein EXECUTE (EX)-Befehl logisch das zweite Byte seines Zielbefehls mit den niederwertigen 8 Bits des Registers 1. Dies bietet den Effekt der Selbstmodifikation, obwohl der eigentliche Befehl im Lager wird nicht verändert.

Bewerbung in Nieder- und Hochsprachen

Die Selbstmodifikation kann je nach Programmiersprache und ihrer Unterstützung für Zeiger und/oder Zugriff auf dynamische Compiler- oder Interpreter-„Engines“ auf verschiedene Weise erreicht werden:

  • Überlagerung bestehender Befehle (oder Teile von Befehlen wie Opcode, Register, Flags oder Adresse) oder
  • direkte Erstellung ganzer Anweisungen oder Befehlsfolgen im Speicher
  • Erstellen oder Ändern von Quellcode- Anweisungen gefolgt von einem 'Mini-Compile' oder einer dynamischen Interpretation (siehe eval- Anweisung)
  • ein ganzes Programm dynamisch erstellen und dann ausführen

Assemblersprache

Selbstmodifizierender Code ist bei Verwendung von Assemblersprache recht einfach zu implementieren . Befehle können dynamisch im Speicher erzeugt werden (oder sonst über existierenden Code im nicht geschützten Programmspeicher gelegt werden), in einer Sequenz, die derjenigen entspricht, die ein Standard-Compiler als Objektcode erzeugen kann . Bei modernen Prozessoren kann es zu unbeabsichtigten Nebeneffekten auf den CPU-Cache kommen , die beachtet werden müssen. Die Methode wurde häufig zum Testen von "Erstzeit"-Bedingungen verwendet, wie in diesem entsprechend kommentierten IBM/360- Assembler- Beispiel. Es verwendet die Befehlsüberlagerung, um die Befehlspfadlänge um (N × 1) – 1 zu reduzieren, wobei N die Anzahl der Datensätze in der Datei ist (–1 ist der Overhead zum Ausführen der Überlagerung).

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
      ...

Alternativer Code könnte das Testen eines "Flags" jedes Mal beinhalten. Die unbedingte Verzweigung ist etwas schneller als ein Vergleichsbefehl und reduziert auch die Gesamtpfadlänge. In späteren Betriebssystemen für Programme, die sich in einem geschützten Speicher befinden , konnte diese Technik nicht verwendet werden, und daher würde stattdessen das Ändern des Zeigers auf die Unterroutine verwendet. Der Zeiger würde sich in einem dynamischen Speicher befinden und könnte nach dem ersten Durchlauf beliebig geändert werden, um das OPEN zu umgehen (wenn man zuerst einen Zeiger laden müsste anstelle einer direkten Verzweigung und Verknüpfung zum Unterprogramm würde die Pfadlänge um N Anweisungen erhöht – aber es würde eine entsprechende Reduktion von N für die nicht mehr benötigte unbedingte Verzweigung).

Unten ist ein Beispiel in der Assemblersprache Zilog Z80 . Der Code inkrementiert Register "B" im Bereich [0,5]. Die Vergleichsanweisung "CP" wird bei jeder Schleife modifiziert.

;======================================================================
ORG 0H
CALL FUNC00
HALT
;======================================================================
FUNC00:
LD A,6
LD HL,label01+1
LD B,(HL)
label00:
INC B
LD (HL),B
label01:
CP $0
JP NZ,label00
RET
;======================================================================

Selbstmodifizierender Code wird manchmal verwendet, um Einschränkungen im Befehlssatz einer Maschine zu überwinden. Beispielsweise kann man im Intel 8080- Befehlssatz kein Byte von einem Eingangsport eingeben, der in einem Register spezifiziert ist. Der Eingangsport ist im Befehl selbst als zweites Byte eines Zwei-Byte-Befehls statisch codiert. Unter Verwendung von selbstmodifizierendem Code ist es möglich, den Inhalt eines Registers im zweiten Byte des Befehls zu speichern und dann den modifizierten Befehl auszuführen, um den gewünschten Effekt zu erzielen.

Hochsprachen

Einige kompilierte Sprachen erlauben explizit selbstmodifizierenden Code. Zum Beispiel kann das ALTER-Verb in COBOL als ein Verzweigungsbefehl implementiert werden, der während der Ausführung modifiziert wird. Einige Batch- Programmiertechniken beinhalten die Verwendung von selbstmodifizierendem Code. Clipper und SPITBOL bieten auch Möglichkeiten zur expliziten Selbstmodifikation. Der Algol-Compiler auf B6700-Systemen bot eine Schnittstelle zum Betriebssystem, wodurch ausführender Code einen Textstring oder eine benannte Disc-Datei an den Algol-Compiler übergeben und dann die neue Version einer Prozedur aufrufen konnte.

Bei interpretierten Sprachen ist der "Maschinencode" der Quelltext und kann spontan bearbeitet werden: In SNOBOL sind die ausgeführten Quellanweisungen Elemente eines Textarrays. Andere Sprachen wie Perl und Python ermöglichen es Programmen, zur Laufzeit neuen Code zu erstellen und ihn mit einer eval- Funktion auszuführen , lassen jedoch nicht zu, dass vorhandener Code mutiert wird. Die Illusion der Modifikation (auch wenn kein Maschinencode wirklich überschrieben wird) wird durch das Ändern von Funktionszeigern erreicht, wie in diesem JavaScript-Beispiel:

    var f = function (x) {return x + 1};

    // assign a new definition to f:
    f = new Function('x', 'return x + 2');

Lisp-Makros ermöglichen auch die Generierung von Laufzeitcode, ohne einen String mit Programmcode zu analysieren.

Die Programmiersprache Push ist ein genetisches Programmiersystem , das explizit für die Erstellung selbstmodifizierender Programme entwickelt wurde. Obwohl es keine Hochsprache ist, ist es nicht so niedrig wie die Assemblersprache.

Compound-Modifikation

Vor dem Aufkommen mehrerer Fenster bieten Befehlszeilensysteme möglicherweise ein Menüsystem, das die Modifikation eines laufenden Befehlsskripts beinhaltet. Angenommen, eine DOS-Skript- (oder "Batch-") Datei Menu.bat enthält Folgendes:

   :StartAfresh                <-A line starting with a colon marks a label.
   ShowMenu.exe

Beim Starten von Menu.bat über die Befehlszeile präsentiert ShowMenu ein Bildschirmmenü mit möglichen Hilfeinformationen, Verwendungsbeispielen usw. Schließlich trifft der Benutzer eine Auswahl, die die Ausführung eines Befehls mit einem Namen erfordert : ShowMenu wird beendet, nachdem die Datei Menu.bat neu geschrieben wurde, um zu enthalten

   :StartAfresh
   ShowMenu.exe
   CALL C:\Commands\somename.bat
   GOTO StartAfresh

Da der DOS-Befehlsinterpreter weder eine Skriptdatei kompiliert und dann ausführt, noch die gesamte Datei in den Speicher einliest, bevor er mit der Ausführung beginnt, noch sich auf den Inhalt eines Datensatzpuffers verlässt, findet der Befehlsinterpreter beim Beenden von ShowMenu ein neues auszuführenden Befehl (es ist der Aufruf der Skriptdatei somename , in einem Verzeichnis und über ein ShowMenu bekanntes Protokoll), und nachdem dieser Befehl abgeschlossen ist, kehrt er zum Anfang der Skriptdatei zurück und reaktiviert ShowMenu für die nächste Auswahl . Sollte die Menüoption Beenden lauten, wird die Datei in ihren ursprünglichen Zustand zurückgeschrieben. Obwohl dieser Startzustand für das Label keine Verwendung hat, wird er oder eine entsprechende Textmenge benötigt, da der DOS-Befehlsinterpreter die Byte-Position des nächsten Befehls abruft, wenn er den nächsten Befehl starten soll, also die neu geschriebene Datei muss die Ausrichtung beibehalten, damit der Startpunkt des nächsten Befehls tatsächlich der Anfang des nächsten Befehls ist.

Abgesehen von der Bequemlichkeit eines Menüsystems (und möglichen Zusatzfunktionen) bedeutet dieses Schema, dass sich das ShowMenu.exe-System nicht im Speicher befindet, wenn der ausgewählte Befehl aktiviert wird, ein wesentlicher Vorteil bei begrenztem Speicher.

Steuertabellen

Steuertabelle Dolmetscher können in Betracht gezogen werden , in einem Sinne sein, ‚Selbst modifiziert‘ durch Datenwerte aus den Tabelleneinträgen extrahierten (anstatt speziell Hand codierte in bedingten Anweisungen der Form „WENN inputx =‚yyy‘“).

Kanalprogramme

Einige IBM- Zugriffsverfahren verwendeten traditionell selbstmodifizierende Kanalprogramme , bei denen ein Wert, wie beispielsweise eine Plattenadresse, in einen Bereich gelesen wird, auf den ein Kanalprogramm verweist, wo er von einem späteren Kanalbefehl verwendet wird, um auf die Platte zuzugreifen.

Geschichte

Der im Januar 1948 demonstrierte IBM SSEC hatte die Fähigkeit, seine Anweisungen zu ändern oder sie auf andere Weise genau wie Daten zu behandeln. In der Praxis wurde die Fähigkeit jedoch selten genutzt. In den frühen Tagen der Computer wurde oft selbstmodifizierender Code verwendet, um die Nutzung von begrenztem Speicher zu reduzieren oder die Leistung zu verbessern oder beides. Es wurde manchmal auch verwendet, um Subroutinenaufrufe und -rückläufe zu implementieren, wenn der Befehlssatz nur einfache Verzweigungs- oder Überspringbefehle zum Variieren des Kontrollflusses vorsah . Diese Verwendung ist in bestimmten Ultra- RISC- Architekturen zumindest theoretisch immer noch relevant ; siehe zum Beispiel einen Befehlssatz-Computer . Die MIX- Architektur von Donald Knuth verwendet auch selbstmodifizierenden Code, um Subroutinenaufrufe zu implementieren.

Verwendungszweck

Selbstmodifizierender Code kann für verschiedene Zwecke verwendet werden:

  • Halbautomatische Optimierung einer zustandsabhängigen Schleife.
  • Laufzeit - Code - Generierung oder Spezialisierung eines Algorithmus in der Laufzeit oder Ladezeit (die populär ist, beispielsweise im Bereich der Echtzeit - Grafik), wie eine allgemeine Sortieren Utility - Vorbereitung Code den Schlüsselvergleich in einem bestimmten beschrieben auszuführen Aufruf.
  • Ändern des Inline- Zustands eines Objekts oder Simulieren der High-Level-Konstruktion von Verschlüssen .
  • Patchen von Subroutinen- ( Zeiger- )Adressaufrufen, normalerweise wie beim Laden/Initialisierung dynamischer Bibliotheken durchgeführt , oder sonst bei jedem Aufruf, Patchen der internen Referenzen der Subroutine auf ihre Parameter, um ihre tatsächlichen Adressen zu verwenden. (dh indirekte 'Selbstmodifikation').
  • Evolutionäre Computersysteme wie Neuroevolution , genetische Programmierung und andere evolutionäre Algorithmen .
  • Verstecken von Code, um Reverse Engineering zu verhindern (durch Verwendung eines Disassemblers oder Debuggers ) oder um die Erkennung durch Viren-/Spyware-Scansoftware und dergleichen zu umgehen.
  • Füllung 100% der Speicher (in einigen Architekturen) mit einem Roll Muster von sich wiederholenden Opcodes , alle Programme und Daten zu löschen oder Burn-in - Hardware.
  • Komprimierender Code, der zur Laufzeit dekomprimiert und ausgeführt werden soll, zB wenn der Arbeitsspeicher oder der Speicherplatz begrenzt sind.
  • Einige sehr begrenzte Befehlssätze lassen keine andere Wahl, als selbstmodifizierenden Code zu verwenden, um bestimmte Funktionen auszuführen. Zum Beispiel kann ein Computer mit einem Befehlssatz (OISC), der nur die Subtrahieren-und-Verzweigen-wenn-Negativ-"Anweisung" verwendet, keine indirekte Kopie ausführen (so etwas wie das Äquivalent von "*a = **b" im C language ) ohne selbstmodifizierenden Code zu verwenden.
  • Booten . Frühe Mikrocomputer verwendeten oft selbstmodifizierenden Code in ihren Bootloadern. Da der Bootloader bei jedem Einschalten über die Frontplatte eingetippt wurde, spielte es keine Rolle, ob sich der Bootloader selbst veränderte. Allerdings sind auch heute noch viele Bootstrap-Loader selbstverlagernd und einige sogar selbstmodifizierend.
  • Änderungshinweise zur Fehlertoleranz.

Optimieren einer zustandsabhängigen Schleife

Beispiel für Pseudocode :

repeat N times {
    if STATE is 1
        increase A by one
    else
        decrease A by one
    do something with A
}

Selbstmodifizierender Code wäre in diesem Fall einfach eine Frage des Umschreibens der Schleife wie folgt:

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
    }
}

Beachten Sie, dass die Ersetzung des Opcodes mit zwei Zuständen leicht als 'xor var at address with the value "opcodeOf(Inc) xor opcodeOf(dec)"' geschrieben werden kann.

Die Wahl dieser Lösung muss vom Wert von N und der Häufigkeit der Zustandsänderung abhängen .

Spezialisierung

Angenommen, für einen großen Datensatz soll eine Reihe von Statistiken wie Durchschnitt, Extrema, Ort der Extrema, Standardabweichung usw. berechnet werden. In einer allgemeinen Situation kann es eine Option geben, den Daten Gewichtungen zuzuordnen, sodass jedes x i mit aw i verknüpft ist und anstatt das Vorhandensein von Gewichtungen bei jedem Indexwert zu prüfen, könnte es zwei Versionen der Berechnung geben, eine zur Verwendung mit Gewichten und einer nicht, mit einem Test am Anfang. Betrachten Sie nun eine weitere Option, bei der jedem Wert ein Boolean zugeordnet sein kann, um anzuzeigen, ob dieser Wert übersprungen werden soll oder nicht. Dies könnte gehandhabt werden, indem vier Codechargen erzeugt werden, eine für jede Permutations- und Code-Bloat-Ergebnisse. Alternativ könnten das Gewichtungs- und das Sprung-Array auf Kosten der Verarbeitung zu einem temporären Array (mit Null-Gewichtungen für zu überspringende Werte) zusammengeführt werden, und es gibt immer noch Aufblähungen. Bei Code-Modifikationen könnte jedoch der Vorlage zum Berechnen der Statistik nach Bedarf der Code zum Überspringen unerwünschter Werte und zum Anwenden von Gewichtungen hinzugefügt werden. Es würde kein wiederholtes Testen der Optionen geben, und auf das Datenarray würde einmal zugegriffen, ebenso wie auf die Gewichtungs- und Skip-Arrays, falls beteiligt.

Als Tarnung verwenden

Selbstmodifizierender Code wurde verwendet, um Kopierschutzanweisungen in festplattenbasierten Programmen der 1980er Jahre für Plattformen wie IBM PC und Apple II zu verbergen . Auf einem IBM-PC (oder einem kompatiblen PC ) würde der Zugriffsbefehl für das Diskettenlaufwerk beispielsweiseint 0x13 nicht im Abbild des ausführbaren Programms erscheinen, sondern in das Speicherabbild des ausführbaren Programms geschrieben werden, nachdem das Programm mit der Ausführung begonnen hat.

Selbstmodifizierender Code wird manchmal auch von Programmen verwendet, die ihre Anwesenheit nicht preisgeben möchten, wie z. B. Computerviren und einige Shellcodes . Viren und Shellcodes, die selbstmodifizierenden Code verwenden, tun dies meist in Kombination mit polymorphem Code . Das Modifizieren eines laufenden Codes wird auch bei bestimmten Angriffen verwendet, z. B. bei Pufferüberläufen .

Selbstreferentielle maschinelle Lernsysteme

Herkömmliche maschinelle Lernsysteme haben einen festen, vorprogrammierten Lernalgorithmus , um ihre Parameter anzupassen . Seit den 1980er Jahren hat Jürgen Schmidhuber jedoch mehrere selbstmodifizierende Systeme mit der Fähigkeit veröffentlicht, ihren eigenen Lernalgorithmus zu ändern. Sie vermeiden die Gefahr katastrophaler Selbstumschreibungen, indem sie sicherstellen, dass Selbstmodifikationen nur dann überleben, wenn sie gemäß einer vom Benutzer vorgegebenen Fitness- , Fehler- oder Belohnungsfunktion nützlich sind .

Betriebssysteme

Aufgrund der Sicherheitsauswirkungen von selbstmodifizierendem Code achten alle wichtigen Betriebssysteme darauf, solche Schwachstellen zu beseitigen, sobald sie bekannt werden. Die Sorge besteht in der Regel nicht darin, dass sich Programme absichtlich selbst modifizieren, sondern dass sie durch einen Exploit böswillig verändert werden könnten .

Als Folge der Probleme, die durch diese Exploits verursacht werden können, wurde eine Betriebssystemfunktion namens W^X (für "write xor execute") entwickelt, die einem Programm verbietet, jede Speicherseite sowohl beschreibbar als auch ausführbar zu machen. Einige Systeme verhindern, dass eine beschreibbare Seite jemals so geändert wird, dass sie ausführbar ist, selbst wenn die Schreibberechtigung entfernt wird. Andere Systeme stellen eine Art " Hintertür " bereit , die es mehreren Abbildungen einer Speicherseite ermöglicht, unterschiedliche Berechtigungen zu haben. Eine relativ portable Möglichkeit, W^X zu umgehen, besteht darin, eine Datei mit allen Berechtigungen zu erstellen und die Datei dann zweimal in den Arbeitsspeicher abzubilden. Unter Linux kann man ein undokumentiertes SysV Shared Memory Flag verwenden, um ausführbaren Shared Memory zu erhalten, ohne eine Datei erstellen zu müssen.

Unabhängig davon können Programme auf der Metaebene ihr eigenes Verhalten ändern, indem sie anderswo gespeicherte Daten ändern (siehe Metaprogrammierung ) oder durch die Verwendung von Polymorphismus .

Zusammenspiel von Cache und selbstmodifizierendem Code

Auf Architekturen ohne gekoppelten Daten- und Befehls-Cache (einige ARM- und MIPS-Kerne) muss die Cache-Synchronisierung explizit durch den modifizierenden Code durchgeführt werden (Daten-Cache leeren und Befehls-Cache für den modifizierten Speicherbereich ungültig machen).

In einigen Fällen werden kurze Abschnitte von selbstmodifizierendem Code auf modernen Prozessoren langsamer ausgeführt. Dies liegt daran, dass ein moderner Prozessor normalerweise versucht, Codeblöcke in seinem Cache-Speicher zu behalten. Jedes Mal, wenn das Programm einen Teil von sich selbst neu schreibt, muss der neu geschriebene Teil erneut in den Cache geladen werden, was zu einer leichten Verzögerung führt, wenn das modifizierte Codelet dieselbe Cache-Zeile mit dem modifizierenden Code teilt, wie es der Fall ist, wenn der modifizierte Speicher Adresse befindet sich innerhalb weniger Bytes zu der des ändernden Codes.

Das Problem der Cache-Ungültigkeitserklärung bei modernen Prozessoren bedeutet normalerweise, dass selbstmodifizierender Code nur dann noch schneller wäre, wenn die Änderung selten auftritt, beispielsweise im Fall eines Zustandswechsels innerhalb einer inneren Schleife.

Die meisten modernen Prozessoren laden den Maschinencode, bevor sie ihn ausführen. Das heißt, wenn ein Befehl geändert wird, der sich zu nahe am Befehlszeiger befindet, bemerkt der Prozessor es nicht, sondern führt den Code so aus, wie er vor der Änderung war. Siehe Prefetch-Eingabewarteschlange (PIQ). PC-Prozessoren müssen aus Gründen der Abwärtskompatibilität mit selbstmodifizierendem Code korrekt umgehen, aber sie sind dabei alles andere als effizient.

Massalins Synthesekern

Die Synthese - Kernel in präsentierte alexia massalin ‚s Ph.D. thesis ist ein winziger Unix- Kernel, der einen strukturierten oder sogar objektorientierten Ansatz für selbstmodifizierenden Code verfolgt, bei dem Code für einzelne Quajekte wie Dateihandles erstellt wird. Das Generieren von Code für bestimmte Aufgaben ermöglicht es dem Synthesis-Kernel (wie es ein JIT-Interpreter tun könnte) eine Reihe von Optimierungen anzuwenden, wie beispielsweise konstante Faltung oder die Eliminierung von gemeinsamen Unterausdrücken .

Der Synthesis-Kernel war sehr schnell, wurde aber komplett in Assembler geschrieben. Der daraus resultierende Mangel an Portabilität hat verhindert, dass die Optimierungsideen von Massalin von irgendeinem Produktionskernel übernommen werden. Die Struktur der Techniken legt jedoch nahe, dass sie von einer höheren Sprache erfasst werden könnten , wenn auch eine komplexere als bestehende Sprachen mittlerer Stufe. Eine solche Sprache und ein solcher Compiler könnten die Entwicklung schnellerer Betriebssysteme und Anwendungen ermöglichen.

Paul Haeberli und Bruce Karsh haben sich gegen die "Marginalisierung" von selbstmodifizierendem Code und die Optimierung im Allgemeinen zugunsten geringerer Entwicklungskosten ausgesprochen.

Vorteile

Nachteile

Selbstmodifizierender Code ist schwieriger zu lesen und zu warten, da die Anweisungen in der Quellprogrammauflistung nicht unbedingt die Anweisungen sind, die ausgeführt werden. Selbstmodifikation, die aus der Ersetzung von Funktionszeigern besteht, ist möglicherweise nicht so kryptisch, wenn klar ist, dass die Namen der aufzurufenden Funktionen Platzhalter für später zu identifizierende Funktionen sind.

Selbstmodifizierender Code kann in Code umgeschrieben werden, der ein Flag testet und basierend auf dem Ergebnis des Tests zu alternativen Sequenzen verzweigt, aber selbstmodifizierender Code läuft normalerweise schneller.

Auf modernen Prozessoren mit einer Befehlspipeline kann Code, der sich häufig ändert, langsamer ausgeführt werden, wenn er Befehle modifiziert, die der Prozessor bereits aus dem Speicher in die Pipeline gelesen hat. Bei einigen dieser Prozessoren besteht der einzige Weg, um sicherzustellen, dass die modifizierten Befehle korrekt ausgeführt werden, darin, die Pipeline zu leeren und viele Befehle erneut zu lesen.

Selbstmodifizierender Code kann in einigen Umgebungen überhaupt nicht verwendet werden, z. B. in den folgenden:

  • Anwendungssoftware, die unter einem Betriebssystem mit strenger W^X-Sicherheit läuft, kann keine Anweisungen auf Seiten ausführen, auf die sie schreiben darf – nur das Betriebssystem darf sowohl Anweisungen in den Speicher schreiben als auch diese Anweisungen später ausführen.
  • Viele Mikrocontroller der Harvard-Architektur können keine Anweisungen im Lese-Schreib-Speicher ausführen, sondern nur Anweisungen im Speicher, in den sie nicht schreiben können, ROM oder nicht selbstprogrammierbarer Flash-Speicher .
  • Eine Multithread-Anwendung kann mehrere Threads haben, die denselben Abschnitt des selbstmodifizierenden Codes ausführen, was möglicherweise zu Rechenfehlern und Anwendungsfehlern führt.

Siehe auch

Verweise

Externe Links