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;
- На уменьшенных устройствах 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 Пространства имён адресов 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-11.4.0/gcc/Named-Address-Spaces.html