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.
По умолчанию любые данные, включая данные только для чтения, размещаются в ОЗУ (общее пространство имён), поэтому для размещения данных только для чтения в памяти flash и для генерации соответствующих инструкций доступа к этим данным без использования (встроенного) ассемблерного кода требуются пространства имён, отличные от общего.
__flash-
Квалификатор
__flashразмещает данные в секции.progmem.data. Данные считываются с помощью инструкцииLPM. Указатели на это пространство имён имеют ширину 16 бит. __flash1__flash2__flash3__flash4__flash5-
Это 16-битные пространства имён, размещающие данные в секции
.progmemN.data, где N относится к пространству имён__flashN. Компилятор устанавливает регистр сегментаRAMPZсоответствующим образом перед чтением данных с помощью инструкцииELPM. __memx-
Это 24-битное пространство имён, которое линейно отображает память flash и ОЗУ: Если старший бит адреса установлен, данные считываются из ОЗУ, используя два младших байта в качестве адреса ОЗУ. Если старший бит адреса сброшен, данные считываются из памяти 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, но доступ к этим данным читается из общего пространства имён, то есть из ОЗУ, поэтому вам нужны специальные средства доступа, такие как 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;
Для такого кода требуется по крайней мере binutils 2.23, см. PR13503.
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-6.5.0/gcc/Named-Address-Spaces.html