Intel I
Intel I
Intel I
Intel Assembly - I
Prof. Kasım Sinan Yıldırım, University of Trento
The Intel x86 Evolution
● An architecture evolved over almost 40 years:
○ E.g., several new features added to the original instruction set
2
The Intel x86 Evolution
● Further evolution…
○ i486 (1989): pipelined, on-chip caches and FPU
○ Pentium (1993): superscalar, 64-bit datapath
○ Pentium Pro (1995), Pentium II (1997)
○ Pentium III (1999): Added SSE (Streaming SIMD Extensions)
○ Pentium 4 (2001): New microarchitecture, Added SSE2 instructions
○ AMD64 (2003): extended architecture to 64 bits
○ Intel Core (2006)
● X86 instruction set largely drove the PC generation of computers
○ still dominates the Cloud portion of the post-PC era.
○ Manufacturing 350M x86 chips per year
3
4
The Intel x86 ISA
● CISC (Complex Instruction Set Computer) architecture
● Provide more powerful instructions than those in RISC-V:
○ Reduces the number of instructions executed by a program.
● CISC processors:
○ Are larger as they contain more transistors
○ May take multiple cycles per line of code, decreasing efficiency
○ Lower clock speed
○ Complex use of pipelining
○ Compared to RISC, they are more complex, which means they are more expensive
5
Intel Assembly
● CISC: different instructions and addressing modes
○ we will not see everything
○ we will mainly focus on differences from RISC-V
● Compatibility:
○ various modes of operation
■ Modern 64-bit CPUs are still capable of running old code 8-bit
○ we will consider only 64-bit modes
6
General Purpose Registers
● They are all preceded by the prefix % (percent)
● 16 64-bit general purpose registers
● They have names that reflect backward compatibility:
○ %rax, %rbx, %rcx, %rdx, %rsi, %rdi, %rbp, %rsp
○ %r8, ..., %r15
○ %rsp: stack pointer
○ %rbp: base pointer
■ pointer to the stack frame
○ %rsi and %rdi for copying of array
■ source index and destination index
7
General Purpose Registers
● %rax-%rbp
○ extend 32-bit registers %eax-%ebp
■ extend 16-bit registers %ax-%bp
● %ax, %bx, %cx, and %dx extend 8-bit registers
indicated by replacing %x with %h or %l:
○ %ax == %ah + %al
● %r8-%r15
○ extend 32-bit registers %r8d-%r15d that
■ extend 16 bit registers %r8w-%r15w that
● include 8-bit registers %r8b-%r15b (least
significant byte)
8
Special Registers
● Instruction Pointer: %rip
● Flags register: %rflags
○ extends %eflags, which extends %flags
○ List of bits (flags) set by logic/arithmetic instructions
■ CF : Carry Flag → Set to 1 if the result is unsigned overflow or if there is carry-out
■ ZF : Zero Flag → Set to 1 if the result is zero
■ SF : Sign Flag → Set to 1 if the result is negative
■ OF : Overflow Flag → Set to 1 if the result has overflowed
○ Used by conditional jump instructions
■ Other flags control CPU operation (IF) or contain other information about the CPU
● There are also other special registers too (check other documents)
9
Intel instructions
● Too many (several online tutorials)
● For a more or less detailed list of instructions:
http://en.wikipedia.org/wiki/X86_instruction_listings
○ Many instructions have been kept for compatibility!
10
Intel instructions
● Typical syntax: <opcode> <source>, <destination>
○ Final character of opcode to indicate "width" (in bits) of the operands
11
Addressing Modes
● Mainly 2-operand instructions: second operand is the destination!
○ Limitation with compared to RISC-V:
■ Impossible to specify two operands and a different destination
● Source (first operand)
○ Immediate Operand (a constant with $ as prefix, e.g. $20)
○ Operand in Register (value of a register, e.g. %rax)
○ Operand in Memory (value in memory location
■ e.g., value at the address 0x0100A8
● Destination (second operand)
○ Operand in Register (one register as destination, e.g. %rdx)
○ Operand in Memory (a memory location specified by the address
■ e.g., location at the address 0x0AA0E2
12
Addressing Modes
● Access to memory location: <displ> (<base reg>, <index reg>, <scale>
■ <displacement>: constant (immediate value) at 8, 16 or 32 bits
● similar to RISC-V - but RISC-V only has 12-bit displacement/offset
■ <base>: value in register (as for RISC-V)
■ <index>: value in register (simplifies iteration on arrays)
■ <scale>: constant value: 1, 2, 4, or 8 (simplifies access to arrays with elements of size
1, 2, 4 or 8 bytes)
○ Address is formed as: displacement + base + (index*scale)
13
Addressing - examples
Name Format Example Description
Scaled index (rb, ri, s) movq (%rdx, %rcx, 4), %rax rax = Mem[rdx+rcx*4]
Scaled index + displacement Num(r b, ri, s) movq 35(%rdx, %rcx, 4), rax = Mem[rdx+rcx*4+35]
%rax
14
Addressing - Special Cases
● Scale = 1 (no scale): <displ> (<base reg>, <index reg>)
● No scale and index: <displ> (<base reg>)
○ Remember access for RISC-V. Only difference: the size in bits offset/displacement
15
Addressing Modes
● Instructions allow you to write to both registers and memory!
○ RISC-V: memory access only for load and store
● Constraint: no both operands in memory!
○ Valid combinations are:
■ Imm → Reg
■ Imm → Mem
■ Reg → Reg
■ Mem → Reg
■ Reg → Mem
16
Addressing Modes
● Both operands cannot be in memory
● E.g., movl 345, (%eax) is not allowed!
○ Because both destinations are in memory: Mem[eax] = Mem[345]
17
Most Common Instructions
● mov: copy data from source to destination
○ movsx: copy data with sign extension
○ movzx: copy data with zero extension
● add/adc: add and add with carry
● inc/dec: add/subtract 1
● sub/sbc: sub and sub with carry
● and/or/xor/not: bitwise boolean operations
○ Arithmetic/logical instructions modify flags (carry, zero, sign, ...)
○ Other instructions for flags modification: clc/stc, cld, cmc …
● neg: two’s complement (negation)
18
Most Common Instructions
● mul/imul signed/unsigned multiplication
● div/idiv signed/unsigned division
● rcl, rcr, rol, ror various forms of "rotate"
● sal, sar, shl, shr shift (arithmetic and logical)
● nop
19
Most Common Instructions
● push push data onto the stack: pushq %reg
○ Decreases %rsp by 8 and writes %reg to the memory specified in %rsp
● Example: pushq %rax
○ Equivalent to:
subq $8, %rsp
movq %rax, (%rsp)
● pop remove data from the stack: popq %reg
○ Stores the value at the address indicated by %rsp in %reg and increases %rsp by 8
● Example: popq %rdx
○ Equivalent to:
movq (% rsp),% rdx
addq $8, %rsp
20
Most Common Instructions
● cmp and test
○ cmp: cmp arg1, arg2
■ Compare arg2 with arg1 (e.g. arg2 < arg1, arg2 = arg1, ...)
■ Do arg2 - arg1 and set flags of the flag register
■ arg1 and arg2 are not modified (subtraction result is not stored)
○ test: test arg1, arg2
■ Compare arg2 with arg1 (e.g. arg2 = arg1, ...)
■ Do arg2 & arg1 and set flag register flags
■ arg1 and arg2 are not modified (result of bitwise and is not stored)
21
Most Common Instructions
Instruction Synonym Cond. flag Description
● jmp unconditional jump
je label jz label ZF Equal or zero
● je/jnz/jc/jnc conditional jne label jnz label ~ZF Different or
jumps js label SF Non-zero
jns label ~SF Negative
jg label jnle label ~(SF^OF) & Non-negative
j <condition> jge label jnl label ~ZF Signed >
jl label jnge label ~(SF^OF) Signed >=
● The jump condition is jle label jng label (SF^OF) Signed <
ja label jnbe label (SF^OF) | ZF Signed <=
established based on the jae label jnb label ~CF & ~ZF Unsigned >
jb label jnae label ~CF Unsigned >=
values in the flag register jbe label jna label CF Unsigned <
○ jump if equal, jump if not CF | ZF Unsigned <=
zero, jump if carry, ...
22
Most Common Instructions
● call procedure call: call label
○ Pushes the address of the next instruction onto the stack
○ Implicitly executes:
subq $8, %rsp
movq %rip, (%rsp)
○ Modifies the program counter to go to the beginning of the desired procedure
● ret return from procedure: ret
○ Pops the return address from the stack and stores it in %rip
○ Changes the program counter to go to the next caller instruction
○ Implicitly executes:
movq (%rsp), %rip
addq $8, %rsp
23
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rax = ffff ffff 1234 5678
24
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rax = ffff ffff 1234 5678
25
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rax = ffff ffff 1234 5678
26
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rax = ffff ffff 1234 5678
27
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rax = ffff ffff 1234 5678
28
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rax = ffff ffff 1234 5678
29
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x004e4] = 0000 0000
Mem[0x004e0] = 0000 0000
rax = 7654 3210 fedc ba98
30
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x004e4] = 0000 0000
Mem[0x004e0] = 0000 0000
rax = 7654 3210 fedc ba98
31
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x004e4] = 0000 0000
Mem[0x004e0] = 0000 0000
rax = 7654 3210 fedc ba98
32
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x004e4] = 0000 0000
Mem[0x004e0] = 0000 0000
rax = 7654 3210 fedc ba98
33
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rax = ffff ffff 1234 5678
34
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rax = ffff ffff 1234 5678
35
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rax = ffff ffff 1234 5678
36
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rax = ffff ffff 1234 5678
37
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rax = ffff ffff 1234 5678
38
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rax = ffff ffff 1234 5678
39
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rax = ffff ffff 1234 5678
40
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rax = ffff ffff 1234 5678
41
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x004e4] = 7654 3210
Mem[0x004e0] = fedc ba98
rax = ffff ffff 1234 5678
42
move
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions: Mem[0x004e4] = 7654 3210
Mem[0x004e0] = fedc ba98
rax = ffff ffff 1234 5678
43
move (Zero, Signed)
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions:
Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rdx = 0123 4567 89ab cdef
● movslq 0x200, %rax rax = ffff ffff fedc ba98 Move sign-extended quadword
44
move (Zero, Signed)
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions:
Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rdx = 0123 4567 89ab cdef
● movslq 0x200, %rax rax = ffff ffff fedc ba98 Move sign-extended quadword
45
move (Zero, Signed)
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions:
Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rdx = 0123 4567 89ab cdef
● movslq 0x200, %rax rax = ffff ffff fedc ba98 Move sign-extended quadword
46
move (Zero, Signed)
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions:
Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rdx = 0123 4567 89ab cdef
● movslq 0x200, %rax rax = ffff ffff fedc ba98 Move sign-extended quadword
47
move (Zero, Signed)
● Syntax: mov[b,w,l,q] src, dst
● Initial conditions:
Mem[0x00204] = 7654 3210
Mem[0x00200] = fedc ba98
rdx = 0123 4567 89ab cdef
● movslq 0x200, %rax rax = ffff ffff fedc ba98 Move sign-extended quadword
● movzbq %dl, %rax rax = 0000 0000 0000 00ef Move zero-extended byte
48
Examples and, or, and, sub
● Syntax: and/or/and/sub[b,w,l,q] src, dst
● Initial conditions: Mem[0x00204] = 7654 3210
Mem[0x00200] = 0f0f ff00
rdx = ffff ffff 1234 5678
rax = 0000 0000 cc33 aa55
49
Load Effective Address
● lea load effective address: lea src, dest
● Copies source address (calculated by displacement, base, index and scale)
into the destination register
○ Calculates the address and stores it in the destination register without loading anything
from the memory.
50
Load Effective Address
● Example:
○ add the content of two registers and save the result in a third register.
● On Intel how can we add %rbx and %rcx while saving the result in %rax?
○ lea (%rbx, %rcx), %rax
51
Load Effective Address
● Syntax: lea src, dst
● Initial conditions:
rcx = 0000 0000 0000 0020
rdx = 0000 0089 1234 4000
rbx = ffff ffff ff00 0300
52
Load Effective Address
● Syntax: lea src, dst
● Initial conditions:
rcx = 0000 0000 0000 0020
rdx = 0000 0089 1234 4000
rbx = ffff ffff ff00 0300
53
Load Effective Address
● Syntax: lea src, dst
● Initial conditions:
rcx = 0000 0000 0000 0020
rdx = 0000 0089 1234 4000
rbx = ffff ffff ff00 0300
54
Load Effective Address
● Syntax: lea src, dst
● Initial conditions:
rcx = 0000 0000 0000 0020
rdx = 0000 0089 1234 4000
rbx = ffff ffff ff00 0300
55
Load Effective Address
void fl(int x) { // x = %edi
return 9 * x + 1;
}
fl: fl:
movl %edi, %eax # tmp = x
leal 1(%edi, %edi, 8), %eax #eax=1+%edi+ %edi*8
sall 3, %eax # tmp = 8*x
ret
addl %edi, %eax # tmp += x
addl $1, %eax # tmp += 1
ret
56
Other Instructions
● inc <register>/dec <register>
○ add / subtract 1 to/from a register
○ Why not just add $1, <register>?
● inc does not require you to encode the immediate value: saves at least 16 bits
57
cmov (Conditional Move)
● cmovx <source> <destination>
● copy a value (from source to destination) depending on the values of the condition codes
58
Example
● String C: character array is terminated by 0
○ ASCII: characters encoded in bytes
● Copy a string:
void copy_string(char *d, const char *s){
int i = 0;
while ((d[i] = s[i]) != 0) {
i += 1;
}
}
59
Recap:
● Calling Conventions are not really part of the architecture
○ Given a CPU/architecture, many different calling
○ They are used to make different compilers/libraries and other parts of the Operating
System compatible
60
x64 Calling Conventions
● First 6 arguments:
○ %rdi, %rsi, %rdx, %rcx, %r8 and %r9
● Other arguments (7 → n): on the stack
● Return values:
○ %rax and %rdx
● Preserved registers:
○ %rbp, %rbx, %r12, %r13, %r14 and %r15
● Not preserved registers:
○ %rax, %r10, %r11, in addition to the registers for parameter passing: %rdi, %rsi, %rdx, %rcx,
%r8 and %r9
61
Example
void copy_string(char *d, const char *s){
int i = 0;
while ((d[i] = s[i]) != 0) {
i += 1;
}
}
● We begin: i = 0; → %rax = 0
movq $0, %rax
62
Example
void copy_string(char *d, const char *s){
int i = 0;
while ((d[i] = s[i]) != 0) {
i += 1;
}
}
● First of all, let's load s[i] in %bl
● Use the indirect addressing mode:
L1: movb (%rsi, %rax), %bl # Init Loop
○ No need to load the address of the i-th element in a register (as in RISC-V)
● Now we store %bl in d[i]
movb %bl, (%rdi, %rax)
63
Example
void copy_string(char *d, const char *s){
int i = 0;
while ((d[i] = s[i]) != 0) {
i += 1;
}
}
64
Example
void copy_string(char *d, const char *s){
int i = 0;
while ((d[i] = s[i]) != 0) {
i += 1;
}
}
65
Example
.text
void copy_string(char *d, const char *s){ .globl copy_string
int i = 0; copy_string:
while ((d[i] = s[i]) != 0) { movq $0, %rax
i += 1; L1 :
} movb (%rsi, %rax), %bl
} movb %bl, (%rdi, %rax)
cmpb $0, %bl
je L2
add $1, %rax
jmp L1
L2 :
ret
66
Code examples - 1
Code Assembler code Assumptions/Notes