У меня есть следующий код:
int func(int a)
{
int b=2;
int c,d,e,f,g;
//some code which involves a,b,c,d,e,f,g
}
int main()
{
int s=3;
func(s);
}
Теперь, что происходит, когда main начинает выполнение:
1. Он толкает в стек
2. Он вызывает func ()
3.func () помещает b, c, d, e, f, g в стек
4. Теперь, когда выполняется код, включающий a, b, c, d, e, f.g, для того, чтобы узнать значение всех локальных переменных функции func (), нужно будет вытолкнуть. Затем получается значение а. Теперь, если снова нужно использовать b.c.d.e.f.g, как будут получены их значения (потому что они уже были извлечены)?
Локальные переменные, как и аргумент, на самом деле не являются толкнул в стеке. Вместо этого компилятор добавляет код для изменения указателя стека на столько, чтобы он соответствовал всем переменным, а затем при обращении к локальной переменной компилятор получает код для получения значения из смещение из указателя стека.
Я рекомендую вам взглянуть на вывод ассемблера вашей примерной программы, чтобы понять, как она работает.
Эквивалентный код для void func (int a)
void func(int a)
{
00413880 push ebp
00413881 mov ebp,esp
00413883 sub esp,108h
00413889 push ebx
0041388A push esi
0041388B push edi
0041388C lea edi,[ebp-108h]
00413892 mov ecx,42h
00413897 mov eax,0CCCCCCCCh
0041389C rep stos dword ptr es:[edi]
int b=2;
0041389E mov dword ptr [b],2
int c,d,e,f,g;
//some code which involves a,b,c,d,e,f,g
}
Теперь давайте посмотрим эквивалентный ассемблерный код для кода ниже:
void func(int a)
{
int b=2;
int c,d,e,f,g;
c = 10 ;
d = 15 ;
e = 20 ;
a = a + 2 ;
}
Код сборки ::
void func(int a)
{
00413880 push ebp
00413881 mov ebp,esp
00413883 sub esp,108h
00413889 push ebx
0041388A push esi
0041388B push edi
0041388C lea edi,[ebp-108h]
00413892 mov ecx,42h
00413897 mov eax,0CCCCCCCCh
0041389C rep stos dword ptr es:[edi]
int b=2;
0041389E mov dword ptr [b],2
int c,d,e,f,g;
c = 10 ;
004138A5 mov dword ptr [c],0Ah
d = 15 ;
004138AC mov dword ptr [d],0Fh
e = 20 ;
004138B3 mov dword ptr [e],14h
a = a + 2 ;
004138BA mov eax,dword ptr [a]
004138BD add eax,2
004138C0 mov dword ptr [a],eax
}
Таким образом, хотя они помещаются в стек (ESP или SP), но указатель на каждую из локальных переменных также сохраняется, так что к ним можно легко получить доступ при необходимости.
Мол, когда код нужно использовать переменная а, dword ptr [a] просто перемещен, чтобы зарегистрироваться EAX.
ПРИМЕЧАНИЕ. Технически не выдвигается, но настраивается для соответствия всем переменным. (Предоставлено Иоахимом Пилеборгом)
чтобы узнать значение всех локальных переменных функции func ()
Эта строка хотя и грамматически неоднозначна. Я предполагаю, что вы хотите сказать, что переменные всплывают при использовании функцией.
Но на самом деле локальные переменные выявляются только тогда, когда функция возвращается к вызывающей стороне.
При условии, что они автоматические.
С другой стороны, когда функция хочет получить доступ (чтение / запись) к переменной. Он использует смещение (расстояние) от базы для доступа к ним, поэтому не возникает вопроса о том, что переменные могут быть выведены во время доступа к ним для оценки.