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