Структура памяти программ в linux

Я немного запутался в том, как программа выглядит в памяти, мои профессора сказали мне, что стек и куча растут навстречу друг другу, когда стек находится по более низкому адресу памяти.

Первое, что беспокоило меня с этим изображением, это то, что если куча выросла с высокой до низкой, то если бы я выделил массив в куче, не должен ли указатель на второй элемент быть меньше по значению int, чем указатель на первый элемент? что бы сбить с толку

Я провел небольшое исследование и наткнулся на эту цифру (обратите внимание, мой вопрос сосредоточен на Linux)

макет http://www.cyberplusindia.com/blog/wp-content/uploads/2008/10/memorysegment.gif

Итак, Data и неинициализированные данные идут после сегмента Text и находятся в начале памяти программы, затем в куче, за которой следуют стек и, наконец, аргументы командной строки и окружение.

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

Итак, мой вопрос: какова правильная схема памяти для процесса в Linux? А также откуда берется память для разделяемой библиотеки (в адресном пространстве процесса)

Простой код с примерами указателей:

#include <iostream>int data[5];

int main()
{
using std::cout;
using std::endl;
int stack = 0;
short *sptr = reinterpret_cast<short *> ( &stack );
int *iptr = new int[5];
cout << "Starting static tests"<< "\nPointer to first element " << data
<< "\nPointer to second element " << &data[1]
<< "\nstarting stack test " <<  sptr
<< "\nsecond short " << &sptr[1]
<< "\nStarting heap test " << iptr
<< "\nsecond int " << &iptr[1];
delete[] iptr;
return 0;
}

Выход:

Starting static tests
Pointer to first element 0x6013e0
Pointer to second element 0x6013e4
starting stack test 0x7fffdf864dbc
second short 0x7fffdf864dbe
Starting heap test 0x1829010
second int 0x1829014

11

Решение

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

Не важно, «как» вы распределяете массив, вы можете увеличивать или уменьшать указатель стека, но в результате у вас есть адресное пространство, зарезервированное для массива.

Вы можете работать с ними обычным способом, так как самый низкий адрес зарезервирован для элемента 0.

поэтому мой вопрос в том, как правильно расположить память для процесса в Linux?

Вы можете проверить это сами. Вставьте куда-нибудь в свою программу что-нибудь
лайк std::cin.get() приостановить вашу программу.

Затем запустите в отдельной оболочке:

ps aux | grep your_program_name
cat /proc/<pid show by grep>/maps

Это печатает отображения памяти вашего процесса, где вы можете увидеть, где куча, стек и другие вещи размещены в памяти.

О стеке: предположим, что у вас обычный компьютер с 64-битным процессором Linux и Intel или AMD. Затем напишите следующий код:

extern void f(int);

void g(int param)
{
f(param);
}

скомпилируйте и разберите:

g++ -ggdb -c test_my_stack.cc  && objdump -S test_my_stack.o

Вы можете увидеть (неважные детали удалены):

 void g(int param)
{
0:   55                      push   %rbp
1:   48 89 e5                mov    %rsp,%rbp
4:   48 83 ec 10             sub    $0x10,%rsp
8:   89 7d fc                mov    %edi,-0x4(%rbp)
f(param);
b:   8b 45 fc                mov    -0x4(%rbp),%eax

как вы можете видеть в sub $0x10,%rsp мы зарезервировали пространство в стеке путем уменьшения (перемещения вниз) указателя стека.

3

Другие решения

Первое, что беспокоило меня с этим изображением, это то, что если куча выросла с высокой до низкой, то если бы я выделил массив в куче, не должен ли указатель на второй элемент быть меньше по значению int, чем указатель на первый элемент? что бы сбить с толку

Не за что. Допустим, вы выделяете массив из 10 байтов из пула памяти, который увеличивается от высокого к низкому. Все, что нужно сделать распределителю, это уменьшить «дно» этого пула памяти на 10, а затем использовать это значение в качестве начала выделенного массива. Массив будет заканчиваться на старом «дне». Арифметика с указателями будет работать, как и ожидалось, но вы будете «расти» в направлении низкого адреса.

2

По вопросам рекламы [email protected]