ASM (x86-64)

Learn about the assembly language understood by our home computers

Easy

ASM (x86-64)
Operators

ASM_(x86-64)::Operators

Now we understand how to assign values to and between registers, but that wouldn't be very useful to do much. That's where operators come in. If you've never heard of the term operators from programming, it is just a fancy way to refer to actions that we can perform.

Basic operator syntax

In x86-64 assembly, most operators tend to follow a general structure. It's helpful to learn this structure so you can learn to use operators you've never seen before, even without consulting the documentation too much.

In general, most operators are used in the following structure:

operator src, dst

src and dst are referred to as operands, meaning they are the objects being operated on. So far, we've covered one type of operand, registers! Another popular form of operands are memory addresses, but we will cover this in a future lesson.

If you're familiar with programming, the above instruction will then do something like so.

src = operator(src, dst);

As we can see, the operator is applied to both operands, and the resultant value is stored back into the src operand. Let's try this out with a real operator.

Arithmetic Operators

As children the first operator we usually learn is addition. Let's do the same here.

add src, dst

The add instruction is the operator that handles addition (+)! As mentioned earlier, the above instruction will reassign src with the value of add(src, dst) (src + dst). Try to predict the resultant value of rax, before running the code to verify your answer.

Initializing...

CODE [0x400000]
Registers
rax:
rbx:
rcx:
rdx:
rdi:
rsi:
r8 :
r9 :
r10:
r11:
r12:
r13:
r14:
r15:
rbp:
rsp:
rip:
On top of add, there are various other instructions for the other arithmetic operations. We've listed the common ones below.

sub

sub is used for subtraction (-). It's functionality is very similar to that of add.

Initializing...

CODE [0x400000]
Registers
rax:
rbx:
rcx:
rdx:
rdi:
rsi:
r8 :
r9 :
r10:
r11:
r12:
r13:
r14:
r15:
rbp:
rsp:
rip:

imul/mul

imul is used for signed multiplication (*).

There are three forms that can be used for this instruction:

  1. one-operand form
  2. two-operand form
  3. three-operand form

two-operand form is similar to that of add and sub. Instructions using this form will be written as:

imul src, dst

Which results in

src = src * dst

one-operand form implicitly assigns the src operand as the rax register. Therefore, you only need to specify the dst operator. The effects of the instruction will be similar to the two-operand form.

We will leave explanation of three-operand form as a exercise of documentation reading to you.

Here, you can see all three forms of the instruction being used. Be sure to step through the code and predict the result of each instruction before it runs.

Initializing...

CODE [0x400000]
Registers
rax:
rbx:
rcx:
rdx:
rdi:
rsi:
r8 :
r9 :
r10:
r11:
r12:
r13:
r14:
r15:
rbp:
rsp:
rip:

overflows

One key difference that the one-operand form has in imul is tht it is the only one that can support an overflow of the dst register. As we know, the operands we have current support up to 64-bits of data. However, multiplying 2 64-bit values could lead to a value larger than 64-bits. Usually, the value is truncated to 64-bits, meaning that the calculation will be done correctly, but any bits beyond 64-bits will just be removed and ignored.

For the one-operand form of imul, it will set rdx to the bits of the calculation that exceed 64-bits. This allows for greater range of calculation.

mul

mul is very similar to one-operand imul, except that the operands are treated as unsigned values.

idiv/div

idiv and div are used for division (*). Similar to imul and mul, they are the signed and unsigned versions respectively.

Binary Operators

not

The not instruction takes one operand, and performs a binary NOT. Also known as one's complement negation, or "flipping all the bits".

and

The and instruction take two operands src and dst and performs a binary AND.

or

The or instruction take two operands src and dst and performs a binary OR.

xor

The xor instruction take two operands src and dst and performs a binary exclusive-OR.

Initializing...

CODE [0x400000]
Registers
rax:
rbx:
rcx:
rdx:
rdi:
rsi:
r8 :
r9 :
r10:
r11:
r12:
r13:
r14:
r15:
rbp:
rsp:
rip:

Unare Quiz #1

To test your knowledge thus far, we've prepared our special unare challenges! Try to understand the assembly snippet below, and write the corresponding C code that could generate such a assembly snippet.

Few things to note:

The first and last few instructions can be ignored as they are instructions preparing the stack, generated by the compiler.

push rbp
mov rbp, rsp
...
pop rbp
ret

The first 6 arguments of a function are passed in the rdi, rsi, rdx, rcx, r8, r9 registers. The return value of a function is copied into rax before the function returns.

With this knowledge, give this problem a try!

Quiz

Write the equivalent C code for the following assembly (x86-64) snippet.

Assembly (x86-64)

C code

Click for answer