Вы находитесь на странице: 1из 97

CSCI-GA.

1144-001
PAC II

Lecture 4: Machine Code And


Assembly Language
Mohamed Zahran (aka Z)
mzahran@cs.nyu.edu
http://www.mzahran.com
Some slides adapted
(and slightly modified)
from:
Clark Barrett
Jinyang Li
Randy Bryant
Dave OHallaron

Intel x86 Processors


Evolutionary design
Backwards compatible up until 8086,
introduced in 1978

Complex instruction set computer (CISC)


Many instructions, many formats
By contrast, ARM architecture (in most cell
phones) is RISC

Intel x86 Evolution: Milestones


Name

8086

Transistors
29K

(1978)

MHz
5-10

First 16-bit processor. Basis for IBM PC & DOS


1MB address space

386

275K

(1985)

16-33

First 32 bit processor , referred to as IA32


Capable of running Unix

Pentium 4F

(2004)

125M

2800-3800

First 64-bit processor, referred to as x86-64

Core i7 (2008)
Xeon E7 (2011)

731M
2.2B

2667-3333
~2400

Instruction
Set
Architecture
(ISA)

Source Code to Execution


C source
Assembly
Assembly

Compiler

Assembly
Assembly
Assembly

Assembler

Library
Library
Library

Loader

DLL
DLL
DLL

Object
File
Object
File
Object File

Linker

Executable

Outline

Assembly primer
Addressing modes
Arithmetic operations
Condition codes:
Jump and branches loops
Procedures the stack

Assembly Programmers View


Memory

CPU

Addresses
PC

Registers

Data
Condition
Codes

Instructions

Execution context
PC: Program counter
Address of next instruction
Called EIP (IA32) or RIP (x86-64)

Registers
Heavily used program data

Condition codes
Info of recent arithmetic operation
Used for conditional branching

Object Code
Program Data
OS Data

Assembly Data Types


Integer data of 1, 2, or 4 bytes
Represent either data value
or address (untyped pointer)

Floating point data of 4, 8, or 10 bytes


No arrays or structures

3 Kind of Assembly Operations


Perform arithmetic on register or memory
data
Add, subtract, multiplication

Transfer data between memory and register


Load data from memory into register
Store register data into memory

Transfer control

Unconditional jumps to/from procedures


Conditional branches

Turning C into Object Code


Optimization
level

Output file
is p

Code in files p1.c p2.c


Compile with command: gcc O1 p1.c p2.c -o p
text

C program (p1.c p2.c)


Compiler (gcc S)

text

Asm program (p1.s p2.s)


Assembler (gcc c)

binary

Object program (p1.o p2.o)


Linker

binary

Executable program (p)

Static libraries
(.a)

Compiling Into Assembly


sum.c

sum.s

int sum(int x, int y)


{
int t = x+y;
return t;
}
gcc c sum.c

gcc S sum.c

gcc c sum.s

sum:
pushl %ebp
movl %esp,%ebp
movl 12(%ebp),%eax
addl 8(%ebp),%eax
popl %ebp
ret
objdump d sum.o

sum.o
80483c4:

55 89 e5 8b 45 0c 03 45 08 5d c3

Note: If your platform is 64-bit, you may want to force it to generate 32-bit assembly
by gcc m32 S sum.c to get the above output.

Compiling Into Assembly


sum.c

sum.s

int sum(int x, int y)


{
int t = x+y;
return t;
}

sum:
pushl %ebp
movl %esp,%ebp
movl 12(%ebp),%eax
addl 8(%ebp),%eax
popl %ebp
ret

Refer to register %eax


Refer to memory
at address %ebp+8

sum.o
80483c4:

55 89 e5 8b 45 0c 03 45 08 5d c3

general purpose

Origin
Integer Registers (IA32)
(mostly obsolete)
%eax

%ax

%ah

%al

accumulate

%ecx

%cx

%ch

%cl

counter

%edx

%dx

%dh

%dl

data

%ebx

%bx

%bh

%bl

base

%esi

%si

source
index

%edi

%di

destination
index

%esp

%sp

%ebp

%bp

stack
pointer
base
pointer
16-bit virtual registers
(backwards compatibility)

Moving Data: IA32


movl Source, Dest

Operand Types

Immediate: Integer constant


e.g. $0x400

Register: One of 8 integer registers


e.g. %eax

Memory: 4 consecutive bytes of memory at


address given by register
Simplest example (%eax)

movl Operand Combinations


Source

movl

Dest

Src,Dest

C Analog

Imm

Reg movl $0x4,%eax


Mem movl $-147,(%eax)

temp = 0x4;

Reg

Reg movl %eax,%edx


Mem movl %eax,(%edx)

temp2 = temp1;

Mem

Reg

movl (%eax),%edx

*p = -147;

*p = temp;
temp = *p;

No memory-to-memory instruction

Outline

Assembly primer
Addressing modes
Arithmetic operations
Condition codes:
Jump and branches loops
Procedures the stack

Memory Addressing Modes


Normal

(R)

Mem[Reg[R]]

Register R specifies memory address


movl (%ecx),%eax

Displacement D(R) Mem[Reg[R]+D]


