Zum Inhalt springen
L

Wikipedia · einfach zusammengefasst · Stand

Bytecode

Bytecode ist in der Informatik die Bezeichnung für eine Sammlung von Befehlen, also die Maschinensprache für eine virtuelle Maschine.

Inhalt4 Abschnitte
  1. 1. Bedeutung und Funktionsweise
  2. 2. Virtuelle Maschinen, Compiler und Einsatz
  3. 3. Interne Nutzung und Speicherersparnis
  4. 4. Dekompilierung und Schutz von Programmen

Bedeutung und Funktionsweise

Bytecode ist eine Sammlung von Befehlen und damit die Maschinensprache einer virtuellen Maschine. Der Begriff bezeichnet sowohl die Vorschrift, wie Quellcode in diesen Objektcode kodiert wird, als auch die so entstandenen ausführbaren Programme. Anders als Quelltexte oder Skripte ist Bytecode nicht menschenlesbar: Programmanweisungen und Werte sind als Bytes gespeichert.

Im Unterschied zu Maschinencode wird Bytecode normalerweise nicht unmittelbar von einem Hardware-Prozessor ausgeführt. Maschinencode läuft direkt auf dem Prozessor, während Bytecode zunächst durch ein besonderes Programm, die virtuelle Maschine, interpretiert oder in Maschinencode übersetzt wird. Passende Hardware-Prozessoren können Bytecode allerdings auch direkt ausführen. Umgekehrt wird Maschinencode meist auf Software-Prozessoren entwickelt und kann insofern ebenfalls als Bytecode betrachtet werden.

Bei der Kompilierung von Quelltext, etwa in Java, entsteht oft nicht sofort Maschinencode, sondern Bytecode als Zwischencode. Er ist meist von der tatsächlichen Hardware unabhängig, entsteht nach einer semantischen Analyse des Quelltexts und ist deutlich kompakter. Außerdem lässt er sich in der Regel wesentlich effizienter interpretieren als der ursprüngliche Quelltext.

Virtuelle Maschinen, Compiler und Einsatz

Eine virtuelle Maschine führt den Bytecode aus. Bei Java ist dies die Java Virtual Machine (JVM). Zur Laufzeit kann sie den Bytecode entweder in die Maschinensprache des jeweiligen Prozessors übersetzen; das heißt Just-in-time-Kompilierung. Oder sie führt passende Maschinencode-Routinen über einen Interpreter aus. Für jede Rechnerplattform, auf der ein Kompilat laufen soll, muss eine passende virtuelle Maschine vorhanden sein.

Bytecode wird unter anderem von UCSD Pascal, Lua, den .Net-Framework-Sprachen C#, F# und Visual Basic, Python, Ruby, Perl, PHP, Prolog, Limbo, Gambas und Tcl verwendet. Bei Java, Python und .NET wird Bytecode als Kompilat gespeichert und unabhängig vom Quellcode ausgeführt. Bei Perl bis Version 5 und bei Tcl wird dagegen beim Programmstart der Quellcode in Bytecode übersetzt; der Bytecode bleibt dann nur im Arbeitsspeicher.

Ein Vorteil ist, dass dieselbe virtuelle Maschine mehrere Sprachen unterstützen kann, etwa die JVM Java, Scala, Groovy und viele weitere. Dann muss für eine höhere Programmiersprache nur ein Bytecode-Compiler entwickelt werden. Ein Compiler, der direkt Maschinencode für mehrere Betriebssysteme und Architekturen erzeugen soll, wäre deutlich aufwendiger. Bytecode kann auch sprachunabhängig für einen bestimmten Zweck entwickelt sein, zum Beispiel WebAssembly.

Die Ausführung durch eine virtuelle Maschine verlängert die Startzeit; diese Beeinträchtigung ist im Allgemeinen eher messbar als wahrnehmbar. JIT-Compiler übersetzen Bytecode-Stücke während der Programmausführung einmalig in Maschinencode und führen diesen aus. So können sich die Ausführungszeiten häufig den Zeiten von vorübersetztem Maschinencode annähern; die Startzeiten werden dadurch jedoch nicht verkürzt.

Interne Nutzung und Speicherersparnis

Viele interpretierte Sprachen erzeugen Bytecode intern und halten ihn für Programmierer und Endbenutzer unsichtbar. Beispiele sind Perl, PHP, Prolog, Tcl und Python. In Python wird Bytecode nach dem ersten Parsen in .pyc-Dateien abgelegt, die den Bytecode enthalten; das ist grundsätzlich ähnlich wie bei Java, aber optional.

