Vous êtes sur la page 1sur 7

machine instructions for control

addl %edx, %eax

eax = eax + edx


eip = eip + 2 (# bytes in current insn)

instructions that affect %eip in other ways


unconditional jump:
jmp S
eip = S
conditional jump
jg, jl, je, etc.
if statements are usually converted into a conditional jump
example:
int x, y, a, b;
void foo() {
if (x < y)
a = 27;
else
b = 19;
}
gcc -m32 -O2
foo:

L12

movl x, %eax
cmpl y, %eax
jg L12
movl $27, a
ret
movl $19, b
ret

Loops
while (some long expression E) {
some long statement S;
}
converted to
L1:
L3:

jmp L3
dozens of instructions for S
dozens of instructions for E
testl %eax, %eax
jnz L1

assembly instructions are not necessarily in the same order as the original C code
do S

while (E);
converted into the same instructions but without the initial jmp L3
for (E1, E2, E3)
S;
converted to

L12:
L10:

e1
jmp L10
S
e3
e2
tstl %eax %eax
jnz L12
e1
jmp L9
e2
tstl %eax, %eax
jnz L90
S
e3

switch (E) {
case -1: S1; break;
case 0: S2; break;
default: S3; break;
}
converted to
e:

L12:
L20:

%eax
tstl %eax, eax
jz L12
cmpl $-1, %eax
je L20
S3
jmp L100
S2
jmp L100
S1
jmp L12

L100:
or can jump directly to the memory location that a register points to based on a
table
e
%eax (1, 19, 57, 97231)

movl tab(, %eax, 4), %edx


jmp (%edx)
tab:
1

19

57

L3
L19
L100

stack pointer pointing to an odd value not aligned with the boundaries of each word
is forbidden by the x86 ABI
selection overlaps another
word
%esp
stack alignment
x86 multiple of 8 on procedure entry
x86-64
multiple of 16

Recursion
ex. function f calls itself:
main f g h f
stack:
fs stuff
hs stuff
gs stuff
fs stuff
mains stuff
A frame is a contiguous stack region associated with a procedure instance
outgoing args

%eb
p

0
4
8
12

fs frame
fs locals
fs temps
saved %ebp
return address
fs arg 1
hs frame
fs arg 2
all args

pushl %ebp
movl %esp, %ebp

subl $4400, %esp


[do work]
addl $4400, %esp
popl %ebp
ret
struct tree {
struct tree *left, *right;
int val;
};
void preorder(struct tree *t, void (*visit)(int)) {
if (t) {
visit(t->val);
preorder(t->left, visit);
preorder(t->right, visit);
}
}
generate assembly using
gcc -m32 -O0
gcc -m32 -O2
gcc -m64 -O2
4/16/15
extern void visit(int);
void postorder(struct tree *t) {
if (t) {
postorder(t->left);
postorder(t->right);
visit(t->val);
}
}
gcc -m64 -O2
postorder:
testq %rdi, %rdi
je
.L12
pushq %rbp
pushq %rbx
movq %rdi, %rbx
movq %rsi, %rbp
subq $8, %rsp
movq (%rdi), %rdi
call
postorder
movq 8(%rbx), %rdi
movq %rbp, %rsi (bug?)
call
postorder
movl 16(%rbx), %edi
addq $8, %rsp

xorl
popq
popq
jmp
L12

%eax, %eax
%rbx
%rbp
visit

rep ret

x86-64 registers
%rax
return value (caller saved)
%rbx
callee saved
%rcx
arg #4
%rdx
arg #3
%rsi
arg #2
%rdi
arg #1
%rsp
stack pointer
%rbp
callee saved
%r8
arg #5
%r9
arg #6
%r10
callee saved
%r11
(used for linking)
%r1215
callee saved
callee saved - caller cannot change register, except temporarily, callee can set them
and doesnt need to restore

C pointers

Just 32-bit integers on x86, 64-bit integers on x86-64


every pointer has a type
int v;
&v is type int*
&a[10] = a + 10 = 10 + a = &10[a]
&*p = p
*&v = v
both are optimized away by compilers
void *p = &v;
void *vp = p;
char *q = vp;

compiler won't warn, void can be cast to anything

typedef char big[10000];


big* bigsub(big *a, long i) {
return a+i;
}
-m32 -O2

bigsub:
mull
addl
ret

$10000, 8(%esp), %eax


4(%esp), %eax

char **charptrsub(char **a, long i) {


return a+i;
}
charptrsub:
movl 8(%esp), %eax
movl 4(%esp), %edx
leal (%edx, %eax, 4), %edx
ret
long double ldoublesub(long double *a, long i) {
return a+i;
}
ldoublesub:
movl
movl
leal
leal
ret

8(%esp), %eax
4(%esp), %edx
(%eax, %eax, 2), %eax
(%edx, %edx, 4), %eax

eax = 3*i
eax = eax*4 + a

Nested Arrays
double a[100][200];
&a[i][j] = (a + i * 1600)*8
memory representation:
a[99]
a[99]

[199]
[198]

a[0][199]

a[0][2]

a[0][1]

Structures

Heterogeneous components
# of elements fixed at compile time
struct {
char c;
int i;
long l;
}
each variable is padded to be properly aligned in memory

a[0][0]

[
c in location 10000
i in location 10004

l i???c]

struct s {
char c;
int i;
char d;
int j;
}
int* foo(struct s, *p) {
return &p->j;
}
equivalent to (int*)((char*)p + 12)
in memory:
[ j| ?|d| i| ?|c]
12
8 4
0
struct s a[100];
&a[i] equivalent to a + 8*i because char is size 8
can check alignment of things in C11 with
gcc -std=gnu11
_Alignof(struct s)
signed int i:9;
signed int foo:1;
register int i = 27;

//9 bit int


//1 bit int (bool foo:1)