die folgende C++ Quellcode vor:Mit Symbol '_end' in g ++ führt zu einem Segmentation Fault
int _end[1050];
int main() {
for (int i = 0; i < 1050; i++)
_end[i] = 0;
return 0;
}
Compilation line: g++ main.cpp -o main -O0
Ausführen dieses Codes führt Fehler der Segmentierung, wenn gcc-4.8 verwenden. 4 und clang-3.6.0 unter Ubuntu 14.04. Das seltsame Verhalten ist, dass das Symbol _end
auf das Ende eines statisch zugewiesenen Arrays zeigt _end
, nicht an seinem Anfang. Wenn wir _end
durch end_
ersetzen, funktioniert alles gut.
$ g++ main.cpp -o main.s -O0 -S
$ g++ main2.cpp -o main2.s -O0 -S
$ diff main.s main2.s
1,2c1,2
< .file "main.cpp"
< .globl _end
---
> .file "main2.cpp"
> .globl end_
5,7c5,7
< .type _end, @object
< .size _end, 4200
< _end:
---
> .type end_, @object
> .size end_, 4200
> end_:
25c25
< movl $0, _end(,%rax,4)
---
> movl $0, end_(,%rax,4)
:
Außerdem, wenn wir gcc zur Ausgabe eines Assembler-Code fragen durch -S Befehlszeilenargument bereitstellt, wird es mit „_end“ und die Version mit einem anderen Array-Name keinen signifikanten Unterschied zwischen der Version sein
Aber wenn wir die ausführbaren Dateien dump verwenden objdump und gegen sie diff laufen, werden wir, dass in der _end
Version der verwendeten Adresse sehen ist 4200 = 4 * 1050 Bytes weiter als nötig:
$ g++ main.cpp -o main -O0
$ g++ main2.cpp -o main2 -O0
$ objdump -d main >main.dump
$ objdump -d main2 > main2.dump
$ diff main.dump main2.dump
2c2
< main: формат файла elf64-x86-64 // "File format" in Russian
---
> main2: формат файла elf64-x86-64
123c123
< 4004ff: c7 04 85 c8 20 60 00 movl $0x0,0x6020c8(,%rax,4)
---
> 4004ff: c7 04 85 60 10 60 00 movl $0x0,0x601060(,%rax,4)
Soweit Ich weiß, GCC-Compiler kann Variab behandeln les beginnt mit Unterstrichen wie es will, ich. 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 des Endes 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 dass sich gcc und clang in diesem Fall identisch verhalten, das ist mir auch fremd.
Genau das, was ich brauchte, danke! Aber warum "-S" Kommandozeilenargument zeigt nichts verdächtiges beim Kompilieren dieses Codes? –
@MaximAkhmedov Das liegt wahrscheinlich daran, dass '_end' ein Zeiger ist wie jeder andere Zeiger, und Zeigerarithmetik wird ausgeführt, wenn Sie Ihrem Array zuweisen. – vsoftco