Программирование ARM IAR 4.0: размещение переменных и данных по заданному адресу Sat, April 20 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

IAR 4.0: размещение переменных и данных по заданному адресу Печать
Добавил(а) microsin   

Здесь приведен перевод документации IAR 4.0 "ARM® IAR C/C++ Compiler Reference Guide", раздел Part 1. Using the compiler -> Placing code and data -> Controlling data and function placement in memory -> Data placement at an absolute location.

[Размещение данных в заданном месте памяти]

Оператор @ а также как альтернатива директива #pragma location могут использоваться для размещения глобальных и статических переменных по абсолютным адресам. Переменные для этого должны быть определены как __no_init или const. Если переменная определена как const, то она может иметь или не иметь инициализатора. Если инициализатор отсутствует, то система времени выполнения не предоставляет никакое значение по этому адресу (значение переменной будет не определено). Чтобы разместить переменную по абсолютному адресу, аргумент оператора @ и директивы #pragma location должен быть в виде литерального числа, представляющего нужный адрес. Этот абсолютный адрес должен удовлетворять требованиям выравнивания для размещаемой в этом месте переменной.

Статические переменные класса C++ могут быть размещены также по абсолютному адресу, как и любая другая статическая переменная.

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

[Определение размещаемой по абсолютному адресу переменной как extern и volatile]

В C++ переменные с атрибутом const являются статическими (static, локальными для модуля), что означает, что каждый модуль с этой декларацией будет содержать собственную отдельную переменную. Когда Вы линкуете приложение из нескольких таких модулей, линкер сообщит о том, что больше чем одна переменная размещена, к примеру, по адресу 0x100.

Чтобы избежать этой проблемы и сделать процедуру объявления одинаковой в C и C++, Вы должны объявить эти переменные как extern, например:

extern volatile const __no_init int x @ 0x100;

Для дополнительной информации о декларировании объектов volatile, см. раздел "Protecting simultaneously accessed variables".

[Примеры]

В этом примере переменная, декларируемая как __no_init, размещена по абсолютному адресу. Это полезно для того, чтобы обмениваться данными между несколькими процессами/приложениями, и т. п.:

__no_init char alpha @ 0x1000;

В следующих примерах определены два объекта const, где первый инициализирован в 0, и второй инициализирован в указанное значение. Оба объекта будут размещены в ROM (FLASH). Это полезно для конфигурационных параметров, к которым планируется осуществлять доступ через некий внешний интерфейс. Обратите внимание на то, что во втором случае компилятор не обязан фактически читать из переменной, потому что её значение заранее известно. Чтобы обеспечить принудительное чтение компилятором переменной, определите её как volatile:

#pragma location=0x1004
volatile const int beta;
volatile const int gamma @ 0x1008 = 3;

В следующем примере значение не инициализируется компилятором; значение должно быть установлено каким-то другим способом. Обычно такая конфигурация используется, когда значения загружаются в ROM отдельно, или для регистров SFR (special function register, регистры специального назначения), которые доступны только для чтения (read-only). Чтобы обеспечить чтение значения компилятором, декларируйте их как volatile:

volatile __no_init const char c @ 0x1004;
void foo(void) { ... a = b + c + d; ... }

В следующем примере показано некорректное использование:

int delta @ 0x100C;         /* Ошибка, нет ни "__no_init", ни "const". */
const int epsilon @ 0x1011; /* Ошибка выравнивания. */

[Размещение данных и функций в сегментах]

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

• Оператор @ и альтернативно директива #pragma location могут использоваться для размещения отдельных переменных или отдельных функций в именованных сегментах. Именованный сегмент может быть либо предварительно заданным сегментом (predefined segment), или сегментом, который определяет пользователь (user-defined segment). Переменные должны быть определены либо через __no_init, либо через const. Если декларирование использует const, то оно может иметь инициализаторы.

• Опция --segment может использоваться для размещения переменных и функций, которые являются частями целого процесса компиляции, в именованных сегментах.

