Содержимое стека во время вызова функции

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

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

Итак, я написал простую программу на 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() имеет смысл, я не мог понять код main(). Почему так много операций? Я ожидал только следующих операций внутри main()

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

Может кто-нибудь объяснить мне код main()? Спасибо!


person hdnivara    schedule 12.01.2014    source источник
comment
возможный дубликат gcc в окнах, генерирующих мусор? окна против линукса   -  person Paul R    schedule 13.01.2014
comment
возможный дубликат Почему это пролог функции использует несколько инструкций для вычисления уменьшения esp?   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 16.07.2015


Ответы (2)


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

person EOF    schedule 13.01.2014

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

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

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

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 (здесь, как указанный Полом Р., и здесь и снова здесь). Эта процедура, кажется, резервирует дополнительное пространство в стеке, но делает это странным образом неэффективным образом. Этот раздел может зависеть от версии gcc и ОС и не кажется необходимым.

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

person red-E    schedule 13.01.2014