Подтвердить что ты не робот

Сборка: переключение между двумя адресами памяти

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

mov byte [t_last], [t_cur]

Ошибка

error: invalid combination of opcode and operands

Я подозреваю, что причина этой ошибки просто в том, что команда mov не может перемещаться между двумя адресами памяти, но полчаса поиска в Google, и я не смог подтвердить это - так ли это?

Кроме того, если я прав, это означает, что мне нужно использовать регистр в качестве промежуточной точки для копирования памяти:

mov cl, [t_cur]
mov [t_last], cl

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

4b9b3361

Ответ 1

Ваше подозрение верное, вы не можете переместиться из памяти в память.

Любой регистр общего назначения. Не забудьте ЗАПИСАТЬ регистр, если вы не уверены, что внутри него и восстановить его после выполнения.

Ответ 2

Это очень просто в 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

Примечание. Точки и всплывающие окна являются необходимыми, если вам нужно сохранить содержимое регистров.

Ответ 3

Также существует команда MOVS для перемещения данных из памяти в память:

MOV SI, OFFSET variable1
MOV DI, OFFSET variable2
MOVS

Ответ 4

Это верно, машинный код x86 не может кодировать инструкцию с двумя явными операндами памяти (произвольные адреса указаны в [])

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

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

Во всех основных 32-битных и 64-битных соглашениях о вызовах EAX, ECX и EDX имеют блокировку вызовов, поэтому AL, CL и DL являются хорошим выбором. Для копирования байтов или слов обычно movzx загрузка 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 по соображениям производительности, если только вы не прочитали и не поняли следующие ссылки, и любые ложные зависимости или срывы частичных регистров не будут проблемой или вообще не произойдут в вашем коде,


(или я должен использовать стек вместо)?

Во-первых, вы вообще не можете выдвинуть один байт, поэтому вы никак не могли бы сделать загрузку байтов/хранилище байтов из стека. Для слова, слова или qword (в зависимости от режима процессора) вы можете push [src]/pop [dst], но это намного медленнее, чем копирование через регистр. Он вводит дополнительную задержку пересылки хранилища/перезагрузки хранилища, прежде чем данные могут быть прочитаны из конечного места назначения, и занимает больше мопов.

Если где-то в стеке нет желаемого места назначения, и вы не можете оптимизировать эту локальную переменную в регистр, в этом случае push [src] просто прекрасно скопировать его и выделить для него место в стеке.

См. Https://agner.org/optimize/ и другие ссылки на производительность x86 в теге x86 вики.

Ответ 5

Технически возможно перейти из памяти в память.

Попробуйте использовать MOVS (переместить строку) и установить [E] SI и [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)

Это менее эффективно, чем использование обычного load + store с одним временным регистром, но оно делает фактическое копирование одной инструкцией.

Вот как MOVS следует использовать и как он работает: https://www.felixcloutier.com/x86/movs:movsb:movsw:movsd:movsq

Обычно он используется только с префиксом rep для блочных копий, а не для одного элемента. (Современные процессоры имеют достаточно эффективный микрокод для rep movsb который близок к скорости цикла, используя инструкции векторной загрузки/сохранения AVX.)

Ответ 6

Просто хочу обсудить "барьер памяти" с вами. В коде 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

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