0% found this document useful (0 votes)
3 views

Lecture9

Uploaded by

minulo
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

Lecture9

Uploaded by

minulo
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 96

CSC 252/452: Computer Organization

Fall 2024: Lecture 9

Instructor: Yanan Guo

Department of Computer Science


University of Rochester
Carnegie Mellon

Announcement
• Programming Assignment 2 is out
• Details: https://www.cs.rochester.edu/courses/252/
fall2024/labs/assignment2.html
• Due on Sep. 30th, 11:59 PM
• You (may still) have 3 slip days

• TA Office hours
• Grace Hopper Conference

2
Carnegie Mellon

Getting a bomb

3
Stack Frame: Putting It Together
Saved
Registers
Local
Caller Variables
Frame
Arguments
7, 8, …
%rsp Return Addr

Callee
Frame

4
Passing Function Arguments
• Two choices: memory or registers
• Registers are faster, but have limited amount

5
Registers
Passing Function Arguments %rdi
%rsi
• Two choices: memory or registers %rdx
• Registers are faster, but have limited amount %rcx
• x86-64 convention (Part of the Calling %r8
Conventions): %r9
• First 6 arguments in registers, in specific order
• The rest are pushed to stack Stack
• Return value is always in %rax
•••
Arg n

•••
Arg 8
Arg 7
5
Registers
Passing Function Arguments %rdi
%rsi
• Two choices: memory or registers %rdx
• Registers are faster, but have limited amount %rcx
• x86-64 convention (Part of the Calling %r8
Conventions): %r9
• First 6 arguments in registers, in specific order
• The rest are pushed to stack Stack
• Return value is always in %rax
•••
• Just conventions, not laws
• Not necessary if you write both caller and callee as Arg n
long as the caller and callee agree
• But is necessary to interface with others’ code •••
Arg 8
Arg 7
5
Stack Frame: Putting It Together
Saved
Registers
Local
Caller Variables
Frame
Arguments
7, 8, …
%rsp Return Addr

Callee
Frame

6
Managing Function Local Variables
• Two ways: registers and long incr(long *p, long val) {
long x = *p;
memory (stack) long y = x + val;
• Registers are faster, but *p = y;
return x;
limited. Memory is slower, }
but large. Smart compilers
will optimize the usage.

7
Stack Frame: Putting It Together
Saved
Registers
Local
Caller Variables
Frame
Arguments
7, 8, …
%rsp Return Addr

Callee
Frame

8
Register Saving Conventions

9
Register Saving Conventions
• Any issue with using registers for temporary storage?

Caller Callee
yoo: who:
… …
movq $15213, %rdx subq $18213, %rdx
call who …
addq %rdx, %rax ret

ret

9
Register Saving Conventions
• Any issue with using registers for temporary storage?
• Contents of register %rdx overwritten by who()

Caller Callee
yoo: who:
… …
movq $15213, %rdx subq $18213, %rdx
call who …
addq %rdx, %rax ret

ret

9
Register Saving Conventions
• Any issue with using registers for temporary storage?
• Contents of register %rdx overwritten by who()
• This could be trouble ➙ Need some coordination

Caller Callee
yoo: who:
… …
movq $15213, %rdx subq $18213, %rdx
call who …
addq %rdx, %rax ret

ret

9
Register Saving Conventions
• Conventions used in x86-64 (Part of the Calling Conventions)
• Some registers are saved by caller, some are by callee.
• Caller saved: %rdi,%rsi,%rdx,%rcx,%r8,%r9,%r10,%r11
• Callee saved: %rbx,%rbp,%r12,%r13,%14,%r15
• %rax holds return value, so implicitly caller saved
• %rsp is the stack pointer, so implicitly callee saved

10
Register Saving Conventions
• Common conventions
• “Caller Saved”
• Caller saves temporary values in its frame (on the stack) before
the call
• Callee is then free to modify their values
• “Callee Saved”
• Callee saves temporary values in its frame before using
• Callee restores them before returning to caller
• Caller can safely assume that register values won’t change after
the function call

11
Example
Stack
long call_incr2(long x) {
long v1 = 15213;
long v2 = incr(&v1, 3000); ...
return x+v2;
}
… %rsp

