2012-03-19 2 views
2

У меня есть простой код:Почему «push ebp» меняет значение ebp?

void func() 
{ 
    func2(); 
} 

Я опускаем реализацию func2 и основной, так как они не имеют никакого отношения. Тогда я использовал WinDbg проследить сборку, следующее вывод ассемблерного кода при выполнении «func2()»: выполняется

eax=cccccccc ebx=7ffd6000 ecx=00000000 edx=00000001 esi=01faf760 edi=0012ff68 
eip=004113f0 esp=0012fe98 ebp=0012ff68 iopl=0   nv up ei pl nz na po nc 
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000    efl=00000202 
SimpleStack!func: 
004113f0 55    push ebp 
0:000> t 
eax=cccccccc ebx=7ffd6000 ecx=00000000 edx=00000001 esi=01faf760 edi=0012fe94 
eip=0041140e esp=0012fdc8 ebp=0012fe94 iopl=0   nv up ei pl nz na pe nc 
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000    efl=00000206 
SimpleStack!func+0x1e: 
0041140e e83dfcffff  call SimpleStack!ILT+75(_func2) (00411050) 

Мы можем видеть, что перед «толкающего EBP», особ = 0012fe98 и EBP = 0012ff68, но после выполнения «push ebp», esp = 0012fdc8, ebp = 0012fe94 ?, поэтому у меня есть два вопроса: 1. Предположительно, код push должен влиять только на esp, почему также изменяется ebp? 2. Предположительно push ebp будет выталкивать 4 байта в стек, поэтому значение esp должно уменьшаться 4, но мы видим здесь, что значение esp descrease на 208 байт? Зачем?

+4

Это не так. 'push ebp' делает именно то, что он говорит на олове. Обратите внимание, что eip увеличился на 1E, если бы был выполнен только push, он увеличился бы на 1. Очевидно, что было сделано больше, чем просто нажатие. – harold

+1

Что-то еще здесь происходит. Разница между байтами EIP (0041140e - 004113f0) = 1E. Слишком большая, чтобы быть одной инструкцией. У вас много потоков? – adelphus

+3

@adelphus: ты прав. Просто разберитесь между '004113f0 .. 0041140e' и вы найдете последовательность (используя здесь синтаксис Intel):' PUSH EBP; MOV EBP, ESP; PUSH ; ...; SUB ESP, ... '; это код ввода функции, сгенерированный компилятором (называемый пролог _function_), который заставляет код реализовывать обычные соглашения о вызове C/ABI. В конце/возврате функции вы найдете соответствующий блок 'ADD ESP, ...; POP ...; ОСТАВЛЯТЬ; RET', который уничтожает все это. –

ответ

1

Как пояснил Стив Джонсон, я снимаю «Режим источника», чтобы проследить сборку, действительно, после нажатия ebp следует множество (действительно много!) Ассемблерного кода, которые были ранее скрыты, когда был установлен «Режим источника». Так что этот случай будет решен, но я нашел другие проблемы, первый смотрите мой более полный код:

void func(); 

int main(int argc, char* argv[]) 
{ 
    func(); 
    return 0; 
} 
void func2(); 

void func() 
{ 
    func2(); 
} 

В FUNC, я не декларировать не локальные переменные, следующую выходное WinDbg, когда я исполняю FUNC() в основном:

