Assemblersprache

hardwarenahe Programmiersprache

EineAssemblersprache,kurz auchAssemblergenannt (vonenglischto assemble‚zusammenfügen‘), ist eineProgrammiersprache,die auf denBefehlsvorrateines bestimmten Computertyps (d. h. dessenProzessorarchitektur) ausgerichtet ist.

Assemblersprachen bezeichnet man deshalb als maschinenorientierte Programmiersprachen und – als Nachfolger der direkten Programmierung mit Zahlencodes – als Programmiersprachen derzweiten Generation:Anstelle einesBinärcodesderMaschinensprachekönnenBefehleund deren Operanden durch leichter verständlichemnemonische Symbolein Textform (z. B. „MOVE “), Operanden z. T. alssymbolische Adresse(z. B. „PLZ “), notiert und dargestellt werden.[1]

DerQuelltexteines Assemblerprogramms wird mit Hilfe einer Übersetzungssoftware (Assembleroder Assemblierer) in Maschinencode übersetzt. Dagegen übersetzt inhöheren Programmiersprachen(Hochsprachen, dritte Generation) ein sogenannterCompilerabstraktere (komplexere, nicht auf den Prozessor-Befehlssatz begrenzte) Befehle in den Maschinencode der gegebenen Zielarchitektur – oder in eine Zwischensprache.[2]

Umgangssprachlich werden die Ausdrücke „Maschinensprache “und „Assembler(sprache) “häufig synonym verwendet.

Übersicht

Bearbeiten

Ein Quelltext in Assemblersprache wird auch alsAssemblercodebezeichnet. Programme in Assemblersprachen zeichnen sich dadurch aus, dass alle Möglichkeiten desMikroprozessorsgenutzt werden können, was heutzutage selten erforderlich ist. Sie werden im Allgemeinen nur noch dann verwendet, wenn Programme bzw. einzelne Teile davon sehr zeitkritisch sind, z. B. beimHochleistungsrechnenoder beiEchtzeitsystemen.Ihre Nutzung kann auch dann sinnvoll sein, wenn für die Programme nur sehr wenig Speicherplatz zur Verfügung steht (z. B. ineingebetteten Systemen).

Unter dem Aspekt der Geschwindigkeitsoptimierung kann der Einsatz von Assemblercode auch bei verfügbaren hochoptimierenden Compilern noch seine Berechtigung haben, Vor- und Nachteile sollten aber für die spezifische Anwendung abgewogen werden. Bei komplexer Technik wieIntel Itaniumund verschiedenendigitalen Signalprozessorenkann ein Compiler u. U. durchaus besseren Code erzeugen als ein durchschnittlicher Assemblerprogrammierer, da das Ablaufverhalten solcher Architekturen mit komplexen mehrstufigen intelligenten Optimierungen (z. B.Out-of-order execution,Pipeline-Stalls,…) hochgradig nichtlinear ist. Die Geschwindigkeitsoptimierung wird immer komplexer, da zahlreiche Nebenbedingungen eingehalten werden müssen. Dies ist ein gleichermaßen wachsendes Problem sowohl für die immer besser werdenden Compiler derHochsprachenals auch für Programmierer der Assemblersprache. Für einen optimalen Code wird immer mehr Kontextwissen benötigt (z. B.Cachenutzung,räumliche und zeitlicheLokalitätder Speicherzugriffe), welches der Assemblerprogrammierer teilweise (im Gegensatz zum Compiler) durchLaufzeitprofilingdes ausgeführten Codes in seinem angestrebten Anwendungsfeld gewinnen kann. Ein Beispiel hierfür ist derSSE-Befehl MOVNTQ, welcher wegen des fehlenden Kontextwissens von Compilern kaum optimal eingesetzt werden kann.

Die Rückwandlung von Maschinencode in Assemblersprache wirdDisassemblierunggenannt. Der Prozess ist allerdings bei fehlenden Debug-Informationen hochgradig verlustbehaftet, da sich viele Informationen wie ursprünglicheBezeichneroderKommentarenicht wiederherstellen, da diese beim Assemblieren nicht in den Maschinencode übernommen wurden oder berechnet wurden.

Beschreibung

Bearbeiten

