Сборка:Перемещение между двумя адресами памяти
-
18-09-2019 - |
Вопрос
Я пытаюсь освоить ассемблер (так что потерпите немного), и я получаю ошибку компиляции в этой строке:
mov byte [t_last], [t_cur]
Ошибка заключается в
error: invalid combination of opcode and operands
Я подозреваю, что причина этой ошибки заключается просто в том, что команда mov не может перемещаться между двумя адресами памяти, но полчаса поиска в Google, и я не смог подтвердить это - так ли это?
Кроме того, предполагая, что я прав, это означает, что мне нужно использовать регистр в качестве промежуточной точки для копирования памяти:
mov cl, [t_cur]
mov [t_last], cl
Какой регистр рекомендуется использовать (или я должен использовать стек вместо этого)?
Решение
Ваше подозрение верно, вы не можете переходить от воспоминания к воспоминанию.
Подойдет любой регистр общего назначения.Не забудьте нажать на регистр, если вы не уверены, что находится внутри него, и восстановить его обратно после завершения.
Другие советы
Это действительно просто в 16 битном формате, просто выполните следующее:
push di
push si
push cx
mov cx,(number of bytes to move)
lea di,(destination address)
lea si,(source address)
rep movsb
pop cx
pop si
pop di
Примечание:нажатия и всплывающие окна необходимы, если вам нужно сохранить содержимое регистров.
Существует также команда MOVS для перемещения данных из памяти в память:
MOV SI, OFFSET variable1
MOV DI, OFFSET variable2
MOVS
Технически возможно перемещаться из памяти в память.
Попробуйте использовать ДВИЖЕНИЯ (переместить строку), и настройка [E]СИ и [E]DI, в зависимости от того, хотите ли вы передать байт (ы), слово (ы) и т.д.
mov si, t_cur ; Load SI with address of 't_cur'
mov di, t_last ; Load DI with address of 't_last'
movsb ; Move byte from [SI] to [DI]
; Some dummy data
t_cur db 0x9a ; DB tells NASM that we want to declare a byte
t_last db 0x7f ; (See above)
Это менее эффективно, чем использование обычной загрузки + хранилища с одним временным регистром, но оно выполняет фактическое копирование с помощью одной инструкции.
Вот как это делается ДВИЖЕНИЯ следует ли использовать и как это работает:https://www.felixcloutier.com/x86/movs:movsb:movsw:movsd:movsq
Обычно он используется только с rep
префикс для блочных копий, а не для отдельного элемента.(Современные процессоры имеют довольно эффективный микрокод для rep movsb
что это близко к скорости цикла с использованием инструкций AVX vector load / store.)
Это верно, машинный код x86 не может кодировать инструкцию с двумя явный операнды памяти (произвольные адреса , указанные в []
)
- Почему не разрешено перемещение из памяти в память?
- Какие инструкции x86 принимают два (или более) операнда памяти?
Какой рекомендуемый регистр
Любой регистр, который вам не нужно сохранять / восстанавливать.
Во всех основных 32-разрядных и 64-разрядных соглашениях о вызовах EAX, ECX и EDX ограничены вызовами, поэтому AL, CL и DL являются хорошим выбором.Для копии в байтах или словах обычно требуется movzx
загружается в 32-разрядный регистр, затем в 8-разрядное или 16-разрядное хранилище.Это позволяет избежать ложной зависимости от старого значения регистра.Используйте только узкий 16- или 8-разрядный mov
загружайте, если вы активно хотеть для слияния с младшими битами другого значения.x86-х годов movzx
является аналогом таких инструкций, как ARM ldrb
.
movzx ecx, byte [rdi] ; load CL, zero-extending into RCX
mov [rdi+10], cl
В 64-разрядном режиме SIL, DIL, r8b, r9b и так Далее Также являются прекрасным выбором, но требуют префикса REX в машинном коде для хранилища, так что есть небольшая причина по размеру кода избегать их.
Обычно избегайте написания AH, BH, CH или DH по соображениям производительности, если только вы не прочитали и не поняли следующие ссылки, и любые ложные зависимости или остановки при слиянии частичных регистров не будут проблемой или вообще не произойдут в вашем коде.
- Почему GCC не использует частичные регистры?
- Как именно выполняются частичные регистры в Haswell / Skylake?Написание AL, похоже, имеет ложную зависимость от RAX, а AH непоследовательно
(или мне следует вместо этого использовать стек)?
Во-первых, вы вообще не можете вставить ни одного байта, поэтому вы никак не могли бы выполнить байтовую загрузку / сохранение байтов из стека.Для word, dword или qword (в зависимости от режима процессора) вы могли бы push [src]
/ pop [dst]
, но это намного медленнее, чем копирование через регистр.Это приводит к дополнительной задержке переадресации хранилища / перезагрузки, прежде чем данные могут быть прочитаны из конечного пункта назначения, и требует больше операций ввода-вывода.
Если только где-нибудь в стеке является желаемое место назначения, и вы не можете оптимизировать эту локальную переменную в регистр, и в этом случае push [src]
просто отлично скопировать его туда и выделить для него место в стеке.
Видишь https://agner.org/optimize/ и другие ссылки на производительность x86 в вики - тег x86
Просто хочу обсудить с вами "барьер памяти".В коде c
a = b;//Take data from b and puts it in a
были бы собраны для
mov %eax, b # suppose %eax is used as the temp
mov a, %eax
Система не может гарантировать атомарность назначения.Вот почему нам нужен юань (читать барьер)