Register R specifies start of memory region
Constant displacement D specifies offset
movl 8(%ebp),%edx

Using Simple Addressing


Modes
void swap(int *xp, int *yp)
{
int t0 = *xp;
int t1 = *yp;
*xp = t1;
*yp = t0;
}

swap:
pushl %ebp
movl %esp,%ebp
pushl %ebx

Set
Up

Point to first argument


Point to second argument

movl
movl
movl
movl
movl
movl

popl
popl
ret

8(%ebp), %edx
12(%ebp), %ecx
(%edx), %ebx
(%ecx), %eax
%eax, (%edx)
%ebx, (%ecx)

%ebx
%ebp

Body

Finish

Understanding Swap

123

Address
0x124

456

0x120
0x11c

%eax

0x118
Offset

%edx
%ecx
%ebx
%esi

yp

12

0x120

0x110

xp

0x124

0x10c

Rtn adr

0x108

%ebp

%edi

0x104

-4

%esp
%ebp

0x114

0x104

movl
movl
movl
movl
movl
movl

8(%ebp), %edx
12(%ebp), %ecx
(%edx), %ebx
(%ecx), %eax
%eax, (%edx)
%ebx, (%ecx)

#
#
#
#
#
#

0x100
edx
ecx
ebx
eax
*xp
*yp

=
=
=
=
=
=

xp
yp
*xp (t0)
*yp (t1)
t1
t0

Understanding Swap

123

Address
0x124

456

0x120
0x11c

%eax
%edx

0x118
Offset

0x124

%ecx
%ebx
%esi

yp

12

0x120

0x110

xp

0x124

0x10c

Rtn adr

0x108

%ebp

%edi

0x104

-4

%esp
%ebp

0x114

0x104

movl
movl
movl
movl
movl
movl

8(%ebp), %edx
12(%ebp), %ecx
(%edx), %ebx
(%ecx), %eax
%eax, (%edx)
%ebx, (%ecx)

#
#
#
#
#
#

0x100
edx
ecx
ebx
eax
*xp
*yp

=
=
=
=
=
=

xp
yp
*xp (t0)
*yp (t1)
t1
t0

Understanding Swap

123

Address
0x124

456

0x120
0x11c

%eax

0x118

%edx

0x124

%ecx

0x120

Offset

%ebx
%esi

yp

12

0x120

0x110

xp

0x124

0x10c

Rtn adr

0x108

%ebp

%edi

0x104

-4

%esp
%ebp

0x114

0x104

movl
movl
movl
movl
movl
movl

8(%ebp), %edx
12(%ebp), %ecx
(%edx), %ebx
(%ecx), %eax
%eax, (%edx)
%ebx, (%ecx)

#
#
#
#
#
#

0x100
edx
ecx
ebx
eax
*xp
*yp

=
=
=
=
=
=

xp
yp
*xp (t0)
*yp (t1)
t1
t0

Understanding Swap

123

Address
0x124

456

0x120
0x11c

%eax

0x118

%edx

0x124

%ecx

0x120

%ebx

Offset

123

%esi

yp

12

0x120

0x110

xp

0x124

0x10c

Rtn adr

0x108

%ebp

%edi

0x104

-4

%esp
%ebp

0x114

0x104

movl
movl
movl
movl
movl
movl

8(%ebp), %edx
12(%ebp), %ecx
(%edx), %ebx
(%ecx), %eax
%eax, (%edx)
%ebx, (%ecx)

#
#
#
#
#
#

0x100
edx
ecx
ebx
eax
*xp
*yp

=
=
=
=
=
=

xp
yp
*xp (t0)
*yp (t1)
t1
t0

Understanding Swap

123

Address
0x124

456

0x120
0x11c

%eax

456

%edx

0x124

%ecx

0x120

%ebx

0x118
Offset

123

%esi

yp

12

0x120

0x110

xp

0x124

0x10c

Rtn adr

0x108

%ebp

%edi

0x104

-4

%esp
%ebp

0x114

0x104

movl
movl
movl
movl
movl
movl

8(%ebp), %edx
12(%ebp), %ecx
(%edx), %ebx
(%ecx), %eax
%eax, (%edx)
%ebx, (%ecx)

#
#
#
#
#
#

0x100
edx
ecx
ebx
eax
*xp
*yp

=
=
=
=
=
=

xp
yp
*xp (t0)
*yp (t1)
t1
t0

Understanding Swap

456

Address
0x124

456

0x120
0x11c

%eax

456
456

%edx

0x124

%ecx

0x120

%ebx

0x118
Offset

123

%esi

yp

12

0x120

0x110

xp

0x124

0x10c

Rtn adr

0x108

%ebp

%edi

0x104

-4

%esp
%ebp

0x114

0x104

movl
movl
movl
movl
movl
movl

8(%ebp), %edx
12(%ebp), %ecx
(%edx), %ebx
(%ecx), %eax
%eax, (%edx)
%ebx, (%ecx)

#
#
#
#
#
#

0x100
edx
ecx
ebx
eax
*xp
*yp

=
=
=
=
=
=

xp
yp
*xp (t0)
*yp (t1)
t1
t0

Understanding Swap