12
Example
Stack
long call_incr2(long x) {
long v1 = 15213;
long v2 = incr(&v1, 3000); ...
return x+v2;
}
… %rsp

call_incr2:
pushq %rbx
pushq $15213
movq %rdi, %rbx
movl $3000, %esi
leaq (%rsp), %rdi
call incr
addq %rbx, %rax
addq $8, %rsp
popq %rbx
ret

12
Example
Stack
long call_incr2(long x) {
long v1 = 15213;
long v2 = incr(&v1, 3000); ...
return x+v2;
}
… %rsp

call_incr2:
pushq %rbx
pushq $15213
movq %rdi, %rbx
movl $3000, %esi
leaq (%rsp), %rdi
call incr
addq %rbx, %rax
addq $8, %rsp
popq %rbx
ret

12
Example
Stack
long call_incr2(long x) {
long v1 = 15213;
long v2 = incr(&v1, 3000); ...
return x+v2;
}

Saved %rbx %rsp
call_incr2:
pushq %rbx
pushq $15213
movq %rdi, %rbx
movl $3000, %esi
leaq (%rsp), %rdi
call incr
addq %rbx, %rax
addq $8, %rsp
popq %rbx
ret

12
Example
Stack
long call_incr2(long x) {
long v1 = 15213;
long v2 = incr(&v1, 3000); ...
return x+v2;
}

Saved %rbx
call_incr2:
pushq %rbx 15213 %rsp
pushq $15213
movq %rdi, %rbx
movl $3000, %esi
leaq (%rsp), %rdi
call incr
addq %rbx, %rax
addq $8, %rsp
popq %rbx
ret

12
Example
Stack
long call_incr2(long x) {
long v1 = 15213;
long v2 = incr(&v1, 3000); ...
return x+v2;
}

Saved %rbx %rsp
call_incr2:
pushq %rbx 15213
pushq $15213
movq %rdi, %rbx
movl $3000, %esi
leaq (%rsp), %rdi
call incr
addq %rbx, %rax
addq $8, %rsp
popq %rbx
ret

12
Example
Stack
long call_incr2(long x) {
long v1 = 15213;
long v2 = incr(&v1, 3000); ...
return x+v2;
}
… %rsp
Saved %rbx
call_incr2:
pushq %rbx 15213
pushq $15213
movq %rdi, %rbx
movl $3000, %esi
leaq (%rsp), %rdi
call incr
addq %rbx, %rax
addq $8, %rsp
popq %rbx
ret

12
Example
Stack
long call_incr2(long x) {
long v1 = 15213;
long v2 = incr(&v1, 3000); ...
return x+v2;
}
… %rsp
Saved %rbx
call_incr2:
pushq %rbx 15213
pushq $15213
movq %rdi, %rbx
movl
leaq
$3000, %esi
(%rsp), %rdi
• call_incr2 needs to save
%rbx (callee-saved) because it
call incr
addq %rbx, %rax will modify its value
addq
popq
$8, %rsp
%rbx
• It can safely use %rbx after call
incr because incr will have to
ret
save %rbx if it needs to use it
(again, %rbx is callee saved)
12
Stack Frame: Putting It Together
Saved
Registers
Local
Caller Variables
Frame
Arguments
7, 8, …
%rsp Return Addr

Callee
Frame

13
Carnegie Mellon

Today: Data Structures and Buffer Overflow


• Arrays
• One-dimensional
• Multi-dimensional (nested)
• Structures
• Allocation
• Access
• Alignment
• Buffer Overflow

14
Carnegie Mellon

Array Allocation: Basic Principle


T A[L];
• Array of data type T and length L
• Contiguously allocated region of L * sizeof(T) bytes in memory

char string[12];

x x + 12

int val[5];

x x+4 x+8 x + 12 x + 16 x + 20

double a[3];

x x+8 x + 16 x + 24

char* p[3];

x x+8 x + 16 x + 24
15
Carnegie Mellon

Byte Ordering

16
Carnegie Mellon

Byte Ordering
• How are the bytes of a multi-byte variable ordered in memory?

16
Carnegie Mellon

Byte Ordering
• How are the bytes of a multi-byte variable ordered in memory?
• Example
• Variable x has 4-byte value of 0x01234567
• Address given by &x is 0x100

0x100 0x101 0x102 0x103


