CS 208 s22 — Arithmetic in x86-64 Assembly
Table of Contents
1 Arithmetic Instructions
Instruction | Description | Effect |
---|---|---|
inc \(D\) |
\(D + 1 \rightarrow D\) | increment |
dec \(D\) |
\(D - 1 \rightarrow D\) | decrement |
neg \(D\) |
\(-D \rightarrow D\) | negate |
not \(D\) |
\(~D \rightarrow D\) | complement |
add \(S,\:D\) |
\(D + S \rightarrow D\) | add |
sub \(S,\:D\) |
\(D - S \rightarrow D\) | subtract |
imul \(S,\:D\) |
\(D * S \rightarrow D\) | multiply |
xor \(S,\:D\) |
\(D\,\widehat{}\,S \rightarrow D\) | exclusive-or |
or \(S,\:D\) |
\(D\,\vert\,S \rightarrow D\) | or |
and \(S,\:D\) |
\(D\,\&\,S \rightarrow D\) | and |
sal \(k,\:D\) |
\(D\) << \(k \rightarrow D\) |
left shift |
shl \(k,\:D\) |
\(D\) << \(k \rightarrow D\) |
left shift (same as sal ) |
sar \(k,\:D\) |
\(D\) >> \(k \rightarrow D\) |
arithmetic right shift |
shr \(k,\:D\) |
\(D\) >> \(k \rightarrow D\) |
logical right shift |
2 Thinking in Assembly
2.1 Assembly to C
A C function with the signature long f(long *p, long i)
compiled to the following assembly code:
f: movq %rsi, %rax addq (%rdi), %rax movq %rax, (%rdi) ret
Register | Use |
---|---|
%rdi |
1st argument (p ) |
%rsi |
2nd argument (i ) |
Possible C code for this function:
long f(long *p, long i) { long return_value = i; // move %rsi to %rax (%rax holds the return value for a function) return_value += *p; // dereference the pointer p, add that to %rax *p = return_value; // move the value in %rax to the memory location p points to return return_value; // return (using %rax as the return value) }
A more concise version that has the same effect:
long f(long *p, long i) { *p += i; return *p; }
2.2 leaq
Instruction
- "load effective address", but more often "lovely efficient arithmetic"
- instead of reading from the memory location given by the source operand, copies the effective address to the destination
- generate pointers for later memory references
- can also do a muliply and an addition in a single instruction
leaq 7(%rdx, %rdx, 4), %rax
will set%rax
equal to5 * %rdx + 7
- destination must be a register
- must have the
q
size designation on a 64-bit systemlea
specifically works with a memory addresses, which will always by 8 bytes on a 64-bit system
movq %rdx, %rax
vsmovq (%rdx), %rax
vsleaq (%rdx), %rax
- rdx holds 0x100, memory address 0x100 holds 0xab
3 Review
4 C to Assembly
Translate this C code to assembly3
long arith(long x, long y, long z) { long t1 = x + y; long t2 = z + t1; long t3 = x + 4; long rval = t2 * t3; return rval; }
Register | Use |
---|---|
%rdi |
1st argument (x ) |
%rsi |
2nd argument (y ) |
%rdx |
3rd argument (z ) |
5 Practice
- Do CSPP practice problems 3.6 (p. 192), 3.7 (p. 193), 3.10 (p. 196), and 3.11 (p. 197)
- To do the comparison for 3.11 part C, you can write an assembly file containing both instructions (e.g.,
xor_test.s
), compile it to an object file (xor_test.o
) and useobjdump
to print out the bytes. See section 3.2.2 of CSPP for an example.
- To do the comparison for 3.11 part C, you can write an assembly file containing both instructions (e.g.,
Footnotes:
1
mov
copies the source to the destination, possibly computing a memory address and reading or writing a value there, while lea
computes a memory address and stores that address in a register (instead of going to memory)
2
0x8(%rdx)
accesses0xf008
(%rdx,%rcx)
accesses0xf100
(%rdx,%rcx,4)
accesses0xf400
0x80(,%rdx,2)
accesses0x1e080
3
One possible assembly implementation of arith
:
arith: addq %rdi, %rsi // computes t1 = x + y, overwrites y since we don't need it after this leaq (%rsi,%rdx), %rax // computes t2 = z + t1 addq $4, %rdi // computes x + 4 imulq %rdi, %rax // computes t2 * t3, stores in %rax to set return value ret