Handbuch zur dynamischen Ablaufverfolgung in Solaris

Zeiger und Adressen

Im Betriebssystem Solaris wird jedem Benutzerprozess mithilfe von virtuellem Speicher eine eigene virtuelle Sicht der Speicherressourcen auf dem System bereitgestellt. Eine virtuelle Sicht der Speicherressourcen wird als Adressraum bezeichnet. Durch ihn wird ein Bereich von Adresswerten (entweder [0 ... 0xffffffff] bei 32-Bit-Adressräumen oder [0 ... 0xffffffffffffffff] bei 64-Bit-Adressräumen) bestimmten Übersetzungen zugewiesen, auf deren Grundlage das Betriebssystem und die Hardware die einzelnen virtuellen Adressen in einen entsprechenden Speicherbereich im physischen Speicher konvertieren. In D stellen Zeiger Datenobjekte dar, die einen Ganzzahlwert einer virtuellen Adresse speichern und ihm einen D-Typ zuordnen, der das Format der an der entsprechenden Speicherposition abgelegten Daten beschreibt.

Um eine D-Variable als Zeigertyp zu deklarieren, geben Sie zunächst den Typ der referenzierten Daten an und fügen dann ein Sternchen ( *) an den Typnamen an, womit Sie zu erkennen geben, dass ein Zeigertyp deklariert werden soll. So wird beispielsweise die Deklaration:

int *p;

eine globale D-Variable namens p deklariert werden, die einen Zeiger auf eine Ganzzahl darstellt. Diese Deklaration bedeutet, dass p selbst eine 32- oder 64-Bit-Ganzzahl ist, deren Wert die Adresse einer anderen Ganzzahl irgendwo im Speicher darstellt. Da die kompilierte Form des D-Codes zum Zeitpunkt der Prüfpunktauslösung innerhalb des Betriebssystemkernels selbst ausgeführt wird, beziehen sich Zeiger in D typischerweise auf den Kernel-Adressraum. Mit dem Befehl isainfo(1) -b lässt sich ermitteln, wie viele Bits der aktive Betriebssystemkernel auf Zeiger verwendet.

Wenn Sie einen Zeiger auf ein Datenobjekt im Kernel erstellen möchten, können Sie dessen Adresse mit dem Operator & berechnen. Nehmen wir beispielsweise das im Betriebssystemkern-Quellcode deklarierte Tunable int kmem_flags. Sie könnten die Adresse dieses int-Tunables erfassen, indem Sie das Ergebnis der Anwendung des Operators & auf den Namen dieses Objekts in D verfolgen:

trace(&`kmem_flags);

Mit dem Operator * können Sie das durch den Zeiger angesprochene Objekt referenzieren. Der Operator hat die umgekehrte Wirkung des Operators &. So haben beispielsweise die beiden folgenden D-Codefragmente dieselbe Bedeutung:

p = &`kmem_flags;				trace(`kmem_flags);
trace(*p);

Das linke Fragment erstellt eine globale D-Variable in Form des Zeigers p. Da das Objekt kmem_flags den Typ int aufweist, nimmt das Ergebnis von &`kmem_flags den Typ int * an (d. h. ein Zeiger auf int). Das linke Fragment erfasst den Wert von *p, der den Zeiger bis zum Datenobjekt kmem_flags zurückverfolgt. Dieses Fragment ist deshalb gleichbedeutend mit dem rechten, das den Wert des Datenobjekts einfach über dessen Namen verfolgt.