x86_64 Linux 3.0: неверные адреса памяти - PullRequest
3 голосов
/ 25 января 2012

Процессы в Linux 3.0 на архитектуре x86_64 имеют 64-разрядное виртуальное адресное пространство.

Очевидно, что 0 гарантированно будет недопустимым адресом памяти [см. Определение ниже] в этом адресном пространстве,поскольку это используется для указания указателя NULL.

Какие еще 64-разрядные числа (если таковые имеются) гарантированно никогда не будут действительными адресами памяти и почему?

Например, может ли1 когда-нибудь будет действительный адрес?А как насчет 2^64-1?

Определение : Что вы подразумеваете под " гарантированно недопустимым адресом памяти "?

void deref_and_assign(uint64_t i)
{
    char* p = (char*) i;
    *p = 42;
}

ДляДля целей этого вопроса гарантированная недействительная ссылка на память означает, что функция deref_and_assign всегда будет вызывать SIGSEGV.

Ответы [ 2 ]

3 голосов
/ 25 января 2012

В x86 / 64, если включена трансляция страниц и память по виртуальному адресу 0 недоступна (из-за способа отображения физической памяти в виртуальное адресное пространство), 1 ... 4095 также не будут доступны, потому чтовсе эти 4096 адресов соответствуют одной странице памяти и могут быть доступны или недоступны в целом.Хорошей идеей является никогда не отображать память по виртуальному адресу 0. Не отображать это поможет поймать много разыменований нулевого указателя.Здесь ЦП будет генерировать ошибку страницы (также известную как #PF) в несопоставленных местах или местах, требующих более высоких прав, чем выполняемый в данный момент код.

В 64-битном режиме ЦП может реализовывать меньше (48+), чем 64 виртуальныхбиты адреса и 64-битные адреса должны содержать либо все нули, либо все единицы в битах, которые не реализованы (значение 0 или 1 должно совпадать со значением наиболее значимого реализованного бита адреса, причем все они могутинтерпретировать как расширение знака адреса).Такие адреса называются каноническими.Если вы попытаетесь прочитать или записать память, используя неканонический адрес, вы получите общую ошибку защиты (AKA #GP).

Таким образом, в зависимости от ОС (фактически, от ее структуры памяти) ифактический процессор вы можете придумать диапазоны "недопустимых" адресов памяти.Если вы попытаетесь прочитать / записать память ядра из приложения пользовательского режима, вы получите #PF.Если вы попытаетесь прочитать / записать не отображенную память (например, по адресу от 0 до 4095), вы получите #PF.Если вы попытаетесь читать / писать по неканоническому адресу, вы получите # GP.

Это то, что вы ищете?

0 голосов
/ 25 января 2012

Вы проверили, что процесс Linux не может mmap с MAP_FIXED сегментом, начинающимся с (void*)0.

Таким образом, для практических целей можно смело предположить, что самая первая страница 0 - 0xfff никогда не * mmap (размер страниц 4 КБ зависит от процессора и системы, но очень часто 4 КБ).Тогда вы можете предположить, что разыменование указателей (из приложения Linux) внутри этой первой страницы дает SIGSEGV

Аналогично для последней страницы, заканчивающейся на 0xffffffffffffffff (то есть 2 ^ 64-1)

...