как работает стековый фрейм? - PullRequest
0 голосов
/ 11 ноября 2019

Я читаю csapp, и некоторые коды (x86-64) сбивают меня с толку.

В книге сказано, что "pushq% rbp" равен:

    subq $8,%rsp 
    movq %rbp,(%rsp)

Код c:

  long P(long x,long y)
  {
      long u = Q(y);
      long v = Q(x);

      return u + v;
  }

И часть кода ассемблера, который дает книга:

    pushq %rbp 
    pushq %rbx
    subq $8,%rsp 

«subq» смущает меня.

Почему это так?

1 Ответ

2 голосов
/ 11 ноября 2019

Стек - это блок памяти, который растет. В памяти есть точка, обозначенная регистром rsp / esp, который является вершиной стека. Вся память над ней занята вещами, помещенными в стек, и вся память под ней свободна.

Если вы хотите поместить что-то в стек, вам нужно уменьшить регистр rsp (это то, что делает инструкция sub) на количество байтов, которое вам нужно, и rsp теперь будет указывать на новую область резервирования, которая вам нужна.

Давайте рассмотрим этот простой пример:

rsp указывает на адрес 100. Каксказал - вся память выше адреса 100 используется, а память ниже 100 свободна. Поэтому, если вам нужно 4 байта, вы уменьшаете rsp на 4, поэтому он указывает на 96. Поскольку вы только что уменьшили rsp, вы знаете, что ячейки памяти 96, 97, 98 и 99 являются вашими, и вы можете использовать их. Когда вам нужно больше байтов в стеке, вы снова можете уменьшить rsp, чтобы получить больше.

Есть два способа размещения вещей в стеке. 1. Вы можете уменьшить rsp, как показано выше. 2. вы можете использовать инструкцию push, которая делает то же самое, но за один шаг: push rax уменьшит rsp на 8 байт (размер регистра rax) и сохранит его значение в зарезервированной области.

Иногда также регистр rbp используется для работы со стеком. Если вам нужна большая область в стеке, например, для локальных переменных, вы резервируете требуемую сумму в стеке, а затем сохраняете текущее значение rsp в rbp. Так что rbp - это своего рода закладка, помнящая, где находится ваш район. Затем вы можете push больше вещей в стеке, не теряя информацию о том, где была выделенная область.

Перед выходом из функции все вещи, помещенные в стек, должны быть извлечены из него. Это делается с помощью инструкции pop, противоположной push - берет значение из стека и перемещает его в регистр, а затем увеличивает rsp. Или вы можете просто увеличить rsp, если вам не нужно восстанавливать значения регистров.

...