6.17 Пространства имён адресов ¶
В качестве расширения GNU C поддерживает пространства имён адресов, как определено в проекте N1275 черновика ISO/IEC DTR 18037. Поддержка пространств имён адресов в GCC будет развиваться по мере изменения черновика технического отчета. Вызовы функций для любого целевого процессора также могут измениться. В настоящее время поддержку пространств адресов, отличных от универсального пространства адресов, обеспечивают только целевые процессоры AVR, M32C, RL78 и x86.
Идентификаторы пространств адресов могут использоваться точно так же, как и любые другие квалификаторы типов C (например, const или volatile). Более подробную информацию см. в документе N1275.
- Пространства имён адресов AVR
- Пространства имён адресов M32C
- Пространства имён адресов 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;
- На уменьшенных устройствах типа 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-битных адресов. Переменные, не являющиеся дальними, предполагаются расположенными в верхней 64 Кбайт адресного пространства.
6.17.4 Пространства имён адресов 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-10.5.0/gcc/Named-Address-Spaces.html