Forum: Compiler & IDEs Woran macht Compiler Entscheidung fest TEXT_ | DATA_?


von fixStackPointer (Gast)


Lesenswert?

Hallo,

ich schreibe gerade einen Compiler für eine selbst entwickelte Sprache - 
(sehr C nah). Als Referenz nutz ich den Microsoft-Compiler+Assembler, 
ich weiß es gibt auch andere. Bei folgendem Code
1
int main(int argc, char *argv[])
2
{
3
UINT64_T bbbb;
4
bbbb = 10;
5
intpr einPointer;
6
einPointer = &bbbb;
7
einPointer = 11;
8
}

erzeugt folgenes assembly:
1
  ;UINT64_T bbbb;
2
  ;bbbb = 10;
3
 mov         qword ptr [bbbb],0Ah  
4
5
  ;intpr einPointer;
6
  ;einPointer = &bbbb;
7
 lea         rax,[bbbb]  
8
 mov         qword ptr [einPointer],rax  
9
10
  ;einPointer = 11;
11
 mov         qword ptr [einPointer],0Bh

Der Pointer landet also der _TEXT Section. Woran macht das der Compiler 
in dem Falle aus? Mein Hobel legt die (lokale?) Variable auf dem Stack 
an...wie die Windows Calling Convention auch "empfiehlt".
Welche Bedingungen muss ich prüfen?

VG Jonas

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

fixStackPointer schrieb:
> Der Pointer landet also der _TEXT Section.

Klär' mich auf: Woran erkennt man das an Deinem Assemblerschnipsel?

von (prx) A. K. (prx)


Lesenswert?

fixStackPointer schrieb:
> Der Pointer landet also der _TEXT Section.

Das steht in Widerspruch zu:

> Mein Hobel legt die (lokale?) Variable auf dem Stack

Ansonsten könnte es helfen, die Frage so zu formulieren, dass 
Normalsterbliche ohne Kristallkugel sie verstehen.

von Le X. (lex_91)


Lesenswert?

A. K. schrieb:
> fixStackPointer schrieb:
> Der Pointer landet also der _TEXT Section.
>
> Das steht in Widerspruch zu:
>
> Mein Hobel legt die (lokale?) Variable auf dem Stack
>
> Ansonsten könnte es helfen, die Frage so zu formulieren, dass
> Normalsterbliche ohne Kristallkugel sie verstehen.

"Mein Hobel" ist wohl der Eigenbau-Compiler des TE, der so die Aussage, 
den Pointer auf den Stack legt.
Der gezeigte Assemblercode stammt wohl vom nicht näher spezifizierten 
Microsoft-Compiler, der als Referenzimplementierung gilt.
Der TE möchte nun herausfinden welcher Compiler sich "richtig" verhält.
Kein Widerspruch.

Allerdings gibt der Assemblercode zu wenig Infos her.
Ich kann da nicht erkennen wo der Pointer liegt.

von fixStackPointer (Gast)


Lesenswert?

Ja es war schon spät...

Sorry, die Architekture ist x86_x64 im "echten" 64 bit Modus. Ich hab 
das Verhalten jetzt so implementiert das alle nicht initalisierten 
Variablen in DATA_ landen, alles was initialisiert werden muss in TEXT_ 
mit entsprechendem Initialiserungscode... sieht ganz gut aus. Vielen 
Dank für eure Beiträge :)

von Markus F. (mfro)


Lesenswert?

fixStackPointer schrieb:
> alles was initialisiert werden muss in TEXT_
> mit entsprechendem Initialiserungscode..

Vielleicht nicht unbedingt empfehlenswert, falls der Code auf einem OS 
laufen soll, das (per MMU) TEXT_ in ein read-only Segment steckt?

von fixStackPointer (Gast)


Lesenswert?

>Vielleicht nicht unbedingt empfehlenswert, falls der Code auf einem OS
>laufen soll, das (per MMU) TEXT_ in ein read-only Segment steckt?

Stimmt, allerdings hab ich da auch ein andere Calling Convention. Ist 
aber soweit abstrahiert, also leicht leicht erweiterbar..

