Befehle in Assemblersprache. Die Struktur des Befehls in der Assemblersprachenprogrammierung auf der Ebene Kurz über die Struktur der Sprache

Anweisungsstruktur in Assemblersprache Das Programmieren auf der Ebene von Maschinenanweisungen ist die Mindestebene, auf der Computerprogrammierung möglich ist. Das System der Maschinenanweisungen sollte ausreichen, um die erforderlichen Aktionen durch Ausgabe von Anweisungen an die Maschinenhardware umzusetzen. Jeder Maschinenbefehl besteht aus zwei Teilen: einem Operationsteil, der definiert, „was zu tun ist“, und einem Operanden, der Verarbeitungsobjekte definiert, das heißt, „was zu tun ist“. Die in Assemblersprache geschriebene Maschinenanweisung des Mikroprozessors ist eine einzelne Zeile mit der folgenden Form: Label-Anweisung/Direktive Operand(en); Kommentare Label, Befehl/Anweisung und Operand werden durch mindestens ein Leerzeichen oder Tabulatorzeichen getrennt. Die Anweisungsoperanden werden durch Kommas getrennt.

Struktur eines Assemblersprachbefehls Ein Assemblersprachbefehl teilt dem Compiler mit, welche Aktion der Mikroprozessor ausführen soll. Assembler-Direktiven sind im Programmtext angegebene Parameter, die den Assembler-Prozess oder die Eigenschaften der Ausgabedatei beeinflussen. Der Operand gibt den Anfangswert der Daten (im Datensegment) oder der Elemente an, auf die der Befehl einwirken soll (im Codesegment). Eine Anweisung kann einen oder zwei Operanden oder keine Operanden haben. Die Anzahl der Operanden wird implizit durch den Befehlscode angegeben. Wenn der Befehl oder die Anweisung in der nächsten Zeile fortgesetzt werden muss, wird der umgekehrte Schrägstrich verwendet: "" . Standardmäßig unterscheidet der Assembler in Befehlen und Direktiven nicht zwischen Groß- und Kleinschreibung. Beispiele für Anweisungen und Befehle Count db 1 ; Name, Direktive, ein Operand mov eax, 0 ; Befehl, zwei Operanden

Bezeichner sind Folgen gültiger Zeichen, die zur Bezeichnung von Variablennamen und Bezeichnungsnamen verwendet werden. Die Kennung kann aus einem oder mehreren der folgenden Zeichen bestehen: alle Buchstaben des lateinischen Alphabets; Zahlen von 0 bis 9; Sonderzeichen: _, @, $, ? . Als erstes Zeichen des Labels kann ein Punkt verwendet werden. Reservierte Assemblernamen (Direktiven, Operatoren, Befehlsnamen) können nicht als Bezeichner verwendet werden. Das erste Zeichen der Kennung muss ein Buchstabe oder ein Sonderzeichen sein. Die maximale Bezeichnerlänge beträgt 255 Zeichen, aber der Übersetzer akzeptiert die ersten 32 Zeichen und ignoriert den Rest. Alle Labels, die in eine Zeile geschrieben werden, die keine Assembler-Direktive enthält, müssen mit einem Doppelpunkt ":" enden. Label, Befehl (Direktive) und Operand müssen nicht an einer bestimmten Position im String beginnen. Es wird empfohlen, sie für eine bessere Lesbarkeit des Programms in eine Spalte zu schreiben.

Labels Alle Labels, die in eine Zeile geschrieben werden, die keine Assembler-Direktive enthält, müssen mit einem Doppelpunkt ":" enden. Label, Befehl (Direktive) und Operand müssen nicht an einer bestimmten Position im String beginnen. Es wird empfohlen, sie für eine bessere Lesbarkeit des Programms in eine Spalte zu schreiben.

Kommentare Die Verwendung von Kommentaren in einem Programm verbessert dessen Übersichtlichkeit, insbesondere wenn der Zweck einer Reihe von Anweisungen unklar ist. Kommentare beginnen in jeder Zeile eines Quellmoduls mit einem Semikolon (;). Alle Zeichen rechts von "; ' am Ende der Zeile stehen Kommentare. Der Kommentar kann alle druckbaren Zeichen enthalten, einschließlich „Leerzeichen“. Der Kommentar kann sich über die gesamte Zeile erstrecken oder dem Befehl in derselben Zeile folgen.

Struktur eines Assemblersprachenprogramms Ein Assemblersprachenprogramm kann aus mehreren Teilen bestehen, die Module genannt werden, von denen jeder ein oder mehrere Daten-, Stack- und Codesegmente definieren kann. Jedes vollständige Assemblersprachenprogramm muss ein Haupt- oder Hauptmodul enthalten, von dem aus seine Ausführung beginnt. Ein Modul kann Programm-, Daten- und Stapelsegmente enthalten, die mit den entsprechenden Direktiven deklariert sind.

Speichermodelle Bevor Sie Segmente deklarieren, müssen Sie das Speichermodell mit einer Direktive angeben. Modifizierer MODEL Speichermodell, Aufrufkonvention, Betriebssystemtyp, Stapelparameter Grundlegende Speichermodelle in Assemblersprache: Speichermodell Codeadressierung Datenadressierung Betriebssystem Code- und Datenverschachtelung TINY NEAR MS-DOS Gültig SMALL NEAR MS-DOS, Windows Nein MEDIUM FAR NEAR NEAR MS-DOS, Windows Nein COMPACT NEAR FAR MS-DOS, Windows Nein LARGE FAR MS-DOS, Windows Nein HUGE FAR MS-DOS, Windows Nein NEAR Windows 2000, Windows XP, Windows Valid FLAT NEAR NT,

Speichermodelle Das winzige Modell funktioniert nur in 16-Bit-MS-DOS-Anwendungen. In diesem Modell befinden sich alle Daten und Codes in einem physischen Segment. Die Größe der Programmdatei überschreitet in diesem Fall 64 KB nicht. Das kleine Modell unterstützt ein Codesegment und ein Datensegment. Daten und Code werden bei Verwendung dieses Modells als near (near) adressiert. Das mittlere Modell unterstützt mehrere Codesegmente und ein Datensegment, wobei alle Links in den Codesegmenten standardmäßig als weit entfernt und Links im Datensegment als nah (near) gelten. Das kompakte Modell unterstützt mehrere Datensegmente, die die Ferndatenadressierung (far) verwenden, und ein Codesegment, das die Nahdatenadressierung (near) verwendet. Das große Modell unterstützt mehrere Codesegmente und mehrere Datensegmente. Standardmäßig werden alle Code- und Datenreferenzen weit berücksichtigt. Das riesige Modell entspricht fast dem großen Speichermodell.

Speichermodelle Das flache Modell geht von einer nicht segmentierten Programmkonfiguration aus und wird nur auf 32-Bit-Betriebssystemen verwendet. Dieses Modell ähnelt dem winzigen Modell darin, dass sich die Daten und der Code im selben 32-Bit-Segment befinden. Entwicklung eines Programms für das flache Modell vor der Richtlinie. model flat sollte eine der Anweisungen platzieren: . 386, . 486, . 586 bzw. 686. Die Wahl der Prozessorauswahldirektive bestimmt den Satz verfügbarer Befehle beim Schreiben von Programmen. Der Buchstabe p nach der Prozessorauswahlanweisung bedeutet Protected Mode of Operation. Die Daten- und Codeadressierung ist nahe, wobei alle Adressen und Zeiger 32-Bit sind.

Gedächtnismodelle. MODEL Modifikator memory_model, calling_convention, OS_type, stack_parameter Der Modifikatorparameter wird verwendet, um Segmenttypen zu definieren und kann die folgenden Werte annehmen: use 16 (Segmente des ausgewählten Modells werden als 16-Bit verwendet) use 32 (Segmente des ausgewählten Modells werden verwendet als 32-Bit). Der Parameter "calling_convention" wird verwendet, um festzulegen, wie Parameter übergeben werden, wenn eine Prozedur aus anderen Sprachen, einschließlich Hochsprachen (C++, Pascal), aufgerufen wird. Der Parameter kann folgende Werte annehmen: C, BASIC, FORTRAN, PASCAL, SYSCALL, STDCALL.

Gedächtnismodelle. Modifizierer MODEL memory_model, calling_convention, OS_type, stack_parameter Der OS_type-Parameter ist standardmäßig OS_DOS und derzeit der einzige unterstützte Wert für diesen Parameter. Der Parameter stack_param ist gesetzt auf: NEARSTACK (SS-Register ist gleich DS, Daten- und Stack-Regionen befinden sich im selben physikalischen Segment) FARSTACK (SS-Register ist nicht gleich DS, Daten- und Stack-Regionen befinden sich in unterschiedlichen physikalischen Segmenten). Der Standardwert ist NEARSTACK.

Ein Beispiel für ein „Nichtstun“-Programm. 686 P. MODELL WOHNUNG, STDCALL. DATEN. CODE START: RET END START RET - Mikroprozessorbefehl. Es sorgt für die korrekte Beendigung des Programms. Der Rest des Programms bezieht sich auf den Betrieb des Übersetzers. . 686 P - Pentium 6 (Pentium II) geschützte Modusbefehle sind erlaubt. Diese Direktive wählt den unterstützten Assembler-Befehlssatz durch Angabe des Prozessormodells aus. . MODEL FLAT, stdcall - flaches Speichermodell. Dieses Speichermodell wird im Windows-Betriebssystem verwendet. stdcall ist die zu verwendende Prozeduraufrufkonvention.

Ein Beispiel für ein „Nichtstun“-Programm. 686 P. MODELL WOHNUNG, STDCALL. DATEN. CODE START: RET ENDE START . DATA - Programmsegment, das Daten enthält. Dieses Programm verwendet den Stack nicht, also segmentieren. STAPEL fehlt. . CODE - ein Segment des Programms, das den Code enthält. START - Etikett. END START - das Ende des Programms und eine Nachricht an den Compiler, dass das Programm ab dem Label START gestartet werden muss. Jedes Programm muss eine END-Direktive enthalten, die das Ende des Quellcodes des Programms markiert. Alle Zeilen, die auf die END-Direktive folgen, werden ignoriert.Das Label nach der END-Direktive teilt dem Compiler den Namen des Hauptmoduls mit, von dem aus die Programmausführung beginnt. Wenn das Programm ein Modul enthält, kann das Label nach der END-Direktive weggelassen werden.

Assembler-Übersetzer Ein Übersetzer ist ein Programm oder eine Hardware, die ein Programm, das in einer der Programmiersprachen präsentiert wird, in ein Programm in der Zielsprache, Objektcode genannt, umwandelt. Zusätzlich zur Unterstützung von Mnemoniken für Maschinenbefehle hat jeder Compiler seinen eigenen Satz von Direktiven und Makros, die oft mit nichts anderem kompatibel sind. Die Haupttypen von Assembler-Übersetzern sind: MASM (Microsoft Assembler), TASM (Borland Turbo Assembler), FASM (Flat Assembler) – ein frei verteilter Multi-Pass-Assembler, geschrieben von Tomasz Gryshtar (Polnisch), NASM (Netwide Assembler) – a Der kostenlose Assembler für die Intel-x-Architektur 86 wurde von Simon Tatham mit Julian Hall erstellt und wird derzeit von einem kleinen Entwicklerteam bei Source entwickelt. Schmiede. Netz.

Src="https://present5.com/presentation/-29367016_63610977/image-15.jpg" alt="(!LANG:Programmübersetzung in Microsoft Visual Studio 2005 1) Erstellen Sie ein Projekt, indem Sie Datei->Neu->Projekt auswählen Menü Und"> Трансляция программы в Microsoft Visual Studio 2005 1) Создать проект, выбрав меню File->New->Project и указав имя проекта (hello. prj) и тип проекта: Win 32 Project. В дополнительных опциях мастера проекта указать “Empty Project”.!}

Src="https://present5.com/presentation/-29367016_63610977/image-16.jpg" alt="(!LANG:Programmübersetzung in Microsoft Visual Studio 2005 2) Im Projektbaum (Ansicht->Solution Explorer) hinzufügen"> Трансляция программы в Microsoft Visual Studio 2005 2) В дереве проекта (View->Solution Explorer) добавить файл, в котором будет содержаться текст программы: Source. Files->Add->New. Item.!}

Übersetzung des Programms in Microsoft Visual Studio 2005 3) Wählen Sie den Dateityp Code C++, aber geben Sie den Namen mit der Erweiterung an. asm:

Übersetzung des Programms in Microsoft Visual Studio 2005 5) Compiler-Optionen setzen. Wählen Sie auf der rechten Schaltfläche im Projektdateimenü Custom Build Rules…

Übersetzung des Programms in Microsoft Visual Studio 2005 und wählen Sie im angezeigten Fenster Microsoft Macro Assembler.

Übersetzung des Programms in Microsoft Visual Studio 2005 Überprüfen Sie mit der rechten Maustaste in der Datei hallo. asm des Projektbaums aus dem Menü Eigenschaften und wählen Sie Allgemein->Tool: Microsoft Macro Assembler.

