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

Machine-Level Programming IV: x86-64 Procedures, Data

The document discusses machine-level programming concepts for x86-64 including procedures, arrays, structures, data types, and how these concepts are implemented in x86-64 assembly. It covers register usage conventions, passing arguments to functions, accessing local variables and structure members, generating pointers, and examples of accessing and looping through arrays in assembly code.

Uploaded by

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

Machine-Level Programming IV: x86-64 Procedures, Data

The document discusses machine-level programming concepts for x86-64 including procedures, arrays, structures, data types, and how these concepts are implemented in x86-64 assembly. It covers register usage conventions, passing arguments to functions, accessing local variables and structure members, generating pointers, and examples of accessing and looping through arrays in assembly code.

Uploaded by

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

Machine-Level Programming IV:

x86-64 Procedures, Data

1
Today
 Procedures (x86-64)
 Arrays
 One-dimensional
 Multi-dimensional (nested)
 Multi-level
 Structures
 Allocation
 Access

2
x86-64 Integer Registers:
Usage Conventions
%rax Return value %r8 Argument #5

%rbx Callee saved %r9 Argument #6

%rcx Argument #4 %r10 Caller saved

%rdx Argument #3 %r11 Caller Saved

%rsi Argument #2 %r12 Callee saved

%rdi Argument #1 %r13 Callee saved

%rsp Stack pointer %r14 Callee saved

%rbp Callee saved %r15 Callee saved

4
x86-64 Registers
 Arguments passed to functions via registers
 If more than 6 integral parameters, then pass rest on stack
 These registers can be used as caller-saved as well

 All references to stack frame via stack pointer


 Eliminates need to update %ebp/%rbp

 Other Registers
 6 callee saved
 2 caller saved
 1 return value (also usable as caller saved)
 1 special (stack pointer)

5
x86-64 Locals in the Red Zone
swap_a:
/* Swap, using local array */
movq (%rdi), %rax
void swap_a(long *xp, long *yp)
movq %rax, -24(%rsp)
{
movq (%rsi), %rax
volatile long loc[2];
movq %rax, -16(%rsp)
loc[0] = *xp;
movq -16(%rsp), %rax
loc[1] = *yp;
movq %rax, (%rdi)
*xp = loc[1];
movq -24(%rsp), %rax
*yp = loc[0];
movq %rax, (%rsi)
}
ret

 Avoiding Stack Pointer Change rtn Ptr %rsp


 Can hold all information within small −8 unused
window beyond stack pointer
−16 loc[1]
−24 loc[0]

7
Interesting Features of Stack Frame
 Allocate entire frame at once
 All stack accesses can be relative to %rsp
 Do by decrementing stack pointer
 Can delay allocation, since safe to temporarily use red zone

 Simple deallocation
 Increment stack pointer
 No base/frame pointer needed

12
Today
 Procedures (x86-64)
 Arrays
 One-dimensional
 Multi-dimensional (nested)
 Multi-level
 Structures
 Allocation
 Access

14
Structure Allocation
struct rec {
int a[3]; Memory Layout
int i; a i n
struct rec *n;
}; 0 12 16 20

 Concept
 Contiguously-allocated region of memory
 Refer to members within structure by names
 Members may be of different types

15
Structure Access
r r+12
struct rec {
int a[3];
int i; a in
struct rec *n;
}; 0 12 16 20

 Accessing Structure Member


 Pointer indicates first byte of structure
 Access elements with offsets

void IA32 Assembly


set_i(struct rec *r,
# %edx = val
int val)
# %eax = r
{
movl %edx, 12(%eax) # Mem[r+12] = val
r->i = val;
}

16
Generating Pointer to Structure Member
r r+idx*4
struct rec {
int a[3];
a i n
int i;
struct rec *n; 0 12 16 20
};

 Generating Pointer to int *get_ap


(struct rec *r, int idx)
Array Element {
 Offset of each structure return &r->a[idx];
member determined at }
compile time
 Arguments movl 12(%ebp), %eax # Get idx
 Mem[%ebp+8]: r sall $2, %eax # idx*4