01 23 45 67

16
Carnegie Mellon

Byte Ordering
• How are the bytes of a multi-byte variable ordered in memory?
• Example
• Variable x has 4-byte value of 0x01234567
• Address given by &x is 0x100
• Conventions
• Big Endian: Sun, PPC Mac, IBM z, Internet
• Most significant byte has lowest address (MSB first)
• Little Endian: x86, ARM
• Least significant byte has lowest address (LSB first)

0x100 0x101 0x102 0x103


01 23 45 67

16
Carnegie Mellon

Byte Ordering
• How are the bytes of a multi-byte variable ordered in memory?
• Example
• Variable x has 4-byte value of 0x01234567
• Address given by &x is 0x100
• Conventions
• Big Endian: Sun, PPC Mac, IBM z, Internet
• Most significant byte has lowest address (MSB first)
• Little Endian: x86, ARM
• Least significant byte has lowest address (LSB first)

Big Endian 0x100 0x101 0x102 0x103


01 23 45 67

16
Carnegie Mellon

Byte Ordering
• How are the bytes of a multi-byte variable ordered in memory?
• Example
• Variable x has 4-byte value of 0x01234567
• Address given by &x is 0x100
• Conventions
• Big Endian: Sun, PPC Mac, IBM z, Internet
• Most significant byte has lowest address (MSB first)
• Little Endian: x86, ARM
• Least significant byte has lowest address (LSB first)

Big Endian 0x100 0x101 0x102 0x103


01 23 45 67

Little Endian 0x100 0x101 0x102 0x103


67 45 23 01
16
Carnegie Mellon

Byte Ordering
• How are the bytes of a multi-byte variable ordered in memory?
• Example
• Variable x has 4-byte value of 0x01234567
• Address given by &x is 0x100
• Conventions
• Big Endian: Sun, PPC Mac, IBM z, Internet
• Most significant byte has lowest address (MSB first)
• Little Endian: x86, ARM
• Least significant byte has lowest address (LSB first)

Big Endian 0x100 0x101 0x102 0x103


01 23 45 67

Little Endian 0x100 0x101 0x102 0x103


67 45 23 01
16
Carnegie Mellon

Representing Integers
Hex: 00003B6D Hex: FFFFC493

int A = 15213; int B = -15213;


Address Increase

Little-E Big-E Little-E Big-E


6D 00 93 FF
3B 00 C4 FF
00 3B FF C4
00 6D FF 93

17
Carnegie Mellon

Representing Integers
Hex: 00003B6D Hex: FFFFC493

int A = 15213; int B = -15213;


Address Increase

Little-E Big-E Little-E Big-E


6D 00 93 FF
3B 00 C4 FF
00 3B FF C4
00 6D FF 93

17
Carnegie Mellon

Representing Integers
Hex: 00003B6D Hex: FFFFC493

int A = 15213; int B = -15213;


Address Increase

Little-E Big-E Little-E Big-E


6D 00 93 FF
3B 00 C4 FF
00 3B FF C4
00 6D FF 93

17
Carnegie Mellon

Array Access: Basic Principle


T A[L];
• Array of data type T and length L
• Identifier A can be used as a pointer to array element 0: Type T*

int val[5]; 1 5 2 1 3
address x x+4 x+8 x + 12 x + 16 x + 20

Reference Type Value


val[4] int 3
val int * x
val+1 int * x+4
val + i int * x+4i
&val[2] int * x+8
val[5] int ??
*(val+1) int 5
18
Carnegie Mellon

Multidimensional (Nested) Arrays

19
Carnegie Mellon

Multidimensional (Nested) Arrays


• Declaration A[0][0] • • • A[0][C-1]

T A[R][C]; • •
• 2D array of data type T
• •
• •
• R rows, C columns
• Type T element requires K bytes A[R-1][0] • • • A[R-1][C-1]

19
Carnegie Mellon

Multidimensional (Nested) Arrays


• Declaration A[0][0] • • • A[0][C-1]

T A[R][C]; • •
• 2D array of data type T
• •
• •
• R rows, C columns
• Type T element requires K bytes A[R-1][0] • • • A[R-1][C-1]

• Array Size
• R * C * K bytes

19
Carnegie Mellon