Src="https://present5.com/presentation/-29367016_63610977/image-22.jpg" alt="(!LANG:Programmübersetzung in Microsoft Visual Studio 2005 6) Kompilieren Sie die Datei, indem Sie Build->Build hello.prj auswählen ."> Трансляция программы в Microsoft Visual Studio 2005 6) Откомпилировать файл, выбрав Build->Build hello. prj. 7) Запустить программу, нажав F 5 или выбрав меню Debug->Start Debugging.!}

Programmierung im Betriebssystem Windows Die Programmierung im Betriebssystem Windows basiert auf der Verwendung von API-Funktionen (Application Program Interface, d. h. Software-Anwendungsschnittstelle). Ihre Zahl erreicht 2000. Das Programm für Windows besteht größtenteils aus solchen Aufrufen. Alle Interaktionen mit externen Geräten und Ressourcen des Betriebssystems erfolgen in der Regel über solche Funktionen. Das Windows-Betriebssystem verwendet ein flaches Speichermodell. Die Adresse jeder Speicherstelle wird durch den Inhalt eines 32-Bit-Registers bestimmt. Es gibt 3 Arten von Programmstrukturen für Windows: Dialog (das Hauptfenster ist ein Dialog), Konsolen- oder fensterlose Struktur, klassische Struktur (Fenster, Rahmen).

Aufrufen von Windows-API-Funktionen In der Hilfedatei wird jede API-Funktion als Typ Funktionsname (FA 1, FA 2, FA 3) dargestellt Typ – Typ des Rückgabewerts; FAX – Liste der formalen Argumente in ihrer Reihenfolge, zum Beispiel int Nachricht. Box (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); Diese Funktion zeigt ein Fenster mit einer Nachricht und einer oder mehreren Exit-Schaltflächen an. Bedeutung der Parameter: h. Wnd - Handle auf das Fenster, in dem das Nachrichtenfenster erscheinen wird, lp. Text - der Text, der im Fenster erscheint, lp. Beschriftung - Text im Fenstertitel, u. Typ - Fenstertyp, insbesondere können Sie die Anzahl der Exit-Schaltflächen angeben.

Aufrufen von Windows-API-Funktionen int Message. Box (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); Fast alle API-Funktionsparameter sind tatsächlich 32-Bit-Ganzzahlen: HWND ist eine 32-Bit-Ganzzahl, LPCTSTR ist ein 32-Bit-String-Zeiger, UINT ist eine 32-Bit-Ganzzahl. Das Suffix "A" wird häufig an den Namen von Funktionen angehängt, um zu neueren Versionen von Funktionen zu springen.

Aufrufen von Windows-API-Funktionen int Message. Box (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); Wenn Sie MASM verwenden, müssen Sie am Ende des Namens @N N hinzufügen – die Anzahl der Bytes, die die übergebenen Argumente auf dem Stapel belegen. Für Win 32-API-Funktionen kann diese Zahl als die Anzahl der Argumente n mal 4 (Bytes in jedem Argument) definiert werden: N=4*n. Um eine Funktion aufzurufen, wird die CALL-Anweisung des Assemblers verwendet. In diesem Fall werden der Funktion alle Argumente über den Stack übergeben (PUSH-Befehl). Übergaberichtung des Arguments: LINKS NACH RECHTS – UNTEN NACH OBEN. Das Argument u wird zuerst auf den Stack geschoben. Art. Der Aufruf der angegebenen Funktion sieht folgendermaßen aus: CALL Message. Kasten. [E-Mail geschützt]

Aufrufen von Windows-API-Funktionen int Message. Box (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); Das Ergebnis der Ausführung einer API-Funktion ist normalerweise eine Ganzzahl, die im EAX-Register zurückgegeben wird. Die OFFSET-Direktive ist ein "Segment-Offset" oder, in Hochsprache ausgedrückt, ein "Zeiger" auf den Beginn einer Zeichenkette. Die Direktive EQU definiert wie #define in C eine Konstante. Die Direktive EXTERN teilt dem Compiler mit, dass eine Funktion oder ein Bezeichner außerhalb des Moduls liegt.

Ein Beispiel für das Programm "Hallo alle zusammen!" . 686 P. MODELL WOHNUNG, STDCALL. STACK 4096. DATA MB_OK EQU 0 STR 1 DB "Mein erstes Programm", 0 STR 2 DB "Hallo zusammen!", 0 HW DD ? EXTERNE Nachricht. Kasten. [E-Mail geschützt]: IN DER NÄHE VON. CODE START: PUSH MB_OK PUSH OFFSET STR 1 PUSH OFFSET STR 2 PUSH HW CALL Nachricht. Kasten. [E-Mail geschützt] ZURÜCK ENDE START

Die INVOKE-Direktive Der MASM-Sprachübersetzer ermöglicht es auch, den Funktionsaufruf mit einem Makrotool zu vereinfachen - der INVOKE-Direktive: INVOKE-Funktion, Parameter1, Parameter2, ... Es besteht keine Notwendigkeit, @16 zum Funktionsaufruf hinzuzufügen; die Parameter werden genau in der Reihenfolge geschrieben, in der sie in der Funktionsbeschreibung angegeben sind. Übersetzer-Makros schieben Parameter auf den Stack. Um die INVOKE-Direktive verwenden zu können, benötigen Sie eine Beschreibung des Funktionsprototyps mit der PROTO-Direktive in der Form: Nachricht. Kasten. A PROTO: DWORD, : DWORD

Befehle der Assemblersprache (Vorlesung)

LEHRPLAN

1. Hauptgruppen von Operationen.

Pentium.

1. Hauptgruppen von Operationen

Mikroprozessoren führen eine Reihe von Anweisungen aus, die die folgenden Hauptgruppen von Operationen implementieren:

Speditionsgeschäfte,

Rechenoperationen,

logische Operationen,

Schichtbetrieb,

Vergleichs- und Testbetrieb,

Bitoperationen,

Programmverwaltungsoperationen;

Prozessorsteuerungsoperationen.

2. Mnemocodes von Prozessorbefehlen Pentium

