6.17 Пространства имён адресов
В качестве расширения GNU C поддерживает пространства имён адресов, определённые в проекте N1275 черновика ISO/IEC DTR 18037. Поддержка пространств имён адресов в GCC будет развиваться по мере изменения чернового технического отчёта. Вызовы функций для любого целевого устройства также могут измениться. В настоящее время пространства имён, отличные от общего пространства имён, поддерживаются только для целевых устройств AVR, SPU, M32C, RL78 и x86.
Идентификаторы пространства имён можно использовать точно так же, как и любой другой квалификатор типа C (например, const или volatile). Дополнительные сведения см. в документе N1275.
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 Пространства имён адресов RL78
На целевом устройстве RL78 переменные, квалифицированные с помощью __far, обрабатываются с помощью 32-битных указателей (20-битных адресов) вместо стандартных 16-битных адресов. Переменные без квалификатора «far» предполагаются в верхних 64 Кбайт адресного пространства.
6.17.4 Пространства имён адресов SPU
На целевом устройстве SPU переменные могут быть объявлены как принадлежащие другому пространству имён адресов путём квалификации типа с помощью идентификатора пространства имён __ea:
extern int __ea i;
Компилятор генерирует специальный код для доступа к переменной i. Он может использовать поддержку библиотеки времени выполнения или генерировать специальные машинные инструкции для доступа к этому пространству имён.
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-9.5.0/gcc/Named-Address-Spaces.html