Соотношение стека, кучи памяти и кода сборки - PullRequest
0 голосов
/ 22 января 2019

Я пытаюсь понять процесс компиляции кода C / C ++ и его управления памятью более подробно.Предполагая следующий код:

#include <iostream>

int main() {
    int a = 5;
    int *b = (int *) malloc(40);
    return 0;
}

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

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

    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    movl    $40, %eax
    movl    %eax, %edi
    movl    $0, -4(%rbp)
    movl    $5, -8(%rbp)
    callq   _malloc
    xorl    %ecx, %ecx
    movq    %rax, -16(%rbp)
    movl    %ecx, %eax
    addq    $16, %rsp
    popq    %rbp
    retq

Мой вопрос:

Что означает a is on the stack (memory) здесь?в соответствии с вышеприведенной сборкой, a встроен непосредственно в инструкцию $5, -8(%rbp), ссылка на ячейку памяти отсутствует.Если он находится в памяти, то каков адрес a?

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

Ответы [ 2 ]

0 голосов
/ 22 января 2019

Что здесь находится в стеке (памяти)?

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

movl    $5, -8(%rbp)

rbp - указатель кадра.Он указывает на текущий кадр вызова стек .Эта инструкция перемещает константу 5 в память, указанную в rbp со смещением -8 байтов.Другими словами, эта инструкция инициализирует переменную a, которая находится в стеке.

Если она находится в памяти, то каков адрес?

Адрес a выглядит как rbp - 8, где rbp - это адрес, сохраненный в указателе кадра.В области C ++ вы можете использовать оператор addressof для получения адреса.


Нет stack (относительно памяти), heap , frame , rbp и т. Д. Определяются языком C ++.Эти слова имеют значение в контексте конкретной архитектуры процессора.

0 голосов
/ 22 января 2019

Нет ничего в языке, который говорит, что a будет в стеке.Компилятор имеет право размещать его там, где он хочет;и, в частности, если ему не нужно никуда его помещать, это не нужно.

Переменная a никогда не используется после того, как вы в нее положили 5, поэтому приличный оптимизатор бросит эту строкуполностью.

Однако, в вашем конкретном случае, мне кажется, что a действительно в стеке.Он находится в -8 байтах от указателя кадра в% rbp.То есть адрес a равен -8 (% rbp) или «значение в регистре rbp, минус 8», что довольно близко к вершине стека.

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

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

Существуют вспомогательные регистры, которые могут использоваться в управлении стеком.Распространенным является наличие «указателя кадра», который играет роль, которую% rbp выполняет здесь.

...