Erstmal Windows CV, dann kommt System-V...

von fixStackPointer (Gast)


Lesenswert?

>Vielleicht nicht unbedingt empfehlenswert, falls der Code auf einem OS
>laufen soll, das (per MMU) TEXT_ in ein read-only Segment steckt?
Ich versuche das Gerade nochmal genau nachzuvollziehen, ist ein bisschen 
schwierig wenn man so tief im Detail steckt. Aber ich glaube ich 
verstehe jetzt was du meinst, das Binary wird ja schlussendlich mal von 
der Platte in den Ram geladen... allerdings muss das ja trotzdem 
irgendwie deterministisch laufen...irgendeine Idee?

Er wächst und gedeiht...
Aber langsam lässt sich die Sache mit den SECTIONEN nicht mehr 
ignorieren... Im Moment wird das nur ganz primitiv per "Scopelevel" oder 
"Blocklevel" entschieden, ganz wie man das nennen mag. Also nur an Hand 
der Position im Code, irgendwelche Qualifier ignoriere ich noch bewusst 
um die Komplexität nicht explodieren zu lassen. Den ein oder anderen 
könnte ich aber schon mal einbauen. static zum Beispiel, sollte ja immer 
in DATA_ landen, oder?

von Markus F. (mfro)


Lesenswert?

Bei "richtigen" Betriebssystemen besteht ein Executable (mindestens) aus 
3 Sections: TEXT, DATA und BSS.

In TEXT gehören m.E. nur Code und (höchstens) Daten, die nur gelesen 
werden (Konstanten).
In DATA gehören (veränderliche) Daten, die einen Initialwert haben.
In BSS gehören (veränderliche) Daten, die beim Programmstart nicht oder 
mit 0 initialisiert werden.

Der Loader (eines "vorsichtigen" Betriebssystems) wird das TEXT-Segment 
(wenn die HW das zulässt) idealerweise in einen Speicherbereich laden, 
der anschließend mittels MMU auf readonly gesetzt wird.
Schreibzugriffe lösen dann einen Fault aus, wenn sie versuchen 
(unabsichtlich oder böswillig), Code zu manipulieren (schließt dann 
natürlich selbstmodifizierenden Code aus, aber das ist meist sowieso 
eine gute Idee).

von S. R. (svenska)


Lesenswert?

Zu dem üblichen TEXT-DATA-BSS-Tripel kommt oft noch RODATA. Dort liegen 
Konstanten, die im Gegensatz zu TEXT nicht ausführbar und im Gegensatz 
zu DATA nicht schreibbar sein müssen.

Dazu kommt noch der Stack. Lokale Variablen gehören nicht nach DATA, 
sondern auf den Stack.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Der Stack gehört aber nicht in die exec, den legt das OS zur Laufzeit an 
und wenn er wächst werden mehr Pages per MMU zugemapped.

von fixStackPointer (Gast)


Lesenswert?

Danke @Markus!!!

>Zu dem üblichen TEXT-DATA-BSS-Tripel kommt oft noch RODATA. Dort liegen
>Konstanten, die im Gegensatz zu TEXT nicht ausführbar und im Gegensatz
>zu DATA nicht schreibbar sein müssen.

Ok, RODATA hab ich auch schon mal gehört, gibt nun 4 Sectionen.

>Der Stack gehört aber nicht in die exec, den legt das OS zur Laufzeit an
>und wenn er wächst werden mehr Pages per MMU zugemapped.

? Das ist ja gerade die Frage in welche SECTION? Auf den Stack bedeudet 
es muss per push oder mov auf den stack geschoben werden, das ist 
ausführbarer code und steht in TEXT_.

von S. R. (svenska)


Lesenswert?

Mw E. schrieb:
> Der Stack gehört aber nicht in die exec, den legt das OS
> zur Laufzeit an und wenn er wächst werden mehr Pages
> per MMU zugemapped.

Das ist richtig, setzt aber voraus, dass deine Hardware eine MMU und ein 
OS hat. Das ist nicht überall gegeben.

