2013-07-14 2 views
11

Я немного смущен тем, как выглядит программа в памяти, мои профессора сказали мне, что стек и куча растут друг к другу, причем стек имеет меньший адрес памяти.Формат памяти программ в linux

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

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

layout http://www.cyberplusindia.com/blog/wp-content/uploads/2008/10/memorysegment.gif

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

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

Итак, мой вопрос в том, что является правильной компоновкой памяти для процесса в 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 

ответ

3

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

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

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

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

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

Затем бегите в отдельной оболочке:

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

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

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

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 мы зарезервированное пространство в стеке, уменьшая (перемещая вниз) указатель стека.

+0

Я проверил карты на примере программы в моем вопросе, и если я не читаю это неправильно как стек и куча расти от низкой до высокой 016ea000-0170b000 Rw-р 00000000 00:00 0 [куча] 7fffe828a000-7fffe82ab000 rw-p 00000000 00:00 0 [stack] с большим количеством .so посередине, и я не могу найти место, зарезервированное для среды и CLA [gist with map] (https: // gist .github.com/ah450/5992828) –

+0

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

+0

Из-за сгенерированного кодом компилятора не выделять стек за значение, он выделяет все сразу. Для вашей программы, скажем, выделяем 0x50 байт, тогда говорят, что «переменная стека» имеет значение «-0x34 (% rbp)», «sptr» - -0x8 (% rbp), поэтому (uint8_t *) & stack <(uint8_t *) & sptr. Это из-за этого уменьшает указатель стека только один раз за функцию. – fghj

2

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

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

Смежные вопросы