Das Verwenden des Symbols '_end' in g ++ führt zu einem Segmentierungsfehler

8

Betrachten Sie den folgenden c ++ Quellcode:

%Vor%

Kompilationszeile: g++ main.cpp -o main -O0

Das Ausführen dieses Codes führt zu Segmentierungsfehlern bei Verwendung von gcc-4.8.4 und clang-3.6.0 unter Ubuntu 14.04. Das seltsame Verhalten ist, dass das Symbol% ​​co_de% am Ende eines statisch zugewiesenen Arrays _end zeigt, nicht am Anfang. Wenn wir _end durch _end ersetzen, funktioniert alles gut.

Wenn wir gcc außerdem bitten, einen Assembler-Code auszugeben, indem wir das Befehlszeilenargument -S angeben, gibt es keinen signifikanten Unterschied zwischen der Version mit "_end" und der Version mit einem anderen Array-Namen:

%Vor%

Aber wenn wir objdump verwenden, um die ausführbaren Dateien zu dumpen und diff gegen sie auszuführen, werden wir sehen, dass in der end_ version die verwendete Adresse 4200 = 4 * 1050 Bytes weiter ist als benötigt:

%Vor%

Soweit ich weiß, kann der gcc-Compiler Variablen, die mit Unterstrichen beginnen, so behandeln, wie sie wollen, d. e. Dies ist eine schlechte Methode, um solche Symbole in Ihrem Code zu verwenden. Aber meine Frage ist: Was passiert hier wirklich? Warum wird _end durch eine Adresse am Ende eines zugewiesenen Arrays ersetzt? Warum gibt es keinen Unterschied, wenn wir das Befehlszeilenargument "-S" verwenden, aber es gibt tatsächlich einen Unterschied in den erstellten Binärdateien? Nicht das gcc und clang verhalten sich in diesem Fall identisch, das ist mir auch fremd.

    
Maxim Akhmedov 17.11.2015, 15:36
quelle

2 Antworten

2

Token, die mit _ beginnen, sind reserviert und sollten nicht verwendet werden. Es scheint, dass _end ein externes Symbol ist, das für unter Linux kompilierte Programme definiert ist und die erste Adresse nach dem Ende des nicht initialisierten Datensegments (auch als BSS-Segment bezeichnet) darstellt.

  

Hinweis: Auf einigen Systemen sind die Namen dieser Symbole vorangestellt          Unterstriche, also: _etext, _edata und _end.

Quelle: Ссылка

    
vsoftco 17.11.2015, 15:40
quelle
0

Standardentwurf C99 N1256 7.1.3 "Reservierte Identifikatoren" sagt:

  

Alle Bezeichner, die mit einem Unterstrich beginnen, sind immer für die Verwendung als Bezeichner mit dem Dateibereich sowohl im normalen als auch im Tag-Namensraum reserviert.

Dann müssen wir das wissen:

    Der Dateibereich
  • ist für Globals (die anderen sind Funktions- und Blockbereich)
  • gewöhnlicher Namensraum enthält Variablen

So können Sie laut C99 den Bezeichner _end nicht verwenden.

Ihre Implementierung

Um zu sehen, warum die Implementierung fehlschlägt, verwenden Sie:

%Vor%

, um das verwendete Linkerskript zu sehen.

Unter Ubuntu 15.10 definiert es das Symbol% ​​co_de% am Ende des Datenabschnitts:

%Vor%

es ist also nicht verwunderlich, dass der Zugriff auf den Speicher, der weit voraus ist, segfault sein kann.

    
quelle

Tags und Links