Aliasing (Computing) - Aliasing (computing)

In computing , aliasing beschreibt eine Situation , in der eine Datenstelle in Speicher kann durch verschiedene symbolische Namen im Programm zugegriffen werden. Wenn Sie also die Daten durch einen Namen ändern, werden implizit die Werte geändert, die allen Aliasnamen zugeordnet sind, was vom Programmierer möglicherweise nicht erwartet wird. Infolgedessen macht es Aliasing besonders schwierig, Programme zu verstehen, zu analysieren und zu optimieren. Aliasing-Analysatoren beabsichtigen, nützliche Informationen zum Verständnis von Aliasing in Programmen zu erstellen und zu berechnen.

Beispiele

Pufferüberlauf

Beispielsweise führen die meisten Implementierungen der Programmiersprache C keine Überprüfung der Array-Grenzen durch . Man kann dann die Implementierung der Programmiersprache durch den Compiler und die Assembler- Konventionen der Computerarchitektur ausnutzen , um Aliasing-Effekte durch Schreiben außerhalb des Arrays zu erzielen (eine Art Pufferüberlauf ). Dies ruft undefiniertes Verhalten gemäß der C-Sprachspezifikation auf; Viele Implementierungen von C zeigen jedoch die hier beschriebenen Aliasing-Effekte.

Wenn ein Array auf dem Stapel erstellt wird und eine Variable direkt neben diesem Array im Speicher angeordnet ist , kann ein Index außerhalb des Arrays erstellt und die Variable direkt geändert werden, indem das entsprechende Array-Element geändert wird. Wenn beispielsweise ein int Array der Größe 2 (in diesem Beispiel wird es aufgerufen arr ) neben einer anderen int Variablen (call it i ) arr[2] (dh dem 3. Element) vorhanden ist, wird ein Alias ​​erstellt, i wenn sie im Speicher benachbart sind.

# include <stdio.h>

int main()
{
  int arr[2] = { 1, 2 };
  int i=10;

  /* Write beyond the end of arr. Undefined behaviour in standard C, will write to i in some implementations. */
  arr[2] = 20;

  printf("element 0: %d \t", arr[0]); // outputs 1
  printf("element 1: %d \t", arr[1]); // outputs 2
  printf("element 2: %d \t", arr[2]); // outputs 20, if aliasing occurred
  printf("i: %d \t\t", i); // might also output 20, not 10, because of aliasing, but the compiler might have i stored in a register and print 10
  /* arr size is still 2. */
  printf("arr size: %d \n", sizeof(arr) / sizeof(int));
}

Dies ist in einigen Implementierungen von C möglich, da ein Array ein Block zusammenhängenden Speichers ist und Array-Elemente lediglich durch Offsets von der Adresse des Anfangs dieses Blocks multipliziert mit der Größe eines einzelnen Elements referenziert werden. Da C keine Begrenzungsprüfung hat, ist eine Indizierung und Adressierung außerhalb des Arrays möglich. Beachten Sie, dass das oben erwähnte Aliasing-Verhalten undefiniertes Verhalten ist . Einige Implementierungen lassen möglicherweise Platz zwischen Arrays und Variablen auf dem Stapel, um beispielsweise Variablen an Speicherorten auszurichten, die ein Vielfaches der nativen Wortgröße der Architektur betragen . Der C-Standard legt im Allgemeinen nicht fest, wie Daten im Speicher angeordnet werden sollen. (ISO / IEC 9899: 1999, Abschnitt 6.2.6.1).

Es ist nicht falsch, wenn ein Compiler Aliasing-Effekte für Zugriffe auslässt, die außerhalb der Grenzen eines Arrays liegen.

Alias-Zeiger

Eine andere Art von Aliasing kann in jeder Sprache auftreten, die sich auf einen Speicherort mit mehr als einem Namen beziehen kann (z. B. mit Zeigern ). Siehe das C- Beispiel des XOR-Swap-Algorithmus, der eine Funktion ist. Es wird davon ausgegangen, dass die beiden übergebenen Zeiger unterschiedlich sind. Wenn sie jedoch tatsächlich gleich sind (oder Aliase voneinander sind), schlägt die Funktion fehl. Dies ist ein häufiges Problem bei Funktionen, die Zeigerargumente akzeptieren, und ihre Toleranz (oder das Fehlen davon) für Aliasing muss sorgfältig dokumentiert werden, insbesondere für Funktionen, die komplexe Manipulationen an an sie übergebenen Speicherbereichen ausführen.

Angegebenes Aliasing

In einigen Fällen kann ein kontrolliertes Aliasing-Verhalten wünschenswert sein (dh ein angegebenes Aliasing-Verhalten, das nicht durch das Speicherlayout in C aktiviert ist). In Fortran ist dies üblich . Die Perl- Programmiersprache gibt in einigen Konstrukten das Aliasing-Verhalten an, z. B. in foreach Schleifen. Dadurch können bestimmte Datenstrukturen direkt mit weniger Code geändert werden. Beispielsweise,

my @array = (1, 2, 3);

foreach my $element (@array) {
    # Increment $element, thus automatically
    # modifying @array, since $element is ''aliased''
    # to each of @array's elements in turn.
    $element++;
}

print "@array \n";

wird als Ergebnis "2 3 4" ausdrucken. Wenn man Aliasing-Effekte umgehen möchte, kann man den Inhalt der Indexvariablen in eine andere kopieren und die Kopie ändern.