004113c3 50    push eax 
0:000> 
eax=0000000a ebx=7ffda000 ecx=00000000 edx=00000001 esi=01f1f760 edi=0012ff68 
eip=004113c4 esp=0012fe98 ebp=0012ff68 iopl=0   nv up ei pl nz na po nc 
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000    efl=00000202 
SimpleStack!main+0x24: 
004113c4 e8e0fdffff  call SimpleStack!ILT+420(_func) (004111a9) 
0:000> t 
eax=0000000a ebx=7ffda000 ecx=00000000 edx=00000001 esi=01f1f760 edi=0012ff68 
eip=004111a9 esp=0012fe94 ebp=0012ff68 iopl=0   nv up ei pl nz na po nc 
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000    efl=00000202 
SimpleStack!ILT+420(_func): 
004111a9 e942020000  jmp  SimpleStack!func (004113f0) 
0:000> t 
eax=0000000a ebx=7ffda000 ecx=00000000 edx=00000001 esi=01f1f760 edi=0012ff68 
eip=004113f0 esp=0012fe94 ebp=0012ff68 iopl=0   nv up ei pl nz na po nc 
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000    efl=00000202 
SimpleStack!func: 
004113f0 55    push ebp 
0:000> t 
eax=0000000a ebx=7ffda000 ecx=00000000 edx=00000001 esi=01f1f760 edi=0012ff68 
eip=004113f1 esp=0012fe90 ebp=0012ff68 iopl=0   nv up ei pl nz na po nc 
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000    efl=00000202 
SimpleStack!func+0x1: 
004113f1 8bec   mov  ebp,esp 
0:000> t 
eax=0000000a ebx=7ffda000 ecx=00000000 edx=00000001 esi=01f1f760 edi=0012ff68 
eip=004113f3 esp=0012fe90 ebp=0012fe90 iopl=0   nv up ei pl nz na po nc 
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000    efl=00000202 
SimpleStack!func+0x3: 
004113f3 81ecc0000000 sub  esp,0C0h 
0:000> t 
eax=0000000a ebx=7ffda000 ecx=00000000 edx=00000001 esi=01f1f760 edi=0012ff68 
eip=004113f9 esp=0012fdd0 ebp=0012fe90 iopl=0   nv up ei pl nz na po nc 
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000    efl=00000202 
SimpleStack!func+0x9: 
004113f9 53    push ebx 
0:000> t 
eax=0000000a ebx=7ffda000 ecx=00000000 edx=00000001 esi=01f1f760 edi=0012ff68 
eip=004113fa esp=0012fdcc ebp=0012fe90 iopl=0   nv up ei pl nz na po nc 
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000    efl=00000202 
SimpleStack!func+0xa: 
004113fa 56    push esi 

действительно, мы видим, что после толчка EBP, то мы EBP, особенно, что на самом деле изменений EBP, но есть код «суб особ, 0C0h» после «мов EBP, ESP», я знаю, что " sub esp, num "означает выделение памяти для локальных переменных в фрейме стека, но я не объявлял локальные переменные в func, поэтому у меня есть следующие вопросы: Что делает« sub esp, 0C0h » повторно? Находясь в функции пролога, выход uf составляет:

0:000> uf func 
SimpleStack!func [d:\code\simplestack\func.c @ 4]: 
    4 004113f0 55    push ebp 
    4 004113f1 8bec   mov  ebp,esp 
    4 004113f3 81ecc0000000 sub  esp,0C0h 
    4 004113f9 53    push ebx 
    4 004113fa 56    push esi 
    4 004113fb 57    push edi 
    4 004113fc 8dbd40ffffff lea  edi,[ebp-0C0h] 
    4 00411402 b930000000  mov  ecx,30h 
    4 00411407 b8cccccccc  mov  eax,0CCCCCCCCh 
    4 0041140c f3ab   rep stos dword ptr es:[edi] 
    5 0041140e e83dfcffff  call SimpleStack!ILT+75(_func2) (00411050) 
    6 00411413 5f    pop  edi 
    6 00411414 5e    pop  esi 
    6 00411415 5b    pop  ebx 
    6 00411416 81c4c0000000 add  esp,0C0h 
    6 0041141c 3bec   cmp  ebp,esp 
    6 0041141e e818fdffff  call SimpleStack!ILT+310(__RTC_CheckEsp) (0041113b) 
    6 00411423 8be5   mov  esp,ebp 
    6 00411425 5d    pop  ebp 
    6 00411426 c3 
+0

Пожалуйста, разместите всю разборку функции. Используйте команду uf, чтобы разобрать всю функцию. –

+0

Выводится вывод «uf func», там содержится код «sub esp, 0c0h» – wangshuaijie

+0

Что вы видите, так это компилятор, обеспечивающий некоторое пространство в стеке, чтобы безопасно обнаруживать ошибки смещения стека и переполнения буфера. Если вы скомпилируете свой код в режиме выпуска, все это исчезнет. –

3

Если вы хотите увидеть, что делает каждая отдельная инструкция, вам необходимо отключить отладку на уровне исходного кода. Откройте меню отладки и снимите флажок «Режим источника». Когда вы переходите в исходный режим, все инструкции, сопоставленные с текущей исходной строкой, выполняются до разрыва отладчика.

+0

Хорошая точка, я попробую, может быть, это windbg, который оптимизировал последовательность кода, что некоторые вещи скрываются от простого представления. – wangshuaijie

Смежные вопросы