addl 8(%ebp), %eax # r+idx*4
 Mem[%ebp+12]: idx

17
struct rec {
int a[3];
Following Linked List int i;
struct rec *n;
 C Code };

void set_val
(struct rec *r, int val) a i n
{ 0 12 16 20
while (r) {
int i = r->i; Element i
r->a[i] = val;
r = r->n; Register Value
} %edx r
}
%ecx val

.L17: # loop:
movl 12(%edx), %eax # r->i
movl %ecx, (%edx,%eax,4) # r->a[i] = val
movl 16(%edx), %edx # r = r->n
testl %edx, %edx # Test r
jne .L17 # If != 0 goto loop
18
Today
 Procedures (x86-64)
 Arrays
 One-dimensional
 Multi-dimensional (nested)
 Multi-level
 Structures

19
Basic Data Types
 Integral
 Stored & operated on in general (integer) registers
 Signed vs. unsigned depends on instructions used
Intel ASMBytes C
byte b 1 [unsigned] char
word w 2 [unsigned] short
double word l 4 [unsigned] int
quad word q 8 [unsigned] long int (x86-64)

 Floating Point
 Stored & operated on in floating point registers
Intel ASMBytes C
Single s 4 float
Double l 8 double
Extended t 10/12/16 long double

20
Array Allocation
 Basic Principle
T A[L];
 Array of data type T and length L
 Contiguously allocated region of L * sizeof(T) bytes

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]; IA32
x x+4 x+8 x + 12

x86-64
x x+8 x + 16 x + 24
21
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
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[2] int * x + 8
val[5] int ??
*(val+1) int 5
val + i int * x + 4 i
22
Array Example
#define ZLEN 5
typedef int zip_dig[ZLEN];

zip_dig ut = { 7, 8, 7, 1, 2 };
zip_dig mit = { 0, 2, 1, 3, 9 };
zip_dig ucb = { 9, 4, 7, 2, 0 };

zip_dig ut; 7 8 7 1 2
16 20 24 28 32 36
zip_dig mit; 0 2 1 3 9
36 40 44 48 52 56
zip_dig ucb; 9 4 7 2 0
56 60 64 68 72 76

 Declaration “zip_dig ut” equivalent to “int ut[5]”


 Example arrays were allocated in successive 20 byte blocks
 Not guaranteed to happen in general
23
Array Accessing Example
zip_dig ut; 7 8 7 1 2
16 20 24 28 32 36

int get_digit
(zip_dig z, int dig)
{
return z[dig];
}  Register %edx contains
starting address of array
IA32  Register %eax contains
# %edx = z array index
# %eax = dig  Desired digit at
movl (%edx,%eax,4),%eax # z[dig] 4*%eax + %edx
 Use memory reference
(%edx,%eax,4)
24
Array Loop Example (IA32)
void zincr(zip_dig z) {
int i;
for (i = 0; i < ZLEN; i++)
z[i]++;
}

# edx = z
movl $0, %eax # %eax = i
.L4: # loop:
addl $1, (%edx,%eax,4) # z[i]++
addl $1, %eax # i++
cmpl $5, %eax # i:5
jne .L4 # if !=, goto loop

25
Pointer Loop Example (IA32)
void zincr_v(zip_dig z) {
void zincr_p(zip_dig z) { void *vz = z;
int *zend = z+ZLEN; int i = 0;
do { do {
(*z)++; (*((int *) (vz+i)))++;
z++; i += ISIZE;
} while (z != zend); } while (i != ISIZE*ZLEN);
} }

# edx = z = vz
movl $0, %eax # i = 0
.L8: # loop:
addl $1, (%edx,%eax) # Increment vz+i
addl $4, %eax # i += 4
cmpl $20, %eax # Compare i:20
jne .L8 # if !=, goto loop

26
Nested Array Example
#define PCOUNT 4
zip_dig pgh[PCOUNT] =
{{1, 5, 2, 0, 6},
{1, 5, 2, 1, 3 },
{1, 5, 2, 1, 7 },
{1, 5, 2, 2, 1 }};

