Указывает, что этот сегмент находится в оперативной памяти

Обновлено: 21.11.2024

Данные запущенного процесса разделены на пять сегментов:

  • Сегмент кода содержит текст программы; то есть инструкции машинного языка, из которых состоит программа.
  • Статический сегмент содержит неизменяемые значения, такие как строковые литералы. Например, если ваша программа содержит строку "Hello, World" , эти символы будут сохранены в статическом сегменте.
  • Глобальный сегмент содержит глобальные переменные и локальные переменные, объявленные статическими.
  • Сегмент кучи содержит блоки памяти, выделяемые во время выполнения, чаще всего путем вызова функции malloc из библиотеки C.
  • Сегмент стека содержит стек вызовов, представляющий собой последовательность кадров стека. Каждый раз, когда функция вызывается, кадр стека выделяется для хранения параметров и локальных переменных функции. Когда функция завершается, ее кадр стека удаляется из стека.

Расположение этих сегментов определяется частично компилятором и частично операционной системой. Детали варьируются от одной системы к другой, но наиболее распространено следующее:

  • Текстовый сегмент находится в нижней части памяти, то есть по адресам, близким к 0.
  • Статический сегмент часто находится непосредственно над текстовым сегментом, то есть по более высоким адресам.
  • Глобальный сегмент часто находится прямо над статическим сегментом.
  • Куча часто находится над глобальным сегментом. По мере расширения он увеличивается в сторону более крупных адресов.
  • Стек находится в верхней части памяти; то есть рядом с самыми высокими адресами в виртуальном адресном пространстве. По мере расширения стека он увеличивается в сторону меньших адресов.

Чтобы определить расположение этих сегментов в вашей системе, попробуйте запустить эту программу, которая находится в файле aspace.c в репозитории этой книги (см. Раздел 0.2).

main — это имя функции; когда он используется как переменная, он ссылается на адрес первой инструкции машинного языка в main , которая, как мы ожидаем, будет в текстовом сегменте.

global — это глобальная переменная, поэтому мы ожидаем, что она будет в глобальном сегменте. local — это локальная переменная, поэтому мы ожидаем, что она будет в стеке.

s относится к «строковому литералу», который является строкой, которая появляется как часть программы (в отличие от строки, которая читается из файла, вводится пользователем и т. д.). Мы ожидаем, что местоположение строка должна находиться в статическом сегменте (в отличие от указателя s , который является локальной переменной).

p содержит адрес, возвращаемый функцией malloc, которая выделяет место в куче. «malloc» означает «выделение памяти».

Последовательность форматирования %p указывает printf форматировать каждый адрес как «указатель», чтобы результаты отображались в шестнадцатеричном формате.

Когда я запускаю эту программу, вывод выглядит следующим образом (я добавил пробелы, чтобы было легче читать):

Как и ожидалось, адрес main является самым нижним, за ним следует расположение строкового литерала. Расположение global следующее, затем адрес p указывает на. Адрес местного гораздо больше.

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

Вклады и атрибуции

Эта страница находится под лицензией CC BY-NC-SA, автором, ремиком и/или куратором которой является Аллен Б. Дауни. Подробная история версий изменений исходного контента доступна по запросу.

Пейджинг и сегментация — это процессы, с помощью которых данные сохраняются на диске компьютера, а затем извлекаются с него.

Пейджинг – это функция управления памятью компьютера, которая представляет ЦП компьютера места хранения в виде дополнительной памяти, называемой виртуальной памятью. Каждому фрагменту данных нужен адрес хранения.

Сегментация – это виртуальный процесс, который создает адресные пространства переменного размера в компьютерной памяти для связанных данных, называемых сегментами. Этот процесс ускоряет поиск.

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

Давайте подробно рассмотрим пейджинг, а затем подробно рассмотрим сегментацию.

Что такое пейджинг?

