2014-01-12 3 views
0

Я пытаюсь понять, что будет присутствовать в стеке во время вызова функции.Содержимое стека во время вызова функции

Насколько я понял, аргументы вызываемого лица (если они есть), обратный адрес вызывающего и базового адреса будут помещены в стек перед вызовом другой функции.

Итак, я написал простую программу C

#include <stdio.h> 

void 
foo() 
{ 
} 

int 
main() 
{ 
    foo(); 
    return 0; 
} 

и соответствующий Дис собранный машинный код

08048334 <foo>: 
8048334: 55      push %ebp 
8048335: 89 e5     mov %esp,%ebp 
8048337: c9      leave 
8048338: c3      ret  

08048339 <main>: 
8048339: 55      push %ebp 
804833a: 89 e5     mov %esp,%ebp 
804833c: 83 ec 08    sub $0x8,%esp 
804833f: 83 e4 f0    and $0xfffffff0,%esp 
8048342: b8 00 00 00 00   mov $0x0,%eax 
8048347: 83 c0 0f    add $0xf,%eax 
804834a: 83 c0 0f    add $0xf,%eax 
804834d: c1 e8 04    shr $0x4,%eax 
8048350: c1 e0 04    shl $0x4,%eax 
8048353: 29 c4     sub %eax,%esp 
8048355: e8 da ff ff ff   call 8048334 <foo> 
804835a: b8 00 00 00 00   mov $0x0,%eax 
804835f: c9      leave 
8048360: c3      ret  
8048361: 90      nop  
8048362: 90      nop  
8048363: 90      nop  

Хотя Foo() код 's имеет смысл, я не мог понять, main's(). Почему так много операций? Я ожидал только следующих операций внутри main()

1. Push the frame pointer 
    2. Call foo (which will inturn save the return address) 

Может кто-нибудь объяснить мне основной() код? Благодаря!

+0

Возможный дубликат [gcc на окна, генерирующий мусор? windows vs linux] (http://stackoverflow.com/questions/19552816/gcc-on-windows-generating-garbage-windows-vs-linux) –

+0

Возможный дубликат [Почему эта функция пролога использует несколько инструкций для вычисления esp уменьшение?] (http://stackoverflow.com/questions/21096708/why-does-this-function-prologue-use-several-instructions-to-calculate-the-esp-re) –

ответ

0

На x86 (к которому вы, возможно, отметили это как), ABI (прикладной двоичный интерфейс) требует, чтобы стек был выровнен с некоторой границей (в этом случае 16 байт) при вызове функции. Поэтому, когда main() хочет позвонить foo(), сначала нужно выровнять указатель стека.

0

Первые три строки основного

8048339: 55      push %ebp 
804833a: 89 e5     mov %esp,%ebp 
804833c: 83 ec 08    sub $0x8,%esp 

называются function prologue. Этот набор инструкций подталкивает базовый указатель в стек, а затем назначает базовому указателю значение текущего стека, создавая новый стек стека. Затем указатель стека уменьшается в резервное пространство для локальных переменных функции (которых у вас нет, но по-прежнему выполняется из-за соглашения о вызове). Следующая инструкция

804833f: 83 e4 f0    and $0xfffffff0,%esp 

выравнивает стек до следующей нижней границы 16 байт. Следующие инструкции

8048342: b8 00 00 00 00   mov $0x0,%eax 
8048347: 83 c0 0f    add $0xf,%eax 
804834a: 83 c0 0f    add $0xf,%eax 
804834d: c1 e8 04    shr $0x4,%eax 
8048350: c1 e0 04    shl $0x4,%eax 
8048353: 29 c4     sub %eax,%esp 

появились на SE несколько раз уже (here, как отметил Пол R, и here и again here). Эта процедура, похоже, резервирует дополнительное пространство в стеке, но делает это странно неэффективно. Этот раздел может зависеть от версии gcc и ОС и не кажется необходимым.

Остальные инструкции вызывают foo и выходят из программы.

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