456

Address
0x124

123

0x120
0x11c

%eax

456

%edx

0x124

%ecx

0x120

%ebx

0x118
Offset

123

%esi

yp

12

0x120

0x110

xp

0x124

0x10c

Rtn adr

0x108

%ebp

%edi

0x104

-4

%esp
%ebp

0x114

0x104

movl
movl
movl
movl
movl
movl

8(%ebp), %edx
12(%ebp), %ecx
(%edx), %ebx
(%ecx), %eax
%eax, (%edx)
%ebx, (%ecx)

#
#
#
#
#
#

0x100
edx
ecx
ebx
eax
*xp
*yp

=
=
=
=
=
=

xp
yp
*xp (t0)
*yp (t1)
t1
t0

General Memory Addressing Modes


Most General Form
D ( Rb, Ri, S )
Base register

Index register
(no %esp)

Scale
(1,2,4,8)

Constant
displacement

Mem[Reg[Rb]+S*Reg[Ri]+ D]
Special Cases
(Rb,Ri)
D(Rb,Ri)
(Rb,Ri,S)

Mem[Reg[Rb]+Reg[Ri]]
Mem[Reg[Rb]+Reg[Ri]+D]
Mem[Reg[Rb]+S*Reg[Ri]]

Size of C objects on IA32 and


x86-64
C Data Type Generic 32-bit Intel IA32

unsigned
int
long int
char
short
float
double
char *

Or any other pointer

4
4
4
1
2
4
8
4

4
4
4
1
2
4
8
4

x86-64
4
4
8
1
2
4
8
8

Carnegie Mellon

Address Computation Examples


%edx

0xf000

%ecx

0x0100

Expression

Address Computation

Address

0x8(%edx)

0xf000
+ 0x8
0x8+%edx

0xf008
0xf008

(%edx,%ecx)

0xf000
+ 0x100
%edx+%ecx

0xf100
0xf100

(%edx,%ecx,4)

0xf000
+ 4*0x100
%edx+4*%ecx

0xf400
0xf400

0x80(,%edx,2)

2*%edx+0x80
2*0xf000
+ 0x80

0x1e080
0x1e080

Carnegie Mellon

lea instruction
leal Src, Dest
Src is address mode expression
Set Dest to address denoted by expression

2 common uses
Computing address

E.g., translation of p = &x[i];

Computing arithmetic expressions x + k*y for k= 1,


2, 4, or 8
Example
int foo(int x)
{
return x*12;
}

leal (%eax,%eax,2), %eax


sall $2, %eax

;t <- x+x*2
;return t<<2

Outline

Assembly primer
Addressing modes
Arithmetic operations
Condition codes:
Jump and branches loops
Procedures the stack

Carnegie Mellon

Arithmetic Operations
addl
subl
imull
incl
decl
negl
notl

Src, Dest
Src, Dest
Src, Dest
Dest
Dest
Dest
Dest

Dest = Dest + Src


Dest = Dest Src
Dest = Dest * Src
Dest = Dest + 1
Dest = Dest 1
Dest = Dest
Dest = ~Dest

sall
sarl
xorl
andl
orl

Src, Dest
Src, Dest
Src, Dest
Src, Dest
Src, Dest

Dest
Dest
Dest
Dest
Dest

= Dest
= Dest
= Dest
= Dest
= Dest

<< Src
>> Src
^ Src
& Src
| Src

Carnegie Mellon

Arithmetic Expression Example


int foo(int x, int y, int z)
{
int t1 = x+y;
int t2 = z+t1;
int t3 = x+4;
int t4 = y * 48;
int t5 = t3 + t4;
int rval = t2 * t5;
return rval;
}

foo:
pushl
movl

%ebp
%esp, %ebp

movl
movl
leal
sall
leal
addl
addl
imull

8(%ebp), %ecx
12(%ebp), %edx
(%edx,%edx,2), %eax
$4, %eax
4(%ecx,%eax), %eax
%ecx, %edx
16(%ebp), %edx
%edx, %eax

popl
ret

%ebp

Note: x, y, and z are stored at offsets 8, 12, and 16 from %ebp

Set
Up

Body

Finish

Carnegie Mellon

Understanding arithmetic

int foo(int x, int y, int z)


{
int t1 = x+y;
int t2 = z+t1;
int t3 = x+4;
int t4 = y * 48;
int t5 = t3 + t4;
int rval = t2 * t5;
return rval;
}
movl
movl
leal
sall
leal
addl
addl
imull

8(%ebp), %ecx
12(%ebp), %edx
(%edx,%edx,2), %eax
$4, %eax
4(%ecx,%eax), %eax
%ecx, %edx
16(%ebp), %edx
%edx, %eax

Stack

#
#
#
#
#
#
#
#

ecx
edx
eax
eax
eax
edx
edx
eax

Offset

16

12

Rtn Addr

= x
0 Old %ebp
= y
= y*3
*= 16 (t4)
= t4 +x+4 (t5)
= x+y (t1)
+= z (t2)
= t2 * t5 (rval)

%ebp

Carnegie Mellon

Observations

Instructions in
different order
from C code
Some expressions
require multiple
instructions
Some instructions
cover multiple
expressions

