Примечание: ниже описывается поведение автономной (или «голой») встроенной среды, и она не всегда универсальна для всех сред. Размещенные системы, которые динамически загружают код из запоминающего устройства, например, существенно различаются - но не настолько, чтобы это не оставалось верным ответом даже в этом случае (т. Е. Никакие адреса не «изменены») ...
Адреса «не изменены». В «типичной» автономной среде с кодом, выполняющимся из ПЗУ (не все встроенные системы организованы таким образом, но, возможно, это объясняется вашим вопросом), компоновщик размещает все символы в определенных местах. Если эти местоположения находятся в ОЗУ и имеют начальные значения, данные инициализации - , а не переменные , сохраняются в ПЗУ и копируются в ОЗУ при запуске -расположение переменных не изменилось - они всегда были в ОЗУ, а данные инициализации всегда в ПЗУ.
Вы можете увидеть это на карте ссылок, которую ваш компоновщик почти наверняка способен произвести.
Адресация данных в объектном коде - будь то ELF, Intel Hex или что-то еще, имеет отношение только тогда, когда код загружен - необработанный двоичный файл не содержит информации об адресе - все объекты расположены компоновщиком и размещеныв требуемом месте загрузчиком (будь то флэш-программист, отладчик или загрузчик), используя информацию об адресе в нем. Необработанный двоичный файл не имеет информации об адресе вообще, и вы должны указать адрес загрузки, когда вы загружаете его, и любые «пробелы» должны быть заполнены заполнением. Если код не является позиционно-независимым (т. Е. Все ссылки на адреса относительны), то необработанный двоичный файл должен быть загружен на правильный конкретный адрес, или он не будет работать как задумано.
Когда отладчик загружает файл ELF, он загружает двоичный файл в целевое устройство и считывает адрес и символическую информацию в отладчик, работающий на хосте. Информация об адресе и символах неявно присутствует в коде и явно не присутствует в цели (если только у вас нет средств отладки на основе цели, которые, возможно, используют такую информацию).
Запуск среды выполнения C выполняет следующие (как минимум) следующие шаги:
- Инициализация указателя стека
- Нулевая инициализация статических данных без явного ненулевого значенияИнициализация (сегмент данных)
- Инициализация явно инициализированных ненулевых статических данных (сегмент BSS)
- Инициализация библиотеки времени выполнения (например, инициализация кучи)
- Перейти к основному.
Для систем, выполняющих код из ОЗУ, также будет этап, на котором этот код копируется из ПЗУ в ОЗУ (в некоторых случаях, включая декомпрессию изображений), и если среда выполнения поддерживает C ++, будетшаг, который вызывает конструкторы всех статических объектов. Зачастую этот код запуска предоставляется вашим набором инструментов, и вы никогда не сможете его заметить, но он почти наверняка будет доступен вам в качестве исходного кода (на ассемблере и / или C) для настройки илипросто посмотрите, как это работает.
Каждый из сегментов данных и BSS обычно представляет собой один непрерывный блок, нулевая инициализация - это просто запись памяти блока в ноль, а инициализация данных - просто копия памяти (возможно, с декомпрессией). ) блока из ПЗУ в ОЗУ.
Сегмент кода - в ПЗУ или ОЗУ называется сегментом текст .
Итак, у вас есть две карты памяти -карта памяти изображений (которая доступна для чтения), содержащая текст, постоянные данные, данные инициализации и загрузочный код или код запуска, а также карта памяти времени выполнения, содержащая текст, постоянные данные, данные, BSS, сегменты стека и кучи. Данные, BSS, стек и куча обязательно находятся в ОЗУ, текстовые и постоянные данные могут быть в ПЗУ или ОЗУ, в зависимости от архитектуры среды выполнения системы.
Ссылка: https://en.wikipedia.org/wiki/Data_segment