IAR 4.0: сегменты памяти |
Добавил(а) microsin | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Здесь приведен перевод раздела даташита ARM® IAR C/C++ Compiler Reference Guide -> Segment reference, посвященный сегментам кода и данных. Компилятор ARM IAR C/C++ размещает код и данные в именованные сегменты, которые используются линкером IAR XLINK при построении двоичного кода. Подробные знания сегментов необходимы при программировании модулей на языке ассемблера. Также эти знания полезны, когда нужно анализировать выходной код на языке ассемблера, генерируемый компилятором. Дополнительную информацию о сегментах можно получить из раздела "Placing code and data" (размещение кода и данных). [Общие сведения о сегментах] Таблица ниже показывает сегменты, которые доступны в среде компиляции ARM IAR C/C++ Compiler.
[Описание сегментов] Сегменты размещаются в памяти при использовании директив линкера для управления размещения сегментов -Z и -P, которые предназначены соответственно для последовательного и пакетного размещения. Некоторые сегменты не могут использовать пакетное размещение, потому что их содержимое должно быть непрерывным. В каждом описании тип памяти сегмента — CODE, CONST или DATA - показывает, должен ли сегмент быть помещен в ROM или RAM. CODE Для исполняемого кода. Подробнее про директивы -Z и -P можно узнать в даташите "IAR Linker and Library Tools Reference Guide". Чтобы узнать, как задать сегменты в файле команд линкера (linker command file), см. раздел "Управление линкером с помощью файла команд". Дополнительную информацию по специальному расширенному синтаксису IAR (extended keywords), см. раздел "Extended keywords". CODE. Этот сегмент содержит код программы, за исключением кода инициализации системы и кода функций, которые определены с атрибутом __ramfunc. Этот код выполняется из ROM (обычно это память FLASH). CODE_I. Этот сегмент содержит код функций, которые определены с атрибутом __ramfunc. Этот код выполняется из RAM (обычно этот тип памяти дает дополнительный прирост скорости выполнения). Код копируется в RAM из сегмента CODE_ID в процессе инициализации. CODE_ID. В этом сегменте расположено хранилище кода, который определен с атрибутом __ramfunc. Этот код выполняется из RAM после того, как будет скопирован в сегмент CODE_I. CSTACK. Содержит внутренние данные стека. Стек используется функциями для сохранения переменных и другой информации, которая используется в функции локально. Стек представляет собой блок непрерывной памяти, на содержимого которого указывает регистр указателя стека SP (stack pointer). Модуль начальной инициализации системы (код cstartup) инициализирует указатель стека, устанавливая его в конец сегмента стека. При помещении данных в стек указатель SP уменьшает свое значение, и стек растет вниз, в сторону уменьшения адреса. По умолчанию в начале файла настройки линкера устанавливается константа, определяющая размер стека: -D_CSTACK_SIZE=2000 Имейте в виду, что здесь указано шестнадцатеричное значение адреса без префикса 0x. Компилятор использует стек для различных операций, которые происходят в программе, так что действительный требуемый размер стека зависит от сложности программы (глубине вложенности вызовов подпрограмм, количество используемых в них локальных переменных). Если указанное программистом значение размера стека слишком мало, то стек перезапишет область память глобальных и статических переменных, что приведет к сбою программы. Если же выбранный размер стека задан слишком большим, то память RAM будет потрачена впустую. Далее в файле настройки линкера действительные сегменты определяются в соответствии с областью памяти, выделенной под стек: -Z(DATA)CSTACK+_CSTACK_SIZE=RAMSTART-RAMEND DATA_AC. Содержит данные инициализируемых констант. Сегменты, содержащие located данные, не нуждаются ни в какой дальнейшей конфигурации, потому что они имеют уже присвоенные адреса до процесса линковки. Словечко "located" означает, что данные размещены по абсолютно заданному месту (location) с использованием оператора @ или директивы #pragma location. DATA_AN. Содержит данные, которые определены с атрибутом __no_init. Все, что сказано для located-данных в описании сегмента DATA_AC, относится и к сегменту DATA_AN. DATA_C. Содержит данные констант (объекты, определенные с ключевым словом const). DATA_I. Содержит статические и глобальные инициализируемые переменные, которые инициализируются путем копирования из сегмента DATA_ID при старте приложения (startup). Этот сегмент не может быть размещен в памяти директивой -P пакетного размещения, потому что содержимое сегмента должно быть непрерывным. Вместо этого нужно использовать директиву -Z, когда Вы задаете этот сегмент в настроечном файле команд линкера. DATA_ID. Хранилище значений для статических и глобальных переменных сегмента DATA_I. Эти значения копируются из DATA_ID в DATA_I при старте приложения (startup). Этот сегмент не может быть размещен в памяти директивой -P пакетного размещения, потому что содержимое сегмента должно быть непрерывным. Вместо этого нужно использовать директиву -Z, когда Вы задаете этот сегмент в настроечном файле команд линкера. DATA_N. Содержит статические и глобальные переменные, которые определены с атрибутом __no_init. DATA_Z. Содержит статические и глобальные переменные, инициализируемые нулем. Этот сегмент не может быть размещен в памяти директивой -P пакетного размещения, потому что содержимое сегмента должно быть непрерывным. Вместо этого нужно использовать директиву -Z, когда Вы задаете этот сегмент в настроечном файле команд линкера. DIFUNCT. Содержит вектор динамической инициализации, используемый C++. HEAP. Содержит кучу, используемую для динамически выделяемых данных, другими словами для данных, выделяемых вызовами malloc и free, а также в C++, new и delete. Сегмент кучи будет использоваться в приложении только тогда, когда действительно используется динамическое выделение памяти. Размер кучи и её размещение в памяти определяются файлом команд линкера - точно так же, как и при определении сегмента стека. Пример: -D_HEAP_SIZE=8000 ... -Z(DATA)HEAP+_HEAP_SIZE=RAMSTART-RAMEND ICODE. Содержит специальный код запуска (startup); эти функции должны быть в пределах доступности инструкций ветвления из сегмента INTVEC. INITTAB. Содержит таблицу адресов и размеров сегментов, которые должны быть инициализированы при startup. INTVEC. Содержит вектор сброса (reset) и вектора исключений (exceptions). В этих векторах размещены инструкции ветвления, делающие переходы в cstartup, обработчики прерываний и т. п. IRQ_STACK. Содержит стек, который используется при обработке исключений IRQ. Другие стеки могут быть добавлены, если это нужно для обработки других типов исключений FOQ, SVC, ABT и UND. Файл кода запуска cstartup.s79 должен быть модифицирован, чтобы инициализировать используемые указатели стека исключений. Архитектура ARM поддерживает 5 режимов исключения, в которые входит процессор при разных событиях исключения (exception). Каждый режим исключения имеет свой собственный стек для того, чтобы избежать порчи стека режима пользователя/системы. В таблице показаны предлагаемые имена для различных стеков исключения, но могут использоваться и любые другие имена.
Для каждого режима процессора, которому нужен стек, в коде загрузки (startup code) должен быть инициализирован отдельный указатель стека, и в файле команд линкера должно быть задано размещение сегмента. В поставляемых файлах cstartup.s79 и lnkarm.xcl предварительно конфигурируется только стек IRQ, но можно легко добавить другие стеки исключений. Чтобы просмотреть любой из этих стеков в окне Stack среды IAR Embedded Workbench IDE, эти предварительно сконфигурированные имена сегментов должны быть использованы вместо имен сегментов, заданных пользователем. SWITAB. Содержит таблицу векторов программных прерываний. [Управление линкером с помощью файла команд] Файл настроек линкера нужно изменять в том случае, когда нужно настроить целевую карту памяти программируемой системы (target system memory map). Предположим, целевая система должна использовать такую карту памяти: 0x000000–0x00003F ROM или RAM ROM может использоваться для сохранения сегментов памяти, которая имеет тип CONST и CODE. Память RAM может содержать сегменты типа DATA. Основное назначение изменения файла команд линкера - проверить, что код и данные Вашего приложения не пересекают границы областей памяти (области памяти технологически ограничены в зависимости от типа процессора) - невыполнение этого условия приведет к отказу в работе приложения. В файле команд линкера (см. пример по умолчанию lnkarm.xcl), адреса начала и конца сегментов ROM и RAM задаются директивой -D: -DROMSTART=08000 -DROMEND=FFFFF -DRAMSTART=100000 -DRAMEND=7FFFFF Содержимое файла команд линкера. Каталог arm\config содержит готовые файлы команд линкера. Кроме того, Вы можете найти готовые файлы команд линкера для различных отладочных плат ARM в подкаталогах arm\src\examples. Настроечные файлы команд содержат информацию, требуемую линкеру, и они сразу готовы к использованию. Если, к примеру, Ваше приложение использует дополнительную внешнюю RAM, то нужно добавить подробную информацию, описывающую эту внешнюю область памяти RAM. Помните о том, что не следует вносить изменения в оригинальные настроечные файлы. Вместо этого рекомендуется сделать копию настроечного файла в рабочую директорию проекта, и модифицировать эту копию. Поставляемые файлы конфигурации линкера снабжены комментариями, описывающими содержимое. Помимо всего прочего, командный файл линкера содержит три различных типа параметров командной строки XLINK: • Тип используемого CPU (-carm), задает тип целевого ядра. Использование команды -Z для последовательного размещения. Используйте команду -Z, когда Вам нужно обеспечить весь сегмент как непрерывный кусок памяти, когда нужно сохранить порядок частей в сегменте, или, что используется реже, чтобы разместить сегменты в определенном порядке. В следующем примере показано, как использовать команду -Z для размещения сегмента MYSEGMENTA перед сегментом MYSEGMENTB в памяти CONST (т. е. в ROM), в диапазоне адресов 0x008000-0x0FFFFF. -Z(CONST)MYSEGMENTA,MYSEGMENTB=008000-0FFFFF Два сегмента разного типа можно разместить в той же самой области памяти, но для этого не нужно указывать диапазон второго сегмента. В следующем примере сегмент MYSEGMENTA будет размещен в памяти первым. Тогда остальная память будет использоваться MYCODE. -Z(CONST)MYSEGMENTA=008000-0FFFFF -Z(CODE)MYCODE Два диапазона памяти могут перекрывать друг друга. Это позволяет сегментам с различными требованиями к размещению использовать разделяемое общее пространство памяти, пример: -Z(CONST)MYSMALLSEGMENT=008000-000FFF -Z(CONST)MYLARGESEGMENT=008000-0FFFFF Несмотря на то, нет строгих рекомендаций на указание конца каждого диапазона памяти, все равно рекомендуется это делать. Когда Вы укажете конец диапазона памяти, то линковщик IAR XLINK Linker предупредит Вас, если Ваши сегменты не умещаются в памяти. Использование команды -P для пакетного размещения. Команда -P отличается от -Z тем, что при использовании -P не требуется размещать сегменты (или части сегмента) последовательно. С использованием -P становится возможным размещать части сегмента в "дырки", оставленные от предыдущих размещений других сегментов. Следующий пример показывает, как можно применить опцию XLINK -P, чтобы использовать память эффективнее. Команда разместит сегмент данных MYDATA в памяти DATA (т. е. RAM) в фиктивном диапазоне памяти: -P(DATA)MYDATA=100000-101FFF,110000-111FFF Если Ваше приложение имеет дополнительную область RAM в диапазоне памяти 0x10F000-0x10F7FF, то просто добавьте к оригинальному определению: -P(DATA)MYDATA=100000-101FFF,10F000–10F7FF,110000-111FFF
|