int foo(int x, int y, int z)


{
int t1 = x+y;
int t2 = z+t1;
int t3 = x+4;
int t4 = y * 48;
int t5 = t3 + t4;
int rval = t2 * t5;
return rval;
}
movl
movl
leal
sall
leal
addl
addl
imull

8(%ebp), %ecx
12(%ebp), %edx
(%edx,%edx,2), %eax
$4, %eax
4(%ecx,%eax), %eax
%ecx, %edx
16(%ebp), %edx
%edx, %eax

#
#
#
#
#
#
#
#

ecx
edx
eax
eax
eax
edx
edx
eax

= x
= y
= y*3
*= 16 (t4)
= t4 +x+4 (t5)
= x+y (t1)
+= z (t2)
= t2 * t5 (rval)

Carnegie Mellon

Another Example
bar:
pushl %ebp
movl %esp,%ebp

int bar(int x, int y)


{
int t1 = x^y;
int t2 = t1 >> 17;
int mask = (1<<13) - 7;
int rval = t2 & mask;
return rval;
}

movl
xorl
sarl
andl

12(%ebp),%eax
8(%ebp),%eax
$17,%eax
$8185,%eax

213 = 8192, 213 7 = 8185

movl
xorl
sarl
andl

12(%ebp),%eax
8(%ebp),%eax
$17,%eax
$8185,%eax

popl %ebp
ret

#
#
#
#

eax
eax
eax
eax

=
=
=
=

y
x^y
(t1)
t1>>17
(t2)
t2 & mask (rval)

Set
Up

Body

Finish

Carnegie Mellon

Processor State (IA32)


Processor state = information kept in
CPU on currently executing program
%eax
%ecx
%edx
%ebx
%esi
%edi
%esp
%ebp

General purpose
registers

Stack top
Stack frame

%eip

CF

Instruction pointer

ZF

SF

OF

Condition codes

Outline

Assembly primer
Addressing modes
Arithmetic operations
Condition codes
Jump and branches loops
Procedures the stack

Carnegie Mellon

Setting Condition Codes


Can be implicitly set by arithmetic operations
Example: addl Src,Dest (t = a+b)
CF (Carry flag) set if carry out from most significant (31st) bit (unsigned overflow)
ZF (Zero flag) set if t == 0
SF (Sign flag) set if t < 0 (as signed)
OF (Overflow flag) set if signed overflow, i.e. carry out
from 30-th bit
(a>0 && b>0 && t<0) || (a<0 && b<0 &&
t>=0)

Not set by lea instruction

Carnegie Mellon

Setting Condition Codes


Can also be explicitly set
cmpl b,a set condition codes based on (a-b)
CF set if (a-b) results in unsigned overflow
ZF set if a == b
SF set if (a-b) < 0 (as signed)
OF set if (a-b) results in signed overflow
testl b,a set condition codes based on value
of a & b

Carnegie Mellon

Reading Condition Codes


SetX instruction: Set the lower byte of some
register based on combinations of condition
codes
SetX
Condition
Description
sete
setne
sets
setns
setg
setge
setl
setle
seta
setb

ZF
~ZF
SF
~SF
~(SF^OF)&~ZF
~(SF^OF)
(SF^OF)
(SF^OF)|ZF
~CF&~ZF
CF

Equal / Zero
Not Equal / Not Zero
Negative
Nonnegative
Greater (Signed)
Greater or Equal (Signed)
Less (Signed)
Less or Equal (Signed)
Above (unsigned)
Below (unsigned)

Carnegie Mellon

Reading Condition Codes (Cont.)


Example
%ax

int gt (int x, int y)


{
return x > y;
}

%ah
%eax

movl 12(%ebp),%eax
cmpl %eax,8(%ebp)
setg %al
movzbl %al,%eax

#
#
#
#

eax = y
Compare x : y
al = x > y
Zero rest of %eax

Move Zero-Extended Byte to Long

%al

Outline

Assembly primer
Addressing modes
Arithmetic operations
Condition codes
Jump and branches loops
Procedures the stack

Carnegie Mellon

Jumping
jX Instruction: Jump to different part of
code depending on condition codes
jX

Condition

Description

jmp

Unconditional

je

ZF

Equal / Zero

jne

~ZF

Not Equal / Not Zero

js

SF

Negative

jns

~SF

Nonnegative

jg

~(SF^OF)&~ZF

Greater (Signed)

jge

~(SF^OF)

Greater or Equal (Signed)

jl

(SF^OF)

Less (Signed)

jle

(SF^OF)|ZF

Less or Equal (Signed)

ja

~CF&~ZF

Above (unsigned)

jb

CF

Below (unsigned)

Carnegie Mellon

Conditional Branch Example


int absdiff(int x, int y)
{
int result;
if (x > y) {
result = x-y;
} else {
result = y-x;
}
return result;
}

absdiff:
pushl %ebp
movl
%esp, %ebp
movl
8(%ebp), %edx
movl
12(%ebp), %eax
cmpl
%eax, %edx
jle
.L6
subl
%eax, %edx
movl
%edx, %eax
jmp .L7
.L6:
subl %edx, %eax
.L7:
popl %ebp
ret