Programmbefehle inMaschinensprachebilden sich aus dem Operationscode (Opcode) und meist weiteren, je nach Befehl individuell festgelegten Angaben wie Adressen, im Befehl eingebettete Literale, Längenangaben etc. Da die Zahlenwerte der Opcodes schwierig zu merken sind, verwenden Assemblersprachen leichter merkbare Kürzel, sogenanntemnemonische Symbole(kurzMnemonics).[3]

Beispiel: Der folgende Befehl in der Maschinensprache vonx86-Prozessoren

10110000 01100001(inhexadezimalerDarstellung: 'B0 61')

entspricht dem Assemblerbefehl

movb$0x61,%al# AT&T-Syntax (alles nach „# “ist Kommentar)
# mnemonisches Kürzel bedeutet „move_byte von/was, nach “

bzw.

moval,61h;Intel-Syntax; das ‚mov‘ als mnemotechnisches Kürzel erkennt
;aus dem angesprochenen ‚al‘, dass nur 1 Byte kopiert werden soll.
;„mov wohin, was/woher “

und bedeutet, dass der hexadezimale Wert „61 “(dezimal 97) in den niederwertigen Teil desRegisters„ax “geladen wird; „ax “bezeichnet das ganze Register, „al “(für low) den niederwertigen Teil des Registers. Der hochwertige Teil des Registers kann mit „ah “angesprochen werden (für „high “).

Am Beispiel ist zu erkennen, dass – obwohl in denselben Maschinencode übersetzt wird – die beiden Assembler-Dialekte deutlich verschieden formulieren.

  • Die Information, dass ein Byte zu kopieren ist, steckt bei AT&T im „movb“;der Intel-mov entnimmt sie dem Umstand, dass Register(teil) „al “ein Byte groß ist.
  • Quelle und Ziel des Kopierens werden vertauscht angegeben.
  • Auch das Format zum Ansprechen eines Registers sowie zur Angabe eines direkten Zahlenwerts ist verschieden.

Mit Computerhilfe kann man das eine in das andere weitgehend eins zu eins übersetzen. Jedoch werden Adressumformungen vorgenommen, so dass man symbolische Adressen benutzen kann. Die Eingabedaten für einen Assembler enthalten neben den eigentlichen Codes/Befehlen (die er in Maschinencode übersetzt) auchSteueranweisungen,die seine Arbeitsweise bestimmen/festlegen, zum Beispiel zur Definition eines Basisregisters.

Häufig werden komplexere Assemblersprachen (Makroassembler) verwendet, um die Programmierarbeit zu erleichtern. Makros sind dabei imQuelltextenthaltene Aufrufe, die vor dem eigentlichen Assemblieren automatisch durch (meist kurze) Folgen von Assemblerbefehlen ersetzt werden. Dabei können einfache, durch Parameter steuerbare Ersetzungen vorgenommen werden. Die Disassemblierung von derart generiertem Code ergibt allerdings den reinen Assemblercode ohne die beim Übersetzen expandierten Makros.

Beispielprogramm

Bearbeiten

Ein sehr einfaches Programm, das zu Demonstrationszwecken häufig benutzteHallo-Welt-Beispielprogramm,kann zum Beispiel in der AssemblerspracheMASMfürMS-DOSaus folgendem Assemblercode bestehen:

ASSUMECS:CODE,DS:DATA;- dem Assembler die Zuordnung der Segmentregister zu den Segmenten mitteilen

DATASEGMENT;Beginn des Datensegments
Meldungdb"HalloWelt";- Zeichenkette „Hallo Welt “
db13,10;- Neue Zeile
db"$";- Zeichen, das die Textausgabefunktion (INT 21h, Unterfunktion 09h) als Zeichenkettenende versteht
DATAENDS;Ende des Datensegments

CODESEGMENT;Beginn des Codesegments
Anfang:;- Einsprung-Label fuer den Anfang des Programms
movax,DATA;- Adresse des Datensegments in das Register „AX “laden
movds,ax;In das Segmentregister „DS “uebertragen (das DS-Register kann nicht direkt mit einem Wert beschrieben werden)
movdx,OFFSETMeldung;- die zum Datensegment relative Adresse des Textes in das „DX “Datenregister laden
;die vollstaendige Adresse von „Meldung “befindet sich nun im Registerpaar DS:DX
movah,09h;- die Unterfunktion 9 des Betriebssysteminterrupts 21h auswaehlen (Textausgaberoutine)
int21h;- den Betriebssysteminterrupt 21h aufrufen (hier erfolgt die Ausgabe des Textes am Schirm)
movax,4C00h;- die Unterfunktion 4Ch (Programmbeendigung) des Betriebssysteminterrupts 21h festlegen
int21h;- damit wird die Kontrolle wieder an das Betriebssystem zurueckgegeben (Programmende)
CODEENDS;Ende des Codesegments