Multidimensional (Nested) Arrays


• Declaration A[0][0] • • • A[0][C-1]

T A[R][C]; • •
• 2D array of data type T
• •
• •
• R rows, C columns
• Type T element requires K bytes A[R-1][0] • • • A[R-1][C-1]

• Array Size
• R * C * K bytes

• Arrangement
•Row-Major Ordering in most languages, including C
int A[R][C];
A A A A A A
[0] • • • [0] [1] • • • [1] • • • [R-1] • • • [R-1]
[0] [C-1] [0] [C-1] [0] [C-1]

4*R*C Bytes
19
Carnegie Mellon

Nested Array Row Access


•T A[R][C];
• A[i] is array of C elements
• Each element of type T requires K bytes
• Starting address A + i * (C * K)

int A[R][C];

A[0] A[i] A[R-1]

A A A A A A
[0] ••• [0] • • • [i] ••• [i] • • • [R-1] ••• [R-1]
[0] [C-1] [0] [C-1] [0] [C-1]

A A+(i*C*4) A+((R-1)*C*4)

20
Carnegie Mellon

Nested Array Element Access


• Array Elements
• A[i][j] is element of type T, which requires K bytes
• Address A + i * (C * K) + j * K = A + (i * C + j)* K

int A[R][C];

A[0] A[i] A[R-1]

A A A A A
[0] ••• [0] • • • ••• [i] ••• • • • [R-1] ••• [R-1]
[0] [C-1] [j] [0] [C-1]

A A+(i*C*4) A+((R-1)*C*4)

A+(i*C*4)+(j*4)
21
Carnegie Mellon

Today: Data Structures and Buffer Overflow


• Arrays
• One-dimensional
• Multi-dimensional (nested)
• Structures
• Allocation
• Access
• Alignment
• Buffer Overflow

22
Carnegie Mellon

Structures
r
struct rec {
int a[4];
double i; a i next
struct rec *next;
}; 0 16 24 32

• Characteristics
• Contiguously-allocated region of memory
• Refer to members within struct by names
• Members may be of different types

23
Carnegie Mellon

Access Struct Members


r
struct rec {
int a[4];
double i; a i next
struct rec *next;
}; 0 16 24 32

• Given a struct, we can use the . operator:


• struct rec r1; r1.i = val;

24
Carnegie Mellon

Access Struct Members


r
struct rec {
int a[4];
double i; a i next
struct rec *next;
}; 0 16 24 32

• Given a struct, we can use the . operator:


• struct rec r1; r1.i = val;
• Suppose we have a pointer r pointing to struct res.
How to access res’s member using r?

24
Carnegie Mellon

Access Struct Members


r
struct rec {
int a[4];
double i; a i next
struct rec *next;
}; 0 16 24 32

• Given a struct, we can use the . operator:


• struct rec r1; r1.i = val;
• Suppose we have a pointer r pointing to struct res.
How to access res’s member using r?
• Using * and . operators: (*r).i = val;

24
Carnegie Mellon

Access Struct Members


r
struct rec {
int a[4];
double i; a i next
struct rec *next;
}; 0 16 24 32

• Given a struct, we can use the . operator:


• struct rec r1; r1.i = val;
• Suppose we have a pointer r pointing to struct res.
How to access res’s member using r?
• Using * and . operators: (*r).i = val;
• Or simply, the -> operator for short: r->i = val;

24
Carnegie Mellon

Generating Pointer to Structure Member


r r+4*idx
struct rec {
int a[4];
double i; a i next
struct rec *next;
}; 0 16 24 32

25
Carnegie Mellon

Generating Pointer to Structure Member


r r+4*idx
struct rec {
int a[4];
double i; a i next
struct rec *next;
}; 0 16 24 32

int *get_ap
(struct rec *r, size_t idx)
{
return &(r->a[idx]);
}

25
Carnegie Mellon

Generating Pointer to Structure Member


r r+4*idx
struct rec {
int a[4];
double i; a i next
struct rec *next;
}; 0 16 24 32

int *get_ap
(struct rec *r, size_t idx)
{
return &(r->a[idx]);
}

&((*r).a[idx])

25
Carnegie Mellon

Generating Pointer to Structure Member


r r+4*idx
struct rec {
int a[4];
double i; a i next
struct rec *next;
}; 0 16 24 32