Das Executable muss nicht wissen, wo der Stack liegt (weil darauf nur 
über den Stackpointer zugegriffen wird), aber der Startup-Code muss den 
Stackpointer initialisieren.

Deswegen muss man den Stack auch im Hinterkopf behalten. :-)

fixStackPointer schrieb:
> Das ist ja gerade die Frage in welche SECTION?

Der Stack ist nur per Stackpointer zugreifbar, liegt also erstmal in 
keiner SECTION. Zumindest nicht, wenn man sich das Executable anschaut.

> Auf den Stack bedeudet es muss per push oder mov auf den stack
> geschoben werden, das ist ausführbarer code und steht in TEXT_.

(a) Nein, man darf auch SP-relativ auf den Stack zugreifen (Stichwort 
"Stack Pointer", "Frame Pointer").
(b) In TEXT stehen auch die Load- und Store-Befehle für Daten. Deswegen 
stehen die Daten selbst aber brav in DATA, RODATA oder BSS - und gehören 
selbst nicht zu TEXT.

Wie gesagt, der Stack muss beim Start korrekt initialisiert werden und 
darf die anderen Sectionen im Speicher nicht überlappen.

Im Executable taucht der Stack nicht auf.
Im Prozessor kann der Stack sein eigenes Segment bekommen (x86) oder 
auch nicht (so ziemlich alle anderen Architekturen).
Im Compiler ist der Stack der Ort für sämtliche lokalen Variablen, 
Register-Spill und andere Dinge.

von Steffen R. (steffen_rose)


Lesenswert?

fixStackPointer schrieb:
>>Der Stack gehört aber nicht in die exec, den legt das OS zur Laufzeit an
>>und wenn er wächst werden mehr Pages per MMU zugemapped.
>
> ? Das ist ja gerade die Frage in welche SECTION? Auf den Stack bedeudet
> es muss per push oder mov auf den stack geschoben werden, das ist
> ausführbarer code und steht in TEXT_.

???
Der Stack ist extra und die Befehle, diesen zu bedienen, stehen im 
_TEXT.

Außerdem scheinst du bereits Optimierungen einzukalkulieren.
Normalerweise steht eine Konstante in RODATA, wird von da geholt und 
dann genutzt.
Per Optimierung ist sie ggf. bereits Teil des Assemblerbefehls. Da 
beginnen dann bereits die Sektionszuordnungen zu verschwimmen.

von fixStackPointer (Gast)


Lesenswert?

>Außerdem scheinst du bereits Optimierungen einzukalkulieren.
>Normalerweise steht eine Konstante in RODATA, wird von da geholt und
>dann genutzt.

Jep, es gibt schon ein compilerflag optfor: size | speed
Wollte ich eigentlich erst nicht machen, aber es fallen einem viel zu 
viele Optimierungen ein, die alle zu verwerfen wäre irgendwie schade.

>Im Executable taucht der Stack nicht auf.

Naja, die Push-Pop Orgien werden ja in der executable gefeiert...XD

Vielen dank für eure Anregungen, aber ich glaub ich habs jetzt soweit 
gerafft :D.
Zwischenstand: Bin gerade bei Arrays... :D It's fun :D

von fixStackPointer (Gast)


Lesenswert?

Guten Abend :D

Ui...gibt einiges neues:
Arrays sind fast fertig...

Mache jetzt einen "pre-compile" Lauf und ermittle dabei:
-wird eine variable initialisiert?
-wie oft wird sie geschrieben (geplante Optimierung: je mehr Zugriffe, 
desto eher in Register halten)
-wann ist der letzte Zugriff auf die variable (Optimierung: Register 
freigeben)

Damit ergeben sich nun (außer nicht implementierte Qualifier)
alle notwendigen Parameter um die richtige Section auszuwählen.
Da bastel ich gerade noch dran rum.

Desweiteren hab ich bindump.exe entdeckt...
Damit wird natürlich vieles klarer.

Sowas sieht schon gar nicht schlecht aus: relative 
Stackpointer-Adressierung, Stack-Init-Optimierung...
1
UINT64_T index1;
2
  UINT64_T index2;