Setup

Body1
Body2a

Body2b
Finish

Conditional Branch Example


(Cont.)
int goto_ad(int x, int y)
{

int result;
if (x <= y) goto Else;
result = x-y;
goto Exit;
Else:
result = y-x;
Exit:
return result;
}

absdiff:
pushl %ebp
movl
%esp, %ebp
movl
8(%ebp), %edx
movl
12(%ebp), %eax
cmpl
%eax, %edx
jle
.L6
subl
%eax, %edx
movl
%edx, %eax
jmp .L7
.L6:
subl %edx, %eax
.L7:
popl %ebp
ret

Carnegie Mellon

Setup

Body1
Body2a

Body2b
Finish

Conditional Branch Example


(Cont.)
int goto_ad(int x, int y)
{

int result;
if (x <= y) goto Else;
result = x-y;
goto Exit;
Else:
result = y-x;
Exit:
return result;
}

absdiff:
pushl %ebp
movl
%esp, %ebp
movl
8(%ebp), %edx
movl
12(%ebp), %eax
cmpl
%eax, %edx
jle
.L6
subl
%eax, %edx
movl
%edx, %eax
jmp .L7
.L6:
subl %edx, %eax
.L7:
popl %ebp
ret

Carnegie Mellon

Setup

Body1
Body2a

Body2b
Finish

Conditional Branch Example


(Cont.)
int goto_ad(int x, int y)
{

int result;
if (x <= y) goto Else;
result = x-y;
goto Exit;
Else:
result = y-x;
Exit:
return result;
}

absdiff:
pushl %ebp
movl
%esp, %ebp
movl
8(%ebp), %edx
movl
12(%ebp), %eax
cmpl
%eax, %edx
jle
.L6
subl
%eax, %edx
movl
%edx, %eax
jmp .L7
.L6:
subl %edx, %eax
.L7:
popl %ebp
ret

Carnegie Mellon

Setup

Body1
Body2a

Body2b
Finish

Conditional Branch Example


(Cont.)
int goto_ad(int x, int y)
{

int result;
if (x <= y) goto Else;
result = x-y;
goto Exit;
Else:
result = y-x;
Exit:
return result;
}

absdiff:
pushl %ebp
movl
%esp, %ebp
movl
8(%ebp), %edx
movl
12(%ebp), %eax
cmpl
%eax, %edx
jle
.L6
subl
%eax, %edx
movl
%edx, %eax
jmp .L7
.L6:
subl %edx, %eax
.L7:
popl %ebp
ret

Carnegie Mellon

Setup

Body1
Body2a

Body2b
Finish

Carnegie Mellon

Do-While Loop Example


C Code
int pcount_do(unsigned x)
{
int result = 0;
do {
result += x & 0x1;
x >>= 1;
} while (x);
return result;
}

Goto Version
int pcount_do(unsigned x)
{
int result = 0;
loop:
result += x & 0x1;
x >>= 1;
if (x)
goto loop;
return result;
}

Count number of 1s in argument x

Carnegie Mellon

Do-While Loop Compilation

Goto Version

int pcount_do(unsigned x) {
int result = 0;
loop:
result += x & 0x1;
x >>= 1;
if (x)
goto loop;
return result;
}

Registers:
%edx
x
%ecx
result

movl
.L2:
movl
andl
addl
shrl
jne

$0, %ecx

%edx, %eax
$1, %eax
%eax, %ecx
%edx
.L2

#
result = 0
# loop:
#
#
#
#

t = x & 1
result += t
x >>= 1
If !0, goto loop

Carnegie Mellon

General Do-While and While


Translation
Goto Version
do
Body
while (Test);

while (Test)
Body

loop:
Body
if (Test)
goto loop
Goto Version
if (!Test)
goto done;
loop:
Body
if (Test)
goto loop;
done:

Carnegie Mellon

For Loop Translation

for (Init; Test; Update )


Body

Init;
if (!Test)
goto done;
loop:
Body
Update
if (Test)
goto loop;
done:

Carnegie Mellon

For Loop Conversion Example


C Code
#define WSIZE 8*sizeof(int)
int pcount_for(unsigned x) {
int i;
int result = 0;
for (i = 0; i < WSIZE; i++) {
unsigned mask = 1 << i;
result += (x & mask) != 0;
}
return result;
}

Goto Version

int pcount_for_gt(unsigned x) {
int i;
int result = 0;
Init
i = 0;
if (!(i < WSIZE)) !Test
goto done;
loop:
Body
{
unsigned mask = 1 << i;
result += (x & mask) != 0;
}
i++; Update
if (i < WSIZE) Test
goto loop;
done:
return result;
}

Carnegie Mellon

Using Conditional Moves

Conditional Move Instructions


Instruction supports:
if (Test) Dest Src

Supported in post-1995 x86


processors
GCC does not always use them

Wants to preserve compatibility with


ancient processors
Enabled for x86-64
Use switch march=686 for IA32

Why?

Branches are very disruptive to


instruction flow through pipelines
Conditional move do not require
control transfer

C Code
val = Test
? Then_Expr
: Else_Expr;

