330 likes | 532 Views
Machine-Level Representation of Programs (x86-64). Outline. x86-64 Machine-Level Programming Data Representation Register Instruction Procedures and Stack Alignment Byte Ordering Suggested reading Chap 3.13. Outline. x86-64 Machine-Level Programming Procedures and Stack Alignment
E N D
Outline • x86-64 Machine-Level Programming • Data Representation • Register • Instruction • Procedures and Stack • Alignment • Byte Ordering • Suggested reading • Chap 3.13
Outline • x86-64 Machine-Level Programming • Procedures and Stack • Alignment • Byte Ordering • Suggested reading • Chap 3.13
Size of Data Type • Data Types in C Language
Integer Register IA32 %eax %ah %al %ebx %bh %bl %ecx %ch %cl %edx %dh %dl %esi %edi %esp %ebp
Integer Register Extend exist registers to 64bits %rax %eax %ah %al %rbx %edx %dh %dl %rcx %ecx %ch %cl %rdx %ebx %bh %bl %rsi %esi %rdi %edi %rsp %esp %rbp %ebp
Integer Register Add 8 new 64bits registers %rax %eax %ah %al %r8 %r8d %rbx %ebx %dh %dl %r9 %r9d %rcx %ecx %ch %cl %r10 %r10d %rdx %edx %bh %bl %r11 %r11d %rsi %esi %r12 %r12d %rdi %edi %r13 %r13d %rsp %esp %r14 %r14d %rbp %ebp %r15 %r15d
Integer Register Make %ebp/%rbp general purpose %rax %eax %ah %al %r8 %r8d %rbx %ebx %dh %dl %r9 %r9d %rcx %ecx %ch %cl %r10 %r10d %rdx %edx %bh %bl %r11 %r11d %rsi %esi %r12 %r12d %rdi %edi %r13 %r13d %rsp %esp %r14 %r14d %rbp %rbp %ebp %ebp %r15 %r15d
Instructions • Long word l (4 Bytes) ↔ Quad word q (8 Bytes) • New Instructions • movl → movq • addl → addq • sall → salq • etc. • 32-bit instructions generate 32-bit results • Set higher order bits of destination register to 0 • Example: addl
Switch Statements Jump Table long switch(long x) { switch(x) { . . . } . . . } .section .rodata .align 4 .L8: .long .L1 # x = 0 .long .L2 # x = 1 .long .L3 # x = 2 .long .L4 # x = 3 .long .L5 # x = 4 .long .L6 # x = 5 .long .L7 # x = 6 switch: pushl %ebp # Setup movl %esp, %ebp # Setup movl 8(%ebp), %edx # edx = x cmpl $6, %edx # x:6 ja .L1 # if > goto default jmp *.L8(,%edx,4) # goto JTab[x]
Switch Statements • x86-64 • Same general idea, adapted to 64-bit code • Table entries 64 bits (pointers) .section .rodata .align 4 .L8: .long .L1 # x = 0 .long .L2 # x = 1 .long .L3 # x = 2 .long .L4 # x = 3 .long .L5 # x = 4 .long .L6 # x = 5 .long .L7 # x = 6 .section .rodata .align 8 .L8: .quad .L1 # x = 0 .quad .L2 # x = 1 .quad .L3 # x = 2 .quad .L4 # x = 3 .quad .L5 # x = 4 .quad .L6 # x = 5 .quad .L7 # x = 6 IA32 x86-64
Example: swap() swap: pushl %ebp movl %esp,%ebp pushl %ebx movl 12(%ebp),%ecx movl 8(%ebp),%edx movl (%ecx),%eax movl (%edx),%ebx movl %eax,(%edx) movl %ebx,(%ecx) movl -4(%ebp),%ebx movl %ebp,%esp popl %ebp ret IA32 void swap(int *xp, int *yp) { int t0 = *xp; int t1 = *yp; *xp = t1; *yp = t0; } Setup Body Finish
Example: swap() swap: movl (%rdi), %edx movl (%rsi), %eax movl %eax, (%rdi) movl %edx, (%rsi) ret x86-64 void swap(int *xp, int *yp) { int t0 = *xp; int t1 = *yp; *xp = t1; *yp = t0; }
Example: swap() swap: movl (%rdi), %edx movl (%rsi), %eax movl %eax, (%rdi) movl %edx, (%rsi) ret Operands passed in registers First (xp) in %rdi Second (yp) in %rsi 64-bit pointers No stack operation required 32-bit data Data held in register %eax and %edx movl operation
Example: swap() swap: movq (%rdi), %rdx movq (%rsi), %rax movq %rax, (%rdi) movq %rdx, (%rsi) ret Swap long int in 64-bit void swap(long int *xp, long int *yp) { long int t0 = *xp; long int t1 = *yp; *xp = t1; *yp = t0; } • 64-bit data • Data held in registers %rax and %rdx • movq operation • “q” stands for quar-word
Procedures - Stack • IA32/Linux Stack Frame • Caller Stack Frame • Arguments for this call • Return Address (pushed by “call”) • Callee Stack Frame • Old %ebp (saved by “push %ebp”) • Saved registers • Local variable s • Arguments for next call Arguments Ret Addr Old %ebp %ebp frame pointer Saved registers Local variables Arguments %esp stack pointer
Procedures - Register Caller-Save • IA32/Linux Register Usage • %eax, %edx, %ecx • Caller saves prior the call if values are used by later • %eax • Return integer value • %ebx, %esi, %edi • Callee saves if want to used them • %esp, %ebp • special %eax %edx %ecx Callee-Save %ebx %esi %edi Special %esp %ebp
Procedures - Register • X86-64/Linux Register Usage • Caller-Save • %rax %rcx %rdx %rsi %rdi %r8 %r9 • Callee-Save • %rbx %rbp %r10 • %r12 %r13 %r14 %r15 • Special • %rsp, %r11 %rax %rax %r8 %r8 %rbx %rbx %r9 %r9 %rcx %rcx %r10 %r10 %rdx %rdx %r11 %r11 %rsi %rsi %r12 %r12 %rdi %rdi %r13 %r13 %rsp %rsp %r14 %r14 %rbp %rbp %r15 %r15
Procedures - Register • X86-64/Linux Register Usage • Arguments passed via regs • %rcx %rdx %rsi %rdi %r8 %r9 • If more than 6 integer parameters, then passrest on stack • Return value by %rax • No frame pointer • Special • %rsp stack pointer • %r11 used for linking %rax ret %rax %r8 arg#5 %r8 %rbx %r9 arg#6 %r9 %rcx arg#4 %rcx %r10 %rdx arg#3 %rdx %r11 link %r11 %rsi arg#2 %rsi %r12 %rdi arg#1 %rdi %r13 %rsp stack %rsp %r14 %rbp %r15
Procedures - Stack • x86-64/Linux Stack Frame • Caller Stack Frame • Arguments passed via registers • Return Address (pushed by “call”) • Callee Stack Frame • Saved registers • Local variables Ret Addr Saved registers Local variables %rsp stack pointer
X86-64 Swap void swap(long *xp, long *yp) { long t0 = *xp; long t1 = *yp; *xp = t1; *yp = t0; } swap: movq (%rdi), %rdx movq (%rsi), %rax movq %rax, (%rdi) movq %rdx, (%rsi) ret • Operands passed in registers • First (xp) in %rdi, second (yp) in %rsi • No stack operations required (except ret) • Avoid stack • Can hold all local information in registers
Local Variables in Stack void swap_a(long *xp, long *yp) { volatile long loc[2]; loc[0] = *xp; loc[1] = *yp; *xp = loc[1]; *yp = loc[0]; } swap_a: movq (%rdi), %rax movq %rax, -24(%rsp) movq (%rsi), %rax movq %rax, -16(%rsp) movq -16(%rsp), %rax movq %rax, (%rdi) movq -24(%rsp), %rax movq %rax, (%rsi) ret • Avoid Stack Pointer change • Can hold all information within small windows beyond stack pointer ret ptr %rsp -8 unused -16 loc[1] -24 loc[0]
Without Stack Frame long scount = 0 void swap_b(long a[], int i) { swap(&a[i], &a[i+1]); scount++ } • No value held while swap being invoked • No callee save registers needed swap_b: movslq %esi,%rsi # sign extend leaq (%rdi,%rsi,8), %rdi # &a[i] leaq 8(%rdi),%rsi # &a[i+1] call swap # swap() incq scount # scount++; ret . . . ret ptr1 ret ptr2 %rsp execute in swap
Call using Jump long scount = 0 void swap_c(long a[], int i) { swap(&a[i], &a[i+1]); } • Directly return from swap • Possible since swap is a “tail call “ swap_c: movslq %esi,%rsi # Sign extend leaq (%rdi,%rsi,8), %rdi # &a[i] leaq 8(%rdi),%rsi # &a[i+1] jmp swap # swap() . . . ret ptr1 %rsp execute in swap
Stack Frame Example swap_d: movq %rbx, -16(%rsp) movslq %esi,%rbx movq %r12, -8(%rsp) movq %rdi, %r12 leaq (%rdi,%rbx,8), %rdi subq $16, %rsp leaq 8(%rdi), %rsi call swap movq (%r12,%rbx,8), %rax addq %rax, sum movq (%rsp), %rbx movq 8(%rsp), %r12 addq $16, %rsp ret long sum = 0 void swap_d(long a[], int i) { swap(a[i], a[i+1]); sum += a[i]; } • Keep values of a and i in callee save registers • Must set up stack frame to save these registers
Understanding x86-64 Stack Frame swap_d: movq %rbx, -16(%rsp) movslq %esi,%rbx movq %r12, -8(%rsp) movq %rdi, %r12 leaq (%rdi,%rbx,8), %rdi subq $16, %rsp leaq 8(%rdi), %rsi . . . addq %rax, sum movq (%rsp), %rbx movq 8(%rsp), %r12 addq $16, %rsp ret ret ptr %rsp # save %rbx %r12 -8 # save %r12 %rbx -16
Understanding x86-64 Stack Frame swap_d: movq %rbx, -16(%rsp) movslq %esi,%rbx movq %r12, -8(%rsp) movq %rdi, %r12 leaq (%rdi,%rbx,8), %rdi subq $16, %rsp leaq 8(%rdi), %rsi . . . addq %rax, sum movq (%rsp), %rbx movq 8(%rsp), %r12 addq $16, %rsp ret ret ptr # save %rbx %r12 +8 # save %r12 %rbx %rsp # move stack frame # restore %rbx # restore %r12
Understanding x86-64 Stack Frame swap_d: movq %rbx, -16(%rsp) movslq %esi,%rbx movq %r12, -8(%rsp) movq %rdi, %r12 leaq (%rdi,%rbx,8), %rdi subq $16, %rsp leaq 8(%rdi), %rsi . . . addq %rax, sum movq (%rsp), %rbx movq 8(%rsp), %r12 addq $16, %rsp ret ret ptr %rsp # save %rbx %r12 -8 # save %r12 %rbx -16 # move stack frame # restore %rbx # restore %r12 # move stack frame
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 • Simple deallocation • Increment stack pointer • No base/frame pointer needed
Example struct s1 { char c; int i[2]; double d; } *p; • IA32 Linux • K = 4; double treated like a 4-byte data type • X86-64 or IA32 Windows: • K = 8; due to double element C 3bytes i[0] i[1] 4bytes d p+0 p+4 p+8 p+24 p+16 C 3bytes i[0] i[1] d p+0 p+4 p+8 p+20 p+12
Byte Ordering IA32 (Little Endian) 0xf0 0xf1 0xf2 0xf3 0xf4 0xf5 0xf6 0xf7 C[0] C[1] C[2] C[3] C[4] C[5] C[6] C[7] S[0] S[1] S[2] S[3] LSB MSB LSB MSB I[0] I[1] LSB MSB L[0] Output on IA32 Characters 0-7 = [0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7] Shorts 0-3 = [0xf1f0,0xf3f2,0xf5f4,0xf7f6] Ints 0-1 = [0xf3f2f1f0,0xf7f6f5f4] Long 0 = [0xf3f2f1f0]
Byte Ordering X86-64 (Little Endian) 0xf0 0xf1 0xf2 0xf3 0xf4 0xf5 0xf6 0xf7 C[0] C[1] C[2] C[3] C[4] C[5] C[6] C[7] S[0] S[1] S[2] S[3] LSB MSB LSB MSB I[0] I[1] LSB MSB L[0] Output on x86-64 Characters 0-7 = [0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7] Shorts 0-3 = [0xf1f0,0xf3f2,0xf5f4,0xf7f6] Ints 0-1 = [0xf3f2f1f0,0xf7f6f5f4] Long 0 = [0xf7f6f5f4f3f2f1f0]