When moving data, it is not normally possible to move data from memory to memory without first storing the data in a register to transfer the data. About the only exception to this rule are the MOVS* instructions. This rule applies to almost all instructions, including comparison operations that do not save the result of their operations. If you have both operands to an instruction as memory locations it is almost certainly incorrect.
MOVZX reg, arg2 MOVSX reg, arg2
MOVZX
,
MOVSX
These instructions are like the MOV instruction, however when moving a value from a smaller register or memory location into a larger register, the value is padded out to fill the destination register appropriately. If the number to be copied is a signed value, use MOVSX to copy the sign bit (the upper most bit) from the source to all the remaining bits of the destination, allowing larger register to maintain the twos compliment value of the original signed value.
MOVZX always pads the upper bits of the destination with 0's which is what you want to use if the original value is an unsigned value.
MOVSX rax, ebx ; Copies the signed 32 bit ebx value to the 64 bit rax
LEA reg, memory
LEA
LEA allows us to use the same semantics for computing an address inside of []'s that MOV allows, but rather than loading the value at that address it just computes the address and loads the register with the computed address.
LEA rsi, [buf + r14] ; Loads rsi with the address of buf offset by the value in r14
The MOVS* instructions move bytes (MOVSB), words (MOVSW), double words (MOVSD) or quad words (MOVSQ) at a time. None of these instructions take any parameters instead they use the registers rsi and rdi as source and destination addresses respectively. If the directory flag (DF) is clear (i.e. 0) then rsi and rdi are incremented after the copy. If the direction flag is set (i.e. 1) then they are decremented after the copy.
MOVS*
MOVSB
MOVSW
MOVSD
MOVSQ
rsi
rdi
NOTE: Keep in mind that system calls will destroy the values of rsi/rdi so using MOVS* in a loop with a system call can be a problem.
; Copies 10 bytes from srcbuf to dstbuf. Uses LOOP instruction, see below: MOV rcx, 10 MOV rsi, srcbuf MOV rdi, dstbuf CLD ; increment rsi/rdi after copy .loop: MOVSB ; C equivalent to: *(rsi++) = *(rdi++); LOOP .loop ; == dec rcx; jnz .loop
CLD - Clears the direction flag
CLD
STD - Sets the direction flag
STD
LOOP addr
LOOP
LOOP uses the rcx register as a loop counter. Each time the loop instruction is run, rcx is decremented by one and then checked to see if it is zero, and if not, a conditional jump to arg is performed. LOOP is equivalent to:
rcx
DEC rcx JNZ arg
NOTE: Keep in mind that system calls will destroy the value of rcx so using LOOP with a loop containing a system call can be a problem.
CALL arg
CALL
RET [ val ]
RET
CALL pushes the current value of the instruction register (i.e. the address of the next instruction) onto the stack then jumps to arg. The address pushed onto the stack is often called the return address which is pop'ed off the stack when a RET instruction is encountered which loads the instruction register with the pop'ed value and execution will continue immediately after the original CALL instruction.
RET acccepts an immediate value, representing the number of additional bytes to remove from the stack (i.e. used to remove any parameters pushed to the stack prior to the system call.)
; Copies the string pointed to by rsi to destination pointed to by rdi strcpy: MOV al, BYTE [rsi] MOV BYTE [rdi], al CMP al, 0 ; Check for end of string JZ .finish INC rsi INC rdi JMP strcpy .finish: RET ... ; Setup parameters to strcpy: MOV rsi, string MOV rdi, buf CALL strcpy ; Copy string to buf ...
PUSH arg
PUSH
Pushes a value onto the hardware stack. The stack pointer is decremented by the size of the data then the data is moved onto the stack at the new stack pointer location.
POP arg
POP
Places the value at the current stack location into either a register or memory location then increments the stack pointer by the size of the data.
Almost all arithmetic operations will modify the flags: OF, SF, ZF, AF, and PF depending on the result of the particular operation. Thus most arithmetic operations can be followed by conditional jumps.
INC arg DEC arg
INC
DEC
Increments (INC) or decrements (DEC) the register or memory location by 1.
ADD
SUB
NEG
AND
OR
XOR
NOT
SHL
SHR
SAL
SAR
cl
Note how the shift instructions may only use the cl register or an immediate value as the second parameter.
MUL arg
MUL
The multiplication that MUL performs depends on the size of the argument:
The RDX:RAX register pairing for example represents a 128 bit quantity since multiplying the 64 bit RAX by another 64 bit quantity could result in a value requiring 128 bits to represent it. For most simple multiplications where one is not concerned with overflow, using the two operand IMUL instruction is more convenient.
IMUL
The first form of IMUL is the same as the unsigned MUL instruction and the registers used for the result depend on the size of the argument size.
DIV arg IDIV arg
DIV
IDIV
Both DIV (unsigned divide) and IDIV (signed divide) both operate in a manner similar to the MUL instruction, merely in reverse.
When dividing a small value by arg care must be taken to make sure that the ?D? register is initialized properly before the division is performed. If the division is to be unsigned, then setting the ?D? register to zero is sufficient, however if the value to be divided may be negative, then one of the following instructions should be used to extend the sign bit of the ?A? register into all the bits of the ?D? register.
Note: ?A? = one of AX, EAX, RAX depending on the size of register required.
CWD Copies the sign bit of AX into all the bits of DX. DX:AX ⟵ AX
CWD
CDQ Copies the sign bit of EAX into all the bits of EDX. EDX:EAX ⟵ EAX
CDQ
CQO Copies the sign bit of RAX into all the bits of RDX. RDX:RAX ⟵ RAX
CQO
These instructions take no operands. They are used to create the 32, 64 or 128 bit quantities used by DIV or IDIV.
To get the modulus (aka. remainder of integer division) we use the DIV or IDIV instruction to get the remainder:
; We assume that rax holds the number to be divided. MOV rbx, 10 ; We'll use rbx to hold the divisor CQO ; Copy the sign bit of rax into all the bits of rdx ; We could use MOV rdx, 0 since we're using DIV and not ; IDIV. DIV rbx ; Perform the division. ; At this point rax holds the result of the division and ; rdx holds the remainder (i.e. modulus result)