Goto Version
tval = Then_Expr;
result = Else_Expr;
t = Test;
if (t) result = tval;
return result;

Carnegie Mellon

Bad Cases for Conditional Move


Expensive Computations
val = Test(x) ? Hard1(x) : Hard2(x);

Both values get computed


Only makes sense when computations are very simple

Risky Computations
val = p ? *p : 0;

Both values get computed


May have undesirable effects

Computations with side effects


val = x > 0 ? x*=7 : x+=3;

Both values get computed


Must be side-effect free

Carnegie Mellon

IA32 Object Code


Assembly Code
switch_eg:
. . .
ja
.L2
# If unsigned > goto default
jmp
*.L7(,%eax,4) # Goto *JTab[x]

Disassembled Object Code


08048410 <switch_eg>:
. . .
8048419: 77 07
804841b: ff 24 85 60 86 04 08

ja
jmp

8048422 <switch_eg+0x12>
*0x8048660(,%eax,4)

Carnegie Mellon

IA32 Object Code (cont.)

Jump Table

Doesnt show up in disassembled code, inspect using


GDB
(gdb) x/7xw 0x8048660
Examine 7 hexadecimal format words (4-bytes each)

0x8048660:
0x8048670:

0x08048422
0x08048422

0x08048432
0x0804844b

0x0804843b
0x0804844b

Address

Value

0x8048660

0x8048422

0x8048664

0x8048432

0x8048668

0x804843b

0x804866c

0x8048429

0x8048670

0x8048422

0x8048674

0x804844b

0x8048678

0x804844b

0x08048429

Carnegie Mellon

Matching Disassembled Targets


Value
0x8048422
0x8048432
0x804843b
0x8048429
0x8048422
0x804844b
0x804844b

8048422:
8048427:
8048429:
804842e:
8048430:
8048432:
8048435:
8048439:
804843b:
804843e:
8048440:
8048443:
8048446:
8048449:
804844b:
8048450:
8048453:
8048454:

mov
jmp
mov
xchg
jmp
mov
imul
jmp
mov
mov
sar
idivl
add
jmp
mov
sub
pop
ret

$0x2,%eax
8048453 <switch_eg+0x43>
$0x1,%eax
%ax,%ax
8048446 <switch_eg+0x36>
0x10(%ebp),%eax
0xc(%ebp),%eax
8048453 <switch_eg+0x43>
0xc(%ebp),%edx
%edx,%eax
$0x1f,%edx
0x10(%ebp)
0x10(%ebp),%eax
8048453 <switch_eg+0x43>
$0x1,%eax
0x10(%ebp),%eax
%ebp

Outline

Assembly primer
Addressing modes
Arithmetic operations
Condition codes
Jump and branches loops
Procedures the stack

Carnegie Mellon

IA32 Stack
Region of memory
managed with stack
discipline
Register %esp
contains
address of top
element

Bottom
increasing
Addresses

Stack
Grows
Down

Stack Pointer: %esp


Top

Carnegie Mellon

IA32 Stack: Push


Bottom

pushl src

Fetch operand at Src


Decrement %esp by 4
Write operand at address given by %esp

Stack Pointer: %esp

Increasing
Addresses

Stack
Grows
Down
-4

Carnegie Mellon

IA32 Stack: Pop

popl dst

Bottom

Write operand at address given by %esp

Increasing
Addresses

to dst
Increment %esp by 4

Stack Pointer: %esp

+4

Stack
Grows
Down

Carnegie Mellon

Procedure Control Flow

Use stack to support procedure call and return


call label_of_procedure
Push return address on stack
Jump to label

ret

Pop address from stack


Jump to address

Return address:

Address of the next instruction right after call


Example:
804854e: e8 3d 06 00 00
call
8048b90 <main>
8048553: 50
pushl %eax
Return address = 0x8048553

Carnegie Mellon

Procedure Call Example


804854e:
8048553:

e8 3d 06 00 00
50

call
pushl

call 8048b90

0x110

0x110

0x10c

0x10c

0x108 123

0x108 123
0x104 0x8048553

%esp 0x108

%esp 0x104

%eip 0x804854e

%eip 0x8048b90

%eip: program counter

8048b90 <main>
%eax

Carnegie Mellon

Procedure Return Example


8048591:

c3

ret

ret

0x110

0x110

0x10c

0x10c

0x108 123

0x108 123

0x104 0x8048553

%eip: program counter

0x8048553

%esp 0x104

%esp 0x108

%eip 0x8048591

%eip 0x8048553

Carnegie Mellon

Using stack for procedure invocation


In addition to return address, stack also
stores
Arguments
local variables
Scratch space

Stack allocated in Frames

state for single procedure instantiation

Stack is well suited for procedure


invocation

State for given procedure needed for from when


called to when return
Callee returns before caller does (last-in-firstout)

Carnegie Mellon

Call Chain Example


