Почему локальные функции и аргументы помещаются в стек? - PullRequest
0 голосов
/ 17 февраля 2020

как функции хранятся в памяти, т. Е. Сегмент данных в виде выражений обычных переменных или сегмент кода в одном из них. Что помещается в стек указателем? или целую функцию, и зачем нам нужно выводить sh локальные переменные и аргументы, если они уже хранятся в сегменте данных?

Ответы [ 3 ]

0 голосов
/ 17 февраля 2020

Функции хранятся в памяти. Часто отдельный сегмент используется для хранения исполняемого кода. Диспетчер памяти может защитить эту память от изменения. С виртуальной памятью любой неиспользуемый код может быть заменен и будет восстановлен, когда код (функция) должен исполниться.

Глобальные данные хранятся в глобальной памяти.

Локальные данные выделяются на стек. Эти данные называются «automati c переменные».

Когда вызывается функция, адрес возврата сохраняется в стеке, которому предшествуют параметры функции.

Итак, нет сама функция (исполняемый код) не хранится в стеке. Только его параметры, локальные данные и обратный адрес.

Примечание: это упрощенное описание основано на Intel. Другие архитектуры могут иметь разные понятия для «стека».

0 голосов
/ 21 февраля 2020

Хотя детали различаются для разных платформ и форматов исполняемых файлов и соглашений о вызовах , программы обычно делятся на несколько сегментов . Вот общий макет программы для x86 (взятый из здесь ):

              +------------------------+
high address  | Command line arguments |   
              | and environment vars   |  
              +------------------------+
              |         stack          |
              | - - - - - - - - - - -  |
              |           |            |
              |           V            |
              |                        |
              |           ^            |
              |           |            |
              | - - - - - - - - - - -  |
              |          heap          |
              +------------------------+
              |    global and read-    |
              |       only data        |
              +------------------------+
              |     program text       |
 low address  |    (machine code)      |
              +------------------------+   

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

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

              +----------------+
high address: | argument N     |
              +----------------+
              | argument N-1   |
              +----------------+
                     ...
              +----------------+
              | argument 1     |
              +----------------+
              | return addr    |
              +----------------+
              | prv frame addr | <---- %ebp
              +----------------+
              | local 1        |
              +----------------+
              | local 2        |
              +----------------+
                     ...
              +----------------+
 low address: | local N        | <---- %esp
              +----------------+

Наряду с регистром указателя стека (%esp на x86, %rsp на x86_64) существует регистр base pointer (%ebp на x86, %rsp на x86_64). Этот регистр хранит адрес фрейма стека, а функция ссылается на локальные объекты и аргументы через смещения от этого адреса. Пример Quick-n-dirty:

int main( void )
{
  int x = 1;
  int y = 2;

  printf( "foo(1,2) = %d\n", foo( x, y ) );
  return 0;
}

Вот фрагмент скомпилированного кода, в котором мы присваиваем x и y (список, полученный с помощью objdump -d в исполняемом файле):

 55d:   c7 45 f0 01 00 00 00    movl   $0x1,-0x10(%ebp)
 564:   c7 45 f4 02 00 00 00    movl   $0x2,-0xc(%ebp)

В этом коде мы записываем значение 1 в ячейку 16 байтов «ниже» адреса, хранящегося в %ebp, а значение 2 в ячейку 12 байтов «ниже».

0 голосов
/ 17 февраля 2020

Например, в C / C ++ всякий раз, когда функция выполняется, область выполнения находится в памяти стека, т.е. память выделяется для этой функции в стеке. Это означает, что локальные переменные внутри него, включая аргументы, доступны только внутри этого стека, если вы не передадите аргумент как передачу по адресу / ссылке вместо передачи по значению. В случае передачи по ссылке / адресу мы используем указатель, чтобы получить доступ к переменной, присутствующей вне этой функции.

Надеюсь, что она отвечает на ваш вопрос. Если нет, пожалуйста, предоставьте более подробную информацию.

...