Frage zu Lokalen Variablen in MASM
-
Lokale Variablen mit hilfe von MASM automatisch anlegen lassen:
[/asm]
function proc near
LOCAL myWordVar:WORD
mov myWordVar,8
ret
function endpErzeugt folgenden Code:
PUSH EBP
MOV EBP,ESP
ADD ESP,-4 ; Warum -4? 1 Word hat doch nur 2 Byte
MOV WORD PTR SS:[EBP-2],8
LEAVE
RETN[/asm]
Ich verstehe einfach nicht warum der Assembler ADD ESP,-4 erstellt.
Müsste der nicht eigentlich sagen ADD ESP,-2 weil eine Word Variable ist doch 2 Byte groß.So legen ich Lokale Variablen manuell an: (Funktioniert ohne Probleme)
function proc near push ebp mov ebp,esp sub esp,2 ; Lokale WORD Variable anlegen ( 1 WORD = 2 Byte ) mov word ptr [ebp-2],8 mov esp ,ebp pop ebp ret function endp
-
ebp schrieb:
Ich verstehe einfach nicht warum der Assembler ADD ESP,-4 erstellt.
Das tut er, um das bestehende stack alignment von 4 zu erhalten. Ein misalignment kann zu Performance Einbrüchen führen als auch das es Probleme mit API Funktion geben kann.
-
Der Stackpointer sollte laut Intel im 32-Bit-Modus immer an einer 32-Bit-Grenze ausgerichtet sein, d.h. das ESP-Register sollte ohne Rest durch 4 teilbar sein. Ansonsten: "Misaligning a stack pointer can cause serious performance degradation and in some instances program failures". Übrigens richtet MASM auch die Variablen aus (z.B. WORD an einer 16-Bit-Grenze).
Das hat vorrangig damit zu tun, wie die CPU auf Speicher zugreift. Auf Speicher wird nicht byteweise, sondern blockweise (je nach Frontside Bus) zugegriffen. Wenn nun der Zeiger nicht ausgerichtet ist, dann kann es sein, dass der gewünschte Wert sich zum Teil in dem einen Block befindet, zum anderen Teil im nächsten Block, somit zwei Speicherzugriffe nötig sind und die CPU das Gewünschte erst mühsam zusammenpfriemeln muss.
viele grüße
ralph
-
Wenn ich jetzt hier auf 00401019 eine Breakpoint setzt und das Programm bis zum Breakpoint ausführe dann hat der ESP den Wert: 0012FFBC
00401016 /$ 55 PUSH EBP 00401017 |. 8BEC MOV EBP,ESP 00401019 |. 83C4 FC ADD ESP,-4 0040101C |. 66:C745 FE 7B0>MOV WORD PTR SS:[EBP-2],7B 00401022 |. C9 LEAVE 00401023 \. C3 RETN
Und woher weiss ich jetzt das ich hier add esp,-4 schreiben muss?
0012FFBC = 1245116 Dezimal / 4 = 311279 Ok jetzt hab ich eine gerade Zahl
Aber angenommen ich will z.b. eine Lokale Variable anlegen welche 22 Zeichen groß ist woher weiss ich jetzt wie viel ich vom Stack abziehen muss um genug Speicherplatz zu reservieren?
Kann man das überhaupt berechnen?
-
Wenn deine Funktion aufgerufen wird, dann stimmt das Alignment. Wenn du eine Funktion aufrufst, musst du sicherstellen dass das es stimmt.
Um das Alignment beizubehalten, rundet man die Größe der lokalen Variable einfach auf das nächste vielfache von 4 auf:add esp,(local_size + 3) AND -4
-
add esp,-((local_size + 3) AND -4)
-
Tag,
ebp schrieb:
Aber angenommen ich will z.b. eine Lokale Variable anlegen welche 22 Zeichen groß ist woher weiss ich jetzt wie viel ich vom Stack abziehen muss um genug Speicherplatz zu reservieren?
Kann man das überhaupt berechnen?
So, dass im Endeffekt dein ganzer Stack-Frame Space durch 4 restlos teilbar ist.
void test(unsigned short s) { unsigned short k; unsigned char lol; char buf[250]; int huhu[2] }
kann dann c.a. so aussehen:
;local var size: 261 ;without padding: 271/4=67,75 ;with padding: 272/4=68 ;entire size: sizeof(s) + sizeof(RETADDR) + sizeof(EBP) + sizeof(k) + sizeof(lol) + sizeof(buf) + sizeof(huhu) + 1 push ebp mov ebp, esp sub esp, 261 ;Code add esp, 261 pop ebp ret
Man hätte also 1 Byte mehr als Padding.
MfG: sk0r