zip_dig
1 5 2 0 6 1 5 2 1 3 1 5 2 1 7 1 5 2 2 1
pgh[4];

76 96 116 136 156

 “zip_dig pgh[4]” equivalent to “int pgh[4][5]”


 Variable pgh: array of 4 elements, allocated contiguously
 Each element is an array of 5 int’s, allocated contiguously
 “Row-Major” ordering of all elements guaranteed
27
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

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
28
Nested Array Row Access
 Row Vectors
 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

29
Nested Array Row Access Code
int *get_pgh_zip(int index) #define PCOUNT 4
{ zip_dig pgh[PCOUNT] =
return pgh[index]; {{1, 5, 2, 0, 6},
} {1, 5, 2, 1, 3 },
{1, 5, 2, 1, 7 },
{1, 5, 2, 2, 1 }};

# %eax = index
leal (%eax,%eax,4),%eax # 5 * index
leal pgh(,%eax,4),%eax # pgh + (20 * index)

 Row Vector
 pgh[index] is array of 5 int’s
 Starting address pgh+20*index
 IA32 Code
 Computes and returns address
 Compute as pgh + 4*(index+4*index)
30
Nested Array Row 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
31
Nested Array Element Access Code
int get_pgh_digit
(int index, int dig)
{
return pgh[index][dig];
}
movl 8(%ebp), %eax # index
leal (%eax,%eax,4), %eax # 5*index
addl 12(%ebp), %eax # 5*index+dig
movl pgh(,%eax,4), %eax # offset 4*(5*index+dig)

 Array Elements
 pgh[index][dig] is int
 Address: pgh + 20*index + 4*dig
 = pgh + 4*(5*index + dig)
 IA32 Code
 Computes address pgh + 4*((index+4*index)+dig)
32
Multi-Level Array Example
zip_dig ut = { 7, 8, 7, 1, 2 };
 Variable univ denotes
zip_dig mit = { 0, 2, 1, 3, 9 }; array of 3 elements
zip_dig ucb = { 9, 4, 7, 2, 0 };  Each element is a pointer
#define UCOUNT 3
 4 bytes
int *univ[UCOUNT] = {mit, ut, ucb};  Each pointer points to array
of int’s

ut
7 8 7 1 2
univ
16 20 24 28 32 36
160 36 mit
0 2 1 3 9
164 16
168 56 ucb 36 40 44 48 52 56
9 4 7 2 0
56 60 64 68 72 76

33
Element Access in Multi-Level Array
int get_univ_digit
(int index, int dig)
{
return univ[index][dig];
}

movl 8(%ebp), %eax # index


movl univ(,%eax,4), %edx # p = univ[index]
movl 12(%ebp), %eax # dig
movl (%edx,%eax,4), %eax # p[dig]

 Computation (IA32)
 Element access Mem[Mem[univ+4*index]+4*dig]
 Must do two memory reads
 First get pointer to row array
 Then access element within array
34
Array Element Accesses
Nested array Multi-level array
int get_pgh_digit int get_univ_digit
(int index, int dig) (int index, int dig)
{ {
return pgh[index][dig]; return univ[index][dig];
} }

Accesses looks similar in C, but addresses very different:

Mem[pgh+20*index+4*dig] Mem[Mem[univ+4*index]+4*dig]

35
N X N Matrix Code #define N 16
typedef int fix_matrix[N][N];
/* Get element a[i][j] */
int fix_ele
 Fixed dimensions (fix_matrix a, int i, int j)
 Know value of N at {
compile time return a[i][j];
}
#define IDX(n, i, j) ((i)*(n)+(j))
 Variable dimensions, /* Get element a[i][j] */
explicit indexing int vec_ele
 Traditional way to (int n, int *a, int i, int j)
implement dynamic {
arrays return a[IDX(n,i,j)];
}

/* Get element a[i][j] */


 Variable dimensions, int var_ele
