Как различные сегменты, такие как куча, стек, текст, связаны с физической памятью? - PullRequest
18 голосов
/ 10 февраля 2012
  1. Когда программа на C компилируется и создается объектный файл (ELF).объектный файл содержит различные разделы, такие как bss, data, text и другие сегменты.Я понял, что эти разделы ELF являются частью адресного пространства виртуальной памяти.Я прав?Пожалуйста, исправьте меня, если я ошибаюсь.

  2. Кроме того, с скомпилированной программой будет связана виртуальная память и таблица страниц.Таблица страниц связывает адрес виртуальной памяти, присутствующий в ELF, с реальным адресом физической памяти при загрузке программы.Правильно ли мое понимание?

  3. Я прочитал, что в созданном файле ELF разделы bss просто хранят ссылку на неинициализированные глобальные переменные.Здесь неинициализированная глобальная переменная означает, что переменные, которые не инициализированы во время объявления?

  4. Также я прочитал, что локальным переменным будет выделено пространство во время выполнения (т. Е. В стеке).Тогда как на них будут ссылаться в объектном файле?

  5. Если в программе есть определенный раздел кода, доступный для динамического выделения памяти.Как на эти переменные будут ссылаться в объектном файле?

Я сбит с толку, что эти различные сегменты объектного файла (такие как текст, родата, данные, bss, стек и куча) являются частьюфизическая память (RAM), где выполняются все программы.Но я чувствую, что мое понимание неверно.Как эти разные сегменты связаны с физической памятью, когда выполняется процесс или программа?

Ответы [ 6 ]

19 голосов
/ 11 февраля 2012

1. Правильно, файл ELF определяет абсолютные или относительные местоположения в виртуальном адресном пространстве процесса, в который операционная система должна скопировать содержимое файла ELF.(BSS - это просто местоположение и размер, поскольку предполагается, что это все нули, поэтому фактически нет нужды иметь нули в файле ELF).Обратите внимание, что местоположения могут быть абсолютными (например, виртуальный адрес 0x100000 или относительные позиции, например, 4096 байт после конца текста).

2. Определение виртуальной памяти (хранится в таблицах страници сопоставляет виртуальные адреса с физическими адресами) не ассоциируется с скомпилированной программой, а с «процессом» (или «задачей» или как ее называет ваша ОС), представляющим работающий экземпляр этой программы.Например, один файл ELF можно загрузить в два разных процесса по разным виртуальным адресам (если файл ELF можно перемещать).

3. Используемый вами язык программирования определяеткакое неинициализированное состояние переходит в bss, а какое явно инициализируется.Обратите внимание, что bss не содержит "ссылки" на эти переменные, является хранилищем этих переменных.

4. Переменные стекассылаются неявно из сгенерированного кода.В файле ELF нет ничего явного о них (или даже о стеке).

5. Как и ссылки на стек, ссылки на кучи неявно присутствуют в сгенерированном коде в файле ELF.(Все они хранятся в памяти, созданной путем изменения виртуального адресного пространства посредством вызова на sbrk или его эквивалент.)

Файл ELF объясняет ОС, как настроить виртуальное адресное пространство для экземплярапрограммы.Различные разделы описывают различные потребности.Например, «.rodata» говорит, что я хотел бы хранить данные только для чтения (в отличие от исполняемого кода).Раздел «.text» означает исполняемый код.«Bss» - это область, используемая для хранения состояния, которое должно быть обнулено ОС.Виртуальное адресное пространство означает, что программа может (опционально) полагаться на то, что ожидает от запуска.(Например, если он запрашивает, чтобы .bss был по адресу 0x4000, то либо ОС откажется запускать его, либо он будет там.)

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

3 голосов
/ 10 февраля 2012

Я не уверен, правильны ли 1, 2 и 3, но я могу объяснить 4 и 5.

4 : на них ссылается смещение от вершины стека.При выполнении функции вершина стека увеличивается, чтобы выделить место для локальных переменных.Компилятор определяет порядок локальных переменных в стеке, поэтому компилятор теперь определяет смещение переменных от вершины стека.

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

5 : Использование указателей - Адрес динамически размещаемой переменной хранится в (локальной) переменной.Это соответствует использованию указателей в C.

Я нашел хорошее объяснение здесь: http://www.ualberta.ca/CNS/RESEARCH/LinuxClusters/mem.html

2 голосов
/ 20 сентября 2012

Просто введите команду readelf, чтобы узнать начальные адреса различных сегментов вашей программы.

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

Переходя ко второму вопросу, это во время выполнения из-за привязки времени выполнения. Третий вопрос верный. Все неинициализированные глобальные переменные и статические переменные попадают в BSS. Также обратите внимание на особый случай: они переходят в BSS, даже если они инициализированы в 0.

2 голосов
/ 19 февраля 2012

Если вы хотите узнать эти вещи, узнайте об ОС с исходным кодом (www.kernel.org), если это возможно.
Вы должны понимать, что ядро ​​ОС на самом деле работает с ЦП и управляет ресурсом памяти,А код C - это всего лишь легкий сценарий для управления ОС и запуска только простой операции с регистрами.

  1. Виртуальная память и физическая память - это TLB ЦП, позволяющий процессу пространства пользователя использоватьнепрерывная память практически благодаря возможности аппаратного обеспечения TLB (с использованием таблицы страниц).Таким образом, фактическая физическая память, сопоставленная с непрерывной виртуальной памятью, может быть разбросана в любом месте ОЗУ.Скомпилированная программа не знает об этих вещах TLB и адресах физической памяти.Они управляются в пространстве ядра ОС.

  2. BSS - это раздел, который ОС готовит как адреса памяти, заполненные нулями, поскольку они не были инициализированы в исходном коде c / c ++ и помечены какbss компилятором / компоновщиком.

  3. Стек - это что-то, подготовленное сначала только небольшим объемом памяти ОС, и каждый раз, когда вызывается функция, адрес будет сдавлен,так что есть больше места для размещения локальных переменных, и выскочить, когда вы хотите вернуться из функции.Новая физическая память будет выделена виртуальному адресу, когда первый небольшой объем памяти заполнен и достигнут дна, и произойдет исключение сбоя страницы, и ядро ​​ОС подготовит новую физическую память, и пользовательский процесс сможет продолжить работу.

  4. Никакой магии.В объектном коде каждая операция, выполняемая с указателем, возвращенным из malloc, обрабатывается как смещение значения регистра, возвращаемого при вызове функции malloc.

На самом деле malloc выполняет довольно сложные вещи.Существуют различные реализации (jemalloc / ptmalloc / dlmalloc / googlemalloc / ...) для улучшения динамического распределения, но на самом деле все они получают новую область памяти из ОС, используя sbrk или mmap (/ dev / zero), которая называется анонимной памятью.

2 голосов
/ 10 февраля 2012

Все адреса различных разделов (.text, .bss, .data и т. Д.), Которые вы видите при проверке ELF с помощью команды размера:

$ size -A -x my_elf_binary

- это виртуальные адреса. MMU с операционной системой выполняет преобразование виртуальных адресов в физические адреса RAM.

1 голос
/ 10 февраля 2012

4. Если вы посмотрите на ассемблерный код, сгенерированный gcc, то увидите, что локальные переменные памяти выделяются в стеке с помощью команды push или путем изменения значения регистра ESP. Затем они инициируются командой mov или чем-то в этом роде.

...