Статические переменные класса C++ могут быть размещены также по абсолютному адресу, как и любая другая статическая переменная.

Если Вы используете свои собственные сегменты в дополнение к предопределенным сегментам, эти сегменты должны быть также определены в файле команд для линкера с использованием директив управления сегментами -Z или -P.

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

Дополнительную информацию о сегментах можете получить в разделе "Placing code and data".

Примеры размещение переменных в именованных сегментах. В следующих трех примерах объект данных размещен в сегменте, определенном пользователем.

__no_init int alpha @ "MYSEGMENT";
#pragma location="MYSEGMENT" const int beta;
const int gamma @ "MYSEGMENT" = 3;

В следующем примере показано некорректное использование:

int delta @ "MYSEGMENT"; /* Ошибка, нет ни "__no_init", ни "const". */

Примеры размещение функций в именованных сегментах:

void f(void) @ "MYSEGMENT";
void g(void) @ "MYSEGMENT" { }
#pragma location="MYSEGMENT" void h(void);

[Результирующая линковка кода и размещение данных]

У линкера есть несколько возможностей, которые помогут Вам управлять размещением кода и данных. Например, это сообщения времени линковки и файл карты памяти линкера (linker map file). Могут диагностироваться проблемы с сегментами - ошибки превышения размера сегмента (segment too long error) и ошибки размещения (range error).

Весь код и все данные, которые размещаются в перемещаемых сегментах (relocatable segments) получат свои реальные абсолютные адреса во время процесса линковки. Также во время линковки будет известно, все ли сегменты будут соответствовать (по размеру и месту размещения) отведенным зарезервированным областям памяти. Если содержимое сегмента не помещается в определенный диапазон адресов, заданный в настроечном файле линкера (linker command file), то линкер XLINK выдаст ошибку segment too long error.

Некоторые инструкции не будут работать, если после линковки не будут выполнены определенные условия, например ветвление должно попасть в определенный интервал, или адрес должен быть четным. XLINK проверяет, что условия выполнены, когда линкует файлы. Если условия не выполнены, то XLINK генерирует ошибку диапазона (range error) или предупреждение (warning) и распечатывает описание ошибки.

Дополнительную информацию об этих типах ошибок смотрите в документации на линкер "IAR Linker and Library Tools Reference Guide".

[Карта памяти приложения (Linker map file)]

XLINK может сгенерировать подробный список перекрестных ссылок (cross-reference listing), который опционально может содержать следующую информацию:

• Карту адресов сегментов (segment map), которая перечисляет все сегменты в порядке появления (dump order).
• Карту модулей (module map), которая перечисляет все сегменты, локальные символы, и записи (entries, символы public) для каждого модуля в программе. Все символы, которые не попали на выход, могут тоже входить в список.
• Общая информация модуля (module summary), которая перечисляет занятую каждым модулем память (в байтах).
• Список символов (symbol list), который содержит каждый встреченный объект (глобальный символ) в каждом модуле.

Чтобы получить листинг линкера, используйте опцию Generate linker listing в свойствах проекта IAR Embedded Workbench, или задайте опцию -X в командной строке линкера, и одну из их подопций.

Обычно XLINK не будет генерировать выходной файл (двоичный код программы), если произошла любая ошибка при линковке, наподобие range error. Используйте опцию Range checks disabled в свойствах проекта IAR Embedded Workbench, или опцию -R в командной строке, чтобы сгенерировать выходной файл даже в том случае, если встретилась ошибка диапазона (range error).

Дополнительную информацию об опциях листинга и листинге линкера см. документацию, "IAR Linker and Library Tools Reference Guide" и "ARM® IAR Embedded Workbench® IDE User Guide".

[Ссылки]

1. IAR EWB for ARM: учимся управлять сегментами на примере добавления версии по фиксированному адресу.

 

Добавить комментарий


Защитный код
Обновить

Top of Page