Bei der Beschreibung von Befehlen werden meist deren mnemotechnische Bezeichnungen (mnemonische Codes) verwendet, die bei der Programmierung in Assembler zur Spezifizierung des Befehls dienen. Für verschiedene Versionen des Assemblers können sich die mnemonischen Codes einiger Befehle unterscheiden. Beispielsweise wird für einen Befehl zum Aufrufen einer Subroutine der mnemonische Code verwendetANRUF oder JSR ("Springen zu Subroutine“). Die mnemonischen Codes der meisten Befehle für die Haupttypen von Mikroprozessoren sind jedoch gleich oder unterscheiden sich geringfügig, da sie Abkürzungen der entsprechenden englischen Wörter sind, die die auszuführende Operation definieren. Betrachten Sie Befehlsmnemoniken, die für Prozessoren übernommen wurden Pentium.

Befehle weiterleiten. Der Hauptbefehl dieser Gruppe ist der BefehlBEWEGUNG , die eine Datenübertragung zwischen zwei Registern oder zwischen einem Register und einer Speicherzelle bereitstellt. Einige Mikroprozessoren implementieren eine Übertragung zwischen zwei Speicherzellen sowie eine Gruppenübertragung der Inhalte mehrerer Register aus dem Speicher. Zum Beispiel Mikroprozessoren der 68er-Familie Motorolaxxx den Befehl ausführenBEWEGUNG , der die Übertragung von einer Speicherzelle zur anderen bereitstellt, und dem BefehlBEWEGUNG , das den Inhalt eines bestimmten Satzes von Registern (bis zu 16 Register) in den Speicher schreibt oder aus dem Speicher lädt. BefehlXCHG führt einen gegenseitigen Austausch der Inhalte zweier Prozessorregister oder eines Registers und einer Speicherzelle durch.

Befehle eingeben IN und Ausgabe AUS die Übertragung von Daten vom Prozessorregister an ein externes Gerät oder den Empfang von Daten von einem externen Gerät an das Register implementieren. Diese Befehle geben die Nummer des Schnittstellengeräts (I/O-Port) an, über das Daten übertragen werden. Beachten Sie, dass viele Mikroprozessoren keine speziellen Befehle für den Zugriff auf externe Geräte haben. In diesem Fall erfolgt die Ein- und Ausgabe von Daten im System über den BefehlBEWEGUNG , die die Adresse des erforderlichen Schnittstellengeräts angibt. Somit wird ein externes Gerät als Speicherzelle adressiert und im Adressraum ein bestimmter Abschnitt zugewiesen, in dem sich die Adressen von mit dem System verbundenen Schnittstellengeräten (Ports) befinden.

Befehle für arithmetische Operationen. Die Hauptbefehle in dieser Gruppe sind Addition, Subtraktion, Multiplikation und Division, die eine Reihe von Optionen haben. Additionsbefehle ADDIEREN und Subtraktion SUB Führen Sie entsprechende Operationen mit durchCBesitzen von zwei Registern, einem Register und einer Speicherstelle, oder Verwenden eines unmittelbaren Operanden. Mannschaften ANZEIGE C , SB B Führen Sie Addition und Subtraktion unter Berücksichtigung des Werts des Attributs durchC, gesetzt während der Bildung der Übertragung im Prozess der Durchführung der vorherigen Operation. Mit Hilfe dieser Befehle wird die sequentielle Addition von Operanden realisiert, deren Stellenzahl die Prozessorkapazität übersteigt. Befehl NEG ändert das Vorzeichen des Operanden und wandelt ihn in das Zweierkomplement um.

Multiplikations- und Divisionsoperationen können mit vorzeichenbehafteten Zahlen durchgeführt werden (Befehleich MUL, ich DIV ) oder unsigned (commands MUL, DIV ). Das Ergebnis der Operation befindet sich im Register. Beim Multiplizieren (BefehleMUL , IMUL ) ergibt ein zweistelliges Ergebnis, das zwei Register zur Unterbringung benötigt. Beim Teilen (BefehleDIV , IDIV ) als Dividende wird ein Operand mit doppelter Kapazität verwendet, in zwei Registern platziert, und als Ergebnis werden der Quotient und der Rest in zwei Register geschrieben.

Logikbefehle . Nahezu alle Mikroprozessoren führen logische Operationen UND, ODER, Exklusiv-ODER durch, die mit Befehlen auf den gleichnamigen Operandenbits ausgeführt werden UND, ODER, x ODER . Operationen werden an den Inhalten von zwei Registern, einem Register und einer Speicherstelle, oder unter Verwendung eines Direktoperanden durchgeführt. Befehl NICHT Invertiert den Wert jedes Bits des Operanden.

Schaltbefehle. Mikroprozessoren führen arithmetische, logische und zyklische Verschiebungen der adressierten Operanden um ein oder mehrere Bits durch. Der zu verschiebende Operand kann sich in einem Register oder einer Speicherstelle befinden, und die Anzahl der Schiebebits wird unter Verwendung des in der Anweisung enthaltenen Direktoperanden angegeben oder durch den Inhalt des angegebenen Registers bestimmt. Das Übergabezeichen ist in der Regel an der Durchführung der Verschiebung beteiligtCim Statusregister (SR oder EFLAGS), die das letzte Bit des Operanden enthält, der aus dem Register oder der Speicherstelle gezogen wird.

Vergleichs- und Testbefehle . Der Operandenvergleich wird normalerweise mit dem Befehl durchgeführtCMP , die die Subtraktion von Operanden mit dem Setzen der Werte der Merkmale durchführt N, Z, V, C im Statusregister entsprechend dem Ergebnis. In diesem Fall wird das Ergebnis der Subtraktion nicht gespeichert und die Werte der Operanden ändern sich nicht. Die anschließende Analyse der gewonnenen Kennwerte ermöglicht die Bestimmung des relativen Wertes (>,<, =) операндов со знаком или без знака. Использование различных способов адресации позволяет производит сравнение содержимого двух регистров, регистра и ячейки памяти, непосредственно заданного операнда с содержимым регистра или ячейки памяти.

Einige Mikroprozessoren führen einen Testbefehl aus TST , die eine Einzeloperandenvariante der Vergleichsanweisung ist. Wenn dieser Befehl ausgeführt wird, werden die Zeichen gesetzt N, Z nach Vorzeichen und Wert (gleich oder ungleich Null) des adressierten Operanden.

Anweisungen für Bitoperationen . Diese Befehle setzen den Wert des AttributsCim Statusregister entsprechend dem Wert des getesteten BitsMrd im adressierten Operanden. Bei manchen Mikroprozessoren wird entsprechend dem Testergebnis eines Bits ein Vorzeichen gesetztZ. Testbitnummernwird entweder durch den Inhalt des im Befehl angegebenen Registers oder durch einen Direktoperanden gesetzt.

Die Befehle dieser Gruppe implementieren verschiedene Optionen zum Ändern des getesteten Bits BT behält den Wert dieses Bits unverändert.Befehl B T S nach dem Testen setzt Wert Mrd=1 und der Befehl B T C - Bedeutung Mrd=0.Befehl B T C invertiert den Wert von Bit bn nach dem Testen.

Programmverwaltungsoperationen. Zur Steuerung des Programms wird eine große Anzahl von Befehlen verwendet, darunter:

- unbedingte Steuerübertragungsbefehle;

- bedingte Sprungbefehle;

- Befehle zum Organisieren von Programmzyklen;

- Befehle unterbrechen;

- Befehle zum Ändern von Funktionen.

Die bedingungslose Übergabe der Steuerung erfolgt durch den BefehlJMP , die in den Programmzähler geladen wirdPCneuer Inhalt, der die Adresse des nächsten auszuführenden Befehls ist. Diese Adresse wird entweder direkt im Befehl angegebenJMP (direkte Adresse) oder berechnet als Summe der aktuellen InhaltePCund dem im Befehl angegebenen Offset, der eine vorzeichenbehaftete Zahl ist (relative Adressierung). AlsPCdie Adresse des nächsten Programmbefehls enthält, dann setzt die letzte Methode die Sprungadresse, relativ zur nächsten Adresse um eine bestimmte Anzahl von Bytes versetzt. Bei positivem Offset erfolgt der Übergang zu den nächsten Befehlen des Programms, bei negativem Offset zu den vorherigen.

Das Unterprogramm wird auch durch unbedingte Steuerübergabe mit dem Befehl aufgerufenANRUF (oder JSR ). Allerdings in diesem Fall vor dem Laden inPC neuen Inhalt, der die Adresse der ersten Anweisung des Unterprogramms angibt, muss dessen aktueller Wert (die Adresse der nächsten Anweisung) gespeichert werden, um nach der Ausführung des Unterprogramms eine Rückkehr zum Hauptprogramm (bzw vorheriges Unterprogramm beim Verschachteln von Unterprogrammen). Bedingte Sprungbefehle (Programmverzweigungen) werden geladenPCneuen Inhalt, wenn bestimmte Bedingungen erfüllt sind, die normalerweise entsprechend dem aktuellen Wert verschiedener Attribute im Statusregister gesetzt werden. Ist die Bedingung nicht erfüllt, wird der nächste Programmbefehl ausgeführt.

Merkmalsverwaltungsbefehle ermöglichen das Schreiben - Lesen des Inhalts des Statusregisters, in dem Merkmale gespeichert sind, sowie das Ändern der Werte einzelner Merkmale. Beispielsweise implementieren Pentium-Prozessoren Befehle LAHF Und SAHF , die das Low-Byte, das die Vorzeichen enthält, aus dem Statusregister laden EFLAG zum niederwertigen Byte des Registers EAX und Auffüllen von Low-Byte EFLAGS aus dem Register E Ax.. Befehle CLC, STC Setzen Sie die Werte des Transfer-Flags CF=0, CF=1 und den Befehl CMC bewirkt, dass der Wert dieser Funktion invertiert wird. Da Traits den Ablauf der Programmausführung während bedingter Sprünge bestimmen, werden normalerweise Trait-Änderungsanweisungen verwendet, um das Programm zu steuern.

Prozessorsteuerbefehle . Diese Gruppe umfasst Stoppbefehle, keine Operation und eine Reihe von Befehlen, die den Betriebsmodus des Prozessors oder seiner einzelnen Blöcke bestimmen. BefehlHLT Beendet die Programmausführung und versetzt den Prozessor in einen Haltezustand, der beim Empfang von Unterbrechungs- oder Neustartsignalen verlassen wird ( zurücksetzen). Befehl NOP Ein ("Leer"-Befehl), der keine Operationen auslöst, dient dazu, Programmverzögerungen zu realisieren oder im Programm entstandene Lücken zu füllen.

Spezielle Teams CLI, ST Deaktivieren und aktivieren Sie den Dienst von Interrupt-Anforderungen. Bei Prozessoren Pentium Dazu wird ein Steuerbit (Flag) verwendetWENN im Register EFLAGS.

Viele moderne Mikroprozessoren geben einen Identifikationsbefehl aus, der es dem Benutzer oder anderen Geräten ermöglicht, Informationen über den in einem bestimmten System verwendeten Prozessortyp zu erhalten. Bei Prozessoren Pentuim dafür ist der Befehl da CPUID , während dessen die notwendigen Daten über den Prozessor in die Register eingetragen werden EAX,ebx,ECX,EDX und kann dann vom Benutzer oder dem Betriebssystem gelesen werden.

Abhängig von den vom Prozessor implementierten Betriebsmodi und den spezifizierten Arten von verarbeiteten Daten kann der Satz von ausführbaren Befehlen erheblich erweitert werden.

Einige Prozessoren führen arithmetische Operationen mit BCD-Zahlen durch oder führen spezielle Anweisungen zur Ergebniskorrektur aus, wenn sie solche Zahlen verarbeiten. Viele Hochleistungsprozessoren enthalten FPU - Nummernverarbeitungseinheit C "Gleitkomma".

In einer Reihe moderner Prozessoren ist eine Gruppenverarbeitung mehrerer Ganzzahlen oder Zahlen implementiert. C „Gleitkomma“ mit einem einzigen Befehl nach dem Prinzip SIMD („Single Instruction – Multiple Data “) – „Ein Befehl – ​​viele Daten“. Die gleichzeitige Ausführung von Operationen auf mehreren Operanden erhöht die Leistung des Prozessors bei der Arbeit mit Video- und Audiodaten erheblich. Solche Operationen werden in großem Umfang in der Bildverarbeitung, Audiosignalverarbeitung und anderen Anwendungen verwendet. Um diese Operationen auszuführen, werden spezielle Blöcke in die Prozessoren eingeführt, die die entsprechenden Befehlssätze implementieren, die in verschiedenen Prozessortypen ( Pentium, Athlon) bekam den NamenMMX (“ Milti-Media-Erweiterung “) – Multimedia-Erweiterung,SSE(„ Streaming-SIMD-Erweiterung “) – Streaming-SIMD - Verlängerung, “3 DVerlängerung- 3D-Erweiterung.

Ein charakteristisches Merkmal der Prozessoren des Unternehmens Intel , beginnend mit Modell 80286, ist die Prioritätssteuerung beim Zugriff auf Speicher, die bereitgestellt wird, wenn der Prozessor im geschützten virtuellen Adressmodus arbeitet - „ Sicherheitsmodus " (Sicherheitsmodus). Um diesen Modus zu implementieren, werden spezielle Befehlsgruppen verwendet, die dazu dienen, den Speicherschutz gemäß dem akzeptierten Prioritätszugriffsalgorithmus zu organisieren.

NATIONALE UNIVERSITÄT VON USBEKISTAN BENANNT NACH MIRZO ULUGBEK

FAKULTÄT FÜR COMPUTERTECHNOLOGIEN

Zum Thema: Semantische Analyse einer EXE-Datei.

Abgeschlossen:

Taschkent 2003.

Vorwort.

Assemblersprache und Befehlsstruktur.

EXE-Dateistruktur (semantische Analyse).

Aufbau einer COM-Datei.

Wie das Virus funktioniert und sich verbreitet.

Disassembler.

Programme.

Vorwort

Der Beruf eines Programmierers ist erstaunlich und einzigartig. Modernste Technik ist in unserer Zeit aus Wissenschaft und Leben nicht mehr wegzudenken. Alles, was mit menschlicher Aktivität zusammenhängt, ist ohne Computertechnologie nicht vollständig. Und dies trägt zu seiner hohen Entwicklung und Perfektion bei. Die Entwicklung von Personal Computern begann vor nicht allzu langer Zeit, aber während dieser Zeit wurden kolossale Schritte bei Softwareprodukten unternommen, und diese Produkte werden noch lange weit verbreitet sein. Das Gebiet des computerbezogenen Wissens ist explodiert, ebenso wie die damit verbundene Technologie. Wenn wir die kaufmännische Seite nicht berücksichtigen, dann können wir sagen, dass es in diesem Bereich der beruflichen Tätigkeit keine Unbekannten gibt. Viele beschäftigen sich mit der Entwicklung von Programmen nicht aus Profit- oder Verdienstgründen, sondern aus freiem Willen, aus Leidenschaft. Natürlich soll dies die Qualität des Programms nicht beeinträchtigen, und in diesem Geschäft gibt es sozusagen Konkurrenz und Nachfrage nach Qualitätsleistung, nach stabiler Arbeit und nach Erfüllung aller Anforderungen unserer Zeit. Erwähnenswert ist hier auch das Erscheinen von Mikroprozessoren in den 60er Jahren, die eine große Anzahl von Lampensätzen ersetzten. Es gibt einige Arten von Mikroprozessoren, die sich stark voneinander unterscheiden. Diese Mikroprozessoren unterscheiden sich hinsichtlich Bitkapazität und eingebauter Systembefehle voneinander. Die gebräuchlichsten sind: Intel, IBM, Celeron, AMD usw. Alle diese Prozessoren beziehen sich auf die fortschrittliche Architektur der Intel-Prozessoren. Die Verbreitung von Mikrocomputern hat aus zwei Hauptgründen zu einem Umdenken in der Assemblersprache geführt. Erstens benötigen in Assemblersprache geschriebene Programme erheblich weniger Speicher und Laufzeit. Zweitens vermittelt die Kenntnis der Assemblersprache und des daraus resultierenden Maschinencodes ein Verständnis der Maschinenarchitektur, das beim Arbeiten in einer Hochsprache kaum gegeben ist. Während die meisten Softwareprofis in Hochsprachen wie Pascal, C oder Delphi entwickeln, für die sich Programme leichter schreiben lassen, wird die leistungsfähigste und effizienteste Software ganz oder teilweise in Assemblersprache geschrieben. Hochsprachen wurden entwickelt, um die speziellen technischen Besonderheiten bestimmter Computer zu umgehen. Und die Assemblersprache wiederum ist auf die spezifischen Besonderheiten des Prozessors ausgelegt. Um ein Assemblersprachenprogramm für einen bestimmten Computer zu schreiben, muss man daher dessen Architektur kennen. Heutzutage ist die Art des Hauptsoftwareprodukts eine EXE-Datei. Angesichts der positiven Aspekte davon kann sich der Autor des Programms seiner Unverletzlichkeit sicher sein. Aber oft ist dies weit davon entfernt. Es gibt auch einen Disassembler. Mit Hilfe eines Disassemblers können Sie Interrupts und Programmcodes herausfinden. Für jemanden, der sich mit Assembler auskennt, wird es nicht schwierig sein, das gesamte Programm nach seinem Geschmack umzugestalten. Vielleicht kommt daher das unlösbarste Problem – der Virus. Warum schreiben Menschen einen Virus? Manche stellen diese Frage überrascht, manche ärgerlich, aber dennoch gibt es Menschen, die sich für diese Aufgabe nicht aus Schadenssicht, sondern aus Interesse an der Systemprogrammierung interessieren. Viren werden aus verschiedenen Gründen geschrieben. Einige mögen Systemaufrufe, andere verbessern ihre Kenntnisse in Assembler. Ich werde versuchen, das alles in meiner Hausarbeit zu erklären. Es sagt auch nicht nur etwas über die Struktur der EXE-Datei aus, sondern auch über die Assemblersprache.

^ Assemblersprache.

Es ist interessant, von der Zeit des Erscheinens der ersten Computer bis zum heutigen Tag den Wandel der Vorstellungen über Assemblersprache unter Programmierern zu verfolgen.

Assembler war einmal eine Sprache, ohne deren Wissen es unmöglich war, einen Computer dazu zu bringen, irgendetwas Nützliches zu tun. Allmählich änderte sich die Situation. Bequemere Kommunikationsmittel mit einem Computer erschienen. Aber im Gegensatz zu anderen Sprachen starb Assembler nicht, außerdem konnte er dies im Prinzip nicht tun. Warum? Auf der Suche nach einer Antwort werden wir versuchen zu verstehen, was Assemblersprache im Allgemeinen ist.

Kurz gesagt, Assemblersprache ist eine symbolische Darstellung der Maschinensprache. Alle Prozesse in der Maschine auf der untersten Hardwareebene werden nur durch Befehle (Anweisungen) der Maschinensprache gesteuert. Daraus wird deutlich, dass trotz des gebräuchlichen Namens die Assemblersprache für jeden Computertyp unterschiedlich ist. Dies gilt auch für das Erscheinungsbild von in Assembler geschriebenen Programmen und die Ideen, die diese Sprache widerspiegelt.

Ohne Assembler-Kenntnisse ist es unmöglich, hardwarebezogene Probleme (oder sogar hardwarebezogene Probleme, wie z. B. die Verbesserung der Geschwindigkeit eines Programms) wirklich zu lösen.

Ein Programmierer oder jeder andere Benutzer kann alle High-Level-Tools verwenden, bis hin zu Programmen zum Erstellen virtueller Welten, und vielleicht nicht einmal ahnen, dass der Computer tatsächlich nicht die Befehle der Sprache ausführt, in der sein Programm geschrieben ist, sondern deren transformierte Darstellung in Form langweiliger und langweiliger Befehlsfolgen einer völlig anderen Sprache - der Maschinensprache. Stellen wir uns nun vor, dass ein solcher Benutzer ein nicht standardmäßiges Problem hat oder einfach etwas schief gelaufen ist. Beispielsweise muss sein Programm mit einem ungewöhnlichen Gerät funktionieren oder andere Aktionen ausführen, die Kenntnisse über die Prinzipien der Computerhardware erfordern. Egal wie schlau ein Programmierer ist, egal wie gut die Sprache ist, in der er sein wunderbares Programm geschrieben hat, ohne Assembler-Kenntnisse kommt er nicht aus. Und es ist kein Zufall, dass fast alle Compiler von Hochsprachen Mittel enthalten, um ihre Module mit Modulen in Assembler zu verbinden oder den Zugriff auf die Assembler-Programmierebene zu unterstützen.

Natürlich ist die Zeit der Computerwagen schon vorbei. Wie das Sprichwort sagt, kann man die Unermesslichkeit nicht umarmen. Aber es gibt etwas Gemeinsames, eine Art Fundament, auf dem jede ernsthafte Computerausbildung aufbaut. Dies ist Wissen über die Prinzipien des Computerbetriebs, seiner Architektur und Assemblersprache als Spiegelung und Verkörperung dieses Wissens.

Ein typischer moderner Computer (i486- oder Pentium-basiert) besteht aus den folgenden Komponenten (Abbildung 1).

Reis. 1. Computer und Peripheriegeräte

Reis. 2. Blockschaltbild eines Personal Computers

Aus der Abbildung (Abbildung 1) ist ersichtlich, dass der Computer aus mehreren physikalischen Geräten besteht, von denen jedes mit einer Einheit verbunden ist, die als Systemeinheit bezeichnet wird. Logischerweise spielt es die Rolle eines koordinierenden Geräts. Schauen wir in die Systemeinheit (Sie müssen nicht versuchen, in den Monitor zu gelangen - dort ist nichts Interessantes, außerdem ist es gefährlich): Öffnen Sie das Gehäuse und sehen Sie einige Platinen, Blöcke und Verbindungskabel. Um ihren funktionalen Zweck zu verstehen, betrachten wir das Blockdiagramm eines typischen Computers (Abb. 2). Sie erhebt keinen Anspruch auf absolute Genauigkeit und soll nur den Zweck, die Verbindung und die typische Zusammensetzung der Elemente eines modernen Personal Computers zeigen.

Betrachten wir das Diagramm in Abb. 2 in einem etwas unkonventionellen Stil.
Es liegt in der Natur des Menschen, bei der Begegnung mit etwas Neuem nach Assoziationen zu suchen, die ihm helfen können, das Unbekannte zu erkennen. Welche Assoziationen weckt der Computer? Für mich zum Beispiel wird der Computer oft mit dem Menschen selbst in Verbindung gebracht. Warum?

Eine Person, die irgendwo in den Tiefen ihrer selbst einen Computer erschuf, dachte, dass sie etwas Ähnliches wie sich selbst erschuf. Der Computer hat Wahrnehmungsorgane für Informationen von der Außenwelt - das sind Tastatur, Maus, Magnetplattenlaufwerke. Auf Abb. 2 Diese Organe befinden sich rechts von den Systembussen. Der Computer hat Organe, die die empfangenen Informationen "verdauen" - dies ist der Zentralprozessor und das RAM. Und schließlich hat der Computer Sprechorgane, die die Ergebnisse der Verarbeitung ausgeben. Dies sind auch einige der Geräte auf der rechten Seite.

Moderne Computer sind natürlich alles andere als menschlich. Sie können mit Wesen verglichen werden, die auf der Ebene einer großen, aber begrenzten Menge unbedingter Reflexe mit der Außenwelt interagieren.
Diese Reihe von Reflexen bildet ein System von Maschinenanweisungen. Egal auf welchem ​​Niveau Sie mit einem Computer kommunizieren, am Ende läuft alles auf eine langweilige und eintönige Abfolge von Maschinenbefehlen hinaus.
Jeder Maschinenbefehl ist eine Art Reiz zur Erregung dieses oder jenes unbedingten Reflexes. Die Reaktion auf diesen Reiz ist immer eindeutig und in Form eines Mikroprogramms im Mikrobefehlsblock „fest verdrahtet“. Dieses Mikroprogramm implementiert die Aktionen zum Implementieren des Maschinenbefehls, jedoch bereits auf der Ebene von Signalen, die an bestimmte Computerlogikschaltungen angelegt werden, wodurch verschiedene Computersubsysteme gesteuert werden. Dies ist das sogenannte Prinzip der Mikroprogrammsteuerung.

Um die Analogie mit einer Person fortzusetzen, stellen wir fest, dass viele Betriebssysteme, Compiler für Hunderte von Programmiersprachen erfunden wurden, damit ein Computer richtig essen kann usw. Aber sie alle sind eigentlich nur ein Gericht, auf dem sie stehen Essen (Programme) wird nach bestimmten Regeln Magen (Computer) geliefert. Nur der Magen eines Computers liebt diätetische, eintönige Kost – gib ihm strukturierte Informationen, in Form von streng organisierten Folgen von Nullen und Einsen, deren Kombinationen die Maschinensprache ausmachen.

Somit versteht der Computer, der äußerlich ein Polyglott ist, nur eine Sprache - die Sprache der Maschinenbefehle. Um mit einem Computer zu kommunizieren und zu arbeiten, ist es natürlich nicht erforderlich, diese Sprache zu beherrschen, aber fast jeder professionelle Programmierer steht früher oder später vor der Notwendigkeit, sie zu lernen. Glücklicherweise muss der Programmierer nicht versuchen, die Bedeutung verschiedener Kombinationen von Binärzahlen herauszufinden, da Programmierer bereits in den 50er Jahren damit begannen, das symbolische Analogon der Maschinensprache zum Programmieren zu verwenden, das als Assemblersprache bezeichnet wurde. Diese Sprache spiegelt alle Merkmale der Maschinensprache genau wider. Aus diesem Grund ist die Assemblersprache im Gegensatz zu Hochsprachen für jeden Computertyp unterschiedlich.

Aus dem Vorhergehenden können wir schließen, dass, da die Assemblersprache für den Computer „nativ“ ist, das effizienteste Programm nur darin geschrieben werden kann (vorausgesetzt, es wird von einem qualifizierten Programmierer geschrieben). Hier gibt es ein kleines „Aber“: Dies ist ein sehr mühsamer Prozess, der viel Aufmerksamkeit und praktische Erfahrung erfordert. In Wirklichkeit schreibt Assembler also hauptsächlich Programme, die ein effizientes Arbeiten mit der Hardware gewährleisten sollen. Manchmal werden kritische Teile des Programms in Bezug auf Ausführungszeit oder Speicherverbrauch in Assembler geschrieben. Anschließend werden sie in Form von Unterprogrammen erstellt und mit Code in einer Hochsprache kombiniert.

Es ist sinnvoll, mit dem Erlernen der Assemblersprache eines beliebigen Computers erst dann zu beginnen, wenn Sie herausgefunden haben, welcher Teil des Computers noch sichtbar und für die Programmierung in dieser Sprache verfügbar ist. Dies ist das sogenannte Computerprogrammmodell, zu dem das Mikroprozessorprogrammmodell gehört, das 32 Register enthält, die dem Programmierer mehr oder weniger zur Verfügung stehen.

Diese Register lassen sich in zwei große Gruppen einteilen:

^16 benutzerdefinierte Register;

16 Systemregister.

Programme in Assemblersprache verwenden Register sehr stark. Die meisten Register haben einen bestimmten funktionalen Zweck.

Wie der Name schon sagt, werden Benutzerregister aufgerufen, weil der Programmierer sie beim Schreiben seiner Programme verwenden kann. Zu diesen Registern gehören (Abb. 3):

Acht 32-Bit-Register, die von Programmierern zum Speichern von Daten und Adressen verwendet werden können (auch Universalregister (RON) genannt):

sechs Segmentregister: cs, ds, ss, es, fs, gs;

Status- und Steuerregister:

Flaggen registrieren Flaggen/Flags;

eip/ip-Befehlszeigerregister.

Reis. 3. Benutzerregister von i486- und Pentium-Mikroprozessoren

Warum werden viele dieser Register mit einem Schrägstrich angezeigt? Nein, das sind keine unterschiedlichen Register – sie sind Teile eines großen 32-Bit-Registers. Sie können im Programm als separate Objekte verwendet werden. Dies geschah, um die Lauffähigkeit von Programmen sicherzustellen, die für die jüngeren 16-Bit-Mikroprozessormodelle von Intel geschrieben wurden, beginnend mit dem i8086. Die i486- und Pentium-Mikroprozessoren haben meistens 32-Bit-Register. Ihre Anzahl, mit Ausnahme der Segmentregister, ist die gleiche wie die des i8086, aber die Dimension ist größer, was sich in ihren Bezeichnungen widerspiegelt - sie haben
Präfix e (Erweitert).

^ Allzweckregister
Alle Register dieser Gruppe erlauben den Zugriff auf ihre „unteren“ Teile (siehe Abb. 3). Beachten Sie beim Betrachten dieser Abbildung, dass nur die unteren 16- und 8-Bit-Teile dieser Register für die Selbstadressierung verwendet werden können. Die oberen 16 Bit dieser Register stehen nicht als eigenständige Objekte zur Verfügung. Dies geschieht, wie oben erwähnt, aus Gründen der Kompatibilität mit den jüngeren 16-Bit-Mikroprozessormodellen von Intel.

Lassen Sie uns die Register auflisten, die zur Gruppe der Mehrzweckregister gehören. Da sich diese Register physisch im Mikroprozessor innerhalb der arithmetischen Logikeinheit (ALU) befinden, werden sie auch als ALU-Register bezeichnet:

eax/ax/ah/al (Akkumulatorregister) - Akkumulator.
Wird zum Speichern von Zwischendaten verwendet. In einigen Befehlen ist die Verwendung dieses Registers obligatorisch;

ebx/bx/bh/bl (Basisregister) - Basisregister.
Wird verwendet, um die Basisadresse eines Objekts im Speicher zu speichern;

ecx/cx/ch/cl (Zählregister) - Zählerregister.
Es wird in Befehlen verwendet, die einige sich wiederholende Aktionen ausführen. Seine Verwendung ist oft implizit und versteckt im Algorithmus des entsprechenden Befehls.
Beispielsweise analysiert der Schleifenorganisationsbefehl zusätzlich zum Übertragen der Steuerung an einen Befehl, der sich an einer bestimmten Adresse befindet, den Wert des ecx/cx-Registers und dekrementiert ihn um eins;

edx/dx/dh/dl (Datenregister) - Datenregister.
Genau wie das eax/ax/ah/al-Register speichert es Zwischendaten. Einige Befehle erfordern seine Verwendung; bei einigen Befehlen geschieht dies implizit.

Die folgenden zwei Register werden verwendet, um die sogenannten Kettenoperationen zu unterstützen, d. h. Operationen, die nacheinander Ketten von Elementen verarbeiten, die jeweils 32, 16 oder 8 Bit lang sein können:

esi/si (Quellindexregister) - Quellindex.
Dieses Register enthält bei Kettenoperationen die aktuelle Adresse des Elements in der Quellkette;

edi/di (Destination Index register) - Index des Empfängers (Empfänger).
Dieses Register enthält bei Kettenoperationen die aktuelle Adresse in der Zielkette.

In der Architektur des Mikroprozessors auf Hardware- und Softwareebene wird eine solche Datenstruktur wie ein Stack unterstützt. Um mit dem Stack zu arbeiten, gibt es im Mikroprozessor-Befehlssystem spezielle Befehle, und im Mikroprozessor-Softwaremodell gibt es dafür spezielle Register:

esp/sp (Stapelzeigerregister) - Stapelzeigerregister.
Enthält einen Zeiger auf den Stapelanfang im aktuellen Stapelsegment.

ebp/bp (Basiszeigerregister) – Stack-Frame-Basiszeigerregister.
Entwickelt, um den wahlfreien Zugriff auf Daten innerhalb des Stacks zu organisieren.

Ein Stack ist ein Programmbereich zur temporären Speicherung beliebiger Daten. Natürlich können auch Daten im Datensegment gespeichert werden, aber in diesem Fall muss für jede temporär gespeicherte Daten eine separate benannte Speicherzelle erstellt werden, was die Größe des Programms und die Anzahl der verwendeten Namen erhöht. Der Vorteil des Stacks besteht darin, dass sein Bereich wiederverwendet wird und das Speichern von Daten auf dem Stack und das Abrufen von Daten von dort mit effizienten Push- und Pop-Befehlen ohne Angabe von Namen erfolgt.
Der Stack wird beispielsweise traditionell verwendet, um den Inhalt der vom Programm verwendeten Register zu speichern, bevor eine Subroutine aufgerufen wird, die wiederum die Prozessorregister "für ihre eigenen Zwecke" verwendet. Die ursprünglichen Inhalte der Register werden bei der Rückkehr von der Subroutine aus dem Stapel entleert. Eine andere gängige Technik besteht darin, die erforderlichen Parameter über den Stapel an eine Unterroutine zu übergeben. Die Subroutine, die weiß, in welcher Reihenfolge die Parameter auf dem Stack platziert sind, kann sie von dort nehmen und sie bei ihrer Ausführung verwenden. Eine Besonderheit des Stapels ist die besondere Reihenfolge der Abtastung der darin enthaltenen Daten: Auf dem Stapel ist immer nur das oberste Element verfügbar, d.h. das letzte Element, das auf den Stack geladen wurde. Wenn Sie das oberste Element aus dem Stapel ziehen, wird das nächste Element verfügbar. Die Elemente des Stacks befinden sich in dem für den Stack zugewiesenen Speicherbereich, beginnend mit dem Boden des Stacks (dh von seiner maximalen Adresse) bis zu sukzessive abnehmenden Adressen. Die Adresse des obersten zugänglichen Elements wird im Stapelzeigerregister SP gespeichert. Wie jeder andere Bereich des Programmspeichers muss der Stack in einem Segment enthalten sein oder ein separates Segment bilden. In jedem Fall wird die Segmentadresse dieses Segments in das Segmentstapelregister SS gestellt. Somit beschreibt ein Registerpaar SS:SP die Adresse einer verfügbaren Stapelzelle: SS speichert die Segmentadresse des Stapels und SP speichert den Offset der letzten auf dem Stapel gespeicherten Daten (Fig. 4, a). Beachten wir, dass der Stapelzeiger SP im Anfangszustand auf eine Zelle zeigt, die unter dem Boden des Stapels liegt und nicht darin enthalten ist.

Abb. 4. Stapelorganisation: a - Anfangszustand, b - nach dem Laden eines Elements (in diesem Beispiel der Inhalt des AX-Registers), c - nach dem Laden des zweiten Elements (Inhalt des DS-Registers), d - nach dem Entladen eines Elements element, e - nach dem Entladen von zwei Elementen und Rückkehr in den ursprünglichen Zustand.

Das Laden auf den Stack erfolgt durch einen speziellen Push-Stack-Befehl. Dieser Befehl dekrementiert zuerst den Inhalt des Stapelzeigers um 2 und platziert dann den Operanden an der Adresse in SP. Wenn wir beispielsweise den Inhalt des AX-Registers temporär auf dem Stack speichern wollen, sollten wir den Befehl ausführen

Der Stapel geht in den in Abb. 1.10, b. Es ist zu erkennen, dass der Stapelzeiger um zwei Bytes nach oben (in Richtung niedrigerer Adressen) verschoben wird und der im Push-Befehl angegebene Operand an diese Adresse geschrieben wird. Der folgende Befehl zum Laden auf den Stack beispielsweise

bewegt den Stapel in den in Abb. 1.10, c. Der Stapel enthält nun zwei Elemente, wobei nur auf das oberste zugegriffen wird, auf das der Stapelzeiger SP zeigt. Wenn wir nach einiger Zeit den ursprünglichen Inhalt der auf dem Stack gespeicherten Register wiederherstellen müssen, müssen wir die Pop-Befehle (pop) vom Stack ausführen:

Pop-DS
Pop-AX

Wie groß soll der Stack sein? Es hängt davon ab, wie intensiv es im Programm verwendet wird. Wenn Sie beispielsweise planen, ein Array von 10.000 Byte auf dem Stack zu speichern, muss der Stack mindestens so groß sein. Zu beachten ist, dass der Stack in einigen Fällen automatisch vom System verwendet wird, insbesondere bei der Ausführung des Interrupt-Befehls int 21h. Mit diesem Befehl schiebt der Prozessor zuerst die Rücksprungadresse auf den Stapel, und dann schiebt DOS die Inhalte der Register und andere Informationen bezüglich des unterbrochenen Programms dorthin. Selbst wenn das Programm den Stack überhaupt nicht verwendet, muss er daher immer noch im Programm vorhanden sein und eine Größe von mindestens mehreren zehn Wörtern haben. In unserem ersten Beispiel legen wir 128 Wörter auf den Stapel, was definitiv ausreicht.

^ Struktur des Assembly-Programms

Ein Assemblersprachenprogramm ist eine Sammlung von Speicherblöcken, die als Speichersegmente bezeichnet werden. Ein Programm kann aus einem oder mehreren dieser Blocksegmente bestehen. Jedes Segment enthält eine Sammlung von Sprachsätzen, von denen jeder eine separate Programmcodezeile belegt.

Es gibt vier Arten von Assembly-Anweisungen:

Befehle oder Anweisungen, die symbolische Entsprechungen von Maschinenanweisungen sind. Während des Übersetzungsprozesses werden Assembleranweisungen in die entsprechenden Befehle des Mikroprozessor-Befehlssatzes umgewandelt;

Makrobefehle - Sätze des Programmtextes, die auf bestimmte Weise gestaltet sind und bei der Übersetzung durch andere Sätze ersetzt werden;

Direktiven, die den Assembler-Compiler anweisen, eine Aktion auszuführen. Direktiven haben keine Entsprechungen in der Maschinendarstellung;

Kommentarzeilen, die beliebige Zeichen enthalten, einschließlich Buchstaben des russischen Alphabets. Kommentare werden vom Übersetzer ignoriert.

^ Syntax der Assemblersprache

Die Sätze, aus denen ein Programm besteht, können ein syntaktisches Konstrukt sein, das einem Befehl, Makro, einer Anweisung oder einem Kommentar entspricht. Damit der Assembler-Übersetzer sie erkennt, müssen sie nach bestimmten syntaktischen Regeln gebildet werden. Verwenden Sie dazu am besten eine formale Beschreibung der Syntax der Sprache, wie die Grammatikregeln. Die gebräuchlichsten Arten, eine Programmiersprache auf diese Weise zu beschreiben, sind Syntaxdiagramme und erweiterte Backus-Naur-Formen. Für den praktischen Gebrauch sind Syntaxdiagramme bequemer. Beispielsweise kann die Syntax von Anweisungen in Assemblersprache unter Verwendung der in den folgenden Abbildungen gezeigten Syntaxdiagramme beschrieben werden.

Reis. 5. Assembler-Satzformat

Reis. 6. Formatanweisungen

Reis. 7. Format von Befehlen und Makros

Auf diesen Zeichnungen:

Labelname – ein Identifizierer, dessen Wert die Adresse des ersten Bytes des Programmquellcodesatzes ist, den er bezeichnet;

name - ein Bezeichner, der diese Direktive von anderen Direktiven mit demselben Namen unterscheidet. Durch die Verarbeitung einer bestimmten Direktive durch den Assembler können diesem Namen bestimmte Eigenschaften zugeordnet werden;

Operationscode (COP) und Direktive sind mnemotechnische Bezeichnungen des entsprechenden Maschinenbefehls, Makrobefehls oder Übersetzerbefehls;

Operanden - Teile der Befehls-, Makro- oder Assembler-Direktiven, die Objekte bezeichnen, an denen Operationen ausgeführt werden. Assembler-Operanden werden durch Ausdrücke mit numerischen und Textkonstanten, Variablenlabels und Bezeichnern mit Operatorzeichen und einigen reservierten Wörtern beschrieben.

^ Wie verwende ich Syntaxdiagramme? Es ist sehr einfach: Alles, was Sie tun müssen, ist, den Pfad von der Eingabe des Diagramms (links) zu seiner Ausgabe (rechts) zu finden und ihm dann zu folgen. Wenn ein solcher Pfad existiert, dann ist der Satz oder die Konstruktion syntaktisch korrekt. Wenn es keinen solchen Pfad gibt, akzeptiert der Compiler diese Konstruktion nicht. Achten Sie bei der Arbeit mit Syntaxdiagrammen auf die durch die Pfeile gekennzeichnete Umgehungsrichtung, da es unter den Pfaden auch solche geben kann, denen von rechts nach links gefolgt werden kann. Tatsächlich spiegeln syntaktische Diagramme die Logik des Übersetzers wider, wenn er die Eingabesätze des Programms parst.

Erlaubte Zeichen beim Schreiben des Textes von Programmen sind:

Alle lateinischen Buchstaben: A-Z, a-z. In diesem Fall werden Groß- und Kleinbuchstaben als gleichwertig betrachtet;

Zahlen von 0 bis 9;

Zeichen?, @, $, _, &;

Trennzeichen, . ()< > { } + / * % ! " " ? \ = # ^.

Assembler-Sätze werden aus Lexemen gebildet, die syntaktisch untrennbare Folgen gültiger Sprachsymbole sind, die für den Übersetzer sinnvoll sind.

Die Token sind:

Bezeichner sind Folgen gültiger Zeichen, die zur Bezeichnung von Programmobjekten wie Opcodes, Variablennamen und Labelnamen verwendet werden. Die Regel für das Schreiben von Bezeichnern lautet wie folgt: Ein Bezeichner kann aus einem oder mehreren Zeichen bestehen. Als Zeichen können Sie Buchstaben des lateinischen Alphabets, Zahlen und einige Sonderzeichen verwenden - _, ?, $, @. Ein Bezeichner darf nicht mit einer Ziffer beginnen. Die Länge des Bezeichners kann bis zu 255 Zeichen betragen, wobei der Übersetzer nur die ersten 32 Zeichen akzeptiert und den Rest ignoriert. Sie können die Länge möglicher Bezeichner mit der Befehlszeilenoption mv anpassen. Außerdem ist es möglich, den Übersetzer anzuweisen, zwischen Groß- und Kleinbuchstaben zu unterscheiden oder deren Unterschied zu ignorieren (was standardmäßig der Fall ist).

^ Befehle in Assemblersprache.

Assembler-Befehle offenbaren die Fähigkeit, ihre Anforderungen an den Computer zu übertragen, den Mechanismus zur Übertragung der Kontrolle im Programm (Schleifen und Sprünge) für logische Vergleiche und Programmorganisation. Allerdings sind Programmieraufgaben selten so einfach. Die meisten Programme enthalten eine Reihe von Schleifen, in denen mehrere Anweisungen wiederholt werden, bis eine bestimmte Anforderung erreicht ist, und verschiedene Überprüfungen, um zu bestimmen, welche der mehreren Aktionen auszuführen ist. Einige Befehle können die Steuerung übertragen, indem sie die normale Schrittfolge ändern, indem sie den Versatzwert im Befehlszeiger direkt ändern. Wie bereits erwähnt, gibt es verschiedene Befehle für verschiedene Prozessoren, aber wir werden einige Befehle für die Prozessoren 80186, 80286 und 80386 betrachten.

Um den Status der Flags nach Ausführung eines bestimmten Befehls zu beschreiben, verwenden wir eine Auswahl aus der Tabelle, die die Struktur des Flag-Registers eflags widerspiegelt:

Die unterste Zeile dieser Tabelle listet die Werte der Flags auf, nachdem der Befehl ausgeführt wurde. In diesem Fall werden die folgenden Notationen verwendet:

1 - nach Ausführung des Befehls wird das Flag gesetzt (gleich 1);

0 - nach Ausführung des Befehls wird das Flag zurückgesetzt (gleich 0);

r - der Wert des Flags hängt vom Ergebnis des Befehls ab;

Nach Ausführung des Befehls ist das Flag undefiniert;

Leerzeichen - nach Ausführung des Befehls ändert sich das Flag nicht;

Zur Darstellung von Operanden in Syntaxdiagrammen wird folgende Notation verwendet:

r8, r16, r32 - Operand in einem der Register der Größe Byte, Wort oder Doppelwort;

m8, m16, m32, m48 - Operand in Speichergröße von Bytes, Wort, Doppelwort oder 48 Bit;

i8, i16, i32 - unmittelbarer Operand der Größe Byte, Wort oder Doppelwort;

a8, a16, a32 - relative Adresse (Offset) im Codesegment.

Befehle (in alphabetischer Reihenfolge):

*Diese Befehle werden ausführlich beschrieben.

ADDIEREN
(Zusatz)

Zusatz

^ Befehlsübersicht:

Ziel, Quelle hinzufügen

Zweck: Addition von zwei Quell- und Zieloperanden der Dimensionen Byte, Wort oder Doppelwort.

Arbeitsalgorithmus:

fügen Sie die Quell- und Zieloperanden hinzu;

schreibe das Ergebnis der Addition in den Empfänger;

Fahnen setzen.

Status der Flags nach der Befehlsausführung:

Anwendung:
Der add-Befehl wird verwendet, um zwei ganzzahlige Operanden zu addieren. Das Ergebnis der Addition wird an die Adresse des ersten Operanden gestellt. Wenn das Ergebnis der Addition die Grenzen des Zieloperanden überschreitet (es kommt zu einem Überlauf), sollte dieser Situation Rechnung getragen werden, indem das cf-Flag analysiert und dann möglicherweise das adc-Kommando verwendet wird. Addieren wir zum Beispiel die Werte in Register ax und Speicherbereich ch. Beim Hinzufügen sollten Sie die Möglichkeit eines Überlaufs berücksichtigen.

Register plus Register oder Speicher:

|000000dw|modregr/rm|

Register AX (AL) plus Sofortwert:

|0000010w|--data--|data if w=1|

Register oder Speicher plus Sofortwert:

|100000sw|mod000r/m|--data--|data if BW=01|

ANRUF
(ANRUF)

Aufrufen einer Prozedur oder Aufgabe

^ Befehlsübersicht:

Zweck:

Übergabe der Steuerung an eine nahe oder ferne Prozedur mit Speichern der Adresse des Rückkehrpunkts auf dem Stapel;

Aufgabenwechsel.

Arbeitsalgorithmus:
bestimmt durch den Operandentyp:

Das Etikett ist nahe – der Inhalt des eip/ip-Befehlszeigers wird auf den Stapel geschoben und ein neuer Adresswert, der dem Etikett entspricht, wird in dasselbe Register geladen;

Far label – Inhalte des eip/ip- und cs-Befehlszeigers werden auf den Stack geschoben. Dann werden die neuen Adresswerte, die der fernen Markierung entsprechen, in dieselben Register geladen;

R16, 32 oder m16, 32 – definieren ein Register oder eine Speicherzelle, die Offsets im aktuellen Befehlssegment enthält, wo die Steuerung übertragen wird. Wenn die Steuerung übertragen wird, wird der Inhalt des eip/ip-Befehlszeigers auf den Stapel geschoben;

Speicherzeiger - definiert eine Speicherstelle, die einen 4- oder 6-Byte-Zeiger auf die aufgerufene Prozedur enthält. Die Struktur eines solchen Zeigers ist 2+2 oder 2+4 Bytes. Die Interpretation eines solchen Zeigers hängt von der Betriebsart des Mikroprozessors ab:

^ Zustand der Flags nach Befehlsausführung (außer Taskwechsel):

Die Befehlsausführung wirkt sich nicht auf Flags aus

Beim Umschalten einer Task werden die Werte der Flags gemäß den Informationen über das eflags-Register im TSS-Statussegment der Task geändert, auf die umgeschaltet wird.
Anwendung:
Mit dem Aufrufbefehl können Sie eine flexible und multivariate Übergabe der Steuerung an ein Unterprogramm organisieren, während die Adresse des Rückkehrpunkts beibehalten wird.

Objektcode (vier Formate):

Direkte Adressierung in einem Segment:

|11101000|Anzeige-niedrig|Diep-hoch|

Indirekte Adressierung in einem Segment:

|11111111|mod010r/m|

Indirekte Adressierung zwischen Segmenten:

|11111111|mod011r/m|

Direkte Adressierung zwischen Segmenten:

|10011010|Offset-low|Offset-high|seg-low|seg-high|

CMP
(Operanden vergleichen)

Operandenvergleich

^ Befehlsübersicht:

cmp Operand1, Operand2

Zweck: Vergleich zweier Operanden.

Arbeitsalgorithmus:

Subtraktion durchführen (operand1-operand2);

je nach Ergebnis Flags setzen, operand1 und operand2 nicht ändern (also das Ergebnis nicht speichern).

Anwendung:
Diese Anweisung wird verwendet, um zwei Operanden durch Subtraktion zu vergleichen, während die Operanden nicht geändert werden. Flags werden als Ergebnis der Befehlsausführung gesetzt. Der cmp-Befehl wird mit den bedingten Sprungbefehlen und dem Byte-nach-Wert-setzen-Befehl setcc verwendet.

Objektcode (drei Formate):

Register oder registrierter Speicher:

|001110dw|modreg/m|

Sofortwert mit Register AX (AL):

|0011110w|--data--|data if w=1|

Sofortwert mit Register oder Speicher:

|100000sw|mod111r/m|--data--|data if sw=0|

DEZ
(Operand um 1 verringern)

Operandendekrement um eins

^ Befehlsübersicht:

dec-Operand

Zweck: Verringern Sie den Wert des Operanden im Speicher oder Register um 1.

Arbeitsalgorithmus:
die Anweisung subtrahiert 1 vom Operanden. Status der Flags nach der Befehlsausführung:

Anwendung:
Der dec-Befehl wird verwendet, um den Wert eines Bytes, Wortes, Doppelwortes im Speicher oder Register um eins zu dekrementieren. Beachten Sie, dass der Befehl das cf-Flag nicht beeinflusst.

Register: |01001reg|

^ Register oder Speicher: |1111111w|mod001r/m|

DIV
(TEILEN ohne Vorzeichen)

Teilung unsigniert

Befehlsschema:

div-Teiler

Zweck: Durchführen einer Divisionsoperation an zwei binären vorzeichenlosen Werten.

^ Arbeitsalgorithmus:
Der Befehl erfordert zwei Operanden - den Dividenden und den Divisor. Der Dividende wird implizit angegeben und seine Größe hängt von der Größe des Divisors ab, der im Befehl angegeben wird:

Wenn der Divisor in Bytes angegeben ist, muss der Dividende im Register ax stehen. Nach der Operation wird der Quotient in al und der Rest in ah gesetzt;

wenn der Divisor ein Wort ist, dann muss der Dividende im Registerpaar dx:ax liegen, wobei der niedrige Teil des Dividenden in ax steht. Nach der Operation wird der Quotient in ax und der Rest in dx gesetzt;

ist der divisor ein doppelwort, dann muss der dividend im registerpaar edx:eax stehen, mit dem niedrigen teil des dividenden in eax. Nach der Operation wird der Quotient in eax und der Rest in edx gestellt.

^ Status der Flags nach der Befehlsausführung:

Anwendung:
Der Befehl führt eine ganzzahlige Division der Operanden durch und gibt das Ergebnis der Division als Quotient und den Rest der Division zurück. Bei der Durchführung einer Divisionsoperation kann eine Ausnahme auftreten: 0 - Divisionsfehler. Diese Situation tritt in einem von zwei Fällen auf: Der Divisor ist 0 oder der Quotient ist zu groß, um in das eax/ax/al-Register zu passen.

Objektcode:

|1111011w|mod110r/m|

INT
(Unterbrechen)

Aufruf einer Interrupt-Service-Routine

^ Befehlsübersicht:

int interrupt_number

Zweck: Aufruf der Interrupt-Service-Routine mit der durch den Befehlsoperanden angegebenen Interrupt-Nummer.

^ Arbeitsalgorithmus:

Schieben Sie das Flags/Flags-Register und die Rücksendeadresse auf den Stack. Beim Schreiben der Rücksprungadresse wird zuerst der Inhalt des cs-Segmentregisters geschrieben, dann der Inhalt des eip/ip-Befehlszeigers;

setze die if- und tf-Flags auf Null zurück;

Übergeben Sie die Steuerung an den Interrupt-Handler mit der angegebenen Nummer. Der Steuerungsübertragungsmechanismus hängt von der Betriebsart des Mikroprozessors ab.

^ Status der Flags nach der Befehlsausführung:

Anwendung:
Wie Sie der Syntax entnehmen können, gibt es zwei Formen dieses Befehls:

int 3 - hat seinen eigenen individuellen Opcode 0cch und belegt ein Byte. Dieser Umstand macht es sehr bequem, in verschiedenen Software-Debuggern Breakpoints zu setzen, indem das erste Byte einer beliebigen Anweisung ersetzt wird. Trifft der Mikroprozessor auf einen Befehl mit dem Opcode 0cch in der Befehlsfolge, ruft er den Interrupt-Handler mit der Vektornummer 3 auf, der zur Kommunikation mit dem Software-Debugger dient.

Die zweite Form der Anweisung ist zwei Bytes lang, hat einen Opcode von 0cdh und ermöglicht es Ihnen, einen Aufruf an eine Interrupt-Serviceroutine mit einer Vektornummer im Bereich von 0-255 zu initiieren. Merkmale der Steuerungsübertragung hängen, wie erwähnt, von der Betriebsart des Mikroprozessors ab.

Objektcode (zwei Formate):

Register: |01000reg|

^ Register oder Speicher: |1111111w|mod000r/m|

JCC
JCXZ/JECXZ
(Sprung wenn Bedingung)

(Sprung wenn CX=Null/Sprung wenn ECX=Null)

Springe, wenn die Bedingung erfüllt ist

Springe, wenn CX/ECX Null ist

^ Befehlsübersicht:

jcc-Etikett
jcxz-Etikett
jecxz-Label

Zweck: Übergang innerhalb des aktuellen Segments von Befehlen, abhängig von einer bestimmten Bedingung.

^ Befehlsalgorithmus (außer jcxz/jecxz):
Überprüfen des Status der Flags in Abhängigkeit vom Opcode (er spiegelt die überprüfte Bedingung wider):

wenn die zu testende Bedingung wahr ist, gehe zu der durch den Operanden angegebenen Zelle;

wenn die zu prüfende Bedingung falsch ist, übergebe die Steuerung an den nächsten Befehl.

jcxz/jecxz-Befehlsalgorithmus:
Prüfung der Bedingung, dass der Inhalt des ecx/cx-Registers gleich Null ist:

wenn der geprüfte Zustand

Befehle können nach Zweck unterschieden werden (Beispiele für mnemonische Opcodes von Befehlen eines PC-Assemblers wie IBM PC sind in Klammern angegeben):

l выполнения арифметических операций (ADD и ADC - сложения и сложения с переносом, SUB и SBB - вычитания и вычитания с заемом, MUL и IMUL - умножения без знака и со знаком, DIV и IDIV - деления без знака и со знаком, CMP - сравнения usw.);

l Ausführung logischer Operationen (OR, AND, NOT, XOR, TEST usw.);

l Datenübertragung (MOV - senden, XCHG - austauschen, IN - in den Mikroprozessor eingeben, OUT - vom Mikroprozessor abziehen usw.);

l Steuerungsübergabe (Programmverzweigungen: JMP - unbedingte Verzweigung, CALL - Prozeduraufruf, RET - Rückkehr von der Prozedur, J* - bedingte Verzweigung, LOOP - Schleifensteuerung usw.);

l Verarbeitung von Zeichenfolgen (MOVS - Übertragungen, CMPS - Vergleiche, LODS - Downloads, SCAS - Scans. Diese Befehle werden normalerweise mit einem Präfix (Wiederholungsmodifikator) REP verwendet;

l Programm-Interrupts (INT - Software-Interrupts, INTO - bedingte Interrupts bei Überlauf, IRET - Rückkehr vom Interrupt);

l Mikroprozessorsteuerung (ST* und CL* - Flags setzen und löschen, HLT - Stopp, WAIT - Standby, NOP - Leerlauf usw.).

Eine vollständige Liste der Assembler-Befehle befindet sich in Arbeit.

Datenübertragungsbefehle

l MOV dst, src - Datenübertragung (move - verschieben von src nach dst).

Überträgt: ein Byte (wenn src und dst im Byte-Format sind) oder ein Wort (wenn src und dst im Wort-Format sind) zwischen Registern oder zwischen Register und Speicher und schreibt einen sofortigen Wert in ein Register oder einen Speicher.

Die Operanden dst und src müssen dasselbe Format haben - Byte oder Wort.

Src kann vom Typ sein: r (Register) – Register, m (Speicher) – Speicher, i (Impedanz) – sofortiger Wert. Dst kann vom Typ r, m sein. Operanden können nicht in einem Befehl verwendet werden: rsegm zusammen mit i; zwei Operanden vom Typ m und zwei Operanden vom Typ rsegm). Operand i kann auch ein einfacher Ausdruck sein:

Bewegung AX, (152 + 101B) / 15

Die Ausdrucksauswertung wird nur während der Übersetzung durchgeführt. Flags ändern sich nicht.

l PUSH src - legt ein Wort auf den Stack (push - durchsetzen; von src auf den Stack schieben). Schiebt den Inhalt von src an die Spitze des Stapels – jedes 16-Bit-Register (einschließlich Segment) oder zwei Speicherstellen, die ein 16-Bit-Wort enthalten. Die Flags ändern sich nicht;

l POP dst - Extrahieren eines Wortes aus dem Stack (pop - pop; Zähle vom Stack in dst). Entfernt ein Wort von der Spitze des Stacks und platziert es in dst – einem beliebigen 16-Bit-Register (einschließlich Segment) oder zwei Speicherstellen. Flags ändern sich nicht.

Einführung.

Die Sprache, in der das ursprüngliche Programm geschrieben ist, wird aufgerufen Eingang Sprache und die Sprache, in die es zur Ausführung durch den Prozessor übersetzt wird - Wochenende Sprache. Der Prozess der Umwandlung einer Eingabesprache in eine Ausgabesprache wird aufgerufen Übertragung. Da Prozessoren in der Lage sind, Programme in binärer Maschinensprache auszuführen, die nicht zum Programmieren verwendet wird, ist eine Übersetzung aller Quellprogramme erforderlich. bekannt zwei WegeÜbersetzungen: Zusammenstellung und Interpretation.

Bei Zusammenstellung das Quellprogramm wird zunächst vollständig in ein äquivalentes Programm in der Zielsprache übersetzt, aufgerufen Objekt Programm und dann ausgeführt. Dieser Vorgang wird mit einem speziellen durchgeführt Programme, namens Compiler. Ein Compiler, für den die Eingabesprache eine symbolische Darstellung der Maschinen-(Ausgabe-)Sprache von Binärcodes ist, wird aufgerufen Monteur.

Bei Interpretationen Jede Zeile des Quellprogrammtextes wird geparst (interpretiert) und der darin angegebene Befehl wird sofort ausgeführt. Die Implementierung dieser Methode liegt bei Dolmetscherprogramm. Die Interpretation dauert lange. Um seine Effizienz zu steigern, wandelt der Interpreter, anstatt jede Zeile zu verarbeiten, vorläufig alle um Befehl Zeichenfolgen zu Zeichen (

). Die erzeugte Folge von Symbolen wird verwendet, um die Funktionen auszuführen, die dem ursprünglichen Programm zugewiesen sind.

Die unten diskutierte Assemblersprache wird durch Kompilierung implementiert.

Merkmale der Sprache.

Die Hauptmerkmale des Assemblers:

● Anstelle von Binärcodes verwendet die Sprache symbolische Namen - Mnemonik. Zum Beispiel für den Additionsbefehl (

) Es wird eine Mnemonik verwendet

Subtraktionen (

Multiplikation (

Abteilungen (

usw. Symbolische Namen werden auch verwendet, um Speicherzellen zu adressieren. Um in Assemblersprache zu programmieren, müssen Sie anstelle von Binärcodes und Adressen nur die symbolischen Namen kennen, die der Assembler in Binärcodes übersetzt;

jede Aussage entspricht ein Maschinenbefehl(Code), das heißt, es gibt eine Eins-zu-Eins-Entsprechung zwischen Maschinenbefehlen und Operatoren in einem Assemblersprachenprogramm;

● Sprache bietet Zugang zu allen Objekten und Mannschaften. Hochsprachen haben diese Fähigkeit nicht. Beispielsweise ermöglicht Ihnen die Assemblersprache, ein Flag-Register-Bit zu überprüfen, und eine Hochsprache (z. B.

) hat diese Fähigkeit nicht. Beachten Sie, dass Sprachen für die Systemprogrammierung (z. B. C) häufig eine Zwischenposition einnehmen. In Bezug auf die Zugänglichkeit sind sie näher an der Assemblersprache, haben aber die Syntax einer Hochsprache;

● Assemblersprache ist keine universelle Sprache. Jede spezifische Gruppe von Mikroprozessoren hat ihren eigenen Assembler. Hochsprachen haben diesen Nachteil nicht.

Im Gegensatz zu Hochsprachen nimmt das Schreiben und Debuggen eines Assemblerprogramms viel Zeit in Anspruch. Trotzdem ist die Assemblersprache geworden breite Verwendung aufgrund folgender Umstände:

● Ein in Assemblersprache geschriebenes Programm ist viel kleiner und viel schneller als ein in einer Hochsprache geschriebenes Programm. Für einige Anwendungen spielen diese Indikatoren eine primäre Rolle, zum Beispiel viele Systemprogramme (einschließlich Compiler), Programme in Kreditkarten, Mobiltelefonen, Gerätetreibern usw.;

● Manche Prozeduren erfordern vollen Zugriff auf die Hardware, was in einer Hochsprache meist nicht möglich ist. Dieser Fall umfasst Interrupts und Interrupt-Handler in Betriebssystemen sowie Gerätecontroller in eingebetteten Echtzeitsystemen.

In den meisten Programmen ist nur ein kleiner Prozentsatz des gesamten Codes für einen großen Prozentsatz der Ausführungszeit des Programms verantwortlich. Typischerweise ist 1 % des Programms für 50 % der Ausführungszeit verantwortlich, und 10 % des Programms sind für 90 % der Ausführungszeit verantwortlich. Um ein bestimmtes Programm unter realen Bedingungen zu schreiben, werden daher sowohl Assembler als auch eine der Hochsprachen verwendet.

Operatorformat in Assemblersprache.

Ein Programm in Assemblersprache ist eine Liste von Befehlen (Anweisungen, Sätzen), von denen jeder eine separate Zeile belegt und vier Felder enthält: ein Beschriftungsfeld, ein Operationsfeld, ein Operandenfeld und ein Kommentarfeld. Jedes Feld hat eine separate Spalte.

Beschriftungsfeld.

Spalte 1 ist dem Beschriftungsfeld zugeordnet.Eine Beschriftung ist ein symbolischer Name oder Bezeichner, Adressen Erinnerung. Es ist notwendig, um in der Lage zu sein:

● einen bedingten oder unbedingten Übergang zum Befehl vornehmen;

● Zugriff auf den Ort erhalten, an dem die Daten gespeichert sind.

Solche Aussagen sind gekennzeichnet. Zur Bezeichnung eines Namens werden (Groß-)Buchstaben des englischen Alphabets und Zahlen verwendet. Der Name muss mit einem Buchstaben beginnen und mit einem Doppelpunkt enden. Die Doppelpunktbezeichnung kann in eine separate Zeile geschrieben werden, und der Opcode kann in die nächste Zeile in Spalte 2 geschrieben werden, was die Arbeit des Compilers vereinfacht. Das Fehlen eines Doppelpunkts macht es unmöglich, zwischen einem Label und einem Opcode zu unterscheiden, wenn sie sich in separaten Zeilen befinden.

In einigen Versionen der Assemblersprache werden Doppelpunkte nur nach Anweisungslabels platziert, nicht nach Datenlabels, und die Labellänge kann auf 6 oder 8 Zeichen begrenzt werden.

Das Label-Feld sollte nicht die gleichen Namen enthalten, da das Label den Adressen von Befehlen zugeordnet ist. Wenn während der Programmausführung kein Befehl oder keine Daten aus dem Speicher aufgerufen werden müssen, bleibt das Label-Feld leer.

Transaktionscode-Feld.

Dieses Feld enthält die Befehlsmnemonik oder Pseudobefehl (siehe unten). Der mnemonische Befehlscode wird von den Sprachentwicklern gewählt. In Assemblersprache

Mnemonik ausgewählt, um Register aus dem Speicher zu laden

) und den Inhalt des Registers im Speicher zu speichern - die Mnemonik

). In Assemblersprachen

Sie können jeweils denselben Namen für beide Operationen verwenden

Wenn die Wahl der mnemonischen Namen willkürlich sein kann, dann ist die Notwendigkeit, zwei Maschinenbefehle zu verwenden, auf die Prozessorarchitektur zurückzuführen

Die Register-Mnemonik hängt auch von der Assembler-Version ab (Tabelle 5.2.1).

Operandenfeld.

Hier sind die zusätzlichen Informationen, die zum Ausführen des Vorgangs erforderlich sind. Im Operandenfeld für Sprungbefehle wird die Adresse angegeben, an die gesprungen werden soll, sowie Adressen und Register, die Operanden für den Maschinenbefehl sind. Als Beispiel sind hier die Operanden aufgeführt, die für 8-Bit-Prozessoren verwendet werden können

● numerische Daten,

in verschiedenen Zahlensystemen dargestellt. Um das verwendete Zahlensystem anzuzeigen, folgt der Konstante einer der lateinischen Buchstaben: B,

Dementsprechend sind binäre, oktale, hexadezimale, dezimale Zahlensysteme (

darf nicht aufgezeichnet werden). Wenn die erste Ziffer der Hexadezimalzahl A, B, C ist,

Dann wird eine unbedeutende 0 (Null) vorangestellt;

● Codes der internen Register und Speicherzellen des Mikroprozessors

M (Quellen oder Empfänger von Informationen) in Form der Buchstaben A, B, C,

M oder deren Adressen in einem beliebigen Zahlensystem (zum Beispiel 10V - Adresse registrieren

im Binärsystem);

● Identifikatoren,

für registrierte Flugzeugpaare,

Die Anfangsbuchstaben B

H; für ein Paar Akku und Merkmalsregister -

; für den Programmzähler -

; für Stapelzeiger -

● Beschriftungen, die Adressen von Operanden oder nächsten Anweisungen in bedingten angeben

(wenn die Bedingung erfüllt ist) und bedingungslose Übergänge. Zum Beispiel Operand M1 im Befehl

bedeutet die Notwendigkeit eines unbedingten Übergangs zu dem Befehl, dessen Adresse im Etikettenfeld mit der Kennung M1 gekennzeichnet ist;

● Ausdrücke,

die durch Verknüpfung der oben diskutierten Daten mit arithmetischen und logischen Operatoren erstellt werden. Beachten Sie, dass die Art und Weise, wie Datenspeicherplatz reserviert wird, von der Version der Sprache abhängt. Assembler-Entwickler für

Definiere das Wort) und führte später eine Alternative ein.

die von Anfang an die Sprache der Prozessoren war

In Sprachversion

benutzt

eine Konstante definieren).