yoo()
{

who();

Example
Call Chain
yoo

who()
{

amI();

amI();

}

who
amI()
{

amI();

}
Procedure amI() is recursive

amI
amI
amI

amI

Carnegie Mellon

Stack Frames
Previous
Frame

Contents

Local variables
Return information
Temporary space

Frame Pointer: %ebp

Frame for
proc
Stack Pointer: %esp

Management

Space allocated when


enter procedure
Set-up code

Deallocated when return


Finish code

Stack Top

Carnegie Mellon

Example
yoo()
{

who();

yoo

%ebp
yoo yoo

who
amI
amI
amI

Stack

%esp
amI

Carnegie Mellon

Example
yoo()
{ who()
{

amI();
who();

amI();

}
}

Stack

yoo
yoo yoo

who
%ebp

amI
amI
amI

amI

who
%esp

Carnegie Mellon

Example
yoo()
{ who()
{
amI()

{
amI();
who();

amI();
amI();

Stack

yoo
yoo yoo

who
amI

who

amI

%ebp
amI

amI
%esp

amI

Carnegie Mellon

Example
yoo()
{ who()
{
amI()

{
amI();
who();
amI()

amI();
amI();

}
amI();

Stack

yoo
yoo yoo

who
amI

who

amI

amI
amI

amI
%ebp

amI
%esp

Carnegie Mellon

Example
yoo()
{ who()
{
amI()

{
amI();
who();
amI()

amI(); amI()
amI();
{
}

amI();

}
amI();

Stack

yoo
yoo yoo

who
amI

who

amI

amI

amI

amI

amI
%ebp

amI
%esp

Carnegie Mellon

Example
yoo()
{ who()
{
amI()

{
amI();
who();
amI()

amI();
amI();

}
amI();

Stack

yoo
yoo yoo

who
amI

who

amI

amI
amI

amI
%ebp

amI
%esp

Carnegie Mellon

Example
yoo()
{ who()
{
amI()

{
amI();
who();

amI();
amI();

Stack

yoo
yoo yoo

who
amI

who

amI

%ebp
amI

amI
%esp

amI

Carnegie Mellon

Example
yoo()
{ who()
{

amI();
who();

amI();

}
}

Stack

yoo
yoo yoo

who
%ebp

amI
amI
amI

amI

who
%esp

Carnegie Mellon

Example
yoo()
{ who()
{
amI()

{
amI();
who();

amI();
amI();

Stack

yoo
yoo yoo

who
amI

who

amI

%ebp
amI

amI
%esp

amI

Carnegie Mellon

Example
yoo()
{ who()
{

amI();
who();

amI();

}
}

Stack

yoo
yoo yoo

who
%ebp

amI
amI
amI

amI

who
%esp

Carnegie Mellon

Example
yoo()
{

who();

yoo

%ebp
yoo yoo

who
amI
amI
amI

Stack

%esp
amI

Carnegie Mellon

IA32/Linux Stack Frame


Current Stack Frame (Top to
Bottom)
Caller
Argument build:
Frame
Parameters for function about to call
Local variables
If cant keep in registers
Frame pointer
%ebp
Saved register context
Old frame pointer

Caller Stack Frame


Return address

Arguments
Return Addr
Old %ebp
Saved
Registers
+
Local
Variables

Pushed by call instruction

Arguments for this call

Stack pointer
%esp

Argument
Build

Carnegie Mellon

Revisiting swap

Calling swap from call_swap

int course1 = 15213;


int course2 = 18243;

void call_swap() {
swap(&course1, &course2);
}

void swap(int *xp, int *yp)


{
int t0 = *xp;
int t1 = *yp;
*xp = t1;
*yp = t0;
}

call_swap:

subl
movl
movl
call

$8, %esp
$course2, 4(%esp)
$course1, (%esp)
swap

Resulting
Stack
%esp

&course2

subl

&course1

%esp

Rtn adr

%esp

call

Carnegie Mellon

Revisiting swap
swap:
pushl %ebp
void swap(int *xp, int *yp)
movl %esp, %ebp
{
pushl %ebx
int t0 = *xp;
int t1 = *yp;
movl 8(%ebp), %edx
*xp = t1;
movl 12(%ebp), %ecx
*yp = t0;
movl (%edx), %ebx
}
movl (%ecx), %eax
movl %eax, (%edx)
movl %ebx, (%ecx)
popl
popl
ret

%ebx
%ebp

Set
Up

Body

Finish

Carnegie Mellon

swap Setup #1
Entering Stack

Resulting Stack
%ebp

%ebp

&course2

yp

&course1

xp

Rtn adr

%esp

Rtn adr
Old %ebp

swap:
pushl %ebp
movl %esp,%ebp
pushl %ebx

%esp

Carnegie Mellon

swap Setup #2
Entering Stack

Resulting Stack
%ebp

&course2

yp

&course1

xp

Rtn adr

%esp

Rtn adr
Old %ebp

swap:
pushl %ebp
movl %esp,%ebp
pushl %ebx

%ebp
%esp

Carnegie Mellon

swap Setup #3
Entering Stack

Resulting Stack
%ebp

&course2

yp

&course1

xp

Rtn adr

%esp

swap:
pushl %ebp
movl %esp,%ebp
pushl %ebx

Rtn adr
Old %ebp

%ebp

Old %ebx

%esp

Carnegie Mellon

swap Body
Entering Stack

Resulting Stack
%ebp

Offset relative to %ebp


12 yp
8 xp

&course2

&course1
Rtn adr

%esp

movl 8(%ebp),%edx
movl 12(%ebp),%ecx
. . .

4 Rtn adr

# get xp
# get yp

Old %ebp

%ebp

Old %ebx

%esp

Carnegie Mellon

swap Finish
Stack Before Finish

Resulting Stack
%ebp

yp

yp

xp

xp

Rtn adr

Rtn adr

Old %ebp

%ebp

Old %ebx

%esp

popl
popl

%ebx
%ebp

%esp

Saved and restored register %ebx,


but not %eax, %ecx, %edx

Carnegie Mellon

Register Saving Conventions


When procedure yoo calls who:
yoo is the caller
who is the callee

Callee might use registers for temporary storage?


yoo:

movl $15213, %edx
call who
addl %edx, %eax

ret

who:

movl 8(%ebp), %edx
addl $18243, %edx

ret

Contents of register %edx overwritten by who


This could be trouble something should be done!
Need some coordination

Carnegie Mellon

Register Saving Conventions


When procedure yoo calls who:
yoo is the caller
who is the callee

Register saving Conventions


Caller Save

Caller saves temporary values in its stack frame


before the call

Callee Save

Callee saves temporary values in its stack frame


before using

Carnegie Mellon

IA32/Linux+Windows Register
Usage

%eax, %edx, %ecx

Caller saves prior to call if


values are used later

Caller-Save
Temporaries

%eax
%edx

Callee-Save
Temporaries

%ecx
%ebx
%esi

%eax

also used to return integer


value

%ebx, %esi, %edi

Callee saves if wants to use


them
Special

%esp, %ebp

special form of callee save


Restored to original values
upon exit from procedure

%edi
%esp
%ebp

Recursive Function
pcount_r:
/* Recursive popcount */
int pcount_r(unsigned x) {
if (x == 0)
return 0;
else return
(x & 1) + pcount_r(x >> 1);
}

Registers

%eax, %edx used without


first saving
%ebx used, but saved at
beginning & restored at end

Carnegie Mellon

pushl %ebp
movl
%esp,%ebp
pushl %ebx
subl
$4,%esp
movl
8(%ebp),%ebx
movl
$0,%eax
testl %ebx,%ebx
je .L3
movl
%ebx,%eax
shrl
%eax
movl
%eax,(%esp)
call pcount_r
movl %ebx,%edx
andl
$1,%edx
leal
(%edx,%eax),%eax
.L3:
addl
$4,%esp
popl
%ebx
popl
%ebp
ret

Carnegie Mellon

Recursive Call #1
/* Recursive popcount */
int pcount_r(unsigned x) {
if (x == 0)
return 0;
else return
(x & 1) + pcount_r(x >> 1);
}

pcount_r:
pushl %ebp
movl %esp,%ebp
pushl %ebx
subl $4,%esp
movl 8(%ebp),%ebx

Actions

Save old value of %ebx on


stack
Allocate space for
argument to recursive call
Store x in %ebx

x
Rtn adr
Old %ebp

%ebp

Old %ebx
%ebx x

%esp

Carnegie Mellon

Recursive Call #2
/* Recursive popcount */
int pcount_r(unsigned x) {
if (x == 0)
return 0;
else return
(x & 1) + pcount_r(x >> 1);
}

Actions
If x == 0 (%eax),
return
%ebx x


movl $0,%eax
testl %ebx,%ebx
je
.L3

.L3:

ret

Carnegie Mellon

Recursive Call #3
/* Recursive popcount */
int pcount_r(unsigned x) {
if (x == 0)
return 0;
else return
(x & 1) + pcount_r(x >> 1);
}

Actions


movl %ebx,%eax
shrl %eax
movl %eax,(%esp)
call pcount_r

Store x >> 1 on stack


Make recursive call

%eax set to function result


%ebx still has value of x

Rtn adr

Effect after calling pcount_r

Old %ebp

%ebp

Old %ebx
%ebx x

x >> 1

%esp

Carnegie Mellon

Recursive Call #4
/* Recursive popcount */
int pcount_r(unsigned x) {
if (x == 0)
return 0;
else return
(x & 1) + pcount_r(x >> 1);
}


movl
%ebx,%edx
andl
$1,%edx
leal
(%edx,%eax),%eax

After calling pcount_r

%eax holds value from recursive call


%ebx holds x

Actions

Compute (x & 1) + computed value

Effect

%eax set to function result

%ebx x

Carnegie Mellon

Recursive Call #5
/* Recursive popcount */
int pcount_r(unsigned x) {
if (x == 0)
return 0;
else return
(x & 1) + pcount_r(x >> 1);
}

L3:
addl $4,%esp
popl %ebx
popl %ebp
ret

Actions

%ebp

Restore %ebx,%ebp

Restore %esp

%esp

Rtn adr

Old %ebp

%ebp
%ebx

Old %ebx
%esp

Old %ebx

Conclusions
Till Now, we have seen:
Hardware: transistors gates
digital structures microarchitecture
(datapath + control unit)
Software: bits data (signed,
unsigned, floating points, ..) +
Instructions

Вам также может понравиться