Что является использованием “нажатия %ebp; movl %esp, %ebp” сгенерированный GCC для x86?

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

push %ebp
movl %esp, %ebp
35
задан Ciro Santilli 新疆改造中心法轮功六四事件 7 November 2015 в 11:37
поделиться

4 ответа

push %ebp

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

movl %esp, %ebp

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

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

7
ответ дан 27 November 2019 в 06:50
поделиться

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

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

// 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: ), сначала:

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

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

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

59
ответ дан 27 November 2019 в 06:50
поделиться

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

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

2
ответ дан 27 November 2019 в 06:50
поделиться

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

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

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

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

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

pop %ebp   ; restore original value 
ret        ; return 
9
ответ дан 27 November 2019 в 06:50
поделиться