All arithmetic instructions are executed in (one of) the ALUs. The ALU can only perform integer arithmetics, for floating point instructions see chapter “Floating Point”.
Basic operations[edit | edit source]
Arithmetic instructions take two operands: a destination and a source.
- The destination must be a register or a memory location.
- The source may be either a memory location, a register, or a constant value.
Note that at most one operand may be a memory location.
Addition and Subtraction[edit | edit source]
|add addend, destination||GAS Syntax|
|add destination, addend||Intel Syntax|
This adds addend to destination and stores the result in destination.
|sub subtrahend, destination||GAS Syntax|
|sub destination, subtrahend||Intel Syntax|
add, only it subtracts subtrahend from destination instead.
destination -= subtrahend;
Multiplication[edit | edit source]
Unsigned Multiplication[edit | edit source]
This multiplies multiplicand by the value of corresponding byte-length in the accumulator.
|width of multiplicand||1 byte||2 bytes||4 bytes||8 bytes|
|product higher part stored in||
|product lower part stored in||
In the second case, the target is not
EAX for backward compatibility with code written for older processors.
Affected flags are:
- OF ≔ higher part of product ≠ 0
- CF ≔ higher part of product ≠ 0
All other flags are undefined.
Signed Multiplication[edit | edit source]
This instruction is almost like
mul, but it treats the sign bit (the MSB), differently.
imul instruction also accepts two other formats:
|imul multiplicand, destination||GAS Syntax|
|imul destination, multiplicand||Intel Syntax|
This multiplies destination by multiplicand and puts the result, the product, in destination.
|imul multiplicand, multiplier, product||GAS Syntax|
|imul product, multiplier, multiplicand||Intel Syntax|
This multiplies multiplier by multiplicand and places it into product.
Division[edit | edit source]
This divides the value in the dividend register(s) by divisor, see table below.
div, only signed.
|width of divisor||1 byte||2 bytes||4 bytes||8 bytes|
|remainder stored in||
|quotient stored in||
The circle (￮) means concatenation.
With divisor size 4, this means that
EDX are the bits 32-63 and
EAX are bits 0-31 of the input number (with lower bit numbers being less significant, in this example).
If quotient does not fit into quotient register, arithmetic overflow interrupt occurs. All flags are in undefined state after the operation.
Sign Inversion[edit | edit source]
Arithmetically negates the argument (i.e. two's complement negation).
Carry Arithmetic Instructions[edit | edit source]
|adc src, dest||GAS Syntax|
|adc dest, src||Intel Syntax|
Add with carry. Adds
dest, storing result in
dest. Usually follows a normal add instruction to deal with values twice as large as the size of the register. In the following example,
source contains a 64-bit number which will be added to
mov eax, [source] ; read low 32 bits mov edx, [source+4] ; read high 32 bits add [destination], eax ; add low 32 bits adc [destination+4], edx ; add high 32 bits, plus carry
|sbb src, dest||GAS Syntax|
|sbb dest, src||Intel Syntax|
Subtract with borrow. Subtracts
dest, storing result in
dest. Usually follows a normal sub instruction to deal with values twice as large as the size of the register.
Increment and Decrement[edit | edit source]
Increment[edit | edit source]
This instruction increments the register value augend by
It performs much faster than
add arg, 1, but it does not affect the CF.
Decrement[edit | edit source]
Operation[edit | edit source]
Decrements the value in minuend by 1, but this is much faster than the semantically equivalent
sub minuend, 1.
Operands[edit | edit source]
Minuend may be either a register or memory operand.
Application[edit | edit source]
- Some programming language represent Boolean values with either all bits zero, or all bits set to one. When you are programming Boolean functions you need to take account of this. The
decinstruction can help you with this. Very often you set the final (Boolean) result based on flags. By choosing an instruction that is opposite of the intended and then decrementing the resulting value you will obtain a value satisfying the programming language’s requirements. Here is a trivial example testing for zero.If you intend to set false the “erroneously” set
xor rax, rax ; rax ≔ false (ensure result is not wrong due to any residue) test rdi, rdi ; rdi ≟ 0 (ZF ≔ rax = 0) setnz al ; al ≔ ¬ZF dec rax ; rax ≔ rax − 1
1will be “fixed” by
dec. If you intend to set true, which is represented by −1, you will decrement the value zero, the “underflow” of which causing all bits to flip. Note, some architectures execute
decslowly, because of the fact that the flags register is overwritten only partially. It therefore is usually more efficient to use
negwhich will affect the CF too, though.
setz al ; al ≔ ZF neg rax ; rax ≔ 0 − rax
decdo not affect the CF, you can use these instructions to update a loop’s counting variable without overwriting some information stored in it. If you need an instruction that does not affect any flags while implicitly also performing a
dec, you could use the rather slow
Pointer arithmetic[edit | edit source]
lea instruction can be used for arithmetic, especially on pointers.
See chapter “data transfer”, § “load effective address”.