Сборка:Перемещение между двумя адресами памяти

StackOverflow https://stackoverflow.com/questions/1299077

Вопрос

Я пытаюсь освоить ассемблер (так что потерпите немного), и я получаю ошибку компиляции в этой строке:

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 не может кодировать инструкцию с двумя явный операнды памяти (произвольные адреса , указанные в [])

Какой рекомендуемый регистр

Любой регистр, который вам не нужно сохранять / восстанавливать.

Во всех основных 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 по соображениям производительности, если только вы не прочитали и не поняли следующие ссылки, и любые ложные зависимости или остановки при слиянии частичных регистров не будут проблемой или вообще не произойдут в вашем коде.


(или мне следует вместо этого использовать стек)?

Во-первых, вы вообще не можете вставить ни одного байта, поэтому вы никак не могли бы выполнить байтовую загрузку / сохранение байтов из стека.Для 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

Система не может гарантировать атомарность назначения.Вот почему нам нужен юань (читать барьер)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top