int *get_ap
(struct rec *r, size_t idx) # r in %rdi, idx in %rsi
{ leaq (%rdi,%rsi,4), %rax
return &(r->a[idx]); ret
}

&((*r).a[idx])

25
Carnegie Mellon

Alignment
struct S1 {
char c;
int i[2];
double v;
} *p;

26
Carnegie Mellon

Alignment
• Unaligned Data struct S1 {
char c;
int i[2];
c i[0] i[1] v double v;
} *p;
p p+1 p+5 p+9 p+17

26
Carnegie Mellon

Alignment
• Unaligned Data struct S1 {
char c;
int i[2];
c i[0] i[1] v double v;
} *p;
p p+1 p+5 p+9 p+17

• Aligned Data
• If the data type requires K bytes, address must
be multiple of K

26
Carnegie Mellon

Alignment
• Unaligned Data struct S1 {
char c;
int i[2];
c i[0] i[1] v double v;
} *p;
p p+1 p+5 p+9 p+17

• Aligned Data
• If the data type requires K bytes, address must
be multiple of K

c
p+0

Multiple of 8
26
Carnegie Mellon

Alignment
• Unaligned Data struct S1 {
char c;
int i[2];
c i[0] i[1] v double v;
} *p;
p p+1 p+5 p+9 p+17

• Aligned Data
• If the data type requires K bytes, address must
be multiple of K

c 3 bytes
p+0 p+4

Multiple of 4

Multiple of 8
26
Carnegie Mellon

Alignment
• Unaligned Data struct S1 {
char c;
int i[2];
c i[0] i[1] v double v;
} *p;
p p+1 p+5 p+9 p+17

• Aligned Data
• If the data type requires K bytes, address must
be multiple of K

c 3 bytes i[0]
p+0 p+4

Multiple of 4

Multiple of 8
26
Carnegie Mellon

Alignment
• Unaligned Data struct S1 {
char c;
int i[2];
c i[0] i[1] v double v;
} *p;
p p+1 p+5 p+9 p+17

• Aligned Data
• If the data type requires K bytes, address must
be multiple of K

c 3 bytes i[0] i[1]


p+0 p+4 p+8

Multiple of 4

Multiple of 8
26
Carnegie Mellon

Alignment
• Unaligned Data struct S1 {
char c;
int i[2];
c i[0] i[1] v double v;
} *p;
p p+1 p+5 p+9 p+17

• Aligned Data
• If the data type requires K bytes, address must
be multiple of K

c 3 bytes i[0] i[1] 4 bytes


p+0 p+4 p+8 p+16

Multiple of 4 Multiple of 8

Multiple of 8
26
Carnegie Mellon

Alignment
• Unaligned Data struct S1 {
char c;
int i[2];
c i[0] i[1] v double v;
} *p;
p p+1 p+5 p+9 p+17

• Aligned Data
• If the data type requires K bytes, address must
be multiple of K

c 3 bytes i[0] i[1] 4 bytes v


p+0 p+4 p+8 p+16 p+24

Multiple of 4 Multiple of 8

Multiple of 8 Multiple of 8
26
Carnegie Mellon

Alignment Principles
• Aligned Data
• If the data type requires K bytes, address must be multiple of K
• Required on some machines; advised on x86-64
• Motivation for Aligning Data: Performance
• Inefficient to load or store data that is unaligned
• Some machines don’t event support unaligned memory access
• Compiler
• Inserts gaps in structure to ensure correct alignment of fields
• sizeof() returns the actual size of structs (i.e., including padding)

27
Carnegie Mellon

Specific Cases of Alignment (x86-64)


• 1 byte: char, …
• no restrictions on address
• 2 bytes: short, …
• lowest 1 bit of address must be 02
• 4 bytes: int, float, …
• lowest 2 bits of address must be 002
• 8 bytes: double, long, char *, …
• lowest 3 bits of address must be 0002

28
Carnegie Mellon

Satisfying Alignment with Structures

29
Carnegie Mellon

Satisfying Alignment with Structures


• Within structure:
• Must satisfy each element’s alignment requirement

29
Carnegie Mellon

Satisfying Alignment with Structures