Как упоминалось выше, функция управления памятью, называемая разбивкой по страницам, указывает места хранения для ЦП в качестве дополнительной памяти, называемой виртуальной памятью. ЦП не может напрямую обращаться к диску хранения, поэтому MMU эмулирует память, сопоставляя страницы с кадрами, которые находятся в ОЗУ.

Прежде чем мы перейдем к более подробному описанию страниц и фреймов, давайте определимся с некоторыми техническими терминами.

  • Страница: непрерывный блок виртуальной памяти фиксированной длины, расположенный на диске.
  • Кадр: непрерывный блок фиксированной длины, расположенный в ОЗУ; размер которых идентичен страницам.
  • Физическая память. Оперативная память компьютера (ОЗУ), обычно содержащаяся в картах DIMM, прикрепленных к материнской плате компьютера.
  • Виртуальная память. Виртуальная память — это часть жесткого диска или твердотельного накопителя, зарезервированная для эмуляции оперативной памяти. MMU передает виртуальную память с диска на ЦП, чтобы снизить нагрузку на физическую память.
  • Виртуальный адрес: ЦП генерирует виртуальный адрес для каждого активного процесса. MMU сопоставляет виртуальный адрес с физическим местоположением в ОЗУ и передает адрес на шину. Виртуальное адресное пространство – это диапазон виртуальных адресов, находящихся под контролем процессора.
  • Физический адрес. Физический адрес — это место в оперативной памяти. Физическое адресное пространство — это набор всех физических адресов, соответствующих виртуальным адресам ЦП. Физическое адресное пространство — это диапазон физических адресов, находящихся под управлением MMU.

Назначая адрес фрагменту данных с помощью «таблицы страниц» между ЦП и физической памятью компьютера, MMU компьютера позволяет системе извлекать эти данные при необходимости.

Процесс пейджинга

В таблице страниц хранится определение каждой страницы. Когда активный процесс запрашивает данные, MMU извлекает соответствующие страницы во фреймы, расположенные в физической памяти, для более быстрой обработки. Этот процесс называется пейджингом.

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

Однако постоянный поиск в таблице может замедлить работу MMU. Кэш памяти, называемый резервным буфером перевода (TLB), хранит последние преобразования виртуальных адресов в физические для быстрого поиска. Многие системы имеют несколько TLB, которые могут располагаться в разных местах, в том числе между ЦП и ОЗУ или между несколькими уровнями таблицы страниц.

Различные размеры фреймов доступны для наборов данных с большими или меньшими страницами и фреймами соответствующего размера. Стандартные размеры – от 4 КБ до 2 МБ, а на высокопроизводительных серверах доступны фреймы размером в 1 ГБ.

Проблема, называемая скрытой фрагментацией, раньше была проблемой в старых развертываниях Windows (95, 98 и Me). Проблема заключалась во внутренней (или скрытой) фрагментации. В отличие от серьезной внешней фрагментации при сегментации, внутренняя фрагментация возникает, если размер каждого кадра не соответствует размеру страницы. Однако в современной ОС Windows это не проблема.

Что такое сегментация?

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

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

Сегментация ускоряет поиск информации компьютером за счет помещения связанных данных в «таблицу сегментов» между ЦП и физической памятью.

Процесс сегментации

В каждом сегменте хранятся основные функции процессов, структуры данных и утилиты. ЦП хранит таблицу карт сегментов для каждого процесса и блока памяти, а также идентификацию сегмента и расположение памяти.

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

Проблема фрагментации

Несмотря на то, что сегментация — это высокоскоростная и высоконадежная функция управления памятью, внешняя фрагментация оказалась непреодолимой проблемой. Сегментация вызывает внешнюю фрагментацию до такой степени, что современные серверы x86-64 рассматривают ее как устаревшее приложение и поддерживают только для обратной совместимости.

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

Сегментированный пейджинг

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

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

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

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

Сложность компьютерной памяти легко принять как должное из-за множества уровней абстракции, с которыми сегодня работают программисты. С начала 60-х годов один и тот же базовый дизайн памяти существовал для всех компьютеров, использующих страничную структуру памяти. Это некоторые из областей, где знание схемы памяти играет решающую роль в переносимости приложений и встроенных ресурсов, безопасности программ, оптимизации кода. Диаграммы, которые я представляю, также помогут вам понять, где во время выполнения программы происходят различные действия.

