2017-08-22 52 views
6

Przeczytałem, że zmienna double (8 bajtów) musi być wyrównana do 8 bajtów.Mylić o wyrównaniu danych dla podwójnych zmiennych

Teraz, jeśli piszę cały kod dla mojego programu, mogę ustawić zmienne 8 bajtów double wyrównane bez żadnego problemu.

Ale powiedz, że mam następujący scenariusz: Tworzę funkcję, która tworzy zmienną double na stosie, a ja daję tę funkcję komuś innemu, aby użyć jej w swoim programie. Teraz, gdy moja funkcja zostanie wywołana, moja funkcja nie będzie miała pojęcia, czy zmienna double zostanie utworzona na adres, który można podzielić przez 8!

Czy ten problem może zostać rozwiązany (zauważ, że nie dbam o znikomą utratę wydajności, nie dostosowując moich zmiennych double, ale jestem zainteresowany, aby wiedzieć, czy istnieje rozwiązanie tego problemu)?

+0

AFAIK 'gcc' już wyrównuje stos do 16 bajtów, co oznacza, że ​​spełnia również 8-bajtowe wymagania wyrównania. –

+0

@ 眠 り ネ ロ ク: Depends.on wersja systemu Linux. Nie pamiętam, kiedy przed 2009 r. Linux nadal korzystał z historycznego SysV i386 ABI, który wymagał tylko 4-bajtowego wyrównania stosów. GCC zmienił to na 16 (zerwanie z oryginalnym ABI), a następnie ABI zmodyfikowano tak, aby był 16-bajtowym wyrównaniem stosu w wywołaniu funkcji. Technicznie, jakie dostosowanie jest w użyciu, zależy od wersji systemu Linux. –

+1

@MichaelPetch w prawo. Zgodnie z https://en.wikipedia.org/wiki/X86_calling_conventions: *** Ponieważ GCC w wersji 4.5 **, podczas wywoływania funkcji stos musi być wyrównany do 16-bajtowej granicy (poprzednie wersje wymagały tylko 4-bajtowego wyrównanie.) * –

Odpowiedz

6

Wewnątrz funkcji można wymusić ustawienie stosu na 8 bajtów, ustawiając na zero trzy najmniej znaczące bity z z esp. Można to osiągnąć za pomocą instrukcji and:

andl $0xfffffff8, %esp 

Otrzymany esp będzie równe (tj .: esp już wyrównane) lub niższej niż poprzedni. Ponieważ stos architektury x86 rośnie w dół, wynikiem jest wypełnienie o rozmiarze od 0 do 7 bajtów przydzielonych na stosie.

Zauważ, że jeśli esp było już 8-bajtowy wyrównany przed wykonaniem instrukcji and (tj jego trzy najmniej znaczące bity były już zero), nie wyściółka w ogóle (tj: a wyściółka z 0 bajtów) jest tworzony na stos.


Po opuszczeniu funkcji, poprzedni zapisany wartość esp zostaną przywrócone, jeśli używasz wspólną funkcję prolog i epilog:

myFunction: 
    //prologue: save the current stack frame 
    pushl %ebp 
    movl %esp, %ebp 

    andl $0xfffffff8, %esp 
    //stack now 8-byte aligned 
    //... 

    leave //restore the previous stack frame 
    ret 

ten sposób wcześniej przydzielone dopełnienie być teraz zwolniony ze stosu.

+1

Warto zwrócić uwagę, że niektóre konwencje wywoływania (takie jak współczesne wersje systemu AB V86 systemu x86) wymagają wyrównania 16B '% esp' przed' wywołaniem' (aby argumenty na stosie były wyrównane i można uzyskać wyrównaną przestrzeń dla mieszkańcy z właściwym wyborem offsetu) –