Подтвердить что ты не робот

Что такое "push% ebp; movl% esp,% ebp", сгенерированный GCC для x86?

Какое влияние эти две инструкции вызывают в коде сборки, сгенерированном gcc для машин x86:

push %ebp
movl %esp, %ebp
4b9b3361

Ответ 1

Разъяснение объяснения - это буквальная правда (несмотря на одну незначительную направленную ошибку), но не объясняет, почему.

%ebp является "базовым указателем" для вашего фрейма стека. Это указатель, используемый средой выполнения C для доступа к локальным переменным и параметрам в стеке. Здесь некоторый типичный пролог-код функции, генерируемый GCC (g++, если быть точным). Сначала источник С++.

// junk.c++
int addtwo(int a)
{
    int x = 2;

    return a + x;
}

Это генерирует следующий ассемблер.

.file   "junk.c++"
    .text
.globl _Z6addtwoi
    .type   _Z6addtwoi, @function
_Z6addtwoi:
.LFB2:
    pushl   %ebp
.LCFI0:
    movl    %esp, %ebp
.LCFI1:
    subl    $16, %esp
.LCFI2:
    movl    $2, -4(%ebp)
    movl    -4(%ebp), %edx
    movl    8(%ebp), %eax
    addl    %edx, %eax
    leave
    ret
.LFE2:
    .size   _Z6addtwoi, .-_Z6addtwoi
    .ident  "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
    .section    .note.GNU-stack,"",@progbits

Теперь, чтобы объяснить этот пролог-код (все вещи до .LCFI2:), сначала:

  • pushl %ebp хранит фрейм стека вызывающей функции в стеке.
  • movl %esp, %ebp принимает текущий указатель стека и использует его как фрейм для вызываемой функции.
  • subl $16, %esp оставляет место для локальных переменных.

Теперь ваша функция готова к работе. Любые ссылки с отрицательным смещением от регистра %ebp% являются вашими локальными переменными (x в этом примере). Любые ссылки с положительным смещением от регистра %ebp% передаются ваши параметры.

Последняя представляющая интерес задача - это инструкция leave, которая представляет собой инструкцию ассемблера x86, которая выполняет работу по восстановлению фрейма стека вызывающей функции. Обычно это оптимизируется в более быстрой последовательности move %ebp %esp и pop %ebp% в коде C. Однако для иллюстративных целей я вообще не собирался с любыми оптимизациями.

Ответ 2

Это типичный код, который вы видите в начале функции.

Сохраняет содержимое регистра EBP в стеке, а затем сохраняет содержимое текущего указателя стека в EBP.

Стек используется во время вызова функции для хранения локальных аргументов. Но в функции указатель стека может измениться, поскольку значения хранятся в стеке.

Если вы сохраните исходное значение стека, вы можете обратиться к сохраненным аргументам через регистр EBP, в то время как вы можете использовать (добавлять значения) в стек.

В конце функции вы, вероятно, увидите команду

pop %ebp   ; restore original value 
ret        ; return 

Ответ 3

push %ebp

Это приведет к 32-разрядному (расширенному) регистру базового указателя в стеке, то есть указатель стека (% esp) вычитается на четыре, тогда значение% ebp будет скопировано в местоположение, на которое указывает указатель стека.

movl %esp, %ebp

Это копирует регистр указателя стека в регистр базового указателя.

Цель копирования указателя стека на базовый указатель заключается в создании фрейма стека, то есть области в стеке, где подпрограмма может хранить локальные данные. Код в подпрограмме будет использовать базовый указатель для ссылки на данные.

Ответ 4

Это часть того, что называется пролог функции.

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

Ответ 5

Я также считаю, что важно отметить, что часто после push %ebp и movl %esp, %ebp сборка будет иметь push %ebx или push %edx. Это номера вызывающих абонентов регистров %ebx и %edx. В конце рутинного вызова регистры будут восстановлены с их исходными значениями.

Также - %ebx, %esi, %edi - все регистры сохранения вызываемого абонента. Поэтому, если вы хотите перезаписать их, вам нужно сначала их сохранить, а затем восстановить.

Ответ 6

Кусок кода устанавливает стек для вашей программы.

В x86 информация стека хранится двумя регистрами.


    Base pointer (bp): Holds starting address of the stack
    Stack pointer (sp): Holds the address in which next value will be stored

Эти регистры имеют разные имена в разных режимах:


                            Base pointer           Stack pointer
    16 bit real mode:       bp                     sp
    32 bit protected mode:  ebp(%ebp)              esp(%esp)
    64 bit mode:            rbp                    rsp

Когда вы устанавливаете стек, указатель стека и базовый указатель получают тот же адрес в начале.

Теперь, чтобы объяснить ваш код,


    push %ebp

Этот код подталкивает текущий адрес стека в стек, чтобы функция могла "выйти" или "вернуться" должным образом.


    movl %esp, %ebp

Этот код устанавливает стек для вашей функции.

Для получения дополнительной информации см. Этот question.

Надеюсь эта помощь!