• Within structure:
• Must satisfy each element’s alignment requirement
• Overall structure placement
• Structure length must be multiples of K, where:
• K = Largest alignment of any element
• WHY?!

29
Carnegie Mellon

Satisfying Alignment with Structures


• Within structure:
• Must satisfy each element’s alignment requirement struct S2 {
double v;
• Overall structure placement int i[2];
char c;
• Structure length must be multiples of K, where: } *p;
• K = Largest alignment of any element
• WHY?!

v i[0] i[1] c 7 bytes


p+0 p+8 p+16 p+24

Multiple of K=8

29
Carnegie Mellon

Saving Space
• Put large data types first in a Struct
• This is not something that a C compiler would always do
• But knowing low-level details empower a C programmer to write
more efficient code
struct S4 {
char c;
int i; c 3 bytes i d 3 bytes
char d;
} *p;

struct S5 {
int i;
char c; i c d 2 bytes
char d;
} *p;
30
Carnegie Mellon

Arrays of Structures
struct S2 {
• Overall structure length multiple of K double v;
int i[2];
• Satisfy alignment requirement char c;
for every element } a[10];

a[0] a[1] a[2] • • •


a+7
a+0 a+24 a+48
2

v i[0] i[1] c 7 bytes


a+24 a+32 a+40 a+48
31
Carnegie Mellon

Return Struct Values

32
Carnegie Mellon

Return Struct Values


struct S{
int a, b;
};

struct S foo(int c, int d){


struct S retval;
retval.a = c;
retval.b = d;
return retval;
}

void bar() {
struct S test = foo(3, 4);
fprintf(stdout, “%d, %d\n”,
test.a, test.b);
// you will get “3, 4” from
the terminal
}

32
Carnegie Mellon

Return Struct Values


• This is perfectly fine.
struct S{
int a, b;
};

struct S foo(int c, int d){


struct S retval;
retval.a = c;
retval.b = d;
return retval;
}

void bar() {
struct S test = foo(3, 4);
fprintf(stdout, “%d, %d\n”,
test.a, test.b);
// you will get “3, 4” from
the terminal
}

32
Carnegie Mellon

Return Struct Values


• This is perfectly fine.
struct S{
int a, b; • A struct could contain many
}; members, how would this work if
the return value has to be in
struct S foo(int c, int d){ %rax??
struct S retval;
retval.a = c;
retval.b = d;
return retval;
}

void bar() {
struct S test = foo(3, 4);
fprintf(stdout, “%d, %d\n”,
test.a, test.b);
// you will get “3, 4” from
the terminal
}

32
Carnegie Mellon

Return Struct Values


• This is perfectly fine.
struct S{
int a, b; • A struct could contain many
}; members, how would this work if
the return value has to be in
struct S foo(int c, int d){ %rax??
struct S retval; • We don’t have to follow that
retval.a = c;
retval.b = d; convention…
return retval;
}

void bar() {
struct S test = foo(3, 4);
fprintf(stdout, “%d, %d\n”,
test.a, test.b);
// you will get “3, 4” from
the terminal
}

32
Carnegie Mellon

Return Struct Values


• This is perfectly fine.
struct S{
int a, b; • A struct could contain many
}; members, how would this work if
the return value has to be in
struct S foo(int c, int d){ %rax??
struct S retval; • We don’t have to follow that
retval.a = c;
retval.b = d; convention…
return retval; • If there are only a few members in
} a struct, we could return through
a few registers.
void bar() {
struct S test = foo(3, 4);
fprintf(stdout, “%d, %d\n”,
test.a, test.b);
// you will get “3, 4” from
the terminal
}

32
Carnegie Mellon

Return Struct Values


• This is perfectly fine.
struct S{
int a, b; • A struct could contain many
}; members, how would this work if
the return value has to be in
struct S foo(int c, int d){ %rax??
struct S retval; • We don’t have to follow that
retval.a = c;
retval.b = d; convention…
return retval; • If there are only a few members in
} a struct, we could return through
a few registers.
void bar() {
struct S test = foo(3, 4);
• If there are lots of members, we
fprintf(stdout, “%d, %d\n”, could return through memory, i.e.,
test.a, test.b); requires memory copy.
// you will get “3, 4” from
the terminal
}

32
Carnegie Mellon

