6.17 Пространства имён адресов
В качестве расширения GNU C поддерживает пространства имён адресов, как определено в проекте N1275 черновика ISO/IEC DTR 18037. Поддержка пространств имён адресов в GCC будет развиваться по мере изменения черновика технического отчета. Правила вызова для любого целевого устройства также могут измениться. В настоящее время только целевые устройства AVR, M32C, PRU, RL78 и x86 поддерживают пространства адресов, отличные от универсального пространства адресов.
Идентификаторы пространств адресов могут быть использованы точно так же, как и любой другой квалификатор типа C (например, const или volatile). Более подробную информацию см. в документе N1275.
- Пространства имён адресов AVR
- Пространства имён адресов M32C
- Пространства имён адресов PRU
- Пространства имён адресов RL78
- Пространства имён адресов x86
6.17.1 Пространства имён адресов AVR
На целевом устройстве AVR существует несколько пространств адресов, которые могут быть использованы для размещения только для чтения данных во флэш-памяти и доступа к этим данным с помощью специальных инструкций LPM или ELPM, необходимых для чтения из флэш-памяти.
Устройства, принадлежащие к avrtiny и avrxmega3, могут получать доступ к флэш-памяти с помощью инструкций LD*, потому что флэш-память отображается в адресном пространстве ОЗУ. Не требуется расширений языка, таких как __flash или атрибут progmem. Стандартные файлы описания компоновщика для этих устройств учитывают эту функцию, и .rodata остаётся во флэш-памяти: компилятор просто генерирует инструкции LD*, а скрипт компоновщика добавляет специфичные для ядра смещения ко всем символам .rodata: 0x4000 в случае avrtiny и 0x8000 в случае avrxmega3. Список соответствующих устройств см. в разделе Параметры AVR.
Для устройств, не входящих в avrtiny или avrxmega3, все данные, включая данные только для чтения, находятся в ОЗУ (универсальное адресное пространство), потому что флэш-память не отображается в адресном пространстве ОЗУ. Для размещения данных только для чтения во флэш-памяти и для генерации правильных инструкций для доступа к этим данным без использования (встроенного) ассемблерного кода необходимы специальные адресные пространства.
-
__flash -
Квалификатор
__flashразмещает данные в разделе.progmem.data. Данные считываются с помощью инструкцииLPM. Указатели на это адресное пространство имеют ширину 16 бит. -
__flash1 __flash2__flash3__flash4__flash5-
Это 16-битные адресные пространства, размещающие данные в разделе
.progmemN.data, где N относится к адресному пространству__flashN. Компилятор устанавливает регистр сегментаRAMPZсоответствующим образом перед чтением данных с помощью инструкцииELPM. -
__memx -
Это 24-битное адресное пространство, которое линейно отображает флэш и ОЗУ: Если старший бит адреса установлен, данные считываются из ОЗУ, используя два младших байта в качестве адреса ОЗУ. Если старший бит адреса сброшен, данные считываются из флэш-памяти с
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 размещает данные во флэш-памяти, но доступ к этим данным осуществляется из универсального адресного пространства, т. е. из ОЗУ, поэтому вам необходимы специальные средства доступа, такие как pgm_read_byte из AVR-LibC вместе с атрибутом progmem.
Ограничения и замечания
- Чтение через границу сегмента 64 КБ пространств адресов
__flashили__flashNдемонстрирует неопределённое поведение. Единственное адресное пространство, которое поддерживает чтение через границы сегментов флэш-памяти 64 КБ, это__memx. - Если вы используете одно из пространств адресов
__flashN, вы должны настроить скрипт компоновщика для размещения разделов.progmemN.dataв соответствии с вашими потребностями. - Любые данные или указатели на не универсальные адресные пространства должны быть квалифицированы как
const, т. е. как данные только для чтения. Это всё ещё применяется, если данные в одном из этих адресных пространств, такие как номер версии программного обеспечения или таблица поиска калибровки, предназначены для изменения после загрузки, например, загрузчиком начального кода. В этом случае правильная квалификация —constvolatile, так что компилятор не должен оптимизировать известные значения или вставлять их в качестве непосредственных операндов инструкций. - Следующий код инициализирует переменную
pfoo, расположенную в статической памяти, 24-битным адресом:extern const __memx char foo; const __memx void *pfoo = &foo;
- На микроконтроллерах Tiny, таких как 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-битными по умолчанию. Переменные, не являющиеся дальними, предполагаются в верхней части 64 КБ адресного пространства.
6.17.5 Пространства имён адресов x86
На целевом устройстве x86 переменные могут быть объявлены как относительные к сегментам %fs или %gs.
-
__seg_fs __seg_gs-
Объект обращается с соответствующим префиксом переопределения сегмента.
Соответствующая база сегмента должна быть установлена каким-либо методом, специфичным для операционной системы. Вместо требования дорогостоящего системного вызова для получения базы сегмента, эти адресные пространства не рассматриваются как подпространства универсального (плоского) адресного пространства. Это означает, что требуется явное приведение типов для преобразования указателей между этими адресными пространствами и универсальным адресным пространством. На практике приложение должно привести тип к
uintptr_tи применить смещение базы сегмента, которое оно установило ранее.Макросы препроцессора
__SEG_FSи__SEG_GSопределены при поддержке этих адресных пространств.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-13.3.0/gcc/Named-Address-Spaces.html