#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. Спасибо — Да, отсюда и мое «часто» (и я не потрудился перепроверить, правильно ли я запомнил детали).