[asm] wyrównanie stosu

0

Pytanie jest zapewne dość proste i oczywiste dla tych ktorzy mają pojęcie o assemblerze. Chodzi mi owyrównanie stosu:
Często w kodzie asm pojawia się taka linia: and esp, ~0x0f , do czego jest i po co służy ?
Np. kod poniżej działa poprawnie:

section .text
extern _printf
global _main

_main:
    push     ebp
    mov      ebp,esp

   and esp, ~0x0f

    push    dword[ff_result]
    push    print_uint32
    call    _printf
    add	    esp, 16 [1]
    
_end:
	xor 	eax,eax
	pop		ebp
	ret

	
section .data
    print_uint32    db		"%d", 0x0
    print_uint8     db      "%c", 0x0
    ff_result       dd      87

A jesli usunę tą linię z wyrównniem stosu to w [1] wystarczy add esp,8 trochę tego nie łapię, hmm, w ogóle...
Any help appreciated :)

0

Prosta matematyka, chodzi o to, aby wyrównać stos do wielokrotności 16, tak jak Intel i AMD w swoich manualach zalecają. Kwestia lekkiego podniesienia wydajności w pewnych sytuacjach i nic poza tym.

0

no i ok, tylko dlaczego wspomniana powyżej inia [1] tak się różni. Wie ktoś dlaczego do 16 a nie np do 32, albo do 8 ?

0

Weź manual Intela o optymalizacji i sam się przekonaj.

0

Intel zaleca wyrównywanie stosu do liczb podzielnych przez 8.
W ogólnym dostępie do danych to znalazłem taką rozpiske w jednym manualu Intela:

· Align 8-bit data on any boundary.
· Align 16-bit data to be contained within an aligned 4-byte word.
· Align 32-bit data on any boundary which is a multiple of four.
· Align 64-bit data on any boundary which is a multiple of eight.
· Align 80-bit data on a 128-bit boundary (that is, any boundary which is a multiple of
16 bytes).

Związane to jest z pamięcią cache i jej specyficznymi własnościami. Jak procesor natrafi na odpowiednio niewyrównany adres to wykonanie instrukcji może się wydłużyć o kilka lub nawet kilkanaście cykli.

0

Dobra inaczej zadam pytanie, dlaczego poniższy kod nie działa, a jak się zmieni wyrównanie do 32 do działa. Jak w ogóle nie będzie się wyrównywać stosu to działa. Jeśli ktoś wiec że to jest to napisane w manualu intela to niech chociaż powie w której części, bo w pierwszej o wyrównywaniu stosu to za wiele nie ma :P

section .text
extern _printf
global _main

_main:
    push     ebp
    mov      ebp,esp

    and esp, ~0x0f

    push    eax
    pop     eax
    
_end:
	xor 	eax,eax
	pop		ebp
	ret

// EDIT1
No dobra, pytanie moze troche zbyt ogolne. Rozumiem że powyższe nie zadziała bo wyrównując stos, zmniejszamy adres najaki wskazuje ESP, a wychodzac z programu trzeba wszystko uporzadkowac tak jak bylo inaczej nastąpi błąd ochrony pamięci. Ale nie rozumiem 1 rzeczy, skąd wiedzieć o ile się cofnąć (wlasciwie to pójsc wyżej) ponad to co się rzuciło na stos ? Chyba poczytam o alokacji pamięci na stos :|

0

Zauważ że na początku esp jest kopiowany do ebp, a dopiero potem and'ujesz esp. Zatem po labelu _end - przed pop ebp - skopiuj ebp do esp by cofnąć "wyrównanie".

0

Albo załatwić prolog jedną instrukcją:

leave

Zrobi to samo, co mov esp, ebp
pop ebp

tylko jest krótsze.
0
pejotr napisał(a)

Jeśli ktoś wiec że to jest to napisane w manualu intela to niech chociaż powie w której części, bo w pierwszej o wyrównywaniu stosu to za wiele nie ma :P

http://www.intel.com/design/Pentiumii/manuals/245127.htm
O wyrównywaniu zaczyna się od strony 51.

1 użytkowników online, w tym zalogowanych: 0, gości: 1