Return Struct Values


• This is perfectly fine.
struct S{
int a, b; • A struct could contain many
}; members, how would this work if
the return value has to be in
struct S foo(int c, int d){ %rax??
struct S retval; • We don’t have to follow that
retval.a = c;
retval.b = d; convention…
return retval; • If there are only a few members in
} a struct, we could return through
a few registers.
void bar() {
struct S test = foo(3, 4);
• If there are lots of members, we
fprintf(stdout, “%d, %d\n”, could return through memory, i.e.,
test.a, test.b); requires memory copy.
// you will get “3, 4” from • But either way, there needs to be
the terminal some sort convention for
} returning struct.

32
Carnegie Mellon

Return Struct Values


struct S{
int a, b;
};

struct S foo(int c, int d){


struct S retval;
retval.a = c;
retval.b = d;
return retval;
}

void bar() {
struct S test = foo(3, 4);
fprintf(stdout, “%d, %d\n”,
test.a, test.b);
// you will get “3, 4” from
the terminal
}

33
Carnegie Mellon

Return Struct Values


struct S{
• The entire calling convention is
int a, b; part of what’s called Application
}; Binary Interface (ABI), which
specifies how two binaries
struct S foo(int c, int d){ should interact.
struct S retval;
retval.a = c; • ABI includes: ISA, data type
retval.b = d; size, calling convention, etc.
return retval; • API defines the interface as the
}
source code (e.g., C) level.
void bar() { • The OS and compiler have to
struct S test = foo(3, 4); agree on the ABI.
fprintf(stdout, “%d, %d\n”,
test.a, test.b); • Linux x86-64 ABI specifies that
// you will get “3, 4” from returning a struct with two
the terminal scalar (e.g. pointers, or long)
}
values is done via %rax & %rdx

33
Carnegie Mellon

Today: Data Structures and Buffer Overflow


• Arrays
• One-dimensional
• Multi-dimensional (nested)
• Structures
• Allocation
• Access
• Alignment
• Buffer Overflow

34
Carnegie Mellon

String Library Code


• Implementation of Unix function gets()
• No way to specify limit on number of characters to read

/* Get string from stdin */


char *gets(char *dest)
{
int c = getchar();
char *p = dest;
while (c != EOF && c != '\n') {
*p++ = c;
c = getchar();
}
*p = '\0';
return dest;
}
35
Carnegie Mellon

Vulnerable Buffer Code


/* Echo Line */
void echo()
{
char buf[4]; /* Way too small! */
gets(buf);
puts(buf);
}

void call_echo() {
echo();
}

36
Carnegie Mellon

String Library Code


• Implementation of Unix function gets()
• No way to specify limit on number of characters to read

/* Get string from stdin */


char *gets(char *dest)
{
int c = getchar();
char *p = dest;
while (c != EOF && c != '\n') {
*p++ = c;
c = getchar();
}
*p = '\0';
return dest;
}
37
Carnegie Mellon

String Library Code


• Implementation of Unix function gets()
• No way to specify limit on number of characters to read

Char buf[4]; A B C D
address x x+1 x+2 x+3 x+4

/* Get string from stdin */


char *gets(char *dest)
{
int c = getchar();
char *p = dest;
while (c != EOF && c != '\n') {
*p++ = c;
c = getchar();
}
*p = '\0';
return dest;
}
37
Carnegie Mellon

String Library Code


• Implementation of Unix function gets()
• No way to specify limit on number of characters to read

Char buf[4]; A B C D F
address x x+1 x+2 x+3 x+4

/* Get string from stdin */


char *gets(char *dest)
{
int c = getchar();
char *p = dest;
while (c != EOF && c != '\n') {
*p++ = c;
c = getchar();
}
*p = '\0';
return dest;
}
37
Carnegie Mellon

String Library Code


• Implementation of Unix function gets()
• No way to specify limit on number of characters to read

Char buf[4]; A B C D E F
address x x+1 x+2 x+3 x+4

/* Get string from stdin */


char *gets(char *dest)
{
int c = getchar();
char *p = dest;
while (c != EOF && c != '\n') {
*p++ = c;
c = getchar();
}
*p = '\0';
return dest;
}
37
Carnegie Mellon

Vulnerable Buffer Code


