Адресная каноническая форма и арифметика указателей

На архитектурах, совместимых с AMD64, адреса должны быть в канонической форме перед разыменовкой.

ОтРуководство Intel, раздел 3.3.7.1:

В 64-битном режиме адрес считается в канонической форме, если биты адреса от 63 до наиболее значимого реализованного бита микроархитектурой установлены на все единицы или все нули.

Теперь наиболее значимым реализованным битом в современных операционных системах и архитектурах является 47-й бит. Это оставляет нам 48-битное адресное пространство.

Особенно когдаASLR включен, пользовательские программы могут ожидать получения адреса с установленным 47-м битом.

Если используются такие оптимизации, как тегирование указателя, а верхние биты используются для хранения информации, программа должна убедиться, что 48-й и 63-й биты установлены обратно в 47-й бит перед разыменованием адреса.

Но рассмотрим этот код:

int main()
{
    int* intArray = new int[100];

    int* it = intArray;

    // Fill the array with any value.
    for (int i = 0; i < 100; i++)
    {
        *it = 20;
        it++;   
    }

    delete [] intArray;
    return 0;
}

Теперь посмотрим, чтоintArray есть, сказать:

0000 0000 0000 00000111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1100

После настройкиit вintArray и увеличиваетсяit один раз, и учитываяsizeof(int) == 4, это станет:

0000 0000 0000 00001000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

47-й бит выделен жирным шрифтом. Здесь происходит то, что второй указатель, полученный с помощью арифметики указателей, недопустим, потому что не в канонической форме. Правильный адрес должен быть:

1111 1111 1111 11111000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

Как программы справляются с этим? Есть ли гарантия у ОС, что вам никогда не будет выделена память, диапазон адресов которой не меняется на 47 бит?

Ответы на вопрос(1)

Ваш ответ на вопрос