implicit indexing (int n, int a[n][n], int i, int j)
 Now supported by gcc {
return a[i][j];
}
36
16 X 16 Matrix Access
 Array Elements
 Address A + i * (C * K) + j * K
 C = 16, K = 4

/* Get element a[i][j] */


int fix_ele(fix_matrix a, int i, int j) {
return a[i][j];
}

movl 12(%ebp), %edx # i


sall $6, %edx # i*64
movl 16(%ebp), %eax # j
sall $2, %eax # j*4
addl 8(%ebp), %eax # a + j*4
movl (%eax,%edx), %eax # *(a + j*4 + i*64)

37
n X n Matrix Access
 Array Elements
 Address A + i * (C * K) + j * K
 C = n, K = 4

/* Get element a[i][j] */


int var_ele(int n, int a[n][n], int i, int j) {
return a[i][j];
}

movl 8(%ebp), %eax # n


sall $2, %eax # n*4
movl %eax, %edx # n*4
imull 16(%ebp), %edx # i*n*4
movl 20(%ebp), %eax # j
sall $2, %eax # j*4
addl 12(%ebp), %eax # a + j*4
movl (%eax,%edx), %eax # *(a + j*4 + i*n*4)

38
Optimizing Fixed Array Access
a j-th column

#define N 16
typedef int fix_matrix[N][N];

/* Retrieve column j from array */


 Computation void fix_column
 Step through all elements in (fix_matrix a, int j, int *dest)
column j {
int i;
 Optimization for (i = 0; i < N; i++)
 Retrieving successive dest[i] = a[i][j];
elements from single }
column

39
Optimizing Fixed Array Access
 Optimization /* Retrieve column j from array */
 Compute ajp = &a[i][j] void fix_column
 Initially = a + 4*j (fix_matrix a, int j, int *dest)
{
 Increment by 4*N int i;
for (i = 0; i < N; i++)
Register Value
dest[i] = a[i][j];
%ecx ajp }
%ebx dest
%edx i

.L8: # loop:
movl (%ecx), %eax # Read *ajp
movl %eax, (%ebx,%edx,4) # Save in dest[i]
addl $1, %edx # i++
addl $64, %ecx # ajp += 4*N
cmpl $16, %edx # i:N
jne .L8 # if !=, goto loop
40
Optimizing Variable Array Access
 Compute ajp = &a[i][j]
 Initially = a + 4*j /* Retrieve column j from array */
 Increment by 4*n void var_column
(int n, int a[n][n],
Register Value int j, int *dest)
{
%ecx ajp int i;
%edi dest for (i = 0; i < n; i++)
%edx i dest[i] = a[i][j];
}
%ebx 4*n
%esi n

.L18: # loop:
movl (%ecx), %eax # Read *ajp
movl %eax, (%edi,%edx,4) # Save in dest[i]
addl $1, %edx # i++
addl $ebx, %ecx # ajp += 4*n
cmpl $edx, %esi # n:i
jg .L18 # if >, goto loop
41
Summary
 Procedures in x86-64
 Stack frame is relative to stack pointer
 Parameters passed in registers
 Arrays
 One-dimensional
 Multi-dimensional (nested)
 Multi-level
 Structures
 Allocation
 Access

42
Malicious Use of Buffer Overflow
Stack after call to gets()

void foo(){
foo stack frame
bar(); return
... address
} A B

int bar() { data written pad


char buf[64]; by gets()
gets(buf);
... exploit bar stack frame
return ...; code
B
}

 Input string contains byte representation of executable code


 Overwrite return address A with address of buffer B

 When bar() executes ret, will jump to exploit code


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

void call_echo() {
echo();
}
unix>./bufdemo
Type a string:1234567
1234567

unix>./bufdemo
Type a string:12345678
Segmentation Fault

unix>./bufdemo
Type a string:123456789ABC
Segmentation Fault
44
Avoiding Overflow Vulnerability
/* Echo Line */
void echo()
{
char buf[4]; /* Way too small! */
fgets(buf, 4, stdin);
puts(buf);
}

 Use library routines that limit string lengths


 fgets instead of gets
 strncpy instead of strcpy
 Don’t use scanf with %s conversion specification
 Use fgets to read the string
 Or use %ns where n is a suitable integer

