Home > Blockchain >  How to move data between registers without MOV instruction?
How to move data between registers without MOV instruction?

Time:10-17

How can I move like: MOV EAX, EBX without using the MOV operator?

CodePudding user response:

You can use lea with a simple register addressing mode as a slower mov (no mov-elimination and runs on fewer ports on Intel before Ice Lake), although it's still one instruction.

# nasm -f elf64 foo.asm && objdump -drwC -Mintel foo.o
0000000000000000 <.text>:
   0:   89 c8                   mov    eax,ecx
   2:   8d 01                   lea    eax,[rcx]  # in 64-bit code,
   4:   67 8d 01                lea    eax,[ecx]  # don't use 32-bit address size

As well as being slower, it takes extra code size for some registers (RSP/R12, and RBP/R13). (I used 64-bit operand-size so they'd all need REX prefixes, so for example RSP and R12 machine code lines up because they both need to use a SIB byte.

  10:   48 89 fe                mov    rsi,rdi
  13:   48 8d 37                lea    rsi,[rdi]
  16:   48 8d 34 24             lea    rsi,[rsp]
  1a:   49 8d 34 24             lea    rsi,[r12]
  1e:   48 8d 75 00             lea    rsi,[rbp 0x0]  # source had just [rbp]
  22:   49 8d 75 00             lea    rsi,[r13 0x0]

The same thing is of course possible in other modes, using lea eax, [ecx] as a 2-byte instruction. (Or 4 bytes in 16-bit mode for 32-bit registers. Even if you only want 16-bit registers, 16-bit mode needs 32-bit address size for source registers other than [bx|bp] [si|di] because of 16-bit addressing mode encoding limitations.)


push/pop is also an option, making it possible to copy a 64-bit register in only 2 bytes of machine code, instead of the usual 3:

  30:   52                      push   rdx
  31:   58                      pop    rax
  32:   48 89 d0                mov    rax,rdx
  35:   48 8d 02                lea    rax,[rdx]

This is useful for code-golf.


Other silly computer tricks include immediate imul by 1.

  40:   6b f1 01                imul   esi,ecx,0x1

Or if you want to consider multiple instructions, you could xor-zero the destination and add, or, or xor into it like Yuri suggests. Zero is the identity element for , | and ^.

Even less efficient would be to AND into all-ones, the identity element for &. (False dependency on the old value of EAX, and it's not xor-zeroing so it can't be eliminated (no execution unit) the way Sandybridge-family CPU do. Also larger code-size)

  or   eax, -1
  and  eax, ecx

CodePudding user response:

First, clean the data on one register XOR EAX, EAX, then perform OR EAX, EBX

  • Related