Prozessoren verarbeiten Operanden unterschiedlicher Länge. Um es zu definieren, haben Assembler-Entwickler verschiedene Entscheidungen getroffen, zum Beispiel:

II Register unterschiedlicher Länge haben unterschiedliche Namen: EAX - zum Platzieren von 32-Bit-Operanden (Typ

); AX - für 16-Bit (Typ

und AN - für 8-Bit (Typ

● für Prozessoren

Suffixe werden jedem Opcode hinzugefügt: Suffix

Für Typ

; Suffix „.B“ für Typ

für Operanden unterschiedlicher Länge werden unterschiedliche Opcodes verwendet, um beispielsweise ein Byte, ein Halbwort (

) und Wörter in 64-Bit-Registern verwenden Opcodes

bzw.

Kommentarfeld.

Dieses Feld enthält Erläuterungen zu den Aktionen des Programms. Kommentare haben keinen Einfluss auf den Betrieb des Programms und sind für eine Person bestimmt. Sie werden möglicherweise benötigt, um ein Programm zu modifizieren, das ohne solche Kommentare sogar für erfahrene Programmierer völlig unverständlich sein kann. Ein Kommentar beginnt mit einem Buchstaben und dient der Erläuterung und Dokumentation von Programmen. Das Startzeichen eines Kommentars kann sein:

● Semikolon (;) in Sprachen für Prozessoren des Unternehmens

● Ausrufezeichen (!) in Sprachen für

Jeder einzelnen für einen Kommentar reservierten Zeile ist ein Startzeichen vorangestellt.

Pseudobefehle (Anweisungen).

In der Assemblersprache können zwei Haupttypen von Befehlen unterschieden werden:

Basic Anweisungen, die dem Maschinencode des Prozessors entsprechen. Diese Befehle führen die gesamte vom Programm bereitgestellte Verarbeitung durch;

Pseudo-Befehle oder Richtlinien, entwickelt, um dem Prozess der Übersetzung des Programms in die Sprache der Codekombinationen zu dienen. Als Beispiel in Tabelle. 5.2.2 zeigt einige Pseudobefehle des as-Assemblers

für die Familie

.

Beim Programmieren gibt es Situationen, in denen laut Algorithmus die gleiche Befehlskette viele Male wiederholt werden muss. Um aus dieser Situation herauszukommen, können Sie:

● Schreiben Sie die gewünschte Befehlsfolge, wann immer sie auftritt. Dieser Ansatz führt zu einer Erhöhung des Umfangs des Programms;

● diese Sequenz zu einer Prozedur (Subroutine) zusammenfassen und ggf. aufrufen. Ein solcher Ausgang hat seine Nachteile: Sie müssen jedes Mal eine spezielle Prozeduraufrufanweisung und eine Rückkehranweisung ausführen, was bei einer kurzen und häufig verwendeten Sequenz die Geschwindigkeit des Programms stark verringern kann.

Der einfachste und effizienteste Weg, eine Befehlskette viele Male zu wiederholen, ist use Makro, Dies kann als Pseudobefehl betrachtet werden, der dazu dient, eine Gruppe von Befehlen, die häufig in einem Programm vorkommen, neu zu übersetzen.

Ein Makro oder Makrobefehl ist durch drei Aspekte gekennzeichnet: Makrodefinition, Makroinversion und Makroerweiterung.

Makrodefinition

Dies ist eine Bezeichnung für eine sich wiederholende Folge von Programmbefehlen, die für Verweise im Programmtext verwendet wird.

Ein Makro hat folgenden Aufbau:

Liste von Ausdrücken; Makrodefinition

Die obige Makrodefinitionsstruktur besteht aus drei Teilen:

● Kopfzeile

Makro, das den Namen enthält

Pseudo-Befehl

und eine Reihe von Parametern;

● gepunktet Karosserie Makro;

● Mannschaft

Abschluss

Makrodefinitionen.

Ein Makroparametersatz enthält eine Liste aller im Operandenfeld angegebenen Parameter für die ausgewählte Anweisungsgruppe. Wenn diese Parameter früher im Programm angegeben werden, können sie im Kopf der Makrodefinition weggelassen werden.

Zum erneuten Zusammensetzen der ausgewählten Befehlsgruppe wird ein Aufruf verwendet, der aus dem Namen besteht

Makro- und Parameterliste mit anderen Werten.

Wenn der Assembler während der Kompilierung auf eine Makrodefinition stößt, speichert er sie in der Makrodefinitionstabelle. Bei späteren Auftritten im Programm des Namens (

) eines Makros ersetzt der Assembler sie durch den Hauptteil des Makros.

Die Verwendung eines Makronamens als Opcode wird aufgerufen Makro-Umkehr(Makroaufruf) und dessen Ersetzung durch den Rumpf des Makros - Makroerweiterung.

Wenn das Programm als eine Folge von Zeichen dargestellt wird (Buchstaben, Zahlen, Leerzeichen, Satzzeichen und Wagenrückläufe, um zu einer neuen Zeile zu gelangen), besteht die Makroerweiterung darin, einige Zeichenfolgen dieser Folge durch andere Zeichenfolgen zu ersetzen.

Die Makroerweiterung erfolgt während des Assemblierungsprozesses, nicht während der Programmausführung. Möglichkeiten, Zeichenfolgen zu manipulieren, wird zugeordnet Makro-Tools.

Der Montagevorgang wird durchgeführt in zwei Durchgängen:

● Beim ersten Durchlauf werden alle Makrodefinitionen beibehalten und Makroaufrufe expandiert. In diesem Fall wird das Quellprogramm gelesen und in ein Programm konvertiert, in dem alle Makrodefinitionen entfernt sind und jeder Makroaufruf durch einen Makrorumpf ersetzt wird;

● Der zweite Durchlauf verarbeitet das empfangene Programm ohne Makros.

Makros mit Parametern.

Um mit sich wiederholenden Befehlsfolgen zu arbeiten, deren Parameter unterschiedliche Werte annehmen können, stehen Makrodefinitionen zur Verfügung:

● mit tatsächlich Parameter, die in das Operandenfeld des Makroaufrufs gestellt werden;

● mit formell Parameter. Während der Makroexpansion wird jeder formale Parameter, der im Hauptteil des Makros erscheint, durch den entsprechenden tatsächlichen Parameter ersetzt.

Verwenden von Makros mit Parametern.

Programm 1 zeigt zwei ähnliche Befehlsfolgen, die sich darin unterscheiden, dass die erste von ihnen P und vertauscht

Und der zweite

Programm 2 enthält ein Makro mit zwei formalen Parametern P1 und P2. Während der Makroexpansion wird jedes P1-Zeichen innerhalb des Makrokörpers durch den ersten tatsächlichen Parameter (P,

), und das Symbol P2 wird durch den zweiten Aktualparameter (

) aus Programm Nr. 1. In einem Makroaufruf

Programm 2 ist markiert: P,

Der erste tatsächliche Parameter,

Der zweite aktuelle Parameter.

Programm 1

Programm 2

MOV EBX,Q MOV EAX,Pl

MOV Q,EAX MOV EBX,P2

MOV P,EBX MOV P2,EAX

Erweiterte Fähigkeiten.

Betrachten Sie einige erweiterte Funktionen der Sprache

Wenn ein Makro, das eine bedingte Verzweigungsanweisung und eine Marke enthält, zu der gesprungen werden soll, zwei- oder mehrmals aufgerufen wird, wird die Marke dupliziert (Etiketten-Duplizierungsproblem), was einen Fehler verursacht. Daher wird jedem Aufruf (vom Programmierer) ein eigenes Label als Parameter zugeordnet. In der Sprache

das Label wird als lokal deklariert (

) und dank der erweiterten Funktionen generiert der Assembler bei jeder Erweiterung des Makros automatisch ein anderes Label.

ermöglicht es Ihnen, Makros in anderen Makros zu definieren. Diese erweiterte Funktion ist sehr nützlich, wenn sie mit bedingter Programmverknüpfung kombiniert wird. Erwägen

WENN WORTGRÖSSE GT 16 M2 MAKRO

Das Makro M2 kann in beiden Teilen der Anweisung definiert werden

Die Definition hängt jedoch davon ab, ob das Programm auf einem 16-Bit- oder 32-Bit-Prozessor zusammengestellt wird. Wenn M1 nicht aufgerufen wird, wird das Makro M2 überhaupt nicht definiert.

Eine weitere erweiterte Funktion ist, dass Makros andere Makros aufrufen können, einschließlich sich selbst - rekursiv Anruf. Im letzteren Fall muss das Makro zur Vermeidung einer Endlosschleife einen Parameter an sich selbst übergeben, der sich bei jeder Erweiterung ändert, und auch prüfen diesen Parameter und beenden die Rekursion, wenn der Parameter einen bestimmten Wert erreicht.

Zur Verwendung von Makros in Assembler.

Bei der Verwendung von Makros muss der Assembler zwei Funktionen ausführen können: Makrodefinitionen speichern Und Makroaufrufe erweitern.

Speichern von Makrodefinitionen.

Alle Makronamen werden in einer Tabelle gespeichert. Jeder Name wird von einem Zeiger auf das entsprechende Makro begleitet, damit es bei Bedarf aufgerufen werden kann. Einige Assembler haben eine separate Tabelle für Makronamen, andere haben eine gemeinsame Tabelle, in der sich neben den Makronamen alle Maschinenbefehle und Anweisungen befinden.

Wenn während der Montage auf ein Makro gestoßen wird erstellt:

neues Tabellenelement mit dem Namen des Makros, der Anzahl der Parameter und einem Zeiger auf eine andere Makrodefinitionstabelle, wo der Makrokörper gespeichert wird;

● Liste formell Parameter.

Der Körper des Makros, der einfach eine Zeichenkette ist, wird dann gelesen und in der Makrodefinitionstabelle gespeichert. Im Schleifenkörper vorkommende Formalparameter sind mit einem speziellen Symbol gekennzeichnet.

Interne Darstellung eines Makros

aus obigem Beispiel für Programm 2 (S. 244) ist:

MOV EAX, MOV EBX, MOV MOV &

wobei das Semikolon als Wagenrücklaufzeichen und das kaufmännische Und & als formales Parameterzeichen verwendet wird.

Makroanruferweiterung.

Immer wenn während der Assemblierung auf eine Makrodefinition gestoßen wird, wird sie in der Makrotabelle gespeichert. Wenn ein Makro aufgerufen wird, unterbricht der Assembler vorübergehend das Lesen von Eingabedaten von der Eingabevorrichtung und beginnt mit dem Lesen des gespeicherten Makrokörpers. Die aus dem Makrorumpf extrahierten formalen Parameter werden durch die eigentlichen Parameter ersetzt und vom Aufruf bereitgestellt. Ein kaufmännisches Und & vor den Parametern ermöglicht es dem Assembler, sie zu erkennen.

Obwohl es viele Assembler-Versionen gibt, haben Assembler-Prozesse gemeinsame Merkmale und sind in vielerlei Hinsicht ähnlich. Nachfolgend wird die Arbeit eines Zwei-Durchgangs-Assemblers betrachtet.

Assembler mit zwei Durchgängen.

Das Programm besteht aus einer Reihe von Anweisungen. Daher scheint es, dass die folgende Abfolge von Aktionen während der Montage verwendet werden kann:

● in Maschinensprache übersetzen;

● Übertragen Sie den empfangenen Maschinencode in eine Datei und den entsprechenden Teil der Auflistung - in eine andere Datei;

● Wiederholen Sie die obigen Verfahren, bis das gesamte Programm ausgestrahlt wird.

Dieser Ansatz ist jedoch nicht effizient. Ein Beispiel ist das sogenannte Problem führender Link. Wenn die erste Anweisung ein Sprung zur P-Anweisung ganz am Ende des Programms ist, kann der Assembler sie nicht übersetzen. Er muss zuerst die Adresse des Operators P ermitteln, und dazu ist es notwendig, das gesamte Programm zu lesen. Jede vollständige Lesung des ursprünglichen Programms wird aufgerufen Passage. Lassen Sie uns zeigen, wie wir das Vorwärtsreferenzproblem mit zwei Durchgängen lösen können:

beim ersten Durchgang sammeln und speichern Sie alle Symboldefinitionen (einschließlich Labels) in der Tabelle und lesen und assemblieren Sie im zweiten Durchgang jede Anweisung. Diese Methode ist relativ einfach, aber der zweite Durchlauf durch das ursprüngliche Programm erfordert zusätzliche I/O-Zeit;

● beim ersten Durchgang, Konvertieren Programm in eine Zwischenform und speichere es in einer Tabelle, und der zweite Durchlauf wird nicht nach dem ursprünglichen Programm, sondern nach der Tabelle durchgeführt. Diese Montagemethode spart Zeit, da beim zweiten Durchlauf keine E/A-Operationen durchgeführt werden.

Erster Pass.

Zweck des ersten Durchgangs- Erstellen Sie eine Symboltabelle. Wie oben erwähnt, besteht ein weiteres Ziel des ersten Durchlaufs darin, alle Makrodefinitionen zu speichern und die Aufrufe so zu erweitern, wie sie erscheinen. Daher erfolgen sowohl die Zeichendefinition als auch die Makroerweiterung in einem Durchgang. Das Symbol kann beides sein Etikette, oder Bedeutung, dem mit der Direktive -you ein bestimmter Name zugewiesen wird:

;Wert - Puffergröße

Indem der Assembler den symbolischen Namen im Befehlskennsatzfeld eine Bedeutung gibt, legt er im Wesentlichen die Adressen fest, die jeder Befehl während der Programmausführung haben wird. Dazu spart der Monteur beim Montagevorgang Befehlsadressenzähler(

) als spezielle Variable. Zu Beginn des ersten Durchlaufs wird der Wert der Sondervariablen auf 0 gesetzt und nach jedem abgearbeiteten Befehl um die Länge des Befehls inkrementiert. Als Beispiel in Tabelle. 5.2.3 zeigt ein Fragment des Programms, das die Länge von Befehlen und Zählerwerten angibt. Beim ersten Durchlauf werden Tabellen generiert Symbolnamen, Direktiven Und Betriebscodes, und ggf wörtlich Tisch. Ein Literal ist eine Konstante, für die der Assembler automatisch Speicher reserviert. Wir stellen sofort fest, dass moderne Prozessoren Anweisungen mit direkten Adressen enthalten, sodass ihre Assembler keine Literale unterstützen.

Symboltabelle

enthält ein Element für jeden Namen (Tabelle 5.2.4). Jeder Eintrag in der Symboltabelle enthält den Namen selbst (oder einen Zeiger darauf), seinen numerischen Wert und manchmal einige zusätzliche Informationen, darunter:

● die Länge des mit dem Symbol verknüpften Datenfelds;

● Speicherneuzuordnungsbits (die anzeigen, ob sich der Wert eines Zeichens ändert, wenn das Programm an einer anderen Adresse geladen wird als vom Assembler vorgesehen);

● Informationen darüber, ob auf das Symbol von außerhalb der Prozedur zugegriffen werden kann.

Symbolische Namen sind Labels. Sie können mit Operatoren angegeben werden (z. B.

Tabelle der Richtlinien.

Diese Tabelle listet alle Direktiven oder Pseudobefehle auf, die beim Assemblieren eines Programms auftreten.

Operationscode-Tabelle.

Die Tabelle hat für jeden Opcode separate Spalten: Opcode-Bezeichnung, Operand 1, Operand 2, Hexadezimalwert des Opcodes, Befehlslänge und Befehlstyp (Tabelle 5.2.5). Operationscodes werden je nach Anzahl und Art der Operanden in Gruppen eingeteilt. Der Befehlstyp bestimmt die Gruppennummer und spezifiziert die Prozedur, die aufgerufen wird, um alle Befehle in dieser Gruppe zu verarbeiten.

Zweiter Durchgang.

Zweck des zweiten Durchgangs- Erstellung eines Objektprogramms und ggf. Ausdruck eines Montageprotokolls; Ausgabeinformationen, die der Linker benötigt, um Prozeduren zu verknüpfen, die zu unterschiedlichen Zeiten zu einer ausführbaren Datei zusammengestellt wurden.

Im zweiten Durchlauf (wie im ersten) werden die Zeilen mit den Anweisungen nacheinander gelesen und verarbeitet. Der ursprüngliche Operator und die davon abgeleitete Ausgabe in hexadezimaler Form Objekt der Code kann gedruckt oder für den späteren Druck gepuffert werden. Nach dem Zurücksetzen des Befehlsadressenzählers wird die nächste Anweisung aufgerufen.

Das Originalprogramm kann Fehler enthalten, zum Beispiel:

das angegebene Symbol ist nicht oder mehr als einmal definiert;

● Der Opcode wird durch einen ungültigen Namen dargestellt (aufgrund eines Tippfehlers), nicht mit genügend Operanden versehen oder hat zu viele Operanden;

● kein Operator

Einige Assembler erkennen möglicherweise ein undefiniertes Symbol und ersetzen es. Wenn jedoch eine Anweisung mit einem Fehler gefunden wird, zeigt der Assembler in den meisten Fällen eine Fehlermeldung auf dem Bildschirm an und versucht, den Assemblierungsprozess fortzusetzen.

Artikel über die Assemblersprache.

Fortsetzung des Themas:
Modems

MatLab präsentiert alle Daten als Arrays. Es ist sehr wichtig zu verstehen, wie man Arrays richtig verwendet. Ohne diese ist ein effektives Arbeiten in MatLab nicht möglich, insbesondere...