45
System-Level Protections
 Randomized stack offsets unix> gdb bufdemo
 At start of program, allocate random amount (gdb) break echo

of space on stack (gdb) run


 Makes it difficult for hacker to predict (gdb) print /x $ebp
beginning of inserted code $1 = 0xffffc638

(gdb) run
(gdb) print /x $ebp
 Nonexecutable code segments $2 = 0xffffbb08
 In traditional x86, can mark region of memory
(gdb) run
as either “read-only” or “writeable” (gdb) print /x $ebp
 Can execute anything readable $3 = 0xffffc6a8
 X86-64 added explicit “execute” permission

46
Stack Canaries
 Idea
 Place special value (“canary”) on stack just beyond buffer
 Check for corruption before exiting function
 GCC Implementation
 -fstack-protector
 -fstack-protector-all

unix>./bufdemo-protected
Type a string:1234
1234

unix>./bufdemo-protected
Type a string:12345
*** stack smashing detected ***

47
Protected Buffer Disassembly echo:
804864d: 55 push %ebp
804864e: 89 e5 mov %esp,%ebp
8048650: 53 push %ebx
8048651: 83 ec 14 sub $0x14,%esp
8048654: 65 a1 14 00 00 00 mov %gs:0x14,%eax
804865a: 89 45 f8 mov %eax,0xfffffff8(%ebp)
804865d: 31 c0 xor %eax,%eax
804865f: 8d 5d f4 lea 0xfffffff4(%ebp),%ebx
8048662: 89 1c 24 mov %ebx,(%esp)
8048665: e8 77 ff ff ff call 80485e1 <gets>
804866a: 89 1c 24 mov %ebx,(%esp)
804866d: e8 ca fd ff ff call 804843c <puts@plt>
8048672: 8b 45 f8 mov 0xfffffff8(%ebp),%eax
8048675: 65 33 05 14 00 00 00 xor %gs:0x14,%eax
804867c: 74 05 je 8048683 <echo+0x36>
804867e: e8 a9 fd ff ff call 804842c <FAIL>
8048683: 83 c4 14 add $0x14,%esp
8048686: 5b pop %ebx
8048687: 5d pop %ebp
8048688: c3 ret
48
Setting Up Canary
Before call to gets /* Echo Line */
void echo()
Stack Frame {
for main char buf[4]; /* Way too small! */
gets(buf);
puts(buf);
Return Address }
Saved %ebp %ebp
Saved %ebx
Canary
[3] [2] [1] [0] buf

Stack Frame
echo:
for echo
. . .
movl %gs:20, %eax # Get canary
movl %eax, -8(%ebp) # Put on stack
xorl %eax, %eax # Erase canary
. . .

49
Checking Canary
Before call to gets /* Echo Line */
void echo()
Stack Frame {
for main char buf[4]; /* Way too small! */
gets(buf);
puts(buf);
Return Address }
Saved %ebp %ebp
Saved %ebx
Canary
[3] [2] [1] [0] buf

Stack Frame
echo:
for echo
. . .
movl -8(%ebp), %eax # Retrieve from stack
xorl %gs:20, %eax # Compare with Canary
je .L24 # Same: skip ahead
call __stack_chk_fail # ERROR
.L24:
. . .
50
Canary Example
Before call to gets Input 1234
Stack Frame Stack Frame
for main for main

Return Address Return Address


Saved %ebp %ebp Saved %ebp %ebp
Saved %ebx Saved %ebx
03 e3 7d 00 03 e3 7d 00
[3] [2] [1] [0] buf 34 33 32 31 buf

Stack Frame Stack Frame


for echo for echo

(gdb) break echo


(gdb) run Benign corruption!
(gdb) stepi 3
(allows programmers to make
(gdb) print /x *((unsigned *) $ebp - 2)
$1 = 0x3e37d00 silent off-by-one errors)
51

You might also like