2016-12-24 7 views
0

Я спрашиваю, что является лучшим способом переноса символов в строке справа или слева в сборке x86 с использованием библиотеки Irvine. есть пример: ABCD -> DABC и т. Д.Каков наилучший способ переноса символов в строке с помощью сборки?

Я написал этот код, но он дал мне неправильный результат.

r1: 
push ecx 
mov ecx,lengthof arr 
mov al,[esi+lengthof arr] 
mov bl,[esi] 
mov [esi],al 
mov [esi+1],bl 
inc esi 
innr1: 
mov al,[esi] 
mov bl,[esi+1] 
mov [esi],al 
inc esi 
loop innr1 
pop ecx 
loop r1 
+1

Цикл 'innr1:' ничего не делает, кроме загрузки 'al' и сохраняет его там, откуда он появился, и' bl' игнорируется. –

+0

Также (кроме случаев, когда 'lengthof arr' является последним * индексом *, а не * длиной *), у вас есть один за другим как при первой загрузке, так и в цикле. –

+0

Если 'innr1' будет делать что-то вроде' str [esi + 1] = str [esi] ', он либо перезапишет целую строку, либо, по крайней мере, второй символ, поскольку' mov [esi + 1], bl' перезаписывает char, который еще не был прочитан => потерян навсегда. Кстати, какой отладчик вы используете? Вы действительно писали столько кода, даже не пытаясь, если сначала «mov al, [esi + ...]' загружает последний символ? Должно быть сложно скомпоновать в сборке, уважительное отношение, похоже на мазохизм. Но вы также не показываете определение 'arr'. ИМО не понимает, как работает программирование в сборке. Сначала данные, вторичные. – Ped7g

ответ

5

В частном случае 4-байтовой строки, как ваш пример, используйте rol dword ptr [arr], 8 сделать Rotate вы описали.

(Помните, что x86 является малоприводным, поэтому сдвиги слева внутри многобайтового операнда перемещают байты на более высокие адреса).

В неспециальных случаях просто установите memmove() с нормальным контуром копирования, чтобы сдвинуть байты и скопируйте байт, который должен обернуться. (Вы можете загрузить байт, который обтекает перед входом в цикл копирования, так что вы можете перезаписать место, где она была сохранена.)


Лучший способ сделать это (для исполнения), вероятно, с SSE movups. rep movsb имеет высокий начальный загружаемый файл, и он медленнее по неверным данным. И, вероятно, плохо работает с перекрывающимися местами назначения, но я не помню, чтобы это упоминалось.

Если это не то, что вы имели в виду под «лучшим», будьте более конкретным и говорите «проще всего понять» или что-то в этом роде.

+2

'MOVS' был * разработан * для работы с перекрывающимися данными путем добавления DF, поэтому в случае OP ABCD -> DABC ему пришлось бы установить esi/edi для завершения буфера и' STD', чтобы сделать ' MOVS' назад. Высоко оптимизированный 'memmove (medium/large_size)' в 80386 раз включал пролог перемещения нескольких байтов в 4B, затем 'MOVSD' для выполнения задания и эпилог завершения оставшихся% 4 байтов. Кроме того, он имел две ветви, конечно, в зависимости от направления перекрытия. – Ped7g

+0

@ Ped7g: Спасибо, что описал, как добиться правильности с помощью 'movsb' /' movsd'. Я бы не хотел делать ставку на высокую производительность, хотя, когда dest находится в пределах 16B от источника. Когда они отдалены, оптимизированная реализация микрокода копирует 16B за раз. И если вы не вращаетесь на 16, либо src, либо dst должны быть неравнозначными, что 'rep movsb' не нравится (более низкая пропускная способность, а также более высокие накладные расходы на запуск для реализации Intel.) –

+0

@ Ped7g: Чтобы добиться правильности и высокой производительность с SSE, я думаю, вы можете просто убедиться, что вы идете в направлении, которое делает перекрытие идти так, как вы хотите. Я не думал об этом, но вам может понадобиться сохранить часть, которая «обертывается» в regs или tmp-буфере во время цикла копирования. Или вы можете конвейер загружать/копировать контур цикла, чтобы иметь по крайней мере пару регистров данных в полете сразу. Это позволяет делать 16B невыровненных нагрузок от частей буфера, которые еще не были затронуты (выровнены). Выйдите из петли в точке обертки и сохраните векторы в полете. –

Смежные вопросы