3
  UINT64_T index3;
4
  UINT64_T index4;
5
  UINT64_T index5;
6
  UINT64_T index6;
7
  UINT64_T index7;
8
  UINT64_T index8;
9
  UINT64_T index9;
10
  UINT64_T index10;
11
  UINT64_T index11;
12
  UINT64_T index12;
13
  UINT64_T index13;
14
  UINT64_T index14;
15
  UINT64_T index15;
16
  UINT64_T index16;
17
  
18
  index1 = 1;
19
  index2 = 2;
20
  index3 = 3;
21
  index4 = 4;
22
  index5 = 5;
23
  index6 = 6;
24
  index7 = 7;
25
  index8 = 8;
26
  index9 = 9;
27
  index10 = 10;
28
  index11 = 11;
29
  index12 = 12;
30
  index13 = 13;
31
  index14 = 14;
32
  index15 = 15;
33
  index16 = 16;
34
  
35
  UINT64_T r;
36
37
  r = index1*index2*index3*index4*index5*index6*index7*index8*index9*index10*index11*index12*index13*index14*index15*index16;
1
;   index1 = 1;
2
mov          RAX          ,           00000001h
3
4
;   index2 = 2;
5
mov          RDX          ,           00000002h
6
7
;   index3 = 3;
8
mov          RCX          ,           00000003h
9
10
;   index4 = 4;
11
mov          R8          ,           00000004h
12
13
;   index5 = 5;
14
mov          R9          ,           00000005h
15
16
;   index6 = 6;
17
mov          RDI          ,           00000006h
18
19
;   index7 = 7;
20
mov          R10          ,           00000007h
21
22
;   index8 = 8;
23
mov          R11          ,           00000008h
24
25
;   index9 = 9;
26
mov          R12          ,           00000009h
27
28
;   index10 = 10;
29
mov          R13          ,           0000000Ah
30
31
;   index11 = 11;
32
mov          R14          ,           0000000Bh
33
34
;   index12 = 12;
35
mov          R15          ,           0000000Ch
36
37
;   index13 = 13;
38
mov          qword ptr [rbp - 8 ]          ,           0000000Dh
39
40
;   index14 = 14;
41
mov          qword ptr [rbp - 16 ]          ,           0000000Eh
42
43
;   index15 = 15;
44
mov          qword ptr [rbp - 24 ]          ,           0000000Fh
45
46
;   index16 = 16;
47
mov          qword ptr [rbp - 32 ]          ,           00000010h
48
49
;   r = index1*index2*index3*index4*index5*index6*index7*index8*index9*index10*index11*index12*index13*index14*index15*index16;
50
imul        RAX          ,           RDX
51
52
;   r = index1*index2*index3*index4*index5*index6*index7*index8*index9*index10*index11*index12*index13*index14*index15*index16;
53
imul        RAX          ,           RCX
54
55
;   r = index1*index2*index3*index4*index5*index6*index7*index8*index9*index10*index11*index12*index13*index14*index15*index16;
56
imul        RAX          ,           R8
57
58
;   r = index1*index2*index3*index4*index5*index6*index7*index8*index9*index10*index11*index12*index13*index14*index15*index16;
59
imul        RAX          ,           R9
60
61
;   r = index1*index2*index3*index4*index5*index6*index7*index8*index9*index10*index11*index12*index13*index14*index15*index16;
62
imul        RAX          ,           RDI
63
64
;   r = index1*index2*index3*index4*index5*index6*index7*index8*index9*index10*index11*index12*index13*index14*index15*index16;
65
imul        RAX          ,           R10
66
67
;   r = index1*index2*index3*index4*index5*index6*index7*index8*index9*index10*index11*index12*index13*index14*index15*index16;
68
imul        RAX          ,           R11
69
70
;   r = index1*index2*index3*index4*index5*index6*index7*index8*index9*index10*index11*index12*index13*index14*index15*index16;
71
imul        RAX          ,           R12
72
73
;   r = index1*index2*index3*index4*index5*index6*index7*index8*index9*index10*index11*index12*index13*index14*index15*index16;
74
imul        RAX          ,           R13
75
76
;   r = index1*index2*index3*index4*index5*index6*index7*index8*index9*index10*index11*index12*index13*index14*index15*index16;
77
imul        RAX          ,           R14
78
79
;   r = index1*index2*index3*index4*index5*index6*index7*index8*index9*index10*index11*index12*index13*index14*index15*index16;
80
imul        RAX          ,           R15
81
82
;   r = index1*index2*index3*index4*index5*index6*index7*index8*index9*index10*index11*index12*index13*index14*index15*index16;
83
imul        RAX          ,           qword ptr [rbp - 8 ]
84
85
;   r = index1*index2*index3*index4*index5*index6*index7*index8*index9*index10*index11*index12*index13*index14*index15*index16;
86
imul        RAX          ,           qword ptr [rbp - 16 ]
87
88
;   r = index1*index2*index3*index4*index5*index6*index7*index8*index9*index10*index11*index12*index13*index14*index15*index16;
89
imul        RAX          ,           qword ptr [rbp - 24 ]
90
91
;   r = index1*index2*index3*index4*index5*index6*index7*index8*index9*index10*index11*index12*index13*index14*index15*index16;
92
imul        RAX          ,           qword ptr [rbp - 32 ]
93
94
;   r = index1*index2*index3*index4*index5*index6*index7*index8*index9*index10*index11*index12*index13*index14*index15*index16;
95
mov          qword ptr [rbp - 40 ]          ,           RAX

