Нарушение доступа к сборке «movdqa»

#assembly #masm #sse2

#сборка #masm #sse2

Вопрос:

В настоящее время я пытаюсь написать функцию в сборке и хочу переместить 128 бит строки, расположенной по адресу памяти rdx , хранящемуся в xmm1 регистре.

Если я использую movdqa xmm1, [rdx] , я получаю исключение нарушения доступа при чтении в позиции 0xFFFFFFFFFFFFFFFF .

Если я попытаюсь использовать movdqu xmm1, [rdx] вместо этого, я не получу исключение. Проблема в том, что если я использую movdqu, порядок битов инвертируется.

Поэтому я не знаю, почему я получаю исключение при использовании movdqa , но не при использовании movdqu

Комментарии:

1. попробуйте выровнять память до 16 байт (чтобы строка начиналась с адреса, кратного 16)

2. я точно не знаю, что вы имеете в виду, но моя строка имеет длину ровно 16 байт

3. Если вы не используете «голый металл» или не находитесь в режиме ядра, этот адрес вам не принадлежит. Кроме того, он не выровнен. Наконец, это, вероятно, является результатом mmap() сбоя (или, не дай бог, вы присваиваете -1 указатель вручную в своем коде).

4. я передаю строку из c в свою функцию сборки, и если я отлажу программу, я могу ввести адрес в rdx вручную, и я смогу увидеть свою строку в правильном месте памяти

5. Если вы ожидаете, что это сработает, вам придется выровнять строку в вашем коде на C по 16-байтовой границе (используя атрибут выравнивания __declspec). Однако, если вы хотите выяснить, действительно ли это выравнивание вызывает проблему — попробуйте изменить инструкцию на MOVDQU в качестве теста. О, я вижу, вы сделали это в соответствии с вашим вопросом. Обращаемые байты были бы правильными из-за порядкового номера. Первый символ должен быть в младшем байте xmm1, а последний байт — в старшем байте xmm1

Ответ №1:

Большая часть этого уже была сказана в комментариях, но позвольте мне подвести итог. В вашем коде / вопросе возникают три проблемы:

1) MOVDQA требует, чтобы адреса, с которыми он имеет дело ( [rdx] в вашем случае), были выровнены по 16-байтовой границе и в противном случае вызовут нарушение доступа. Это то, что вы видите. Выравнивание по 16-байтовой границе (DQWORD) означает, что, используя ваш пример, вы должны читать, например 0xFFFFFFFFFFFFFFF0 , вместо 0xFFFFFFFFFFFFFFFF , потому что последнее число не делится на 16.

2) Адрес, который вы используете, 0xFFFFFFFFFFFFFFFF , почти наверняка недействителен.

3) При условии, что вы используете MOVDQA для чтения из допустимой ячейки памяти, выровненной по 16 байтам, результаты ( xmm1 в вашем случае) будут ИДЕНТИЧНЫ тем, которые вы используете MOVDQU . Единственное существенное различие между ними здесь заключается в том, что movdqU позволяет вам считывать данные из U выровненной (следовательно, U) памяти, тогда movdqA как требуется (16 байт) Привязанная ячейка памяти. (Последний случай часто будет быстрее, но я не думаю, что вам нужно беспокоиться об этом на данном этапе.)

Комментарии:

1. Спасибо, ваше право. Если я согласен с __delspec, я могу использовать MOVDQA. Кроме того, я новичок в сборке, поэтому я не знал, что проблема с «перевернутыми» битами на самом деле является ожидаемым поведением.

2. MOVDQA и MOVDQU имеют одинаковую производительность, если адрес выровнен во время выполнения, на процессорах Nehalem и более новых. В наши дни они отличаются только своим поведением с невыровненными адресами: либо ошибка, либо невыровненная загрузка (которая замедляется только в том случае, если она пересекает границу строки кэша, или намного хуже на pre-Skylake, границе страницы).

3. @PeterCordes. Спасибо — Да, отсюда и мое «часто» (и я не потрудился перепроверить, правильно ли я запомнил детали).