Переменные и вызовы в программе на C и ее соответствующее расположение в адресном пространстве процесса Linux - PullRequest
0 голосов
/ 11 января 2019

В настоящее время я изучаю адресное пространство процесса Linux, и я не уверен, где эти переменные C соответствуют в адресном пространстве процесса.

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

В чем я не уверен, так это в указателях в кадре:

У меня есть эта функция:

int main(){
    char *pointer1 = NULL;
    char *pointer2 = (void *)0xDDDDDDDD;
    pointer1 = malloc(80);
    strcpy(pointer1, "Testing..");
    return(0);
}

Когда вызывается main, создается новый фрейм.

Переменные инициализируются.

Что я не уверен насчет этих указателей, где:

  • *pointer1 соответствует в адресном пространстве процесса - раздел данных или текста?

  • *pointer2 соответствует в адресном пространстве процесса - раздел данных или текста?

  • Принадлежит ли NULL и 0xDDDDDDDD к данным или текстовому разделу?

  • начиная с pointer1 = malloc(80), относится ли он к секции стека?

Ответы [ 3 ]

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

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

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

Продолжая, в современных системах, подобных ПК, указатель - это не более чем простое целое число без знака, а его значение - это адрес, на который он указывает. Значения, которые вы используете для инициализации (NULL и 0xDDDDDDDD), представляют собой просто целочисленные значения. Инициализация выполняется так же, как и для простой переменной int. И как таковые, значения, используемые для инициализации, на самом деле не существуют как «данные», вместо этого они могут быть закодированы непосредственно в машинном коде и, как таковые, будут храниться в сегменте «текст» (код).

И, наконец, для динамического размещения не изменяется место хранения pointer1. Что значит просто присвоить новое значение pointer1. Распределяемая память находится в «куче», которая отделена от любого раздела программы (то есть ни в коде, ни в данных, ни в сегментах стека).

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

Как только что сказал какой-то программист, чувак , в спецификации C не указана область, в которую должны быть помещены автоматические переменные. Но компиляторы обычно увеличивают стек, чтобы разместить их там. Однако они могут заканчиваться в области .data, и они будут, если они, например, будут определены как static char *pointer1.

Значения инициализации могут существовать или не существовать в программной области. В вашем случае, поскольку тип значений - int, большинство архитектур вместо встроенных инициализаций будут использовать соответствующие машинные инструкции, если доступны инструкции с соответствующими встроенными операторами. Например, в x86_64 будет выполнена одна операция mov / movq для помещения 0 (NULL) или другого целого числа в соответствующее место в памяти стека.

Однако переменные, инициализированные с глобальной областью действия, такие как static char string[40] = "Hello world" или другие инициализированные глобальные переменные, попадают в область .data и занимают там место. Вместо этого компиляторы могут помещать объявленные, но неопределенные глобальные переменные в области .bss.

Вопрос , так как pointer1 = malloc (80), относится ли он к секции стека? нечетко определен, поскольку содержит две вещи.

Значение pointer1 - это значение, которое будет сохранено в &pointer1. Адрес, который, учитывая вышеизложенное, возможно, компилятор поместил в стек.

Результатом malloc(80) является значение, которое относится к области в куче, другой области, динамически выделяемой за пределами сопоставленного программного пространства. В Linux результат вызова malloc может даже создать новую область памяти с NULL-поддержкой (то есть временную область, которая не постоянно хранится в файле; хотя она может быть заменена ядром).

В сущности, вы можете думать о том, как ведет себя malloc (80), как что-то вроде (не принимая во внимание free (), поэтому это упрощение ):

int space_left = 0; void *last_mapping = NULL;
void *malloc(int req) {
    void *result;
    if (space_left < req) {
        last_mapping = mmap(NULL, MALLOC_CHUNK_LENGTH, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        space_left = MALLOC_CHUNK_LENGTH;
    }
    space_left -= req;
    result = last_mapping;
    last_mapping += req;
    return result;
}

Огромная разница между вызовами malloc и mmap с помощью MAP_PRIVATE состоит в том, что mmap - это системный вызов Linux, который должен переключать контекст ядра, выделять новую карту памяти и сбрасывать уровень MMU для каждого выделенного блока памяти, в то время как malloc может быть более интеллектуальным и использовать один большой регион в качестве «кучи» и управлять различными malloc и free в пространстве пользователя после инициализации кучи (до тех пор, пока куча не исчерпает пространство, где может потребоваться управление несколькими кучами).

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

Последний раздел ваших сомнений, т. Е. «Так как pointer1 = malloc (80), относится ли он к разделу стека?», Я могу вам сказать

В C динамическая память выделяется из кучи с использованием некоторых стандартных библиотечных функций. Двумя ключевыми функциями динамической памяти являются malloc () и free ().

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

      void *malloc(size_t size);

Функция free () берет указатель, возвращенный функцией malloc (), и освобождает память. Никаких признаков успеха или неудачи не возвращается. Прототип функции выглядит так:

      void free(void *pointer);

Вы можете сослаться на документ https://www.design -reuse.com / article / 25090 / динамическое выделение памяти-фрагментация-c.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...