6.17 Пространства имён адресов
В качестве расширения GNU C поддерживает пространства имён адресов, как определено в проекте N1275 черновика ISO/IEC DTR 18037. Поддержка пространств имён адресов в GCC будет развиваться по мере изменения чернового технического отчета. Правила вызова для любого целевого устройства могут также измениться. В настоящее время только целевые устройства AVR, M32C, PRU, RL78 и x86 поддерживают пространства адресов, отличные от универсального пространства адресов.
Идентификаторы пространств адресов могут использоваться точно так же, как и любой другой квалификатор типа C (например, const или volatile). Более подробную информацию см. в документе N1275.
6.17.1 Пространства имён адресов AVR
На целевом устройстве AVR есть несколько пространств адресов, которые можно использовать для размещения только для чтения данных в памяти flash и доступа к этим данным с помощью специальных инструкций LPM или ELPM, необходимых для чтения из flash.
Устройства, относящиеся к avrtiny и avrxmega3, могут обращаться к памяти flash с помощью инструкций LD*, поскольку память flash отображается в адресном пространстве RAM. Нет необходимости в расширениях языка, таких как __flash или атрибуте progmem. По умолчанию, файлы описания компоновщика для этих устройств учитывают эту функцию и .rodata остается в памяти flash: компилятор просто генерирует инструкции LD*, а скрипт компоновщика добавляет специфичные для ядра смещения ко всем символам .rodata: 0x4000 в случае avrtiny и 0x8000 в случае avrxmega3. Список соответствующих устройств см. в разделе Параметры AVR.
Для устройств, не входящих в avrtiny или avrxmega3, все данные, включая данные только для чтения, находятся в RAM (универсальное адресное пространство), так как память flash не отображается в адресном пространстве RAM. Для размещения данных только для чтения в памяти flash и для генерации правильных инструкций для доступа к этим данным без использования (встроенного) кода ассемблера необходимы специальные пространства адресов.
__flash-
Квалификатор
__flashразмещает данные в секции.progmem.data. Данные считываются с помощью инструкцииLPM. Указатели на это адресное пространство имеют ширину 16 бит. __flash1__flash2__flash3__flash4__flash5-
Это 16-битные адресные пространства, размещающие данные в секции
.progmemN.data, где N относится к адресном пространству__flashN. Компилятор устанавливает регистр сегментаRAMPZсоответствующим образом перед чтением данных с помощью инструкцииELPM. __memx-
Это 24-битное адресное пространство, которое линейно отображает flash и RAM: если старший бит адреса установлен, данные читаются из RAM, используя два младших байта в качестве адреса RAM. Если старший бит адреса сброшен, данные читаются из flash с
RAMPZустанавливается в соответствии со старшим байтом адреса. См.__builtin_avr_flash_segment.Объекты в этом адресном пространстве размещаются в
.progmemx.data.
Пример
char my_read (const __flash char ** p)
{
/* p is a pointer to RAM that points to a pointer to flash.
The first indirection of p reads that flash pointer
from RAM and the second indirection reads a char from this
flash address. */
return **p;
}
/* Locate array[] in flash memory */
const __flash int array[] = { 3, 5, 7, 11, 13, 17, 19 };
int i = 1;
int main (void)
{
/* Return 17 by reading from flash memory */
return array[array[i]];
}
Для каждого пространства имени адреса, поддерживаемого avr-gcc, определена аналогичная, но заглавная встроенная макрокоманда. Цель состоит в облегчении проверки доступности соответствующей поддержки адресного пространства:
#ifdef __FLASH
const __flash int var = 1;
int read_var (void)
{
return var;
}
#else
#include <avr/pgmspace.h> /* From AVR-LibC */
const int var PROGMEM = 1;
int read_var (void)
{
return (int) pgm_read_word (&var);
}
#endif /* __FLASH */
Обратите внимание, что атрибут progmem размещает данные в flash, но доступ к этим данным читается из универсального адресного пространства, то есть из RAM, поэтому вам нужны специальные средства доступа, такие как pgm_read_byte из AVR-LibC вместе с атрибутом progmem.
Ограничения и замечания
- Чтение через границу раздела 64 Кбайт пространств адресов
__flashили__flashNдемонстрирует неопределённое поведение. Единственное адресное пространство, поддерживающее чтение через границы 64-килобайтовых сегментов flash, —__memx. - Если вы используете одно из пространств адресов
__flashN, вы должны организовать свой скрипт компоновщика для размещения секций.progmemN.dataв соответствии с вашими потребностями. - Любые данные или указатели на пространства адресов, отличные от универсальных, должны быть квалифицированы как
const, то есть как данные только для чтения. Это все еще относится к данным в одном из этих пространств адресов, таких как номер версии программного обеспечения или таблица поиска откалибровки, которые предполагается изменять после загрузки, скажем, загрузчиком. В этом случае правильной квалификацией являетсяconstvolatile, чтобы компилятор не оптимизировал известные значения или не вставлял их в качестве непосредственных операндов инструкций. - Следующий код инициализирует переменную
pfoo, расположенную в статическом хранилище, 24-битным адресом:extern const __memx char foo; const __memx void *pfoo = &foo;
- На уменьшенных устройствах типа ATtiny40 не поддерживаются пространства адресов. Просто используйте обычный код C/C++ без избыточной нагрузки, как описано выше. Атрибут
progmemподдерживается, но работает по-другому, см. Атрибуты переменных AVR.
6.17.2 Пространства имён адресов M32C
На целевом устройстве M32C, с вариантами процессоров R8C и M16C, переменные, квалифицированные с помощью __far имеют доступ с использованием 32-битных адресов, чтобы иметь доступ к памяти, выходящей за первые 64 Кбайта. Если __far используется с вариантами процессоров M32CM или M32C, он не имеет никакого эффекта.
6.17.3 Пространства имён адресов PRU
На целевом устройстве PRU, переменные, квалифицированные с помощью __regio_symbol являются псевдонимами, используемыми для доступа к специальным регистрам ввода/вывода процессора. Они должны быть объявлены как extern, поскольку такие переменные не будут выделены в памяти данных. Они также должны быть помечены как volatile, и могут быть только 32-битными целочисленными типами. Единственными именами, которые могут иметь эти переменные, являются __R30 и __R31, представляющие соответственно R30 и R31 специальные регистры ввода/вывода процессора. Следовательно, следующий пример является единственным допустимым использованием __regio_symbol:
extern volatile __regio_symbol uint32_t __R30; extern volatile __regio_symbol uint32_t __R31;
6.17.4 Пространства имён адресов RL78
На целевом устройстве RL78 переменные, квалифицированные с помощью __far имеют доступ с помощью 32-битных указателей (20-битных адресов), а не стандартных 16-битных адресов. Переменные, не помеченные как far, считаются расположенными в верхних 64 Кбайтах адресного пространства.
6.17.5 Пространства имён адресов x86
На целевом устройстве x86 переменные могут быть объявлены как относительные к сегментам %fs или %gs.
__seg_fs__seg_gs-
К объекту осуществляется доступ с соответствующим префиксом сегмента.
Соответствующий базовый адрес сегмента должен быть установлен с помощью метода, специфичного для операционной системы. Вместо того, чтобы требовать дорогостоящего системного вызова для получения базового адреса сегмента, эти адресные пространства не считаются подпространствами универсального (плоского) адресного пространства. Это означает, что для преобразования указателей между этими адресными пространствами и универсальным адресным пространством требуются явные преобразования. На практике приложение должно преобразовать в
uintptr_tи применить смещение базового адреса сегмента, установленное ранее.Препроцессорные символы
__SEG_FSи__SEG_GSопределяются при поддержке этих адресных пространств.
Далее: Длина ноль, Предыдущий: Фиксированная точка, Вверх: Расширения C [Содержание][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Named-Address-Spaces.html