Stack

11/01/2011 - 15:12 von Sebastian Koschmieder | Report spam
Hallo,

ich bin mal auf ein kleines Problem gestoßen welches ich nicht wirklich
Nachvollziehen kann. Folgende Bsp:

void x10Bytes( void ) {
804850c: 55 push %ebp
804850d: 89 e5 mov %esp,%ebp
804850f: 83 ec 10 sub $0x10,%esp
unsigned char foo[ 0x8 ];

Bsp2:

unsigned char * foo = ( char * ) alloca( size + 1 );
804862e: 8b 45 08 mov 0x8(%ebp),%eax
8048631: 83 c0 01 add $0x1,%eax
8048634: 83 c0 0f add $0xf,%eax
8048637: 83 c0 0f add $0xf,%eax
804863a: c1 e8 04 shr $0x4,%eax
804863d: c1 e0 04 shl $0x4,%eax
8048640: 29 c4 sub %eax,%esp
8048642: 89 e0 mov %esp,%eax
8048644: 83 c0 0f add $0xf,%eax
8048647: c1 e8 04 shr $0x4,%eax
804864a: c1 e0 04 shl $0x4,%eax
804864d: 89 45 f4 mov %eax,-0xc(%ebp)

Bei dem ersten Bsp definiere ich ja eine lokale Variable, mit 8x1Byte.
Jedoch werden auf dem Stack 16Bytes reserviert. Bzw der Stack-Pointer wird
um 16 Bytes Subtrahiert. In dem zweiten Bsp habe ich mit alloca gearbeitet.
und selbst dort ist es dass der Stack-Pointer sehr viel weiter gesetzt wird
als nötig. Aber auch hier wieder, es ist immer ein Teiler von 16.
Ich habe dazu nun 2 Theorien gehabt. Wobei diese nicht wirklich zutreffen
können.
Erstens:
Es gibt ja Möglichkeiten einen Buffer-Overflow zu verhindern. Eine davon ist
das der Stack-Protector. Dabei wird ein Wert zwischen die lokalen Variablen
und der Rücksprungadresse gelegt. Der wird dann zum Schluss wieder
verglichen. Das habe ich aber extra deaktiviert. Außerdem müssten es dann
12Byte sein und keine 16...
Die andere Möglichkeit ist Fragmentierung vorzubeugen. Jedoch habe ich dies
auch als Unsinn abgetan, da der Stack so oder so aufgeràumt wird, sobald man
aus einer Funktion raus springt.
Dann viel mir eine andere Möglichkeit ein, welche ich aber auch nicht
wirklich navollziehen kann. Bedingt durch die 8086-Prozessoren. Dort wurden
die Adressen aus Segment:Offset berechnet. Wobei eine Adresse welche nur aus
Segment bestand ja auch ein Teiler von 16 hat. Ich habe auch gefunden, dass
der kleinste Block, welcher von einer CPU angefordert werden kann 16Byte
ist. Also ein Paragraph.
Meine Frage nun dazu ist. Liege ich in der richtigen Richtung, bzw weiß
jemand warum das so funktioniert. Bzw wie wird der Stack aus sicht des OS
für Programme zur Verfügung gestellt?
Für Literatur in dem Bereich wàre ich sehr dankbar.

mfg
Sebastian
 

Lesen sie die antworten

#1 Jan Seiffert
11/01/2011 - 15:37 | Warnen spam
Sebastian Koschmieder schrieb:
Hallo,



[snip - warum waechst mein Stack in 16er schritten auf x86]

#include <stddisclaimer.h>
Du bist mit dieser Frage hier OT.
Auch wenn dein Code in C geschrieben ist, ist dies denoch keine Gruppe um ueber
konkrete implementation und besonders CPUs zu reden (-> de.comp.lang.assembler?).

<OT>

x86 CPUs unterstuetzen SSE, also Vektoroperationen auf 16 Byte auf einmal.
Es kann diese von unaligned-tem Speicher holen, aber das ist sehr langsam.
Darum versucht dein Compiler (ich tippe es ist GCC) den Stack immer zu 16
ausgerichtet zu halten, sodass wenn der Compiler fuer dich etwas "vektorisiert",
er im Hintergrund mit movdqa|movap{ds} (das "a" steht fuer aligned, die
Operationen faulten wenn das nicht so ist...) Register ein- und auslagern kann
(spillen).
Allokationen aufzurunden ist eben billiger als den Stack dann auszurichten, wenn
es gebraucht wird. Nebenbei ist es dann warsch. so Vorschrift in der ABI deines
Systems (also: der Stack ist immer zu 16 ausgerichtet zu halten).
Ist auch nebenbei praktischer fuer andere Datenformate (long long, double, long
double, etc.).

</OT>

mfg
Sebastian



Gruss
Jan

Just In Time
Euphemismus fuer:
Out of Stock

Ähnliche fragen