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

Как различные сегменты, такие как куча, стек, текст, связанный с физической памятью?

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

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

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

  • Кроме того, я читал, что локальным переменным будет выделено пространство во время выполнения (т.е. в стеке). Затем как они будут ссылаться в объектном файле?

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

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

4b9b3361

Ответ 1

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 не нужно знать какие-либо детали, в которых используются физические страницы.

Ответ 2

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

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

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

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

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

Ответ 3

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

$ size -A -x my_elf_binary

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

Ответ 4

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

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

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

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

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

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

Ответ 5

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

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

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

Ответ 6

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