Konflikte mit der Optimierung

Optimierer müssen häufig konservative Annahmen über Variablen treffen, wenn Aliasing möglich ist. Wenn Sie beispielsweise den Wert einer Variablen kennen (z. B. x 5), können Sie normalerweise bestimmte Optimierungen vornehmen (z. B. konstante Ausbreitung ). Der Compiler kann diese Informationen jedoch nach einer Zuweisung zu einer anderen Variablen (z. B. in C *y = 10 ) nicht verwenden, da dies möglicherweise *y ein Alias ​​von ist x . Dies könnte nach einer Aufgabe wie der Fall sein y = &x . Infolge dieser Zuordnung zu *y würde sich auch der Wert von x ändern, sodass die Weitergabe der Informationen von x 5 an die folgenden Anweisungen *y = 10 möglicherweise falsch wäre (wenn *y es sich tatsächlich um einen Alias ​​von handelt x ). Wenn jedoch Informationen zu Zeigern vorhanden sind, kann der Prozess der konstanten Weitergabe eine Abfrage wie folgt ausführen: Kann x ein Alias ​​von *y ? Wenn die Antwort dann Nein lautet, x = 5 kann sie sicher weitergegeben werden.

Eine weitere durch Aliasing betroffene Optimierung ist die Neuordnung von Code. Wenn der Compiler entscheidet, dass x kein Aliasing vorliegt *y , kann Code, der den Wert von verwendet oder ändert x , vor der Zuweisung verschoben werden *y = 10 , wenn dies die Planung verbessern oder die Durchführung weiterer Schleifenoptimierungen ermöglichen würde .

Um solche Optimierungen auf vorhersehbare Weise zu ermöglichen, legt der ISO-Standard für die Programmiersprache C (einschließlich der neueren C99- Ausgabe, siehe Abschnitt 6.5, Absatz 7) fest, dass es (mit einigen Ausnahmen) illegal ist, mit Zeigern von auf denselben Speicherort zuzugreifen verschiedene Typen. Ein Compiler kann daher annehmen, dass solche Zeiger keinen Alias ​​haben. Diese Regel, die als strikte Aliasing-Regel bezeichnet wird , ermöglicht manchmal beeindruckende Leistungssteigerungen, es ist jedoch bekannt, dass sie einen ansonsten gültigen Code beschädigt. Mehrere Softwareprojekte verstoßen absichtlich gegen diesen Teil des C99-Standards. Python 2.x hat dies beispielsweise getan, um die Referenzzählung zu implementieren , und Änderungen an den grundlegenden Objektstrukturen in Python 3 erforderlich gemacht, um diese Optimierung zu ermöglichen. Der Linux-Kernel tut dies, weil striktes Aliasing Probleme bei der Optimierung von Inline-Code verursacht. In solchen Fällen wird beim Kompilieren mit gcc die Option -fno-strict-aliasing aufgerufen, um unerwünschte Optimierungen zu verhindern, die zu unerwartetem Code führen können.

Hardware-Aliasing

Der Begriff Aliasing wird auch verwendet, um die Situation zu beschreiben, in der aufgrund einer Hardware-Entwurfsauswahl oder eines Hardwarefehlers eines oder mehrere der verfügbaren Adressbits bei der Speicherauswahl nicht verwendet werden. Dies kann eine Entwurfsentscheidung sein, wenn mehr Adressbits verfügbar sind, als zur Unterstützung der installierten Speichergeräte erforderlich sind. Bei einem Fehler können ein oder mehrere Adressbits kurzgeschlossen oder gegen Masse (logisch 0) oder Versorgungsspannung (logisch 1) gedrückt werden.

Beispiel

In diesem Beispiel wird ein Speicherdesign mit 8 Positionen angenommen, für das nur 3 Adressleitungen (oder Bits ) erforderlich sind, da 2 3 = 8). Adressbits (mit A2 bis A0 bezeichnet) werden decodiert, um eindeutige Speicherstellen wie folgt auszuwählen, und zwar auf standardmäßige Weise als binärer Zähler :

A2 A1 A0 Speicherort
0 0 0 0
0 0 1 1
0 1 0 2
0 1 1 3
1 0 0 4
1 0 1 5
1 1 0 6
1 1 1 7

In der obigen Tabelle wählt jede der 8 eindeutigen Kombinationen von Adressbits einen anderen Speicherort aus. Wenn jedoch ein Adressbit (z. B. A2) gegen Masse kurzgeschlossen würde, würde die Tabelle wie folgt geändert:

A2 A1 A0 Speicherort
0 0 0 0
0 0 1 1
0 1 0 2
0 1 1 3
0 0 0 0
0 0 1 1
0 1 0 2
0 1 1 3

In diesem Fall, in dem A2 immer Null ist, werden die ersten vier Speicherplätze dupliziert und erscheinen erneut als die zweiten vier. Die Speicherplätze 4 bis 7 sind nicht mehr zugänglich.

Wenn diese Änderung an einem anderen Adressbit vorgenommen würde, wären die Decodierungsergebnisse unterschiedlich, aber im Allgemeinen wäre der Effekt der gleiche: Der Verlust eines einzelnen Adressbits halbiert den verfügbaren Speicherplatz, was zu einer Duplizierung (Aliasing) des führt verbleibender Platz.

Siehe auch

Verweise

Externe Links