Ответ 1
Ваше подозрение верное, вы не можете переместиться из памяти в память.
Любой регистр общего назначения. Не забудьте ЗАПИСАТЬ регистр, если вы не уверены, что внутри него и восстановить его после выполнения.
Я пытаюсь изучить ассемблер (так что терпите меня), и я получаю ошибку компиляции в этой строке:
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
Это верно, машинный код 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 вики.
Технически возможно перейти из памяти в память.
Попробуйте использовать 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.)
Просто хочу обсудить "барьер памяти" с вами. В коде 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 (читать барьер)