ENDAnfang;- dem Assembler- und Linkprogramm den Programm-Einsprunglabel mitteilen
;- dadurch erhaelt der Befehlszaehler beim Aufruf des Programmes diesen Wert

Vergleichende Gegenüberstellungen für dasHallo-Welt-Programm in unterschiedlichen Assemblerdialekten enthältdiese Liste.

In einemPascal-Quelltext (eine Hochsprache) kann der Programmcode für„Hallo Welt “dagegen deutlich kürzer sein:

programHallo(output);
begin
writeln('Hallo Welt')
end.

Verschiedene Assemblersprachen

Bearbeiten

Jede Computerarchitektur hat ihre eigene Maschinensprache und damit Assemblersprache. Mitunter existieren auch mehrere Assemblersprachen-Dialekte („verschiedene Assemblersprachen “, sowie zugehörige Assembler) für die gleiche Prozessorarchitektur. Die Sprachen verschiedener Architekturen unterscheiden sich in Anzahl und Typ der Operationen.

Jedoch haben alle Architekturen die folgenden grundlegenden Operationen:

  • Daten lesen und schreiben von/nach Hauptspeicher in/aus dem Prozessor (i. A. von/zu einemRegister); fast immer auch von-Register-zu-Register, meistens auch von-Hauptspeicher-zu-Hauptspeicher,
  • einfache logische Operationen (z. B.Bit-Operationen wie AND/OR/NOT/SHIFT),
  • einfache Kontrolle des Programmflusses (v. a. durchProzessor-Flag-bedingte Sprünge),
  • einfache arithmetische Operationen (z. B. Ganzzahl-Addition, Ganzzahl-Vergleich).

Bestimmte Rechnerarchitekturen haben oft auch komplexere Befehle (CISC) wie z. B.:

  • Aufrufe von Ein- bzw. Ausgabegeräten,
  • eine einfache Operation (z. B. Addition) auf einen Vektor von Werten anwenden,
  • Speicherblock-Operationen (z. B. kopieren oder mit Nullen füllen),
  • höhere Arithmetik: Befehle, die durch (mehrere) einfache nachgebaut werden könnten (z. B. „Verringere Wert in Register A um 1; wenn es nun =0 ist, springe an Programmstelle xyz “(DJZ A,xyz~ 'decrement A, Jump if Zero to xyz')),
  • Gleitkomma-Arithmetik wie Gleitkomma-Addition, -Multiplikation,Sinus-, Kosinus- und Wurzelberechnung (entweder über spezielle Zusatzprozessoren realisiert oder über Softwareroutinen),
  • massive, direkte Parallelprogrammierbarkeit des Prozessors, etwa beidigitalen Signalprozessoren,
  • Synchronisation mit anderen Prozessoren fürSMP-Systeme,
  • Unterbrechungssteuerungen, die besonders fürProzessrechnerbenötigt werden.

Geschichte

Bearbeiten

Die erste Assemblersprache wurde 1947 vonKathleen Boothentwickelt.[4][5]Sie entwarf im Anschluss denAssemblerfür die ersten Computersysteme amBirkbeck College der University of London.Zwischen 1948 und 1950 schriebNathaniel Rochestereinen der frühsten symbolischenAssemblerfür eineIBM 701.

In den 1980er und frühen 1990er Jahren wechselte die Sprache, in der Betriebssysteme für größere Rechner geschrieben wurden, von Assembler zu Hochsprachen hin, meist C, aber auch C++ oder Objective C. Hauptauslöser war die steigende Komplexität von Betriebssystemen bei größerem verfügbaren Speicher im Bereich oberhalb von einem Megabyte. In Assembler verblieben zum Beispiel das Zwischenspeichern von Registern bei Prozesswechsel (sieheScheduler), oder bei derx86-Architektur der Teil des Boot-Loaders, der innerhalb des 512 Byte großenMaster Boot Recordsuntergebracht sein muss. Auch Teile vonGerätetreibernwerden in Assemblersprache geschrieben, falls aus den Hochsprachen kein effizienter Hardware-Zugriff möglich ist. Manche Hochsprachencompiler erlauben es, direkt im eigentlichenQuellcodeAssemblercode, sogenannteInline-Assembler,einzubetten.

