-
HINTERGRUND
-
Technisches Gebiet
-
Diese
Erfindung betrifft ein System, Verfahren und eine Vorrichtung zum
direkten Ausführen
eines architekturunabhängigen
Binärprogramms
direkt auf einem Computer. Insbesondere betrifft die Erfindung ein System,
ein Verfahren und eine Vorrichtung, welches) einem Benutzer gestattet,
ein architekturunabhängiges Binärprogramm
ohne Identifizieren eines Interpreterprogramms, welches verwendet
wird, um das architekturunabhängige
Programm zu interpretieren, und ohne Spezifizieren von Bibliotheken,
die zum Auflösen
von Laufzeit-Programmaufrufen benötigt werden, aufzurufen.
-
Hintergrund
der Erfindung
-
Grundsätzlich werden
Computerprogramme in einer oder zwei Formen gespeichert. In einer
Form wird das Programm als eine Textdatei (Quellcode) gespeichert,
die aus für
einen Menschen verständlichen
Angaben unter Verwendung einer Kodierung von Buchstaben, Ziffern
und anderen druckbaren Zeichen in einem Zeichencode besteht, wie
zum Beispiel „American
Standard Code for Information Interchange" (ASCII) oder „Extended Binary Coded Decimal
Interchange Code" (EBCDIC).
Solche Programme sind nicht direkt von einem Computer ausführbar und
müssen,
um ausgeführt
zu werden, durch ein spezielles Programm, das als Interpreter bezeichnet
wird, interpretiert werden, welches geschrieben wurde, um die Sprache
zu verstehen, in welcher das Programm geschrieben ist. Ein typisches
Beispiel ist ein Programm, das in „Beginner's All-purpose Symbolic Instruction Code" (BASIC) geschrieben
ist. BASIC-Programme werden einem Interpreter typischerweise in
Quellform bereitgestellt und Zeile für Zeile interpretiert.
-
Bei
einer weiteren Form wird eine Quellcodedatei durch einen Übersetzer
(Compiler) verarbeitet, um eine Objektdatei zu erzeugen. Die Objektdatei
umfasst eine Sequenz binärer
Daten (Objektcode), die nur für eine
besondere Computerarchitektur sinnvoll sind, auf der die Daten eine
Sequenz von Anweisungen für
diese spezielle Architektur repräsentieren.
Die Objektdatei kann in den Speicher des Computers geladen werden und
die Anweisungen können
mittels Anweisen des Computers, die Anweisungen von dem Ort zu holen
und auszuführen,
an dem das Programm geladen ist, direkt von dem Computer ausgeführt werden,
ohne dass ein Interpreter benötigt
wird. Alternativ kann die Objektdatei von einem Binder (Linker)
als Eingabe verwendet werden, um eine Datei zu erzeugen, die einen
ausführbaren
Programmcode aus mehreren solchen Objektdateien umfasst. Im Hinblick
auf das BASIC-Beispiel kann eine BASIC-Quelldatei übersetzt
werden, um eine Objektdatei zu erzeugen, die auf einem Zielcomputer
direkt ausführbar
ist.
-
Ein
Nachteil dieses Ansatzes ist, dass ein solches Programm nicht portierbar
ist. Weil der Binärcode maschinenspezifisch
ist, kann das Programm nicht einfach auf ein Computersystem einer
verschiedenen Architektur portiert werden. Dies macht die Verwendung
von reinen Binärprogrammen
in heterogenen Umgebungen unattraktiv.
-
Ein
Ansatz war es, Computerprogramme in einem von Menschen lesbaren
Textformat bereitzustellen, anstatt in einem Binärformat. Ein Interpreter wird
aufgerufen, um das Textprogramm (oft als „Skript" bezeichnet, um es von einem Binärprogramm
zu unterscheiden) zu lesen und die Angaben in dem Programm zu interpretieren,
wobei sie zu dem Zeitpunkt ausgeführt werden. Dies ist effektiv
der erste Ansatz zur Verwendung eines interpretierten BASIC-Programms.
Ein Nachteil dieses Ansatzes ist, dass es einen signifikanten Overhead
beim Interpretieren der Textangaben gibt. Zum Beispiel muss der
Interpreter zum lexikalischen Scannen und Validieren jeder Angabe
erhebliche Computerbetriebsmittel verwenden, um sicherzustellen,
dass sie eine syntaktisch korrekte und ausführbare Operation repräsentiert.
Diese Betriebsmittelintensität
macht die Verwendung von Skripten unattraktiv.
-
Sun® Microsystems
hat eine als Java® bekannte Lösung entwickelt,
wobei Java® ausgelegt
ist, die Herausforderungen einer Anwendungsentwicklung in dem Kontext
von heterogenen, Netzwerk-weit verteilten Umgebungen zu erfüllen. Die
Herausforderungen umfassen die sichere Lieferung von Anwendungen,
die das Minimum an Systembetriebsmitteln benötigen, die auf jeder Hardware-
und Software-Plattform laufen können und
dynamisch erweitert werden können.
Die Anforderung, auf mehreren Plattformen in heterogenen Netzwerken
zu laufen, stößt die traditionellen
Schemata von binärer
Verbreitung, Ausgabe (release), Aufrüstung (upgrade), Korrektur
(patch) usw. um. Stattdessen bietet das Java®-System
ein architekturneutrales, portierbares und dynamisch adaptierbares
Quasi-Maschinencodebinärformat.
-
Es
wird Bezug genommen wird auf „The
Java Language Environment – A
White Paper" von
James Gosling und Henry McGilton (veröffentlicht am 1. Oktober 1995
von Sun Microsystems, Inc., Mountain View, California, USA), das
den Oberbegriff der Ansprüche
1 und 7 bildet.
-
Eine
verbleibende Schwierigkeit ist bei diesem Format jedoch, dass der
Benutzer wissen muss, ob ein Programm, welches er oder sie ausführen möchte, in
Java® geschrieben
ist oder als ein natives Binärprogramm
kodiert ist, das für
seine Computerplattform geeignet ist. Falls es in dem nativen Format
kodiert ist, ist das Programm direkt ausführbar. Falls es als eine Java®-Klassendatei kodiert
ist, muss der Benutzer den Java®-Interpreter
aufrufen, um den Bytecode in der Datei zu interpretieren.
-
Uns
ist auch das Dokument „ELF:
from the Programmer's
Perspektive" von
Hongjiu Lu von NYNEX Science and Technology, Inc., 500 Westchester
Avenue, White Plains, New York, USA, bekannt, das das ELF-Dateiformat
beschreibt, in dem Bibliotheken aus gemeinsamem Code dynamisch geladen
werden können.
-
Es
ist deshalb wünschenswert,
ein Verfahren zum Kodieren einer Java®-Klassendatei in ein
Format bereitzustellen, das konsistent mit der Computerplattform
ist, auf der das Programm auszuführen
ist. Es ist weiterhin wünschenswert,
die Datei in einem Format zu kodieren, das ein Industriestandard
ist und das zur Implementierung auf einer großen Vielzahl von Computerplattformen
abänderbar
ist, wodurch sichergestellt wird, dass die Dateien über solche
Plattformen portierbar bleiben. Es ist weiterhin wünschenswert,
eine Unterstützung
in dem Format zum Identifizieren der Speicherstelle von Programmdateien
zu bieten, die außerhalb
der ausgeführten
Datei liegen, um die dynamische Auflösung dieser externen Dateien
zur Laufzeit zu erlauben.
-
ZUSAMMENFASSUNG
DER ERFINDUNG
-
Ein
System, Verfahren und eine Vorrichtung zum Ausführen eines architekturunabhängigen Binärprogramms
auf einem Computer wird offenbart. Eine Objektdatei wird gelesen
und Objektcode wird aus der Objektdatei extrahiert. Ein Feld in
dem Objektcode wird abgefragt, um zu ermitteln, ob der Objektcode
ein architekturunabhängiger
Objektcode ist, der eine Interpretation benötigt. Falls dies so ist, wird
ein Interpreter aufgerufen, um den architekturunabhängigen Objektcode
zu interpretieren. Dynamische Abhängigkeitsinformation kann auch
aus der Objektdatei extrahiert werden und dem Interpreter bereitgestellt
werden. Die Objektdatei liegt vorzugsweise in einem architekturneutralen
Format vor, vorzugsweise in dem ELF-Format, das als die Standard-Binärschnittstelle
definiert ist, die von Anwendungsprogrammen auf Betriebssystemen
verwendet wird, die der UNIX System V Schnittstellendefinition entsprechen.
-
Zusätzliche
Merkmale der Erfindung werden bei der Prüfung der folgenden Beschreibung
deutlich, insbesondere mit Bezug auf die beiliegenden Zeichnungen.
-
BESCHREIBUNG
DER ZEICHNUNGEN
-
Die
vorgenannten und andere Aufgaben, Aspekte und Vorteile werden aufgrund
der folgenden detaillierten Beschreibung einer bevorzugten Ausführungsform
der Erfindung mit Bezug auf die Zeichnungen besser verstanden, in
welchen:
-
1 ist
ein Blockdiagramm einer repräsentativen
Hardware-Umgebung gemäß einer
bevorzugten Ausführungsform;
-
2 zeigt
ein Beispielprogramm, das in Java geschrieben ist;
-
3 zeigt
den Java®-Übersetztungsprozess;
-
4 zeigt
das Format einer Java®-Klassendatei;
-
5 zeigt
die Ausführung
einer übersetzten
Java®-Klasse;
-
6 zeigt
eine Erweiterung der standardisierten exec()-Systemverarbeitung,
die erweitert ist, um übersetzte
Java®-Klassendateien
zu unterstützen;
-
7 zeigt
die Schritte eines Programms javald zum Erzeugen einer Skriptdatei,
um erforderliche Umgebungsvariablen zu setzen und den Interpreter
aufzurufen;
-
8 zeigt
ein Beispiel einer Skriptdatei, welche von dem Programm der 7 erzeugt
wird;
-
9 zeigt
die Ausführung
einer übersetzten
Java®-Klasse
durch ein in 8 gezeigtes Skript;
-
10 zeigt
eine Prozedur zum Erzeugen einer einzelnen ausführbaren Datei, die sowohl Java®-Klassendateiinhalte
als auch dynamische Bibliotheks-Speicherstelleninformation umfasst;
-
11 zeigt
das Format einer Binärdatei
im ELF-Format, welches eingerichtet ist, um einen architekturunabhängigen binär ausführbaren
Code zu unterstützen;
und
-
12 zeigt
die Ausführung
der binären
ELF-Datei der 11.
-
DETAILLIERTE
BESCHREIBUNG
-
Eine
bevorzugte Ausführungsform
eines Systems gemäß der vorliegenden
Erfindung wird vorzugsweise in dem Kontext eines Computers verwirklicht,
wie zum Beispiel einer Sun® Sparcstation®, einer
UNIX-basierten Workstation, oder einem Personal Computer, wie zum
Beispiel einem IBM PS/2, Apple Macintosh Computer. Eine repräsentative
Hardwareumgebung ist in 1 gezeigt, die eine typische
Hardwarekonfiguration einer Workstation gemäß einer bevorzugten Ausführungsform
illustriert, mit einer zentralen Verarbeitungseinheit 10,
wie zum Beispiel einem Mikroprozessor, und einer Anzahl von anderen
Einheiten, die über
ein Systembus 12 miteinander in Verbindung stehen. Die
in 1 gezeigte Workstation umfasst einen flüchtigen
Speicher (RAM) 14, einen Permanentspeicher (ROM) 16 und
einen I/O-Adapter 18 zum
Verbinden von Periphergeräten,
wie zum Beispiel Plattenspeichereinheiten 20, mit dem Bus 12,
einen Benutzerschnittstellenadapter 22 zum Verbinden einer
Tastatur 24, einer Maus 26, einem Lautsprecher 28,
einem Mikrophon 32 und/oder andere Benutzerschnittstellengeräte, wie
zum Beispiel ein Touch Screen (nicht abgebildet), mit dem Bus 12, einen
Kommunikationsadapter 34 zum Verbinden der Workstation
mit einem Kommunikationsnetzwerk (zum Beispiel ein Datenverarbeitungsnetzwerk)
und einen Anzeigeadapter 36 zum Verbinden des Bus 12 mit
einer Anzeigenvorrichtung 38. Die Workstation hat typischerweise
ein auf ihr residierendes Be triebssystem, wie zum Beispiel Solaris® von
Sun® Microsystems
oder ein anderes UNIX-basiertes Betriebssystem, oder ein anderes Betriebssystem,
wie zum Beispiel das Microsoft Windows Betriebssystem (OS), das
IBM OS/2 Betriebssystem oder das Apple Computer MACOS. Der Fachmann
wird erkennen, dass die vorliegende Erfindung auch auf andere als
den erwähnten
Plattformenbetriebssystemen implementiert werden kann.
-
Die
Java®-Computersprache
und -Umgebung ist ausgelegt, um Anwendungen zu unterstützen, die
in heterogen vernetzten Umgebungen eingesetzt werden. In solchen
Umgebungen müssen
Anwendungen imstande sein, auf einer Vielzahl von Hardwarearchitekturen
ausgeführt
werden zu können.
Innerhalb dieser Vielzahl von Hardwareplattformen müssen Anwendungen
unter einer Vielzahl von Betriebssystemen laufen und mit vielen
Programmiersprachenschnittstellen interagieren. Um der Vielfalt
von Betriebsumgebungen entgegenzukommen, erzeugt der Java®-Übersetzer
Klassendateien, die Bytecodes umfassen, die ein architekturneutrales
Zwischenformat sind, das ausgelegt ist, um Codes effizient zu vielfältigen Hardware-
und Softwareplattformen zu transportieren. Das interpretierte Wesen
von Java® löst sowohl
das Binärverbreitungsproblem und
das Versionsproblem, da der gleiche Java®-Sprachen-Bytecode
auf jeder Plattform läuft.
-
Java® bietet
strenge Datentypdefinitionen in seiner Spezifikation der Basissprache.
Die Java®-Spezifikation
spezifiziert die Größe ihrer
Basisdatentypen und das Verhalten ihrer arithmetischen Operatoren.
Im Ergebnis sind Programme auf jeder Plattform gleich – es gibt
keine Datentypinkompatibilität über Hardware-
und Softwarearchitekturen hinweg.
-
Die
architekturneutrale und portierbare Sprachumgebung von Java® ist
als die virtuelle Java®-Maschine bekannt. Die
virtuelle Java®-Maschine
ist die Spezifikation einer abstrakten Maschine, für die Java®-Sprachübersetzer
Code erzeugen können.
Spezifische Implementierungen der virtuellen Java®-Maschine für spezifische
Hardware und Softwareplattformen bieten dann die konkrete Realisierung
der virtuellen Maschine. Die virtuelle Java®-Maschine basiert
primär
auf der POSIX-Schnittstellenspezifikation – eine Industriestandardefinition
einer portablen Systemschnittstelle. Eine Implementierung der virtuellen
Java®-Maschine
auf neuen Architekturen ist eine relativ unkomplizierte Aufgabe,
solange die Zielplattform grundlegenden Forderungen genügt, wie
zum Beispiel einer Unterstützung
von Multithreading.
-
2 zeigt
ein Beispielprogramm 201, das in Java® geschrieben
ist. Das Programm beginnt mit einer Sequenz aus Zeilen, die einen
Kommentar 210 bilden. Ein Kommentar ist eine Angabe, die
keine Funktion ausführt
und die von einem Übersetzer,
der die Datei verarbeitet, ignoriert wird; sein Zweck ist, eine
von Menschen lesbare Dokumentation im Hinblick auf das Programm
zu bieten.
-
Die
nächsten
beiden Zeilen bilden eine Klassenangabe 220. Die Kaassenangabe
bietet Information in Bezug auf die Attribute einer Programmkomponente,
die als eine Klasse bezeichnet wird. Diese Attribute umfassen. den
Klassennamen (hier „HelloWorldApp"), ihre Speicherattribute
(hier public, static, void und main) und der Name, Anzahl und Typ
von Parametern, die von der Klasse akzeptiert werden (hier ein einzelner
Parameter mit dem Namen „args" des Datentyps „String[]").
-
Die
nächste
Zeile 230 zeigt ein Aufrufen eines externen Programms.
Hier ruft das Java®-Programm 201 ein
weiteres Programm (das als „Metthode" bezeichnet wird)
mit dem Namen „System.out.println" auf und übergibt
ihm die Zeichenkette „Hello,
World!". System.out.println
ist eine Methode, deren Funktion es ist, eine übergebene Textzeile anzuzeigen.
Wenn die Klasse HelloWorldApp ausgeführt wird, wird der Text „Hello, World!" auf dem Bildschirm
des Benutzers angezeigt.
-
Die
letzte Zeile 240 ist eine alternative Form einer Kommentarangabe.
Das hier präsentierte
Beispiel dient nur erläuternden
Zwecken. Die Java®-Sprache wird in Gosling, Joy & Steele, The Java® Language
Specification (1996), vollständig
beschrieben.
-
3 zeigt
den Java®-Übersetzungsprozess.
Die Übersetzung
ergibt sich typischerweise, wenn der Benutzer den Namen des Java®-Übersetzers
(typischerweise „javac") eingibt, gefolgt
von dem Namen der zu übersetzenden
Klasse (zum Beispiel „javac
HelloWorldApp").
Eine Quelldatei 310, die Java®-Quellcode
umfasst, wie zum Beispiel ein Java®-Programm 201,
wird dem Java®-Übersetzer 320 bereitgestellt.
Der Java®-Übersetzer 320 analysiert
den Quellcode und erzeugt eine Klassendatei 330. Der Java®-Überstzer
erzeugt keinen „Maschinencode" in dem Sinne von
nativen Hardwareanweisungen. Stattdessen erzeugt er eine Sequenz
aus Bytecodes: ein maschinenunabhängiger Hochsprachen-Code für eine hypothetische
Maschine, die durch den Java®-Interpreter und das Laufzeitsystem
implementiert werden. Eines der frühen Beispiele des Bytecode-Ansatzes
war das USCD P-System, das Mitte der 1970er und in den frühen 1980ern
Jahren auf eine Vielzahl von 8-Bit-Architekturen portiert wurde
und während
dieses Zeitraums eine große
Popularität
genoss. Heutzutage besitzen aktuelle Architekturen die Leistungsfähigkeit,
den Bytecode-Ansatz bei verteilter Software zu unterstützen. Java®-Bytecodes
sind ausgelegt, um auf einer beliebigen Maschine leicht interpretierbar oder
dynamisch in nativen Maschinencode übersetzbar zu sein, falls dies
aufgrund von Leistungsanforderungen erforderlich ist.
-
Das Java®-Klassenformat
-
4 zeigt
das Format einer Klassendatei 330, die in dem Java®-Klassenformat kodiert
ist. Das Java®-Klassenformat
ist ein hochgradig strukturiertes Format und wird in der Spezifikation
der virtuellen Java®-Maschine, Release 1.0 Beta DRAFT (21.
August 1995) von Sun® Microsystems beschrieben.
-
Jede
Klassendatei umfasst die übersetzte
Version von entweder einer Java®-Klasse oder einer
Java®-Schnittstelle.
Ein Interpreter oder eine „virtuelle
Maschine", die ausgelegt
ist, um ein Java®-Programm auszuführen, unterstützt alle
Klassendateien, die diesem Format entsprechen.
-
Eine
Java®-Klassendatei
umfasst einen Strom aus 8-Bit-Bytes. Alle 16-Bit und 32-Bit Quantitäten werden
durch Einlesen von jeweils zwei oder vier 8-Bit-Bytes gebildet. Die Bytes werden in
Netzwerkreihenfolge (big-endian) verbunden, bei der die höchsten Bytes
zuerst kommen. Dieses Format wird von den Java®-Schnittstellen
java.io.DataInput und java.io.DataOutput und Klassen unterstützt, wie
zum Beispiel java.io.DataInputStream und java.io.DataOutputStream.
-
Das
Klassendateiformat wird hier unter Verwendung einer Strukturnotation
beschrieben. Aufeinanderfolgende Felder in der Struktur erscheinen
in der externen Repräsentation
ohne Auffüllung
(padding) oder Ausrichtung (alignment). Arrays von verschiedener
Größe, die
oft aus Elementen verschiedener Größe sind, werden als Tabellen
bezeichnet und sind in diesen Strukturen üblich. Die Typen u1, u2 und
u4 bezeichnen jeweils eine vorzeichenlose Ein-, Zwei- oder Vier-Byte-Quantität, die von
einer Methode, wie zum Beispiel readUnsignedByte, readUnsignedShort
und readInt der java.io.DataInput-Schnittstelle, gelesen werden.
-
Die
Klassendatei
330 ist wie folgt strukturiert:
-
magic
-
Das
Feld „magic" 412 ist
vier Byte lang und wird verwendet, um die Datei als eine Datei vom
Java®-Klassenformat
zu identifizieren. Das magic-Feld hat den Wert 0xCAFEBABE.
-
minor_version (Unterversion)
und major_version (Hauptversion)
-
Das
Feld minor_version 414 und das Feld major_version 416 enthalten
die Versionsnummer des Java®-Übersetzers, der diese Klassendatei
erzeugt hat. Die Kombination der beiden Felder kann von einer virtuellen
Maschine abgefragt werden, um zu ermitteln, ob sie imstande ist,
die übersetzte
Klasse auszuführen. Eine
Implementierung der virtuellen Maschine wird normalerweise einen
Bereich von Unterversionsnummern 0 – n einer bestimmten Hauptversionsnummer
unterstützen.
Falls die Hauptversionsnummer inkrementiert wird, wird der neue
Code nicht auf den alten virtuellen Maschinen laufen, sondern es
ist möglich,
eine neue virtuelle Maschine herzustellen, die Versionen bis zu
der Versionsnummer n + 1 laufen lassen kann. Eine Veränderung
der Hauptversionsnummer zeigt eine größere inkompatible Veränderung,
eine, die eine verschiedene virtuelle Maschine benötigt, die
die alte Hauptversion in keiner Weise unterstützen kann.
-
constant_pool_count
-
Das
Feld constant_pool_count 422 zeigt die Anzahl von Einträgen in dem
Konstantenpool 425 in der Klassendatei.
-
constant_pool (Konstantenpool)
-
Der
Konstantenpool 425 ist eine Tabelle aus Werten. Die Werte
in dem Konstantenpool 425 umfassen verschiedene Zeichenketten-(„string")-Konstanten, Klassennamen,
Feldnamen und andere, auf die von der Klassenstruktur oder von dem
ausführbaren
Code in der Klasse Bezug genommen wird. Der erste Eintrag im Konstantenpool,
der als constant_pool[0] bezeichnet wird, bleibt von dem Übersetzer
immer unbenutzt und kann von einer Implementierung für einen
beliebigen Zweck verwendet werden.
-
Jeder
der constant_pool-Einträge
1 bis constant_pool_count-1 ist ein Eintrag variabler Länge, dessen Format
durch das erste „tag"-Byte gemäß der folgenden
Tabelle angegeben wird:
-
Ein
Konstantenpool-Eintrag einer Zeichenkette im utf-8-Format repräsentiert
einen konstanten Zeichen-(„character")-Zeichenkettenwert.
Utf-8-Zeichenketten
werden so kodiert, dass Zeichenketten, die nur Nicht-Null-ASCII-Zeichen enthalten,
nur unter Verwendung eines Bytes pro Zeichen repräsentiert
werden können,
aber Zeichen von bis zu 16 Bit auch repräsentiert werden können.
-
Alle
Zeichen in dem Bereich von 0x0001 bis 0x007F werden durch ein einzelnes
Byte repräsentiert, bei
dem Bit 0 auf eine binäre „0" gesetzt ist und
bei dem Bits 1–7
jeweils den ASCII-Code 0x0001 bis 0x007F repräsentieren. Das Null-Zeichen
0x0000 und die Zeichen in dem Bereich 0x0080 bis 0x07FF werden durch ein
Paar aus zwei Bytes oder 16 Bit repräsentiert, die hier als Bits
0–15 bezeichnet
werden. Bits 0–2
sind auf das binäre „110" gesetzt und Bits
8–9 sind
auf das binäre „10" gesetzt. Die verbleibenden
elf Bits 3–7
und 10–15
entsprechen jeweils den niederwertigen elf Bits in dem zu kodierenden
Zeichen.
-
Zeichen
in dem Bereich 0x0800 bis 0xFFFF werden durch drei Byte oder 24
Bit repräsentiert,
die hier als Bit 0–23
bezeichnet werden. Bits 0–3,
8–9 und
16–17
sind jeweils auf binäre
Werte „1110", „10" und „10" gesetzt. Die verbleibenden
acht Bits 4–7,10–15 und
18–23
entsprechen den acht Bit in dem zu kodierenden Zeichen.
-
Das
Null-Zeichen 0x00 wird eher im Zwei-Byte-Format als im Ein-Byte-Format kodiert, mit
dem Ergebnis, dass kodierte Zeichenketten niemals eingebettete Nullen
haben. Es werden nur Ein-Byte-, Zwei-Byte- und Drei-Byte-Formate verwendet,
längere
utf-8-Formate bleiben unerkannt.
-
Eine
utf-8-Zeichenkette ist wie folgt strukturiert:
-
Das
Feld tag hat den konstanten Wert 0x0001, der eine utf-8-kodierte
Zeichenkette anzeigt. Das Feld length ist ein Zwei-Byte-Feld, das
die Länge
der Zeichenkette angibt. Das Feld bytes ist die kodierte Zeichenkette.
-
Eine
Unicode-Zeichenkette als Konstantenpool-Eintrag repräsentiert
einen konstanten unkodierten Zeichenkettenwert. Eine Unicode-Zeichenkette
ist wie folgt strukturiert:
-
Das
Feld tag hat den konstanten Wert 0x0002, der eine Zeichenkette im
Unicode-Format angibt. Das Feld length ist ein Zwei-Byte-Feld, das
die Länge
der Zeichenkette angibt. Das Feld bytes ist der Zeichenkettenwert.
-
Eine
Ganzzahl („integer") als Konstantenpool-Eintrag
repräsentiert
eine Vier-Byte-Ganzzahl. Der Konstantenpool-Eintrag ist wie folgt
strukturiert:
-
Das
Feld tag hat den konstanten Wert 0x0003, welcher eine Ganzzahl angibt.
Das Feld bytes ist der ganzzahlige Wert.
-
Eine
Fließkommazahl
(„float") als Konstantenpool-Eintrag
repräsentiert
eine Vier-Byte-Fließkommazahl.
Der Konstantenpool-Eintrag ist wie folgt strukturiert:
-
Das
Feld tag hat den konstanten Wert 0x0004, der eine Fließkommazahl
angibt. Das Byte-Feld ist der Fließkommawert.
-
Eine
große
Ganzzahl („long
integer") als Konstantenpool-Eintrag
repräsentiert
eine Acht-Byte-Ganzzahl. Der Konstantenpool-Eintrag ist wie folgt
strukturiert:
-
Das
Feld tag hat den konstanten Wert 0x0005, der eine große Ganzzahl
angibt. Die Felder high_bytes und low_bytes bilden zusammen den
ganzzahligen Wert. Eine große
Ganzzahl als Konstantenpool-Eintrag nimmt bis zu zwei Plätze in dem
Konstantenpool 425 ein. Falls dies der n-te Eintrag in
dem Konstantenpool 425 ist, dann wird der nächste Eintrag
mit n + 2 nummeriert.
-
Eine
doppelte Fließkommazahl
(„double
float") als Konstantenpool-Eintrag
repräsentiert
eine Acht-Byte-Fließkommazahl.
Der Konstantenpool-Eintrag ist wie folgt strukturiert:
-
Das
Feld tag hat den konstanten Wert 0x0006, der eine doppelte Fließkommazahl
angibt. Die Felder hight_bytes und low_bytes bilden zusammen den
Fließkommawert.
Eine doppelte Fließkommazahl
als Konstantenpool-Eintrag
nimmt bis zu zwei Plätze
in dem Konstantenpool 425 ein. Falls dies der n-te Eintrag
in dem Konstantenpool 425 ist, dann wird der nächste Eintrag
mit n + 2 nummeriert.
-
Eine
Klasse („class") als Konstantenpool-Eintrag
repräsentiert
eine Java
®-Klasse oder eine
Schnittstelle. Der Konstantenpool-Eintrag ist wie folgt strukturiert:
-
Das
Feld tag hat den konstanten Wert 0x0007, der eine Klasse angibt.
Das Feld name_index ist ein Verweis in den Konstantenpool 425 auf
eine Zeichenkettenkonstante vom utf-8-Format, die den Zeichenkettennamen
der Klasse angibt.
-
Eine
Zeichenkette („string") als Konstantenpool-Eintrag
repräsentiert
Java
®-Objekte des eingebauten Java
®-Typs „String". Der Konstantenpool-Eintrag
ist wie folgt strukturiert:
-
Das
Feld tag hat den konstanten Wert 0x0008, der eine Zeichenkette angibt.
Das Feld string_index ist ein Verweis in den Konstantenpool 425 auf
eine Zeichenkette vom utf-8-Format, die den Wert angibt, auf den das
Objekt vom Typ „String" initialisiert wird.
-
Ein
Feld als Konstantenpool-Eintrag, eine Methode als Konstantenpool-Eintrag und eine
Schnittstellenmethodenreferenz als Konstantenpool-Eintrag repräsentieren
jeweils Referenzen auf Java
®-Felder, -Methoden und
-Schnittstellenmethoden. Die Konstantenpool-Einträge sind
wie folgt strukturiert:
-
Das
Feld tag hat den konstanten Wert 0x0009, 0x000A oder 0x000B, die
jeweils eine Feldreferenz, eine Methodenreferenz oder eine Schnittstellenmethodenreferenz
angeben. Das Feld class_index ist ein Verweis in den Konstantenpool 425 auf
eine Klassenkonstante, die verwendet wird, um den Namen der Klasse oder
der Schnittstelle zu identifizieren, die das Feld oder die Methode
umfasst. Das Feld name_and_type_index ist ein Verweis in den Konstantenpool 425 auf
eine Konstante NameAndType, die verwendet wird, um den Namen und
eine Signatur des Felds oder der Methode zu identifizieren.
-
Ein „NameAndType" als Konstantenpool-Eintrag
repräsentiert
ein Feld oder eine Methode ohne Angeben der Klasse, zu der der Name
bzw. das Feld gehört.
Der Konstantenpool-Eintrag ist wie folgt strukturiert:
-
Das
Feld tag hat den konstanten Wert 0x000C, der einen NameAndType-Eintrag angibt. Das
Feld name_index ist ein Verweis in den Konstantenpool 425 auf
eine Zeichenkettenkonstante vom utf-8-Format, die den Namen des
Felds oder der Methode angibt. Das Feld signature_index ist ein
Verweis in den Konstantenpool 425 auf eine Zeichenkettenkonstante
vom utf-8-Format, die eine Signatur des Feldes oder der Methode angibt.
Die Signatur bezieht sich in diesem Kontext auf eine Zeichenkette,
die einen Typ einer Methode, eines Felds oder eines Arrays repräsentiert.
Die Feldsignatur repräsentiert
den Wert eines Arguments für
eine Funktion oder den Wert einer Variablen. Eine Rückgabetyp-Signatur
repräsentiert
den Rückgabewert
von einer Methode. Eine Argumentsignatur repräsentiert ein Argument, das
einer Methode übergeben
wird. Eine Methodensignatur umfasst ein oder mehrere Argumentsignaturen
und eine Rückgabesignatur,
wobei sie die Argumente, die von einer Methode erwartet werden,
und den Wert, den sie zurückgibt,
repräsentieren.
-
Die
Struktur und das selbstreferenzierende Wesen des Zellenpools bietet
dabei eine große
Flexibilität bei
einer Implementierung von Daten, die in einer Klassendatei kodiert
sind.
-
access_flags
-
Das
Feld access_flags
432 umfasst eine Maske von bis zu 16
Modifikatoren, die mit Klassen-, Methoden- und Felddeklarationen
verwendet werden. Die gleiche Kodierung wird auf ähnlichen
Federn in field_info und method_info wie nachfolgend beschrieben
verwendet. Das Feld access_flag ist wie folgt kodiert:
-
this_class
-
Das
Feld this_class 434 ist ein Index in dem Konstantenpool 425,
wobei constant_pool[this_class] vom Typ CONSTANT_class sein muss.
-
super_class
-
Das
Feld super_class 436 ist ein Index in den Konstantenpool 425.
Falls der Wert des Felds super_class 436 nicht Null ist,
dann muss constant_pool[super_class] eine Klasse sein und gibt den
Index der Oberklasse dieser Klasse (das heißt, die Klasse, von der die
vorliegende Klasse abgeleitet ist) in dem Konstantenpool 425 an.
Falls der Wert des Felds super_class 436 Null ist, muss
die definierte Klasse java.lang.Object sein und hat keine Oberklasse.
-
interfaces_count
-
Das
Feld interfaces_count 438 gibt die Anzahl von Schnittstellen
an, die diese Klasse implementiert.
-
Schnittstellentabelle
-
Jeder
Wert in der Schnittstellentabelle 440 ist ein Index in
den Konstantenpool 425. Falls ein Tabellenwert nicht Null
(„nonzero") ist (interfaces[i]!=0,
wobei 0 <= i < interfaces_count),
dann muss constant_pool[interfaces(i]] eine Schnittstelle sein,
die diese Klasse implementiert.
-
fields_count
-
Das
Feld fields_count 450 gibt die Anzahl von Instanzvariablen
an, sowohl statisch als auch dynamisch, die von dem Feld thisclass
definiert werden. Die Feldertabelle 455 umfasst nur solche
Variablen, die explizit von „this_class" definiert werden.
Sie umfasst nicht solche Instanzvariablen, die von „this class„ zugreifbar
sind, aber von Oberklassen geerbt werden.
-
Feldertabelle
-
Jeder
Wert in der Feldertabelle
450 ist eine vollständigere
Beschreibung eines Felds in der Klasse. Jedes Feld ist durch eine
Struktur field_info von variabler Länge beschrieben. Das Format
dieser Struktur ist wie folgt:
-
Das
Feld access_flags ist eine Menge aus sechzehn Flags, die von Klassen,
Methoden und Feldern verwendet werden, um verschiedene Eigenschaften
zu beschreiben und beschreiben, wie sie von Methoden in anderen
Klassen angesprochen werden können.
Dieses Feld hat die gleichen Namen, Werte und Bedeutungen wie das
vorher offenbarte Feld access_flag 432.
-
Die
möglichen
Flags, die für
ein Feld gesetzt werden können,
sind ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL,
ACC_VOLATILE und ACC_TRANSIENT. Für jede Methode kann höchstens
eines von ACC_PUBLIC, ACC_PROTECTED und ACC_PRIVATE gesetzt werden.
-
Das
Feld name_index ist ein Verweis, der verwendet wird, um in den Konstantenpool 425 zu
indizieren, der eine CONSTANT_Utf8-Zeichenkette angibt, die der
Name des Felds ist.
-
Das
Feld signature_index ist ein Verweis, der verwendet wird, um in
den Konstantenpool 425 zu indizieren, um eine CONSTANT_Utf8-Zeichenkette
anzugeben, die die Signatur des Feldes ist.
-
Das
Feld attributes_count gibt die Anzahl von zusätzlichen Attributen über dieses
Feld an.
-
Das
Feld Attribute repräsentiert
die Attribute eines bestimmten Felds, die von der Struktur field_info repräsentiert
werden. Ein Feld kann eine beliebige Anzahl von optionalen Attributen
haben, die mit ihm assoziiert sind. Zum Beispiel gibt das Attribut „ConstantValue", das angibt, dass
dieses Feld eine statische numerische Konstante ist, den konstanten
Wert des Felds an.
-
methods_count
-
Das
Feld methods_count 460 gibt die Anzahl von Methoden an,
sowohl statisch als auch dynamisch, die von dieser Klasse definiert
werden. Diese Tabelle umfasst nur solche Methoden, die von dieser
Klasse explizit definiert werden. Sie umfasst keine geerbten Methoden.
-
Methodentabelle
-
Jeder
Wert in der Methodentabelle
465 ist eine vollständigere
Beschreibung einer Methode in der Klasse. Jede Methode wird durch
eine Struktur method_info von variabler Länge beschrieben. Das Format
dieser Struktur ist wie folgt:
-
Das
Feld access_flags ist eine Menge aus sechzehn Flags, die von Klassen,
Methoden und Feldern verwendet werden, um verschiedene Eigenschaften
und wie sie von Methoden und anderen Klassen angesprochen werden
können,
zu beschreiben. Dieses Feld hat die gleichen Namen, Werte und Bedeutungen
wie das Feld access_flags 432, das vorher offenbart wurde.
Die möglichen
Felder, die für
eine Methode gesetzt werden können,
sind ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONZED,
ACC_NATIVE und ACC_ABSTRACT. Für
jede Methode kann höchstens
eines von ACC_PUBLIC, ACC_PROTECTED und ACC_PRIVATE gesetzt werden.
-
Das
Feld name_index ist ein Verweis, der verwendet wird, um in den Konstantenpool 425 zu
indizieren, der eine CONSTANT_Utf8-Zeichenkette angibt, die der
Name der Methode ist.
-
Das
Fled signature_index ist ein Verweis, der verwendet wird, um in
den Konstantenpool 425 zu indizieren, um eine CONSTANT_Utf8-Zeichenkette
anzugeben, die die Signatur der Methode ist.
-
Das
Feld attributes_count gibt die Anzahl von zusätzlichen Attributen über diese
Methode an.
-
Das
Feld Attribute repräsentiert
die Attribute einer bestimmten Methode, die durch die Struktur method_info
repräsentiert
werden. Eine Methode kann jede Anzahl von optionalen Attributen
mit ihr assoziiert haben. Jedes Attribut hat einen Namen und andere
zusätzliche
Information. Zum Beispiel beschreibt das Attribut „Code" (siehe unten) die
Bytecodes, die ausgeführt
werden, um diese Methode auszuführen,
und das Attribut „Exceptions" beschreibt die Java®-Ausnahmen
(„Exceptions"), die deklariert
werden, um aus der Ausführung
der Methode zu resultieren.
-
attributes_count
-
Das
Feld attributes_count 470 gibt die Nummer von zusätzlichen
Attributen über
diese Klasse an.
-
Attribute
-
Die
Attributtabelle 475 definiert die mit der Klasse assoziierten
Attribute. Eine Klasse kann jede Zahl von optionalen Attributen
mit ihr assoziiert haben. Zum Beispiel gibt das Attribut „SourceFile" den Namen der Quelldatei
an, aus der diese Klasse übersetzt
wurde.
-
Das Code-Attribut
-
Das
Code-Attribut hat das folgende Format:
-
Das
Feld attribute name_index ist ein Verweis, der verwendet wird, um
in den Konstantenpool 425 zu indizieren, der eine CONSTANT_Utf8-Zeichenkette angibt,
die „Code" umfasst.
-
Das
Feld attribute_length gibt die Gesamtlänge des „Code"-Attributs ohne die anfänglichen
sechs Bytes an.
-
Das
Feld max_stack definiert die maximale Anzahl von Einträgen in dem
Operandenstapel (operand stack), der während einer Ausführung der
Methode verwendet wird.
-
Das
Feld max_locals definiert die Anzahl der lokalen variablen Plätze („slots"), die von dieser
Methode verwendet werden.
-
Das
Feld code_length definiert die Anzahl von Bytes in dem virtuellen
Maschinencode für
diese Methode.
-
Das
Feld code umfasst die tatsächlichen
Bytes des virtuellen Maschinencodes, die die Methode implementieren.
-
Das
Feld exception_table_length definiert die Anzahl von Einträgen in der
folgenden Ausnahmentabelle exception_table. Diese Tabelle wird von Übersetzern
verwendet, die angeben, für
welche Ausnahmen eine Methode deklariert ist, zu ziehen. Jeder Eintrag
in der Ausnahmentabelle beschreibt eine Ausnahmenbehandlung („exception
handler") in dem
Code. Die beiden Felder start_pc und end_pc geben die Bereiche in dem
Code an, bei welchem die Ausnahmenbehandlung aktiv ist. Die Werte
von beiden Feldern sind Offset-Werte
von dem Beginn des Codes. Das Feld start_pc ist inklusive und das
Feld end_pc ist exklusive. Das Feld handler_pc gibt die Startadresse
der Ausnahmenbehandlung an. Der Wert des Feldes ist ein Offset-Wert von
dem Start-Wert des Codes.
-
Falls
das Feld catch_type nicht Null(„nonzero") ist, ist constant_pool[catch_type]
die Klasse von Ausnahmen, für
die diese Ausnahmenbehandlung eingerichtet ist, sie abzufangen.
Diese Ausnahmenbehandlung sollte nur aufgerufen werden, falls die
gezogene Ausnahme eine Instanz der gegebenen Klasse ist. Falls catch_type
Null ist, sollte diese Ausnahmenbehandlung für alle Ausnahmen aufgerufen
werden.
-
Das
Feld attributes_count gibt die Anzahl von zusätzlichen Attributen über den
Code an. Das Code-Attribut kann seinerseits Attribute haben, die
bestimmt sind, die Felder attributes[attribute_count] zu verwenden. Ein
Code-Attribut kann
jede Anzahl von optionalen Attributen mit sich assoziiert haben.
Jedes Attribut hat einen Namen und andere zusätzliche Information. Gegenwärtig sind
die einzigen definierten Code-Attribute „LineNumber-Table" und „LocalVariableTable", wobei beide Debugging-Information
umfassen.
-
Die
Bytecodes repräsentieren
eine Folge von Maschinen-unabhängigen
Anweisungen (das heißt
Objektcode), die bestimmt sind, in einer hypothetischen 8-Bit-Stapel-basierten
Umgebung ausgeführt
zu werden. Operationen der virtuellen Java®-Maschine
nehmen ihre Operanden häufig
von dem Stapel und legen ihre Ergebnisse zurück auf den Stapel.
-
Zum
Beispiel wird die Anweisung „iload
vindex" durch zwei
8-Bit-Bytes repräsentiert.
Das erste Byte mit einem Wert von 0x15 (dezimal 21) gibt die iload-Anweisung
an. Das zweite Byte stellt einen Index in den gegenwärti gen Java®-Frame
einer lokalen Variable bereit, deren Wert auf den Operandenstapel
gelegt werden soll.
-
Zum
Beispiel kann eine Bytecodesequenz zum Ausführen der beispielhaften Klasse
HelloWorldApp aus der Neun-Byte-Zeichenkette 0xB200081201B60007B1
bestehen. Diese Sequenz wird wie folgt interpretiert:
-
Die
Anweisung getstatic0008 verwendet den Wert 0008, um einen Index
in dem Konstantenpool zu bilden, der auf eine Feldreferenz auf ein
statisches Feld zeigt. In dem vorliegenden Beispiel kann dies verwendet
werden, um einen Parameter anzugeben, der einer anderen Klasse übergeben
werden soll, hier der Zeichenkette mit dem Wert „Hello, World!". Die Anweisung fconst_1
bewirkt, dass eine Fließkommazahl „1" von einfacher Genauigkeit
auf den Stapel gelegt wird. Die Anweisung aconst_null bewirkt, dass
eine Null-Objektreferenz auf den Stapel gelegt wird. Die Anweisungen
fconst_1 und aconst_null stellen Daten bereit, die verwendet werden
können,
um die Parameter auf dem Stapel zu interpretieren.
-
Die
Anweisung invokevirtual0007 wird verwendet, um eine virtuelle Methode
zu aufzurufen, die unter Verwendung der Parameter auf dem Stapel
ausgeführt
werden sollte. Der Operand 0007 wird verwendet, um einen Index in
den Konstantenpool zu bilden. Das Element an dem Index des Konstantenpools
enthält
eine vollständige
Methodensignatur für
die Methode, die aufzurufen gewünscht
ist. In dem vorliegenden Beispiel kann dies verwendet werden, um
eine Methode anzugeben, deren Aufruf gewünscht wird, hier die Methode mit
dem Namen „System.out.println".
-
Die
Rückgabeanweisung
wird verwendet, um eine Ausführung
der Klasse HelloWorldApp zu beenden.
-
5 zeigt
die Ausführung
einer übersetzten
Java®-Klasse.
Diese Ausführung
ergibt sich typischerweise, wenn der Benutzer den Namen des Java®-Interpreters (typischerweise „java") eingibt, gefolgt
von dem Namen der auszuführenden
Klasse (zum Beispiel „java
HelloWorldApp").
Der Interpreter 510 nimmt die Klassendatei 330 als
Eingabe. Der Interpreter fragt die Umgebungsvariable 530 mit
dem Namen „JAVA_HOME" ab. Der Wert der
Umgebungsvariablen JAVA_HOME ist der Name des Home-Verzeichnisses 535 für das Java®-Laufzeitsystem,
das den Java®-Interpreter
und Unterstützungsprogramme
umfasst, und wird verwendet, um Systemroutinen, die bei der Ausführung der
Klasse verwendet werden, zu laden. Die Umgebungsvariable „CLASSPATH" 520 umfasst
die Namen von verschiedenen Benutzerklassenbibliotheken 527 und
Systemklassenbibliotheken 525, die zusätzliche Klassen beinhalten,
die zur Laufzeit aufgerufen werden können.
-
Wie
angemerkt, ist es ein Nachteil des in 5 gezeigten
Ausführungsprozesses,
dass er erfordert, dass dem Benutzer bekannt ist, dass das auszuführende Programm
eine Java®-Klasse
anstelle einer plattformnativen Programmdatei ist, und dass der
Benutzer deshalb den Java®-Interpreter explizit
aufrufen muss. Das heißt,
der Benutzer muss „java
HelloWorldApp" anstelle
von einfach „HelloWorldApp" eingeben. 6 zeigt
eine Ausführung
mit der Standardsystemverarbeitung exec(), die verwendet wird, um
plattformnative Programmdateien aufzurufen, und erweitert diese
Funktio nalität
auf übersetzte
Java®-Klassendateien.
Die Erweiterung in 6 wird aufgerufen, wenn der
Benutzer den Namen der übersetzten
Java®-Klassendatei direkt
angibt, ohne zu spezifizieren, dass sie interpretiert werden muss
(zum Beispiel „HelloWorldApp" anstatt „java HelloWorldApp").
-
Eine
Ausführung
beginnt in Schritt 610. In Schritt 620 liest die
Erweiterung die Klassendatei. In Schritt 630 prüft die Erweiterung
den Inhalt des Magic-Felds 412,
um zu verifizieren, dass es den vorgegebenen Wert 0xCAFEBABE enthält. Falls
das Magic-Feld 412 nicht 0xCAFEBABE enthält, bricht
die Erweiterung mit einem Rückgabecode
ENOEXEC in Schritt 635 ab. Der Rückgabecode ENOEXEC ist ein
Standard exec()-Rückgabecode,
der angibt, dass die Zieldatei nicht ausführbar ist. Falls der Test erfolgreich
ist, fährt
die Steuerung mit Schritt 640 fort. Im Schritt 640 erhält die Erweiterung
die Speicherstelle des Interpreters (zum Beispiel „/usr/bin/java"). In Schritt 650 prüft die Erweiterung,
um zu sehen, ob eine Datei mit dem angegebenen Namen an der angegebenen
Speicherstelle existiert. Falls nicht, bricht die Erweiterung in
Schritt 655 mit einer Fehlerbedingung ab. Anderenfalls
ruft die Erweiterung die benannte Datei in Schritt 670 durch Übergeben
des Namens der Zielklassendatei an den Interpreter zur Ausführung auf.
Fortfahrend mit der Ausführung
der benannten Klassendatei durch den Interpreter bricht die Erweiterung
bei Schritt 690 ab.
-
Obwohl
der in 6 gezeigte Prozess ein direktes implizites Aufrufen
des Java®-Interpreters
ermöglicht,
ohne dass eine Notwendigkeit besteht, dass der Benutzer weiß, dass
die Datei eine Klassendatei ist. Dies ist jedoch nicht ohne Nachteil.
Wie in 5 gezeigt ist, verwendet der Java®-Interpreter
die Umgebungsvariablen CLASSPATH und JAVA_HOME, um die Bibliotheken
zu ermitteln, die nach zur Laufzeit aufzurufenden Routinen und Methoden
durchgesucht werden. In einem komplexen System, das viele ver schiedene übersetzte
Klassendateien umfasst, ist es notwendig, dass der Benutzer die
CLASSPATH-Variable ersetzt, um dem Java®-Interpreter
die Speicherstelle der Klassendateien bereitzustellen. Deshalb ist
die Verwendung von Java® für den Benutzer, der zusätzliche
Schritte unternehmen muss, um sein Programm korrekt auszuführen, selbst unter
dem in 6 gezeigten Ansatz nicht transparent.
-
Eine
zweite Lösung
ist, eine automatisierte Einrichtung zum Erzeugen eines ausführbaren
Skripts bereitzustellen, das verwendet werden kann, um die Umgebungsvariablen
zu setzen und den Java
®-Interpreter unter Verwendung
der benannten Java
®-Klassendatei aufzurufen.
Solch ein Programm ist verwandt mit einem Standard-Binder, wie zum
Beispiel dem Programm „ld". Ein Java
®-Pseudo-Binder,
der zum Beispiel mit „javald" benannt wird, wird
wie folgt aufgerufen:
-
Diese
Syntax bedeutet, dass das Programm javald aufgerufen wird, das eine
Ausgangsdatei mit dem Namen „foo" erzeugt, die bewirkt,
dass die Java®-Klassendatei „progname.class" interpretiert wird,
wenn sie als das Kommando „foo" aufgerufen wird.
Die Umgebungsvariable CLASSPATH soll gesetzt sein, um zwei Bibliotheken
zu umfassen, nämlich „/opt/acme/lib" und „lib". Die Referenz /opt/acme/lib
ist eine absolute Referenz, indem sie relativ zu dem Root-Verzeichnis „/" definiert ist. Das
Root-Verzeichnis beinhaltet ein Verzeichnis mit dem Namen „opt", welches wiederum
ein Verzeichnis mit dem Namen „atme" enthält, welches
wiederum ein Verzeichnis mit dem Namen „lib" enthält, welches das spezifizierte
Verzeichnis ist. Die Referenz „lib" ist eine relative
Referenz und bezieht sich auf einen Verzeich nisnamen „lib", der relativ zu
dem Verzeichnis, das die Datei foo enthält, angeordnet ist.
-
7 zeigt
die Schritte eines Programms javald zum Erzeugen einer Skriptdatei,
um die erforderlichen Variablen zu setzen und den Interpreter zu
aufzurufen. 7 wird am besten verstanden
mit Bezug auf 8, die ein Beispiel einer Skriptdatei 801 zeigt,
die durch das Programm der 7 erzeugt
wird. Eine Ausführung beginnt
in Schritt 710. In Schritt 720 schreibt das Programm
ein Standard-Prolog-Codesegment 810, das den Code enthält, der
immer eingeschlossen werden muss. In Schritt 730 schreibt
javald eine Codezeile, um die Variable JAVA_HOME zu setzen. In Schritt 740 wählt javald
den ersten der Bibliotheksnamen aus, um in die Umgebungsvariable
CLASSPATH eingefügt
zu werden. Diese Namen wurden unter Verwendung des Flags -C spezifiziert,
als javald aufgerufen wurde. In Schritt 750 ermittelt javald,
ob der Bibliotheksname als eine absolute oder relative Referenz
spezifiziert wurde. Im Falle einer absoluten Referenz erzeugt Schritt 670 eine
absolute Referenz. Im Falle einer relativen Referenz erzeugt Schritt 765 einen
Funktionsaufruf, der die Speicherstelle der spezifizierten Bibliothek
zur Laufzeit relativ zu dem Ort des ausführbaren Shell-Skript 801 ermittelt. In
Schritt 770 prüft
javald, ob Bibliotheken zur Verarbeitung übrig sind. Falls dies der Fall
ist, kehrt die Steuerung zu Schritt 740 zurück; anderenfalls
fährt die
Steuerung mit Schritt 780 fort. In Schritt 780 schreibt
javald eine Codezeile 830, die die Variable CLASSPATH auf
eine Zeichenkette setzt, die die angegebenen Bibliotheksnamen getrennt
durch Doppelpunkte, und eine Codezeile 840, die den Java®-Interpreter
aufruft, enthält.
-
Wie
oben erwähnt,
zeigt 8 eine Skriptdatei 801, um die erforderlichen
Umgebungsvariablen zu setzen, und den Java®-Interpreter
zur Laufzeit aufzurufen. Eine zeilenweise Beschreibung folgt.
-
Die
erste Zeile enthält
die Zeichenkette:
-
Eine
Zeichenkette „#!"ist, falls sie vorhanden
ist, die Verwendung eines Standard-UNIX-Konstrukts, um den Namen
eines Skript-Interpreters bereitzustellen, der verwendet wird, um
das Skript auszuführen.
Die Datei /bin/ksh ist ein Standardname für das Korn-Shell-Programm,
einen bekannten Skript-Interpreter. Skript 801 ist in der
Korn-Shell-Sprache geschrieben.
-
Die
nächste
Zeile enthält
die Zeichenkette:
-
Diese
Zeile bewirkt, dass die Variable D auf den vollständig angegebenen
Pfadnamen des Verzeichnisses gesetzt wird, in dem die Skriptdatei
liegt. Dies funktioniert wie folgt. Wenn das Skript eine Ausführung beginnt,
setzt ksh die Variable $0 auf den Namen des in der Kommandozeile
ausgeführten
Programms, der entweder der Name der Skriptdatei allein (zum Beispiel „progname"), relativ zu dem
gegenwärtigen
Verzeichnis (zum Beispiel „bin/progname") oder als ein absoluter
Pfad (zum Beispiel „/usr/bin/test/progname") ist. Die Shell
führt die
Kommandozeile aus, die in den umgekehrten einzelnen Anführungszeichen
eingeschlossen ist („'", üblicherweise
als „backticks" bezeichnet), in
diesem Fall „/usr/bin/dirname$0". Die Anweisung dirname
ist eine Standard-UNIX-Anweisung,
die einen Suffix von dem Dateinamen abschneidet, der nicht einen
Verzeichnisnamen repräsentiert.
Zum Beispiel wird ein „dirname
progname" als Ausgabe „." erzeugen, was das
gegenwärtige
Verzeichnis angibt. „dirname
bin/progname" wird „./bin" erzeugen und „dirname
/usr/bin/test/progname" wird „/usr/bin/test" erzeugen. Weil die
in einfachen Anführungszeichen
eingeschlossene Anweisung der Standard cd-Anweisung („change directory") folgt, wird ksh
versuchen, eine cd-Anweisung
auf dem angegebenen Verzeichnis auszuführen. Falls dies erfolgreich
ist, wird die dem „&&" folgende Anweisung „print
-n $PWD" ausgeführt, welche
als Ausgabe den vollständig
angegebenen Pfadnamen des gegenwärtigen
Verzeichnisses $PWD erzeugt, wobei die üblichen Zeilenumbruchzeichen
unterdrückt
werden. Falls die cd-Anweisung nicht erfolgreich ist, wird ein Fehler
zurückgegeben.
Somit ist das Ergebnis entweder der vollständig angegebene Pfadname des
Verzeichnisses, in dem das Shell-Skript existiert, falls ein solches
Verzeichnis existiert, oder eine Fehlerbedingung, falls es nicht
existiert. Das Korn-Shell-Konstrukt $() gibt den Wert zurück, der in
D vorhanden ist. Dieses Verzeichnis wird als Zielverzeichnis bezeichnet.
-
Die
Funktionsdefinition „_" wird nicht bis zur
CLASSPATH-Konstruktion aufgerufen, die nachfolgend beschrieben wird.
-
Die
nächste
Zeile enthält
die Zeichenkette:
-
Diese
Korn-Shell-Syntax soll die Umgebungsvariable JAVA_HOME- auf "/usr/java" setzen, falls sie nicht
bereits gesetzt ist. Die Verwendung der Anweisung export macht die
Variable für
nachfolgend hervorgebrachte Prozesse verfügbar.
-
Die
nächste
Zeile enthält
die Zeichenkette:
-
Dies
setzt die Umgebungsvariable CLASSPATH auf eine Konkatenation der
absoluten Referenz /opt/acme/lib und einer relativen Referenz lib,
die durch einen Doppelpunkt getrennt sind. Die Verwendung der Anweisung
export macht die Variable für
nachfolgend hervorgebrachte Prozesse verfügbar. Die absolute Referenz
/opt/acme/lib wird als ein Literal ausgedrückt und erfordert keine Erläuterung.
Die zweite Referenz ist ein Aufruf der „_"-Funktion.
Die „_"-Funktion ist wie
folgt definiert:
-
Die
Angabe „function_" definiert eine Funktion
mit dem Namen „_" und eingeschlossen
durch Klammern {}. Die Funktion operiert auf dem Wert des relativen
Verzeichnisnamens, der ihr übergeben
wird, zum Beispiel „lib", „../lib", etc. Der Ausdruck
{[$1 = ${1##/}]] beurteilt, ob der Verzeichnisname mit einem führenden Schrägstrich-Zeichen
(„/") beginnt. Falls
der Name mit einem führenden
Schrägstrich
beginnt, ist der Verzeichnisname eine absolute Referenz. Falls der
Verzeichnisname nicht mit einem führenden Schrägstrich
beginnt, ist der Verzeichnisname relativ zu, aber nicht notwendigerweise
direkt in dem Zielverzeichnis. Zum Beispiel bezieht sich die Referenz „lib" auf das Verzeichnis „lib" in dem Zielverzeichnis,
aber die Referenz „../lib" bezieht sich, da
sie relativ zu dem Zielverzeichnis ist, auf ein Verzeichnis in dem
Vaterverzeichnis des Zielverzeichnisses. Falls die Verzeichnisreferenz eine
relative Referenz ist, stellt die „print -n ${_D}/"-Angabe der relativen
Referenz eine absolute Referenz auf das Zielverzeichnis voran und
das resultierende Konstrukt wird mit einem Schrägstrich verbunden. Dies hat
den Effekt eines Konvertierens der relativen Referenz in eine absolute
Referenz. Die nächste
Zeile („print
-n $1") erzeugt
die spezifizierte Verzeichnisreferenz.
-
Zum
Beispiel dann, wenn das Zielverzeichnis den Namen „/usr/bin/test" hat, liefert diese
Funktion den Wert „/usr/bin/test/lib" für einen
Eingabeparameter von „lib" zurück und „/usr/bin/test/../lib" für einen
Eingabeparameter von „../lib". Das Ergebnis dieser
Funktion ist deshalb ein vollständiger
Pfadname zu der angegebenen relativ referenzierten Bibliothek, die
dann der CLASSNAME-Zeichenkette hinzugefügt wird.
-
Die
letzte Zeile ist der Aufruf des Java
®-Interpreters:
-
Diese
Zeile ruft den Java®-Interpreter mit dem Namen „java" auf, der in dem
Unterverzeichnis des Java®-Home-Verzeichnisses wie
von der Umgebungsvariablen JAVA_HOME spezifiziert zu finden ist.
Dem Interpreter wird der Name des Programms (hier „progname") und alle Parameter übergeben,
die der Skriptdatei übergeben
wurden. Die $*-Variable wird von der Korn-Shell auf eine Zeichenkette
aus allen Parameterwerten gesetzt, die dem Skript übergeben
wurden.
-
9 zeigt
die Ausführung
einer Java®-Klasse
unter Verwendung der in den 7 und 8 gezeigten
Methoden. Der Benutzer gibt den Namen der Korn-Shell-Skriptdatei 801 ein.
Diese Datei wird von dem UNIX-Kern 910 gelesen, der die
Zeichenkette #!/bin/ksh sieht und die Korn-Shell 920 aufruft,
welche die Skriptdatei liest und interpretiert. Die Korn-Shell 920 setzt
die Umgebungsvariable CLASSPATH 520 und die Umgebungsvariable
JAVA_HOME 530 und ruft den Java®-Interpreter 510 durch
Spezifizieren des Namens der Klassendatei 330 auf. Von
diesem Punkt an fährt
die Ausführung
wie in Bezug auf 5 erläutert fort. Das heißt, der
Java®-Interpreter 510 nimmt
die Klassendatei 330 als Eingabe. Der Interpreter fragt
die Umgebungsvariable 530 mit dem Namen „JAVA_HOME" ab und ermittelt
dadurch den Namen des Home-Verzeichnisses 535 für das Java®-Laufzeitsystem. Der
Java®-Interpreter
fragt auch die Umgebungsvariable „CLASSPATH" 520 ab, wodurch die Namen
von verschiedenen Benutzerklassenbibliotheken 527 und Systemklassenbibliotheken 525 ermittelt
werden, die zusätzliche
Klassen enthalten, die zur Laufzeit aufgerufen werden können.
-
Obwohl
der Prozess der 7 eine Skriptdatei erzeugt,
die verwendet werden kann, um das Aufrufen der Java®-Klassendatei
mittels des Skripts zu ermöglichen,
ist ein Nachteil dieses Ansatzes, dass die Skriptdatei 801 und
die ausgeführte
Klassendatei 330 innerhalb der gleichen Verzeichnisstruktur
gehalten werden müssen.
Dies ist normalerweise in großen
Systemen kein großes
Problem, weil solche Systeme üblicherweise Benutzerklassenbibliotheken 527 umfassend
verwenden und die Verzeichnisbeziehung der ausgeführten Klassendatei 330 und
der Benutzerklassenbibliotheken 527 in jedem Falle aufrechterhalten
werden muss. Jedoch bringt der Prozess der 7 zusätzliche
Wartungspflichten auf kleinen Systemen (wie zum Beispiel das Beispiel
der Anwendung „HelloWorldApp") mit sich, wo solche
Dateibeziehungswartung normalerweise nicht benötigt wird. Ein zusätzlicher
Nachteil dieses Ansatzes ist, dass er eine Interpretation nicht
nur für
den Java®-Objektcode benötigt, sondern
auch für
das Shell-Skript. Dieser zusätzliche Anteil
an Interpretation verbraucht zusätzliche
Systembetriebsmittel. Um diese Wartung zu eliminieren und die zum
Aufrufen der Shell benötigten
Betriebsmittel zu reduzieren, ist es wünschenswert, eine Einrichtung
bereitzustellen, durch die eine ausführbare Datei, wie zum Beispiel
das Shell-Skript 801,
erzeugt werden kann, in welcher jedoch die resultierende Datei den
ausführbaren
Java®-Code
enthält,
anstelle eines Aufrufens einer separaten Datei.
-
Das ELF-Format
-
11 zeigt
das Format einer Binärdatei 1101 im
ELF-Format, das eingerichtet ist, um architekturunabhängigen binären ausführbaren
Code zu unterstützen.
Um eine maximale Portierbarkeit zu bieten, wird die Datei gemäß dem ELF-Format
(„Executable
and Linking Format")
formatiert, das als die Standardbinärschnittstelle definiert ist,
die von Anwendungsprogrammen auf Betriebssystemen verwendet wird,
die mit der Schnittstellendefinition des UNIX System V übereinstimmen.
Das ELF-Format ist in „System
V Application Binary Interface",
dritte Auflage (1993) („das
ABI")" beschrieben.
-
Das
Format von Abschnitten einer Binärdatei 1101 wird
hier unter Verwendung einer Strukturnotation beschrieben. Aufeinanderfolgende
Felder erscheinen in der Struktur in der externen Repräsentation
ohne Auffüllung
(padding) oder Ausrichtung (alignment). Arrays von variabler Größe, oft
aus Elementen verschiedener Größe, werden
als Tabellen bezeichnet und sind in diesen Strukturen üblich. Der
Typ Elf32_Addr bezieht sich auf eine vorzeichenlose Programmadresse
mit einer Größe von vier
Bytes und ausgerichtet an einer 4-Byte-Grenze. Der Typ Elf32_Half
bezieht sich auf eine vorzeichenlose mittlere Ganzzahl mit einer
Größe von zwei
Bytes und ausgerichtet an einer 2-Byte-Grenze. Der Typ Elf32_Off
bezieht sich auf einen vorzeichenlosen Datei-Offsetwert mit einer
Größe von vier
Byte und ausgerichtet an einer 4-Byte-Grenze. Der Typ Elf32_Sword bezieht
sich auf eine vorzeichenbehaftete große Ganzzahl mit einer Größe von vier
Byte und ausgerichtet an einer 4-Byte-Grenze. Der Typ Elf32_Word
bezieht sich auf eine vorzeichenbehaftete große Ganzzahl einer Größe von zwei
Byte und ausgerichtet an einer 2-Byte-Grenze. Der Typ „unsigned
char" bezieht sich
auf eine vorzeichenlose kleine Ganzzahl mit einer Größe von einem
Byte und ausgerichtet an einer 1-Byte-Grenze.
-
Die
ELF-Datei 1101 der vorliegenden Erfindung umfasst einen
ELF-Kopf („header") 1110,
eine Programmkopftabelle (PHT) 1120, einen Klassenabschnitt 1130,
einen dynamischen Abschnitt 1140, eine dynamische Zeichenkettentabelle 1150 und
eine Abschnittskopftabelle (SHT) 1160. Obwohl 11 die
Komponententeile einer Binärdatei 1101 in
einer bestimmten Reihenfolge zeigt, kann der tatsächliche
Dateiaufbau variierend sein. Abgesehen von dem ELF-Kopf 1110,
der eine festgelegte Position an dem Start der Datei hat, haben
die von dem ELF-Kopf verschiedenen unterschiedlichen Abschnitte
und Segmente keine spezielle Reihenfolge.
-
ELF-Kopf
-
Der
ELF-Kopf 1110 befindet sich an dem Beginn der Datei 1101 und
hält einen
Fahrplan, der die Organisation der Datei beschreibt. Der ELF-Kopf 1110 hat
das folgende Format.
-
-
-
Das
Feld e_ident umfasst anfängliche
Bytes (Bytes 0-15), die die Datei als eine Objektdatei markieren und
die maschinenunabhängige
Daten bereitstellen, mit welchen der Inhalt der Datei dekodiert
und interpretiert wird. Die Bytes 0–3 (bezeichnet mit EI_MAG0,
EI_MAG1, EI_MAG2 und EI_MAG3) ist eine Konstante, um die Datei zu
validieren. Byte 0 (EI_MAG0) enthält einen Wert 0x7F. Bytes 1-3
(EI_MAG1, EI_MAG2 und EI_MAG3) enthalten jeweils die Werte „E", „L" und „F". Byte 4 (EI_CLASS)
identifiziert den Typ der Architektur der Datei. Ein Wert von 1
(ELFCLASS32) gibt eine 32-Bit-Architektur
an, während
ein Wert von 2 (ELFCLASS64) eine 64-Bit-Architektur angibt. Ein Wert von Null(ELFCLASSNONE)
gibt einen ungültigen
Architekturtyp an. In einer typischen Ausführungsform der vorliegenden
Erfindung hat EI_CLASS einen Wert ELFCLASS32.
-
Byte
5 (EI_DATA) spezifiziert die Datenkodierung von Daten in der Datei.
Ein Wert von 1 (ELFDATA2LSB) gibt eine little-endian-Kodierung an,
ein Wert von 2 (ELFDATA2MSB) gibt eine big-endian-Kodierung an,
ein Wert von 0 gibt eine ungültige
Kodierung an. In der vorliegenden Erfindung hat EI_DATA einen Wert
ELFDATA2MSB. Byte 6 (EI_VERSION) spezifiziert die Versionsnummer
des ELF-Kopfes der Version, für
die der Kopf erzeugt wurde. Der Rest von e_ident wird nicht verwendet.
-
Das
Feld e-type identifiziert den Typ der Objektdatei. Dieses Feld wird
auf 2 (ET_EXEC) gesetzt, um eine ausführbare Datei anzugeben.
-
Das
Feld e_machine identifiziert den Maschinentyp (z.B. 1 für eine SPARK®-Architektur von Sun® Microsystems,
3 für eine
80386-Architektur von Intel, 21 für eine RS6000-Architektur von
IBM, etc.). Dieses Feld wird auf eine beliebig, aber vorgegeben
zugewiesene Zahl gesetzt, die den Typ der Maschine angibt, deren Architektur
kompatibel mit dem ausführbaren
Code ist, der in der Datei enthalten ist. Gegenwärtig sind die Werte 22 bis
65535 nicht zugewiesen und einer dieser Werte (zum Beispiel 22)
wird zugewiesen, um die hypothetische Architektur der virtuellen
Java®-Maschine
zu repräsentieren.
-
Das
Feld e_version repräsentiert
die Objektdateiversion.
-
Das
Feld e_entry gibt die virtuelle Adresse an, an die das System zunächst die
Steuerung übergibt, womit
der Prozess gestartet wird. Für
die vorliegende Erfindung hält
dieses Element eine Null.
-
Das
Feld e_phoff hält
den Dateioffsetwert der Programmkopftabelle in Bytes.
-
Das
Feld e_shoff hält
den Dateioffsetwert der Abschnittskopftabelle in Bytes.
-
Das
Feld e_flags hält
prozessorspezifische Flags, die mit der Datei assoziiert sind.
-
Das
Feld e_ehsize hält
die Größe des ELF-Kopfs
in Byte.
-
Das
Feld e_phentsize hält
die Größe eines
Eintrags in der Programmkopftabelle (PHT) 1120 der Datei in
Byte. Alle PHT-Einträge
haben die gleiche Größe.
-
Das
Feld e_phenum hält
die Anzahl an Einträgen
in der Programmkopftabelle. Somit ergibt das Produkt aus e_phentsize
und e_phnum die Größe der Tabelle
in Byte.
-
Das
Feld e_shentsize hält
die Größe des Abschnittskopfs
in Byte. Ein Abschnittskopf ist ein Eintrag in der Abschnittkopftabelle
(SHT) 1160, wobei alle Einträge die gleiche Größe haben.
-
Das
Feld e_shnum hält
die Anzahl der Einträge
in der Abschnittskopftabelle 1160. Somit ergibt das Produkt
aus e_shentsize und e_shnum die Größe der Abschnittskopftabelle
in Byte an.
-
Das
Feld e_shstrndx hält
den Abschnittskopftabellenindex des Eintrags, der mit der Abschnittsnamenzeichenkettentabelle 1150 assoziiert
ist.
-
Programmkopftabelle
-
Die
Programmkopftabelle (PHT) 1120 ist ein Array aus Strukturen,
wobei jede ein Segment oder eine andere Information beschreibt,
die das System benötigt,
um das Programm zur Ausführung
vorzubereiten. Eine Datei spezifiziert ihre eigene Programmkopfgröße mit den
Feldern e_phentsize und e_phnum im ELF-Kopf 1110.
-
PHT
1120 hat
das folgende Format:
-
Das
Feld p_type gibt an, welche Art von Segment dieses Array-Element
beschreibt oder wie die Information des Array-Elements zu interpretieren
ist. Wie gegenwärtig
in dem ABI beschrieben ist, sind die Werte 0 bis 6 gültig und
definieren Werte für
p_type. Werte 7 bis 0x6FFFFFFF werden nicht verwendet und Werte
in dem Bereich von 0x70000000 (PT_LOPROC) bis 0x7FFFFFFF (PT_HIPROC)
sind für
eine prozessorspezifische Semantik reserviert.
-
Für die vorliegende
Erfindung werden wenigstens zwei Werte verwendet. Der erste verwendete
Wert ist 2 (PT_DYNAMIC). PT_DYNAMIC gibt einen dynamischen Abschnitt 1140 an,
der dynamische Bindeinformation umfasst. Der zweite verwendete Wert
ist ein vorgegebener Wert, der noch nicht zu gewiesen ist (z.B. im
Bereich von 7 bis 0x6FFFFFFF) (PT_CLASS), um einen Klassenabschnitt 1130 von
ladbarem Code anzugeben, der das Äquivalent der Java®-Klassendatei
enthält.
-
Das
Feld p_offset gibt den Offsetwert des Anfangs der Datei, an dem
das erste Byte des Abschnitts liegt.
-
Das
Feld p_vaddr gibt die virtuelle Adresse an, an der das erste Byte
des Segments im Speicher liegt. Das Feld p_paddr wird bei der vorliegenden
Erfindung nicht verwendet.
-
Das
Feld p_filesz gibt die Anzahl an Bytes in dem Dateibild („file image") des Segments an,
sie kann Null sein.
-
Das
Feld p_memsz gibt die Anzahl an Bytes in dem Speicherbild („memory
image") des Abschnitts
an, sie kann Null sein.
-
Das
Feld p_flags hält
Erlaubnisflags, die angeben, ob der Abschnitt Ausführungs-,
Schreib- oder Leserechte hat.
-
Das
Feld p_align wird bei der vorliegenden Erfindung nicht verwendet.
-
Klassenabschnitt
-
Der
Klassenabschnitt 1130 enthält das gleiche Binärbild („binary
image") wie das,
das in der Klassendatei 330 enthalten ist. Diese Daten
werden aus der Binärdatei 1101 während einer
Ausführung
gelesen und dem Java®-Interpreter 510 bereitgestellt.
Der Klassenabschnitt 1130 wird durch das Flag PT_CLASS
angegeben, das in dem korrespondierenden Eintrag der PHT 1120 gesetzt
ist.
-
Dynamischer
Abschnitt
-
Der
dynamische Abschnitt 1140 (in dem ELF-Format als „dynamic" bezeichnet) ist
ein Array aus Strukturen, wobei jede Zeiger und andere Informationen
bereitstellt, die Systemklassenbibliotheken 525 und Benutzerklassenbibliotheken 527 identifizieren.
Der dynamische Abschnitt 1140 wird durch einen Eintrag
des Typs SHT_DYNAMIC in der Abschnittskopftabelle 1160 und
durch einen Eintrag des Typs PT_DYNAMIC in der Programmkopftabelle 1120 angegeben.
-
Der
dynamische Abschnitt
1140 hat die folgende Struktur:
-
Das
Feld union d_un wird entweder als ein Wort d_val oder als eine Adresse
d_ptr interpretiert oder wird abhängig von dem Wert von d_tag
ignoriert.
-
Die
ELF-Dateistruktur unterstützt
eine große
Anzahl von Werten für
d_tag. Wie in dem ABI gegenwärtig
beschrieben ist, sind die Werte 0 bis 23 gültig und definieren Werte für d_tag.
Werte 24 bis 0x6FFFFFFF werden nicht ver wendet und Werte im Bereich
von 0x70000000 (DT_LOPROC) bis 0x7FFFFFFF (DT_HIPROC) sind für eine prozessorspezifische
Semantik reserviert. Die vorliegende Erfindung verwendet zwei existierende
Werte für
d_tag und drei neue Werte. Die beiden existierenden Werte sind DT_NULL
und DT_STRTAB. Die drei neuen Werte sind DT_JAVA_CLASSNAME, DT_JAVA_NEEDED_CLASSDIR
und DT_JAVA_NEEDED_LIBDIR.
-
Falls
d_tag einen Wert von 0 (DT_NULL) hat, dann markiert der Eintrag
das Ende des Arrays. Falls d_tag einen Wert von 5 (DT_STRTAB) hat,
dann wird d_un als eine Adresse d_ptr interpretiert und hält die Adresse
der Zeichenkettentabelle 1150.
-
Die
Werte DT_JAVA_CLASSNAME, DT_JAVA_NEEDED_CLASSDIR und DT_JAVA_NEEDED_LIBDIR
sind vorgegebene Werte, die bisher von dem ABI nicht zugewiesen
wurden (d.h. drei Werte in dem Bereich von 24 bis 0x6FFFFFFF). Nur
zum Zwecke des Beispiels kann angenommen werden, dass die symbolischen
Werte DT_JAVA_CLASSNAME, DT_JAVA_NEEDED_CLASSDIR und DT_JAVA_NEEDED_LIBDIR
jeweils den numerischen Werten 24, 25 und 26 entsprechen. Natürlich können drei
beliebige vorzeichenlose Werte anstelle von 24, 25 und 26 verwendet
werden.
-
Falls
d_tag den Wert DT_JAVA CLASSNAME (z.B. 24) hat, wird d_un als ein
Wort d_val interpretiert und hält
einen Offsetwert in die Zeichenkettentabelle 1150 einer
auf Null endenden Zeichenkette. Die auf Null endende Zeichenkette
bietet den Namen der Klasse, die von dem Inhalt des Klassenabschnitts 1130 repräsentiert
wird. Der Offsetwert ist ein Index in die Tabelle, der in dem Eintrag
DT_STRTAB bezeichnet ist.
-
Falls
d_tag den Wert DT_JAVA_NEEDED_CLASSDIR (z.B. 25) hat, wird d_un
als ein Wort d_val interpretiert und hält einen Offsetwert in die
Zeichenkettentabelle 1150 einer auf Null endenden Zeichenkette. Die
auf Null endende Zeichenkette stellt den Namen eines Verzeichnisses
bereit, das als eine Benutzerklassenbibliothek 527 durchsucht
wird, die zusätzliche
Klassen enthält,
die zur Laufzeit aufgerufen werden können. Der Offsetwert ist ein
Index in die Tabelle, der in dem Eintrag DT_STRTAB aufgezeichnet
ist. Das dynamische Array kann vielfache Einträge dieses Typs enthalten. Die
relative Reihenfolge dieser Einträge ist wesentlich; obwohl die
Beziehung von Einträgen
zu anderen Typen es nicht ist.
-
Falls
d_tag den Wert DT_JAVA_NEEDED_LIBDIR (z.B. 26) hat, wird d_un als
ein Wort d_val interpretiert und hält einen Offsetwert in die
Zeichenkettentabelle 1150 einer auf Null endenden Zeichenkette.
Die auf Null endende Zeichenkette stellt den Namen eines Verzeichnisses
bereit, das als eine Systemklassenbibliothek 525 durchsucht
wird, die zusätzliche
Kassen enthält,
die zur Laufzeit aufgerufen werden können. Der Offsetwert ist ein
Index in die Tabelle, der in dem Eintrag DT_STRTAB aufgezeichnet
ist. Das dynamische Array kann vielfältige Einträge mit diesem Typ enthalten.
Die relative Reihenfolge dieser Einträge ist wesentlich, obwohl ihre
Beziehung zu Einträgen
von anderen Typen es nicht ist.
-
Dynamische
Zeichenkettentabelle
-
Die
dynamische Zeichenkettentabelle 1150 (in dem ELF-Format
als „.dynstr" bezeichnet) hält auf Null endende
Zeichensequenzen, die üblicherweise
als Zeichenketten bezeichnet werden. Die Objektdatei verwendet diese
Zeichenketten, um Symbol- und Abschnittsnamen zu repräsentieren.
Man referenziert eine Zeichenkette als einen Index in den Zeichenkettentabellenab schnitt.
Das erste Byte, welches der Index Null ist, ist definiert, ein Null-Zeichen zu halten.
Entsprechend ist das letzte Byte einer Zeichenkettentabelle definiert,
ein Null-Zeichen zu halten, was ein Enden auf Null für alle Zeichenketten
sicherstellt. Eine Zeichenkette, deren Index Null ist, spezifiziert
entweder keinen Namen oder einen Null-Namen, abhängig von dem Kontext. Ein leerer
Zeichenkettentabellenabschnitt ist erlaubt; das Element sh_size
seines Kopfs würde
Null enthalten. Nicht-Null-Indizes sind für eine leere Zeichenkettentabelle
ungültig.
Ein Element sh_name des Abschnittskopfs hält einen Index in den Abschnittskopf
des Zeichenkettentabellenabschnitts, so wie es durch das Element e_shstrndx
des ELF-Kopfs angegeben wird.
-
Abschnittskopftabelle
-
Die
Abschnittskopftabelle
1160 ist eine Sequenz aus Elf32_Shdr-Strukturen
in dem folgenden Format:
-
Das
Feld sh_name spezifiziert den Namen des Abschnitts. Sein Wert ist
ein Index in den Abschnittskopf des Zeichenkettentabellenabschnitts,
der die Speicherstelle einer auf Null endenden Zeichenkette angibt.
-
Das
Feld sh_type kategorisiert den Inhalt und die Semantik des Abschnitts.
Die vorliegende Erfindung verwendet für sh_type zwei Werte: SHT_STRTAB
und SHT_DYNAMIC. Falls sh_type einen Wert von 3 (SHT_STRTAB) hat,
dann beschreibt der Eintrag SHT einen Abschnitt, der die dynamische
Zeichenkettentabelle 1150 hält. Falls sh_type einen Wert
von 6 (SHT_DYNAMIC) hat, dann beschreibt der Eintrag SHT einen Klassenabschnitt 1120.
Zusätzlich
gibt ein Wert von 0 (SHT_NULL) einen inaktiven Eintrag an, der nicht
zu irgendeinem Abschnitt gehört.
-
Das
Feld sh_flags bietet 1-Bit-Flags, die verschiedene Attribute beschreiben.
-
Das
Feld sh_addr wird in der vorliegenden Erfindung nicht verwendet.
-
Der
Wert des Feld sh_offset gibt den Byte-Offsetwert von dem Anfang
der Datei zu dem ersten Byte in dem Abschnitt an.
-
Das
Feld sh_size gibt die Größe des Abschnitts
in Byte an.
-
Die
Felder sh_link und sh_info werden in der vorliegenden Erfindung
nicht verwendet.
-
Das
Feld sh_addralign wird verwendet, um Ausrichtungsanforderungen des
Abschnitts anzugeben.
-
Das
Feld sh_entsize wird für
Abschnitte verwendet, die eine Tabelle aus Einträgen festgelegter Größe enthalten,
wie zum Beispiel eine Symboltabelle. Für einen solchen Abschnitt gibt
dieses Feld die Größe jedes Eintrags
in Byte an. Das Feld enthält
0, falls der Abschnitt keine Tabelle aus Einträgen mit fester Größe enthält. Dieses
Feld wird in der vorliegenden Erfindung nicht verwendet.
-
10 zeigt
eine Prozedur zum Erzeugen einer einzelnen ausführbaren Datei, die sowohl Java
®-Klassendateiinhalte
als auch Speicherstelleninformation von dynamischen Bibliotheken
enthält,
wodurch eine direkte Ausführung
von Java
®-Klassen
ohne Berücksichtigung
einer Dateibeziehungskorrelation erlaubt wird. Die Prozedur der
10 wird
in der gleichen Weise und Syntax aufgerufen, wie die Prozedur der
7,
zum Beispiel:
-
Eine
Ausführung
beginnt in Schritt 1010. In Schritt 1020 initialisiert
das Programm einen ELF-Kopf 1110. In Schritt 1030 initialisiert
das Programm PHT 1120. In Schritt 1040 erzeugt
das Programm eine dynamische Zeichenkettentabelle 1150.
Diese Tabelle wird mit den erforderlichen Zeichenkettenkonstanten
gefüllt, die
die Systemklassenbibliotheken 525 und die Benutzerklassenbibliotheken 527 identifizieren.
In Schritt 1050 erzeugt das Programm einen dynamischen
Abschnitt 1140 und füllt
ihn mit Zeigern auf Zeichenkettentabelleneinträgen in der dynamischen Zeichenkettentabelle 1150.
In Schritt 1060 liest das Programm die Klassendatei 330 ein
und kopiert sie in den Klassenabschnitt 1130. In Schritt 1070 erzeugt
das Programm eine Abschnittskopftabelle 1160 und initialisiert
Abschnittskopftabelleneinträge,
die den dynamischen Abschnitt 1140 und den Klassenabschnitt 1130 beschreiben.
Eine Ausführung
endet in Schritt 1090. An diesem Punkt wurde eine Binärdatei im
ELF-Format erzeugt, die sowohl den Inhalt der Klassendatei 330 als
auch die Daten enthält,
die erforderlich sind, um Klassenbibliotheken 525 und 527 zu
spezifizieren.
-
12 zeigt
die Ausführung
der binären
ELF-Datei der 11. Der Benutzer gibt den Namen
der Binärdatei 1101 ein.
Diese Datei wird von dem UNIX-Kern („Kernel") 910 gelesen, der den Inhalt
der Datei wie im Zusammenhang mit 11 beschrieben
untersucht und interpretiert. Der Kern 910 setzt CLASSPATH 520 und
JAVA_HOME 530 gemäß den Werten,
die in der Zeichenkettentabelle 1150 gespeichert sind und
auf die von dem dynamischen Abschnitt 1140 gezeigt wird.
Der Kern 910 übergibt
dann den Inhalt des Datenabschnitts 1130 an den Java®-Interpreter 510.
Der Inhalt kann durch eine Vielzahl von Methoden übergeben
werden, umfassend, zum Beispiel, eine UNIX-Pipe. Alternative Methoden
umfassen ein Übergeben
eines Datei-Deskriptors an den Java®-Interpreter,
der auf den Offsetwert des Klassenabschnitts 1130 innerhalb
der Binärdatei 1101 zeigt,
oder ein Abbilden des Klassenabschnittes 1130 in einen
Speicher und Übergeben
der Basisadresse der abgebildeten Speicherstelle an den Java®-Interpreter.
Der Java®-Interpreter 510 referenziert nicht
die Eingangsklassendatei 330 und erhält stattdessen die Java®-Klasseninformation
von der ELF-Datei 1101, so wie sie von dem Kern 910 geliefert
wird. Der Interpreter fragt die Umgebungsvariable 530 mit
dem Namen „JAVA_HOME" ab und ermittelt
dadurch den Namen des Home-Verzeichnisses 535 des Java®-Laufzeitsystems.
Der Java®-Interpreter fragt
auch die „CLASSPATH"-Umgebungsvariable 520 ab,
wodurch die Namen verschiedener Benutzerklassenbibliotheken 527 und
Systemklassenbibliotheken 525 ermittelt werden, die zusätzliche
Klassen enthalten, die zur Laufzeit aufgerufen werden können. Falls
der Java®-Interpreter durch Übergeben
des Datei-Deskriptors oder der Basisadresse einer abgebil deten Speicherstelle
an ihn aufgerufen wird, kann der Java®-Interpreter
alternativ die Abhängigkeitsinformation
direkt von der ELF-Datei erhalten.
-
Dieser
dritte Ansatz ist insbesondere dadurch attraktiv, dass er eine dynamische
Auflösung
des CLASSNAME ohne Übernehmen
der Pflicht einer Koordination von Speicherstellen der Java®-Klassendatei 330 und
einer Skriptdatei erlaubt. Es gibt keine Skriptdatei und die Java®-Klassendatei
kann faktisch nach der javald-Operation gelöscht werden, wobei die Klassendatei
nur in dem javald-Prozess verwendet wird und während einer Ausführung niemals
referenziert wird.
-
Während verschiedene
Ausführungsformen
einer bevorzugten Ausführungsform
oben beschrieben wurden, ist es selbstverständlich, dass sie nur als Beispiele
und nicht zur Beschränkung
dargestellt werden. Somit wird die Breite und der Schutzbereich
einer bevorzugten Ausführungsform
nicht durch eine der oben beschriebenen beispielhaften Ausführungsformen
beschränkt,
sondern wird nur in Zusammenhang mit den vorliegenden Ansprüchen und
deren Äquivalenten
definiert.