Подтвердить что ты не робот

Инструкция MOVDQU + граница страницы

У меня есть простая тестовая программа, которая загружает регистр xmm с помощью команда movdqu, доступ к данным через границу страницы (OS = Linux).

Если отображается следующая страница, это работает отлично. Если это не отображается, тогда я получаю SIGSEGV, который, вероятно, ожидается.

Однако это уменьшает полезность неуравновешенных нагрузок немного. Кроме того, инструкции SSE4.2 (например, pcmpistri), которые допускайте, чтобы ссылки на неравнозначные ссылки отображали это поведение также.

Что все хорошо - кроме там много реализации strcmp используя pcmpistri, который я обнаружил, что, похоже, не рассматривают эту проблему вообще - и я смог выработать тривиальные тестовые приводят к сбою этих реализаций, тогда как байт по времени тривиальный Реализация strcmp будет работать отлично с тем же макетом данных.

Еще одно замечание - похоже, что реализация библиотеки GNU C для 64-разрядный Linux имеет вариант __strcmp_sse42, который, как представляется, использует pcmpistri более безопасным образом. Реализация этот strcmp довольно сложный, но, похоже, он тщательно пытается чтобы избежать проблемы с границей страницы. Я не уверен, что из-за вопрос, который я описываю выше, или это просто побочный эффект от попыток получить более высокую производительность, совместив данные.

В любом случае вопрос, который у меня есть, в первую очередь - где я могу узнать больше об этой проблеме? Я набрал "границу страницы переходов movdqu" и каждый вариант, о котором я могу думать в Google, но не натолкнулся ничего особенно полезного. Если кто-нибудь может указать мне на дополнительную информацию на этом было бы весьма полезно.

4b9b3361

Ответ 1

Во-первых, любой алгоритм, который пытается получить доступ к немаркированному адресу, вызовет SegFault. Если в потоке кода, отличном от AVX, используется 4 байтовая загрузка для доступа к последнему байту страницы и первым 3 байтам "следующей страницы", которые не были сопоставлены, тогда это также вызовет SegFault. Нет? Я считаю, что "проблема" в том, что регистры AVX (1/2/3) намного больше, чем "типичные", что алгоритмы, которые были небезопасными (но ушли с ним), попадают, если они тривиально распространяются на более крупные регистры.

У согласованных нагрузок (MOVDQA) никогда не может быть этой проблемы, поскольку они не пересекают границы их собственного размера или больше. Несбалансированные нагрузки CAN могут иметь эту проблему (как вы уже отметили) и "часто". Причина этого заключается в том, что инструкция определена для загрузки полного размера целевого регистра. Вы должны внимательно изучить типы операндов в определениях команд. Неважно, какая часть данных вам интересна. Это важно для того, что команда должна выполнять.

Однако...

AVX1 (Sandybridge) добавила возможность "маскированного перемещения", которая медленнее, чем movdqa или movdqu, но не будет (архитектурно) получать доступ к незапечатанной странице, пока маска не будет включена для той части доступа, которая упала бы на этой странице. Это предназначено для решения этой проблемы. В общем случае, двигаясь вперед, кажется, что маскированные части (см. AVX512) нагрузок/хранилищ также не будут вызывать нарушения доступа на IA.

(Это обход о поведении PCMPxSTRx. Возможно, вы могли бы добавить 15 байтов заполнения к вашим "строковым" объектам?)

Ответ 2

Перед аналогичной проблемой с библиотекой, которую я писал, Я получил некоторую информацию от очень полезного автора.

Ядро идеи состоит в том, чтобы выровнять 16-байтовое чтение до конца строки, а затем обрабатывать оставшиеся байты в начале. Это работает, потому что конец строки должен находиться на доступной странице, и вам гарантируется, что 16-байтовый усеченный стартовый адрес также должен находиться на доступной странице.

Поскольку мы никогда не читаем за строкой, мы не можем потенциально заблудиться на защищенной странице.

Чтобы обрабатывать начальный набор байтов, я решил использовать функции PCMPxSTRM, которые возвращают битмаску с соответствующими байтами. Тогда это просто вопрос сдвига результата, чтобы игнорировать любые биты маски, которые происходят перед истинным началом строки.