Bis ca. 1990 wurden die meistenComputerspielein Assemblersprachen programmiert, da nur so aufHeimcomputernund den damaligenSpielkonsoleneine akzeptable Spielgeschwindigkeit und eine den kleinen Speicher dieser Systeme nicht sprengende Programmgröße zu erzielen war. Noch heute gehören Computerspiele zu den Programmen, bei denen am ehesten kleinere assemblersprachliche Programmteile zum Einsatz kommen, um so Prozessorerweiterungen wieSSEzu nutzen.

Bei vielen Anwendungen für Geräte, die vonMikrocontrollerngesteuert sind, war früher oft eine Programmierung in Assembler notwendig, um die knappen Ressourcen dieser Mikrocontroller optimal auszunutzen. Um Assemblercode für solche Mikrocontroller zu Maschinencode zu übersetzen, werdenCross-Assemblerbei der Entwicklung eingesetzt. Heute sind Mikrocontroller so günstig und leistungsfähig, dass moderne C-Compiler auch in diesem Bereich die Assembler weitgehend abgelöst haben. Nicht zuletzt aufgrund größerer Programmspeicher bei geringen Aufpreisen für die Chips fallen die Vorteile von Hochsprachen gegenüber den teils geringen Vorteilen der Assemblersprache immer mehr ins Gewicht.

Vergleich zur Programmierung in einer Hochsprache

Bearbeiten

Nachteile

Bearbeiten

Assemblerprogramme sind sehrhardwarenahgeschrieben, da sie direkt die unterschiedlichen Spezifikationen undBefehlssätzeder einzelnen Computerarchitekturen (Prozessorarchitektur) abbilden. Daher kann ein Assemblerprogramm im Allgemeinen nicht auf ein anderes Computersystem (andere Prozessorarchitektur) übertragen werden, ohne dass derQuelltextangepasst wird. Das erfordert, abhängig von den Unterschieden der Assemblersprachen, hohen Umstellungsaufwand, unter Umständen ist ein komplettes Neuschreiben des Programmtextes erforderlich. Im Gegensatz dazu muss bei Hochsprachen oft nur einCompilerfür die neue Zielplattform verwendet werden.

Quelltexte in Assemblersprache sind fast immerdeutlich längerals in einer Hochsprache, da die Instruktionen weniger komplex sind und deshalb gewisse Funktionen/Operationen mehrere Assemblerbefehle erfordern; z. B. müssen beim logischen Vergleich von Daten (= > <…) ungleicheDatenformateoder -Längen zunächst angeglichen werden. Die dadurchgrößere Befehlsanzahlerhöht das Risiko, unübersichtlichen, schlecht strukturierten und schlecht wartbarenProgrammcodeherzustellen.

Vorteile

Bearbeiten

Nach wie vor dient Assembler zur Mikro-Optimierung von Berechnungen, für die der Hochsprachencompiler nicht ausreichend effizienten Code generiert.[6][7]In solchen Fällen können Berechnungen effizienter direkt in Assembler programmiert werden. Beispielsweise sind im Bereich des wissenschaftlichen Rechnens die schnellsten Varianten mathematischer Bibliotheken wieBLAS[8][9]oder bei architekturabhängigen Funktionen wie der C-Standardfunktionmemcpy[10][11]weiterhin die mit Assembler-Code. Auch lassen sich gewisse, sehr systemnahe Operationen unter Umgehung des Betriebssystems (z. B. direktes Schreiben in den Bildschirmspeicher) nicht in allen Hochsprachen ausführen.

Der Nutzen von Assembler liegt auch im Verständnis der Arbeits- und Funktionsweise eines Systems, das durch Konstrukte in Hochsprachen versteckt wird. Auch heute noch wird an vielen Hochschulen Assembler gelehrt, um ein Verständnis für die Rechnerarchitektur und seine Arbeitsweise zu bekommen.

Siehe auch

Bearbeiten
  • C−−– eine „portable “Assemblersprache

Literatur