Bytecompiling wurde bereits in den 1960er Jahren für Lisp eingesetzt: Die 256 atomaren Funktionen waren jeweils in einem Byte kodiert. Frühe BASIC-Versionen der 1970er und 1980er Jahre ersetzten Schlüsselwörter durch Byte-Werte, sogenannte Tokens. Das beschleunigte die Ausführung und speicherte Programmtexte kompakter. Variablen, mathematische Ausdrücke und Zeichenketten blieben dagegen unverändert. Beim LIST-Befehl wurden Tokens wieder als lesbare Schlüsselwörter ausgegeben. Ein früher Heimcomputer mit Bytecode war der TI 99/4a von Texas Instruments.

Bei den ersten Homecomputern war Speicher stark begrenzt. BASIC-Programme mussten deshalb oft als Bytecode in den RAM überführt werden; sonst blieb als Alternative nur direkt eingegebener Maschinencode. Reiner Text hätte die Speichergrenze schnell erreicht. Auch bei späteren langsamen und begrenzten Massenspeichern blieb die Platzersparnis vorteilhaft. Bytecode kann zudem schneller als normaler Quelltext ausgeführt werden: Statt die Buchstaben eines Befehls vergleichen zu müssen, genügen ein oder wenige Bytes, die den Befehl darstellen.

Dekompilierung und Schutz von Programmen

Wenn Quellcode nicht offengelegt werden soll, ist die Möglichkeit der Rückgewinnung wichtig. Bei Sprachen wie C, die direkt zu Maschinencode kompiliert werden, lässt sich der ursprüngliche Quellcode normalerweise nicht zurückgewinnen. Dafür müssten mindestens die Algorithmen des verwendeten Compilers bekannt sein. Funktionsbezeichner und Variablennamen sind nur ermittelbar, wenn das Kompilat Daten für einen Debugger enthält.

Bei Bytecode ist Dekompilieren meist deutlich einfacher, weil er sich weniger an abstrakter Maschinensprache orientiert und oft näher an der zugrundeliegenden Programmiersprache liegt. Der exakte Quellcode kann nicht rekonstruiert werden, aber häufig äquivalenter Code in der Quellsprache. Bei Java und .NET gelingt dies in den meisten Fällen sehr gut; bei Prolog mit WAM-Bytecode ist eine Rückgewinnung immer möglich.

Ein Obfuskator kann die Nutzbarkeit des dekompilierten Quelltexts stark einschränken. Er kann beispielsweise Befehlsfolgen einbauen, die es in der Quellsprache nicht gibt, etwa Code nach dem Ende einer Methode. Dann ist eine Dekompilierung in die Quellsprache gar nicht mehr möglich.

Weiterlesen

Informatik Als einfache Rechengeräte leisteten Abakus und später der Rechenschieber unschätzbare Dienste. 1641 konstruierte Blaise Pascal eine mechanische … Befehlssatz Der Befehlssatz, auch Instruktionssatz (englisch instruction set), eines Prozessors ist in der Rechnerarchitektur die Menge der Maschinenbefehle, die ein … Quelltext Quelltext, auch Quellcode (englisch source code) oder unscharf Programmcode genannt, ist in der Informatik der für Menschen lesbare, in einer … Maschinensprache Mit einem Assembler: Assemblersprachen formulieren die Prozessorbefehle des Maschinencodes als Mnemonics in einer einfachen Syntax. Dieser Quelltext wird … Prozessor Aufbau und Funktionale Einheiten · Hauptprozessor (CPU) und Mehrprozessorkerne · Steuer- bzw. Leitwerk · Rechenwerk und Register · Datenleitungen · Caches und MMU. Compiler Ein Übersetzer zur Übertragung von Assembler-Quellprogrammen in Maschinensprache wird als Assembler oder Assemblierer bezeichnet. Geschichte. Bearbeiten. Programmiersprache Bei deklarativen Programmiersprachen ist der Ausführungsalgorithmus schon vorab festgelegt und wird nicht im Quelltext ausformuliert/beschrieben, sondern es … Java (Programmiersprache) Java ist eine objektorientierte Programmiersprache und eine eingetragene Marke des Unternehmens Sun Microsystems, welches 2010 von Oracle übernommen wurde. Hardware Unterteilung · Ausgabegeräte (Drucker, Bildschirm, Beamer, Lautsprecher …) · Eingabegeräte (Tastatur, Maus, Joystick …) · Einlesegeräte (Mikrofone, … Laufzeit (Informatik) Der Begriff Laufzeit (englisch runtime) beschreibt in der Informatik einerseits die Zeitdauer, die ein Programm, ausgeführt durch einen Rechner, … Python (Programmiersprache) Python ([ˈpʰaɪθn̩], [ ˈpʰaɪθɑn], auf Deutsch auch [ ˈpʰyːtɔn]) ist eine universell nutzbare, üblicherweise interpretierte, höhere Programmiersprache. Prolog (Programmiersprache) Prolog (vom Französischen: programmation en logique, deutsch: „Programmieren in Logik“) ist eine Programmiersprache, die Anfang der 1970er Jahre maßgeblich …