Память (ОЗУ)

Оперативная память (ОЗУ) — это место, где будет находиться большая часть вашей программы, пока она активно работает. Как видно из названия, любая позиция в вашем приложении может быть адресована аппаратным обеспечением. Когда ваша программа будет выполнена, она будет загружена по некоторому начальному адресу. Этот адрес обычно называется базовым адресом. Значение базового смещения отличается от системы к системе. Техника, называемая рандомизация адресного пространства (ASLR), загружает модули вашей программы по случайным адресам, чтобы немного затруднить взлом.

Адреса оперативной памяти начинаются с нуля и достигают любого предела, установленного системой, в которой вы работаете. Однако не каждый адрес доступен вашей программе; некоторые области зарезервированы для операционной системы. Аппаратное обеспечение и операционная система работают вместе, чтобы абстрагироваться от деталей доступа к ячейкам в оперативной памяти. Следовательно, оперативную память можно рассматривать как один непрерывный линейный массив байтов. Пусть это будет базовым представлением схемы ОЗУ для этого обсуждения.

Все описанные ниже разделы находятся в оперативной памяти.

Сегментация

Системы, использующие сегментированную оперативную память, начали появляться в 60-х годах, когда операционные системы были написаны на языках более высокого уровня. Первоначально сегментация предоставляла множество услуг, таких как создание адреса памяти с возможностью адресации выше, чем размер слова процессора. Для разработчиков Windows спецификатор FAR является остатком ограниченной возможности доступа к адресам на 16-разрядных чипах Intel, таких как 80386.

Теперь основная функция, реализованная с помощью сегментированной памяти, — это подкачка памяти (сегмент) и виртуальная адресация. Я не хочу вдаваться в технические подробности, касающиеся виртуальной памяти, но могу вернуться к этой теме в будущем. А пока поймите, что эти функции позволяют системе хранить и упорядочивать все активные ресурсы наиболее эффективным способом, скрывая детали от программиста.

С этого момента я буду называть сегмент памяти страницей. Страница — это заранее определенное количество байтов, которые считаются одной группой. Память наиболее эффективно управляется как страницы. Все современные архитектуры, с которыми я работал, использовали размер страницы 4 КБ (4096 байт). Зачем останавливаться на достигнутом? Потому что 4097 байт было бы слишком много?!

Теперь, когда введена сегментация памяти, давайте немного изменим представление ОЗУ, чтобы упростить иллюстрации. Эта новая абстракция поможет нам визуализировать концепции более удобным способом:

Структура программы

