Кодировать дополнительную информацию в указателе

Моя проблема:

Мне нужно закодировать дополнительную информацию об объекте в указателе на объект. Я думал, что смогу сделать это, используя часть указателя. То есть использовать несколько битов для кодирования логических флагов. Насколько я знаю, то же самое делается с определенными типами дескрипторов в ядре windows.

Фон:

Я пишу небольшую систему управления памятью, которая может собирать неиспользуемые объекты. Чтобы уменьшить потребление памяти ссылками на объекты и ускорить копирование, я хочу использовать указатели с дополнительными закодированными данными, например. состояние объекта (живой или готовый к сбору), бит блокировки и подобные вещи, которые могут быть представлены одним битом.

Мой вопрос:

Как я могу закодировать такую ​​информацию в 64-битный указатель, фактически не перезаписывая важные биты указателя?

Поскольку x64 windows имеет ограниченное адресное пространство, я считаю, что не все 64 бита указателя используются, поэтому я считаю, что это должно быть возможно. Однако мне не удалось найти, какие биты окна действительно используют для указателя, а какие нет. Чтобы уточнить, этот вопрос касается пользовательского режима в 64-битных окнах.

Заранее спасибо.


person thebear8    schedule 25.05.2020    source источник
comment
Если вы убедитесь, что ваши указатели всегда указывают на четные адреса, то нижний бит всегда будет равен нулю и, следовательно, доступен для других целей. Это стандартная техника. Распределение памяти в куче обычно возвращает указатели, выровненные по восьмибайтовым множителям, что дает три бита для игры.   -  person john    schedule 25.05.2020
comment
Все биты указателя важны. Когда процессы выполняются в пространстве виртуальной памяти, допустимым указателем может быть что угодно.   -  person Sam Varshavchik    schedule 25.05.2020
comment
@SamVarshavchik Значит, неиспользуемых битов нет?   -  person thebear8    schedule 25.05.2020
comment
@SamVarshavchik Вам нужно будет выполнять побитовые операции, чтобы замаскировать использование незначащих битов, чтобы каждый раз разыменовывался только исходный указатель. Это кажется ужасно хрупким и непортативным.   -  person François Andrieux    schedule 25.05.2020
comment
Нет битов, которые гарантированно не будут использоваться вечно.   -  person Sam Varshavchik    schedule 25.05.2020
comment
@FrançoisAndrieux Я намереваюсь использовать закодированные указатели в своего рода таблице дескрипторов для выделенных объектов, поэтому эти указатели не будут использоваться напрямую. Это правда, что он не будет очень портативным.   -  person thebear8    schedule 25.05.2020
comment
На практике ваш объект, вероятно, потребует 8-байтового выравнивания, поэтому младшие 3 бита всегда будут равны нулю, и вы можете скрыть информацию там. Для старших бит вы можете вызвать Get­System­Info и посмотреть на lp­Maximum­Application­Address, чтобы увидеть количество битов, используемых ОС. Конечно, вы должны быть готовы к тому, что битов не хватит на то, что вам нужно, и использовать резервный механизм в этом случае.   -  person Raymond Chen    schedule 25.05.2020


Ответы (1)


Это сильно зависит от используемой архитектуры, ОС и компилятора, но если вы знаете эти вещи, вы можете кое-что с этим сделать.

x86_64 определяет 48-битное 1 байтовое виртуальное адресное пространство в аппаратном обеспечении, что означает, что практически все операционные системы и компиляторы будут использовать его. Что это значит:

  • верхние 17 бит всех действительных адресов должны быть одинаковыми (все 0 или все 1)
  • младшие k биты любого 2k-байтового адреса, выровненного по байтам, должны быть равны нулю
  • кроме того, почти все операционные системы (по крайней мере, Windows, Linux и OSX) резервируют адреса с установленными старшими битами в качестве адресов ядра — все пользовательские адреса должны иметь старшие 17 бит, все 0

Таким образом, это дает вам множество способов упаковать действительный указатель менее чем в 64 бита, а затем восстановить исходный указатель с помощью инструкций сдвига и/или маски.

Если вам нужно только 3 бита и вы всегда используете указатели с выравниванием по 8 байтам, вы можете использовать нижние 3 бита для кодирования дополнительной информации и маскировать их перед использованием указателя.

Если вам нужно больше битов, вы можете сдвинуть указатель вверх (влево) на 16 бит и использовать эти младшие 16 бит для информации. Чтобы восстановить указатель, просто сдвиньте вправо на 16.

Чтобы выполнять операции сдвига и маскирования указателей, вам нужно привести их к intptr_t или int64_t (они будут одного типа в любой 64-битной реализации C или C++).


1Есть некоторые намеки на то, что скоро может появиться аппаратное обеспечение, которое расширяет это до 56 бит, поэтому только 9 старших бит должны быть 0 или 1, но пройдет некоторое время, прежде чем какая-либо ОС будет поддерживать это

person Chris Dodd    schedule 25.05.2020
comment
Спасибо за ответ! - person thebear8; 26.05.2020