6.16 Пространства имён адресов
В качестве расширения GNU C поддерживает пространства имён адресов, определённые в проекте N1275 черновика ISO/IEC DTR 18037. Поддержка пространств имён адресов в GCC будет развиваться по мере изменения черновика технического отчета. Способы вызова для любого целевого процессора также могут измениться. В настоящее время только целевые процессоры AVR, SPU, M32C, RL78 и x86 поддерживают пространства адресов, отличные от универсального пространства адресов.
Идентификаторы пространства адресов могут быть использованы точно так же, как и любой другой квалификатор типа C (например, const или volatile). Дополнительные сведения см. в документе N1275.
6.16.1 Пространства имён адресов AVR
В целевом процессоре AVR есть несколько пространств адресов, которые можно использовать для размещения только для чтения данных в памяти флэш-памяти и доступа к этим данным с помощью специальных инструкций LPM или ELPM, необходимых для чтения из флэш-памяти.
По умолчанию все данные, включая данные только для чтения, находятся в ОЗУ (универсальное пространство адресов), поэтому для размещения данных только для чтения в памяти флэш-памяти и для генерации правильных инструкций доступа к этим данным без использования (встраиваемого) ассемблерного кода необходимы пространства адресов, отличные от универсального.
__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;
Для этого кода требуется как минимум binutils 2.23, см. PR13503.
- Для упрощённых устройств Tiny, таких как ATtiny40, пространства адресов не поддерживаются. Данные можно разместить в памяти флэш-памяти и читать их с помощью атрибута
progmem, см. Атрибуты переменных AVR.
6.16.2 Пространства имён адресов M32C
В целевом процессоре M32C, с вариантами процессоров R8C и M16C, переменные, квалифицированные как __far , доступны с помощью 32-битных адресов для доступа к памяти за пределами первых 64 Кбайт. Если __far используется с вариантами процессоров 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-7.5.0/gcc/Named-Address-Spaces.html