/* Echo Line */
void echo()
{
char buf[4]; /* Way too small! */
gets(buf);
puts(buf);
}

void call_echo() {
echo();
}

38
Carnegie Mellon

Vulnerable Buffer Code


/* Echo Line */
void echo()
{
char buf[4]; /* Way too small! */
gets(buf);
puts(buf);
}

void call_echo() {
echo();
}

unix>./bufdemo-nsp
Type a string:0123
0123

38
Carnegie Mellon

Vulnerable Buffer Code


/* Echo Line */
void echo()
{
char buf[4]; /* Way too small! */
gets(buf);
puts(buf);
}

void call_echo() {
echo();
}

unix>./bufdemo-nsp
Type a string:0123
0123

unix>./bufdemo-nsp
Type a string:01234
Segmentation Fault

38
Carnegie Mellon

Buffer Overflow Stack Example


Before call to gets
void echo() echo:
Stack Frame { subq $24, %rsp
for call_echo char buf[4]; movq %rsp, %rdi
gets(buf); call gets
… …
}
00 00 Address
Return 00 00
00 (840bytes)
06 f6
Stack Frame call_echo:
for echo . . .
20 bytes unused 4006f1: callq 4006cf <echo>
4006f6: add $0x8,%rsp
. . .
[3] [2] [1] [0] buf %rsp

39
Carnegie Mellon

Buffer Overflow Stack Example #1


After call to gets
void echo() echo:
Stack Frame { subq $24, %rsp
for call_echo char buf[4]; movq %rsp, %rdi
gets(buf); call gets
… …
}
00 00 Address
Return 00 00
00 (8
40bytes)
06 f6
00 32 31 30 call_echo:
39 38 37 36 . . .
35 34 unused
20 bytes 33 32 4006f1: callq 4006cf <echo>
31 30 39 38 4006f6: add $0x8,%rsp
37 36 35 34 . . .
33 32 31 30 buf %rsp
unix>./bufdemo-nsp
Type a string:01234567890123456789012
01234567890123456789012

Overflowed buffer, but did not corrupt state


40
Carnegie Mellon

Buffer Overflow Stack Example #2


After call to gets
void echo() echo:
Stack Frame { subq $24, %rsp
for call_echo char buf[4]; movq %rsp, %rdi
gets(buf); call gets
… …
}
00 00 Address
Return 00 00
00 (8
40bytes)
00 34
33 32 31 30 call_echo:
39 38 37 36 . . .
35 34 unused
20 bytes 33 32 4006f1: callq 4006cf <echo>
31 30 39 38 4006f6: add $0x8,%rsp
37 36 35 34 . . .
33 32 31 30 buf %rsp
unix>./bufdemo-nsp
Type a string:0123456789012345678901234
Segmentation Fault

Overflowed buffer, and corrupt return address


41
Carnegie Mellon

Buffer Overflow Stack Example #3


After call to gets
void echo() echo:
Stack Frame { subq $24, %rsp
for call_echo char buf[4]; movq %rsp, %rdi
gets(buf); call gets
… …
}
00 00 Address
Return 00 00
00 (8
40bytes)
06 00
33 32 31 30 call_echo:
39 38 37 36 . . .
35 34 unused
20 bytes 33 32 4006f1: callq 4006cf <echo>
31 30 39 38 4006f6: add $0x8,%rsp
37 36 35 34 . . .
33 32 31 30 buf %rsp
unix>./bufdemo-nsp
Type a string:012345678901234567890123
012345678901234567890123

Overflowed buffer, corrupt return address, but


program appears to still work! 42
Carnegie Mellon

Buffer Overflow Stack Example #4


After call to gets
Stack Frame register_tm_clones:
for call_echo
. . .
400600: mov %rsp,%rbp
400603: mov %rax,%rdx
00 00 Address
Return 00 00
400606: shr $0x3f,%rdx
00 (8
40bytes)
06 00 40060a: add %rdx,%rax
33 32 31 30 40060d: sar %rax
39 38 37 36 400610: jne 400614
35 34 unused
20 bytes 33 32 400612: pop %rbp
400613: retq
31 30 39 38
37 36 35 34
33 32 31 30 buf %rsp

“Returns” to unrelated code


Could be code controlled by attackers!

43

You might also like