Bearbeiten
  • Gerhard Niemeyer:Einführung in das Programmieren in ASSEMBLER. Systeme IBM, Siemens, Univac, Comparex, IBM-PC/370.6. bearbeitete und erweiterte Auflage. de Gruyter, Berlin u. a. 1989,ISBN 3-11-012174-3(De-Gruyter-Lehrbuch).
  • Joachim Rohde:Assembler ge-packt. (Schnelles und effektives Nachschlagen aller relevanten Befehlssätze für AMD und Intel. MMX und 3DNow! SSE und seine Erweiterungen).2. aktualisierte Auflage. Mitp-Verlag, Heidelberg 2007,ISBN 978-3-8266-1756-0(Die ge-packte Referenz).
  • Joachim Rohde, Marcus Roming:Assembler. Grundlagen der Programmierung. (Theorie und Praxis unter DOS und Windows. MMX und 3DNOW! Programme optimieren und Reverse Engineering).2. aktualisierte und erweiterte Auflage. Mitp-Verlag, Bonn 2006,ISBN 3-8266-1469-0(3-8266-1469-0).
  • Jeff Duntemann:Assembly Language Step-by-Step. Programming with DOS and Linux.2. Auflage. Wiley, New York NY u. a. 2000,ISBN 0-471-37523-3(mit 1 CD-ROM).
  • Paul Carter:PC Assembly Language,2001.
  • Robert Britton:MIPS Assembly Language Programming.Prentice Hall, Upper Saddle River NJ 2003,ISBN 0-13-142044-5.
  • Steve McConnell:Code Complete. A practical Handbook of Software Construction.Microsoft Press, Redmond WA 1993,ISBN 1-55615-484-4.
  • Randall Hyde:The Art of Assembly Language.2. Auflage, No Starch Press, 2010,ISBN 978-1593272074.
Bearbeiten
Wiktionary: Assemblersprache– Bedeutungserklärungen, Wortherkunft, Synonyme, Übersetzungen
Wikibooks: Assembler-Programmierung– Lern- und Lehrmaterialien

Einzelnachweise

Bearbeiten
  1. Informatik Duden.ISBN 3-411-05232-5.
  2. Hering, Gutekunst, Dyllon:Handbuch der praktischen und technischen Informatik.S. 302,books.google.de
  3. Jörg Roth:Die Maschinenprogrammebene eines RechnersKapitelMaschinensprache und Assembler(Archiv-Version vom 17. Oktober 2018), abgerufen am 19. November 2020.
  4. Steven Dufresne:Kathleen Booth: Assembling Early Computers While Inventing Assembly.21. August 2018, archiviert vomOriginalam24. März 2020;abgerufen am 10. Februar 2019(englisch).
  5. Andrew Donald Booth,Kathleen Hylda Valerie Britten:General considerations in the design of an all purpose electronic digital computer.2. Auflage.Birkbeck College, London,The Institute for Advanced Study, Princeton, New Jersey, USA September 1947 (englisch,Online[PDF; abgerufen am 10. Februar 2019]):“The non-original ideas, contained in the following text, have been derived from a number of sources,... It is felt, however, that acknowledgement should be made to Prof. John von Neumann and to Dr. Herman Goldstein for many fruitful discussions...”
  6. Måns Rullgård:Bit-field-badness.hardwarebug.org, 30. Januar 2010, archiviert vomOriginalam5. Februar 2010;abgerufen am 4. März 2010(englisch).
  7. Måns Rullgård:GCC makes a mess.hardwarebug.org, 13. Mai 2009, archiviert vomOriginalam16. März 2010;abgerufen am 4. März 2010(englisch).
  8. John Markoff:Writing the Fastest Code, by Hand, for Fun: A Human Computer Keeps Speeding Up Chips.New York Times,28. November 2005,abgerufen am 4. März 2010(englisch).
  9. BLAS Benchmark-August2008.eigen.tuxfamily.org, 1. August 2008,abgerufen am 4. März 2010(englisch).
  10. Mike Wall:Using Block Prefetch for Optimized Memory Performance (2001, Archiv-Version).(PDF; 136 kB)mit.edu,archiviert vomOriginalam30. August 2017;abgerufen am 19. November 2020(englisch).
  11. Agner Fog:Optimizing subroutines in assembly language.(PDF; 873 kB) Copenhagen University College of Engineering, 29. Februar 2012,S. 100,abgerufen am 22. September 2012(englisch): „12.11 Loop unrolling “