von fixStackPointer (Gast)


Lesenswert?

So ... lange Nacht hinter mir, aber:
-Sectionen gibt es nun fünf.

Eine Frage dazu, warum gibt es zwei "gleiche Sectionen" pdata und idata?
Beide mit gleichen flags:
-read Only
-Initialized Data

static, const und extern wird nun ausgewertet. in verbindung mit 
scope-und filelevel und dem vorherigen Ermitteln der Initialisierung und 
der Schreibzugriffe versuche ich nun die "LifeTimeDuration" der Objekte 
zu ermitteln...

lg

von fixStackPointer (Gast)


Lesenswert?

code refactoring...

von fixStackPointer (Gast)


Lesenswert?

Arg... doofes c# oder doofer fixStackPointer:

CopyTo() erstellt keine deep-copy sondern nur eine shadow-copy...

hat mich einen Tag gekostet :(
Egal, weiter geht's :D, frohe Weihnachten!

von Fipo (Gast)


Lesenswert?

Kennt wer ein Gutes Tutorial für avx 512?

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Guck dir die Intel Intrinsics an und machs in C:
https://software.intel.com/sites/landingpage/IntrinsicsGuide/#techs=AVX_512
Im makefile dann -native angeben mit er auch AVX nutzt.

Mit AVX2 hab ich meinen Mandelbrotzeichner beschleunigt.

S. R. schrieb:
> Mw E. schrieb:
>> Der Stack gehört aber nicht in die exec, den legt das OS
>> zur Laufzeit an und wenn er wächst werden mehr Pages
>> per MMU zugemapped.
>
> Das ist richtig, setzt aber voraus, dass deine Hardware eine MMU und ein
> OS hat. Das ist nicht überall gegeben.

Ja gut, aber wo wir hier über x86 und eigen gebautem Compiler reden hab 
ich ein unterliegendes OS sowie eine MMU angenommen ;)

von S. R. (svenska)


Lesenswert?

Mw E. schrieb:
> Ja gut, aber wo wir hier über x86 und eigen gebautem Compiler reden hab
> ich ein unterliegendes OS sowie eine MMU angenommen ;)

Und vollkommen zurecht. :-)

fixStackPointer schrieb:
> Wollte ich eigentlich erst nicht machen, aber es fallen einem viel zu
> viele Optimierungen ein, die alle zu verwerfen wäre irgendwie schade.

Hast du dich mal mit dem Aufbau klassischer Compiler beschäftigt, also 
SSA und sowas? In den Büchern stehen die viele grundlegende 
Optimierungen schon drin. ;-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.