Описания, которые я даю ниже, даны в общих чертах, поскольку существуют тонкие нюансы между различными форматами исполняемых файлов, определенными для каждой платформы. Например:

  • Unix/Linux:
    • COFF — устаревший формат.
    • Текущий формат – ELF.
    • Мах-О
    • NE, созданный на основе форматов DOS для 16-разрядной версии Windows.
    • PE, 32-разрядная версия Windows
    • PE32+ для 64-разрядной версии Windows.

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

    Заголовок программы

    При обсуждении форматов исполняемых файлов следует учитывать два основных типа разделов: 1) сегменты только для чтения, 2) сегменты для чтения и записи.

    Фактический файл, в котором хранится программа, напрямую не используется. Заголовок программы направляет загрузчик к различным сегментам, которые описаны ниже.

    Только для чтения

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

    Чтение-запись

    Каждому сегменту чтения-записи должна быть предоставлена ​​собственная копия по отношению к процессу, который его использует. Эти сегменты не могут быть безопасно разделены между процессами, если только разработчик не позаботится об этом.

    Заголовок раздела

    Каждый тип сегмента программы описан ниже. Я укажу, обычно ли это сегмент только для чтения или для чтения-записи, а также роль, которую он играет в выполнении программы. Большинство форматов модулей не ограничивают типы сегментов одним экземпляром. Я опишу некоторые возможности в соответствующих разделах ниже.

    .текст (RO)

    Еще одно имя, используемое для этого сегмента, — сегмент code. Здесь последовательность аппаратных команд последовательно кодируется для управления процессором. Важно, чтобы этот сегмент загружался в доступную только для чтения область оперативной памяти системы, чтобы предотвратить самомодифицирующийся код. Самомодифицирующийся код чрезвычайно сложно отлаживать, и он создает большой потенциал для уязвимостей в системе безопасности.

    Также важно отметить, что в большинстве систем сегменты памяти должны быть отмечены привилегией «исполняемый файл», чтобы обрабатывать сегмент как исполняемые инструкции.

    .rodata (RO)

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

    .данные (RW)

    Раздел данных содержит предварительно выделенное пространство для хранения всех глобальных и статических переменных, определенных в вашей программе. Эти значения эффективно упаковываются для целевой платформы, поэтому к ним можно получить доступ на соответствующей границе памяти для размера типа данных. Команды, сгенерированные в сегменте .text, ссылаются на значения в этом сегменте с относительным смещением во время выполнения. Сначала находится адрес сегмента, затем при необходимости осуществляется доступ к относительному смещению нужной переменной.

    В программе может потребоваться определить несколько сегментов .data, чтобы создать простой механизм обмена данными между двумя процессами. Это называется разделом общих данных. Я использовал этот метод только в Windows, поэтому не знаю особенностей его использования на других платформах.

    Общий сегмент загружается в глобально доступную системную память. Любой процесс, загружающий этот модуль, будет иметь доступ к тем же переменным. Если один процесс изменит значение, это немедленно отразится на всех остальных процессах. Я использовал этот механизм для синхронизации уникальных данных между различными программами в одной системе.

    .bss (RW)

    Раздел .bss уникален по сравнению с другими сегментами. В каждом модуле есть только один файл .bss, и он фактически не включен в модуль. Это связано с тем, что .bss — это сегмент, в котором расположены все неинициализированные поля данных модуля.

    Размер, необходимый для хранения неинициализированных полей, — это все, что требуется в определении файла .bss. Определенные ниже инициализированные поля будут помещены в адресное пространство .bss:

    Структура выполнения

    Теперь, когда мы определили каждый из основных типов сегментов, существующих во всех современных компьютерных архитектурах, давайте опишем, как они структурированы в работающей программе. Есть три типа памяти, на которые напрямую ссылаются машинные инструкции.

    Куча — это место, где находится вся динамически выделяемая память. Другое название этой коллекции памяти — Free-Store.Куча — это, по сути, вся оставшаяся доступная оперативная память, которая не используется вашими программными модулями или не зарезервирована для стека.

    Стек вызовов

    The Stack – это псевдоним для Call-Stack. Стек вызовов — это место, где параметры передаются в функции, а память выделяется для локальных переменных. Вот почему это называется «созданием переменной в стеке». стековый фрейм используется для представления каждого экземпляра вызова функции. Каждый раз, когда вызывается функция, текущее состояние функции записывается в текущем месте стека, а новый кадр стека заталкивается в стек для отслеживания следующей функции. Когда вызов функции возвращается, текущий кадр стека извлекается из стека, а предыдущее состояние функции восстанавливается для продолжения выполнения.

    Для каждого потока, запущенного в программе, выделяется один стек вызовов. Чтобы эффективно использовать доступное адресное пространство в системе, размер стека обычно определяется для стека вызовов каждого потока. Факторы, которые вы хотите учитывать при выборе размера вашего стека вызовов, — это размер локальных переменных, созданных в ваших функциях, и то, насколько глубоко выполняются ваши вызовы функций.

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

    Системные регистры

    Аппаратные регистры — это области памяти, которые фактически размещены внутри ЦП. Регистры имеют тот же размер, что и размер слова для ЦП. С появлением компьютеров Word приобрел другое значение. В контексте оборудования размер слова всегда означает разрядность конвейера обработки ЦП. Например, размер слова на 32-разрядном процессоре – 32 бита, а размер слова на 64 разрядном процессоре – 64 бита.

    Они имеют решающее значение для структуры компьютерной системы. Регистры — это единственный способ процессора работать со значениями при выполнении команды. Значения загружаются в регистры из адресуемых ячеек ОЗУ через системную шину. Если ЦП имеет внутреннюю кэш-память, большие фрагменты данных могут быть предварительно загружены из ОЗУ. Это гарантирует, что данные будут готовы, когда ЦП будет готов обработать инструкцию. Кэш ЦП может значительно повысить производительность.

    Основные регистры x86 и AMD64

    Типы доступных регистров зависят от ISA ЦП (архитектура промышленного стандарта). Я собираюсь кратко представить часто используемые регистры для x86 ISA, потому что все три основные настольные операционные системы (Apple, Linux, Windows) поддерживают эту платформу.

    Есть восемь регистров общего назначения и указатель инструкций, который содержит программный счетчик. Регистры названы на основе цели, которая изначально предусматривалась для каждого регистра. Есть специальные операции, предназначенные для конкретных регистров; например, Accumulator, EAX, имеет эффективный код операции для добавления указанного для него байтового индекса. Однако другие регистры также поддерживают эти операции; только коды операций являются более длинными командами общего назначения.

    < td>BX< td>CX< td>SI< td>DI< td>SP

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

    Взаимодействия

    Игнорируя ограничения, связанные с разрешениями, к ОЗУ можно обращаться как к одной непрерывной последовательности от младшего адреса к старшему. Система будет перемещать сегменты в ОЗУ и из него по одной странице памяти за раз. Обычно существуют области адресного пространства, зарезервированные для операционной системы (ядра). Если в системе разрешена общая память между процессами, то регион также будет зарезервирован для глобально доступного адресного пространства.

    Ваша программа сама загружается в доступное адресное пространство. Не существует общепринятой схемы адресации для размещения сегмента .text (исполняемый код), сегмента .data (переменные) и других сегментов программы. Однако макет самой программы хорошо сформирован в соответствии с системой, которая будет выполнять программу. Это позволяет системному загрузчику программ перемещаться по файлу программы и правильно загружать программу в ОЗУ. Таблицы переходов и другие внутренние структуры исправлены, чтобы можно было правильно обращаться к различным сегментам памяти на основе их конечного адреса.

    На приведенной ниже диаграмме в упрощенном виде показаны элементы одной программы, загруженные в память системы. ЦП обращается к ОЗУ через системную шину.

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

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

    Обзор

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

    Безопасность — это одна из концепций компьютерного программирования, где необходимо лучше понимать эту структуру. Даже если вы никогда не будете просматривать дизассемблированную программу или обращаться к регистрам вручную, важно понимать, что вызывает уязвимость системы безопасности, а также качества, делающие уязвимость пригодной для эксплуатации. Таким образом, с этой основой структуры памяти я смогу писать о методах безопасного программирования, а также демонстрировать некоторые методы, используемые для использования этих недостатков.

    Существуют разные сегменты памяти, в которые после компиляции помещаются различные типы данных из кода C. То есть: .text , .data , .bss , стек и куча. Я просто хочу знать, где каждый из этих сегментов будет находиться в памяти микроконтроллера. То есть, какие данные помещаются в какой тип памяти, учитывая типы памяти: RAM, NVRAM, ROM, EEPROM, FLASH и т. д.

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

    Любая помощь приветствуется. Заранее спасибо!

    \$\begingroup\$ NVRAM, ROM, EEPROM и Flash — это просто разные названия одного и того же: энергонезависимой памяти. \$\конечная группа\$

    \$\begingroup\$ Немного не связан с вопросом, но код может (в исключительных случаях) существовать практически в любом из них, особенно если вы рассматриваете использование патчей или калибровки. Иногда он будет перемещен перед выполнением, иногда выполнен на месте. \$\конечная группа\$

    \$\begingroup\$ @SeanHoulihane ОП спрашивает о микроконтроллерах, которые почти всегда выполняются из Flash (вы уточнили свой комментарий как исключительный). Микропроцессоры с МБ внешней оперативной памяти, работающие под управлением Linux, например, будут копировать свои программы в оперативную память для их выполнения, возможно, с SD-карты, выступающей в качестве монтируемого тома. \$\конечная группа\$

    \$\begingroup\$ @tcrosley В настоящее время существуют микроконтроллеры с TCM, а иногда микроконтроллеры являются частью более крупной SoC. Я также подозреваю, что бывают такие случаи, как устройства eMMC, где mcu загружается для запуска из ОЗУ из собственного хранилища (на основе памяти какого-то телефона, который был взломан пару лет назад). Я согласен, это не прямой ответ, но я думаю, что очень важно, что типичные сопоставления никоим образом не являются жесткими правилами. \$\конечная группа\$

    \$\begingroup\$ нет правил для соединения одного элемента с другим, конечно, данные только для чтения, такие как текст и родаты, в идеале должны быть во флэш-памяти, но .data, смещение и размер .bss остаются там тоже (а затем копируется загрузочным кодом). эти термины (.text и т. д.) не имеют ничего общего с микроконтроллерами, это вещь компилятора/инструментальной цепочки, которая применяется ко всем целям компиляторов/инструментальных цепочек. в конце дня программист решает, куда идти, и обычно информирует инструментальную цепочку через скрипт компоновщика. \$\конечная группа\$

    3 ответа 3

    Сегмент .text содержит фактический код и запрограммирован во флэш-память для микроконтроллеров. При наличии нескольких несмежных блоков флэш-памяти может быть более одного текстового сегмента; например начальный вектор и векторы прерывания, расположенные в верхней части памяти, и код, начинающийся с 0; или отдельные разделы для начальной загрузки и основной программы.

    .bss и .data

    Существует три типа данных, которые могут быть размещены вне функции или процедуры; первый - это неинициализированные данные (исторически назывался .bss, который также включает 0 инициализированных данных), а второй - инициализированный (не-bss) или .data. Название «bss» исторически происходит от «Block Started by Symbol», использовавшегося в ассемблере около 60 лет назад. Обе эти области находятся в оперативной памяти.

    По мере компиляции программы переменные будут размещаться в одной из этих двух общих областей. На этапе связывания все элементы данных будут собраны вместе. Для всех переменных, которые необходимо инициализировать, будет выделена часть памяти программы для хранения начальных значений, и непосредственно перед вызовом main() переменные будут инициализированы, как правило, модулем с именем crt0. Раздел bss инициализируется всеми нулями с помощью одного и того же кода запуска.

    Для некоторых микроконтроллеров существуют более короткие инструкции, позволяющие получить доступ к первой странице (первые 256 ячеек, иногда называемые страницей 0) ОЗУ. Компилятор для этих процессоров может зарезервировать ключевое слово, например, рядом, чтобы указать переменные, которые будут помещены туда. Точно так же существуют микроконтроллеры, которые могут обращаться только к определенным областям через регистр указателя (требующий дополнительных инструкций), и такие переменные обозначаются как far . Наконец, некоторые процессоры могут адресовать раздел памяти побитно, и у компилятора будет способ указать это (например, ключевое слово bit ).

    Таким образом, могут быть дополнительные сегменты, такие как .nearbss, .neardata и т. д., в которых собираются эти переменные.

    .rodata

    Третий тип данных, внешних по отношению к функции или процедуре, аналогичен инициализированным переменным, за исключением того, что они доступны только для чтения и не могут быть изменены программой. В языке C эти переменные обозначаются с помощью ключевого слова const. Обычно они хранятся как часть флэш-памяти программ. Иногда они идентифицируются как часть сегмента .rodata (данные только для чтения). На микроконтроллерах с гарвардской архитектурой компилятор должен использовать специальные инструкции для доступа к этим переменным.

    стек и куча

    И стек, и куча размещаются в оперативной памяти. В зависимости от архитектуры процессора стек может расти вверх или вниз. Если он вырастет, он будет размещен в нижней части оперативной памяти. Если он растет вниз, он будет помещен в конец ОЗУ. Куча будет использовать оставшуюся оперативную память, не выделенную для переменных, и будет увеличиваться в противоположном направлении стека. Максимальный размер стека и кучи обычно можно указать в качестве параметров компоновщика.

    Переменные, помещаемые в стек, — это любые переменные, определенные в функции или процедуре без ключевого слова static . Когда-то они назывались автоматическими переменными (ключевое слово auto), но это ключевое слово не нужно. Исторически auto существует, потому что он был частью языка B, который предшествовал C, и там он был нужен. Параметры функции также помещаются в стек.

    Вот типичный макет для оперативной памяти (при условии отсутствия специального раздела страницы 0):

    EEPROM, ROM и NVRAM

    До появления флэш-памяти для хранения программы и постоянных данных (сегментов .text и .rodata) использовалась EEPROM (электрически стираемая программируемая постоянная память). Теперь имеется лишь небольшой объем (например, от 2 КБ до 8 КБ байт) EEPROM, если он вообще есть, и он обычно используется для хранения данных конфигурации или других небольших объемов данных, которые необходимо сохранить при включении питания. цикл.Они не объявляются в программе как переменные, а записываются в специальные регистры микроконтроллера. EEPROM также может быть реализован в виде отдельного чипа и доступен через шину SPI или I²C.

    ПЗУ по существу такое же, как флэш, за исключением того, что оно запрограммировано на заводе (не программируется пользователем). Он используется только для устройств с очень большой громкостью.

    NVRAM (энергонезависимое ОЗУ) является альтернативой EEPROM и обычно реализуется как внешняя ИС. Обычная оперативная память может считаться энергонезависимой, если она питается от батареи; в этом случае никаких специальных методов доступа не требуется.

    Хотя данные можно сохранять во флэш-память, флэш-память имеет ограниченное количество циклов стирания/программирования (от 1000 до 10 000), поэтому она не предназначена для этого. Также требуется стирание сразу блоков памяти, поэтому обновлять всего несколько байт неудобно. Он предназначен для кода и переменных только для чтения.

    EEPROM имеет гораздо более высокие ограничения на количество циклов стирания/программирования (от 100 000 до 1 000 000), поэтому она лучше подходит для этой цели. Если на микроконтроллере есть доступная EEPROM и она достаточно велика, вы хотите сохранить энергонезависимые данные именно в ней. Однако вам также придется сначала стереть блоки (обычно 4 КБ) перед записью.

    Если нет EEPROM или он слишком мал, то нужен внешний чип. EEPROM объемом 32 КБ стоит всего 66 центов и может быть стерт/записан до 1 000 000 раз. NVRAM с тем же количеством операций стирания/программирования намного дороже (x10). NVRAM обычно быстрее для чтения, чем EEPROM, но медленнее для записи. Они могут быть записаны по одному байту за раз или блоками.

    Лучшей альтернативой обоим из них является FRAM (сегнетоэлектрическая RAM), которая имеет практически бесконечные циклы записи (100 триллионов) и не имеет задержек записи. Это примерно такая же цена, как NVRAM, около 5 долларов за 32 КБ.

    Читайте также:

    Зарегистрируйте имена
    16-разрядная32-разрядная64-разрядная Назначение
    AX EAXRAX Аккумулятор
    EBXRBX Базовый индекс (массивы)
    ECXRCX Счетчик (циклы)
    DX EDXRDX Увеличивает точность аккумулятора
    ESIRSI Индекс исходного кода для строковых операций
    EDIRDI Индекс назначения для строковых операций
    ESPRSP Указатель стека
    BP EBPRBP Базовый указатель
    IP EIPRIP Указатель инструкций