2012-01-25 17 views
10

I zdemontowany plik obiektowy (najprawdopodobniej generowane przy użyciu kompilatora Visual C++) za pomocą DumpBin i zobaczyłem następujący fragment kodu:Dlaczego kompilator generuje ten kod?

...   ... 
mov   dword ptr [ebp-4],eax  // Why save EAX? 
push  dword ptr [ebp+14h] 
push  dword ptr [ebp+10h] 
push  dword ptr [ebp+0Ch] 
push  dword ptr [ebp+8] 
mov   eax,dword ptr [ebp-4]  // Why restore EAX? Did it change at all? 
call  <function> 
...   ... 

Może ktoś proszę wyjaśnić dlaczego rejestr EAX jest zapisane i przywrócone przez te 4 push instrukcje?

+2

Widziałem kompilatory robiące głupsze rzeczy niż to ... – Mysticial

+0

@Mysticial: Oh lol ... po raz pierwszy zauważyłem coś takiego. :) Dobrze wiedzieć. – Mehrdad

+7

Być może w pierwszym pchnięciu jest gałąź. –

Odpowiedz

9

Być może jest skompilowany w trybie zwolnienia, ale ta zmienna została oznaczona jako volatile, która mówi kompilatorowi, że taka zmienna może się zmienić bez jej wiedzy, więc jest zmuszona do ciągłego zapisu/przywracania jej ze stosu

+0

Ahhhh to całkiem możliwe! +1 dzięki. – Mehrdad

+0

Nie jestem pewien, czy "lotny" miałby tutaj znaczenie. 'volatile' odnosi się do lokalizacji w pamięci, ale EAX jest rejestrem; nie można oznaczyć rejestru jako niestabilnego. Więc 'volatile' wyjaśniałoby, że [ebp-4] jest ponownie ładowany * na * eax bezpośrednio przed każdą operacją, ale nie eax jest zapisywany. – Crashworks

+0

Dla pewnej arytmetyki kompilator _has_ ładuje położenie pamięci oznaczone jako lotne do rejestru, ponieważ operacja nie jest możliwa jako instrukcja odczytu-modyfikacji-zapisu. Po tym fragmencie kodu może nastąpić sklep, a przed nim ładunek może poprzedzać, więc z dostępnych informacji może być absolutnie możliwe. Ale nie jest to tylko pominięta optymalizacja przez VC. – hirschhornsalz

6

Czy został on zbudowany w trybie debugowania? Jeśli tak, kompilator przechowuje każdą zmienną lokalną na stosie, aby debugger mógł je znaleźć w spójny sposób.

Eliminacja takich niepotrzebnych zapasów i przeładowań jest jedną z optymalizacji, która stanowi tryb "wydania".

+0

Wierzę, że to * przypuszczenie * jest kodem trybu zwolnienia (nie ma wersji "debugującej" niczego, co można zobaczyć gdziekolwiek ...), ale nie jestem pewien ... Nie mam kodu źródłowego zarówno. Ale +1 to rozsądne domysły, dzięki. – Mehrdad

2

volatile czy nie, tylko techniczny powód EAX byłoby muszą być inicjowane bezpośrednio przed nawiązaniem połączenia funkcji w systemie Windows były jeśli function deklaruje __syscall, czyli używając wzywającą konwencję Okna CS_SYSCALL. Koncepcyjnie jest to trochę podobne do konwencji UN * X x86_64, w której %al zawiera liczbę argumentów typu zmiennopozycyjnego przekazanych w rejestrach %xmm.

Konwencja wywoływania syscall w systemie Windows jest identyczna z __cdecl, tj. Funkcja działa na stosie w odwrotnej kolejności, ale z dodatkiem, że AL zawiera liczbę argumentów; robi się to tak, że kod jądra, który zwykle znajduje się na końcu tego, wie, ile danych należy odczytać z stosu użytkownika na stosie jądra, aby pobrać argumenty.

EAX jest rejestrem zdrapek dla wszystkich konwencji wywoływania w 32-bitowych systemach Windows, jego wartość nigdy nie jest zachowywana przez wywołania funkcji, inicjowanie go bezpośrednio przed wykonaniem połączenia jest zbędne. Nawet jeśli zmienna, którą trzyma, to volatile - ponieważ proste ponowne ładowanie nie jest barierą pamięci i nie "zatwierdza" poprzedniego sklepu. Ponadto lokalizacja [EBP - 4] znajduje się w zakresie stosu, więc zmienna to lokalna (a kwalifikator volatile ma niewielki sens).

Jeśli nie jest stracona optymalizacja może to być wezwanie z __syscall function(...) z różną liczbą argumentów, takich jak hipotetycznie

__syscall printf_syscall_conv(char *fmt, ...); 

void possibly_print_three_vals(char *fmt, int val1, int val2, int val3) 
{ 
    if (*strchr('%', fmt) == '\0') // if no "%" in fmt, pass no args 
     printf_syscall_conv(fmt); 
    else 
     printf_syscall_conv(fmt, val1, val2, val3); 
} 

ta mogłaby tworzyć montażowej jak twoje.

Powiązane problemy