Machine-Level Programming II: Basics Comp 21000: Introduction to Computer Organization & Systems Spring 2016 Instructor: John Barr * Modified slides from the book “Computer Systems: a Programmer’s Perspective”, Randy Bryant & David O’Hallaron, 2015
Machine Programming I: Basics History of Intel processors and architectures C, assembly, machine code Assembly Basics: Registers, operands, move Intro to x86-64
Special memory areas: stack and heap Kernel virtual memory Memory mapped region for shared libraries Run-time heap (created at runtime by malloc) User stack (created at runtime) Unused Read/write segment (.data, .bss) Read-only segment (.init, .text, .rodata) Stack Space in Memory allocated to each running program (called a process) Used to store “temporary” variable values Used to store variables for functions Heap Space in Memory allocated to each running program (process) Used to store dynamically allocated variables
Example of Simple Addressing Modes void swap (long *xp, long *yp) { long t0 = *xp; long t1 = *yp; *xp = t1; *yp = t0; } swap: movq (%rdi), %rax movq (%rsi), %rdx movq %rdx, (%rdi) movq %rax, (%rsi) ret Note: if you look at the assembly code, it’s much more complicated; we’re ignoring some code to simplify.
Understanding Swap() Memory Registers void swap (long *xp, long *yp) { long t0 = *xp; long t1 = *yp; *xp = t1; *yp = t0; } %rdi %rsi %rax %rdx Register Value %rdi xp %rsi yp %rax t0 %rdx t1 swap: movq (%rdi), %rax # t0 = *xp movq (%rsi), %rdx # t1 = *yp movq %rdx, (%rdi) # *xp = t1 movq %rax, (%rsi) # *yp = t0 ret
Understanding Swap() Memory Registers 0x120 0x118 0x110 0x108 0x100 Address 123 %rdi %rsi %rax %rdx 0x120 0x100 456 swap: movq (%rdi), %rax # t0 = *xp movq (%rsi), %rdx # t1 = *yp movq %rdx, (%rdi) # *xp = t1 movq %rax, (%rsi) # *yp = t0 ret
Understanding Swap() Memory Registers 0x120 0x118 0x110 0x108 0x100 Address 123 %rdi %rsi %rax %rdx 0x120 0x100 123 456 swap: movq (%rdi), %rax # t0 = *xp movq (%rsi), %rdx # t1 = *yp movq %rdx, (%rdi) # *xp = t1 movq %rax, (%rsi) # *yp = t0 ret
Understanding Swap() Memory Registers 0x120 0x118 0x110 0x108 0x100 Address 123 %rdi %rsi %rax %rdx 0x120 0x100 123 456 456 swap: movq (%rdi), %rax # t0 = *xp movq (%rsi), %rdx # t1 = *yp movq %rdx, (%rdi) # *xp = t1 movq %rax, (%rsi) # *yp = t0 ret
Understanding Swap() Memory Registers 0x120 0x118 0x110 0x108 0x100 Address 456 %rdi %rsi %rax %rdx 0x120 0x100 123 456 456 swap: movq (%rdi), %rax # t0 = *xp movq (%rsi), %rdx # t1 = *yp movq %rdx, (%rdi) # *xp = t1 movq %rax, (%rsi) # *yp = t0 ret
Understanding Swap() Memory Registers 0x120 0x118 0x110 0x108 0x100 Address 456 %rdi %rsi %rax %rdx 0x120 0x100 123 456 123 swap: movq (%rdi), %rax # t0 = *xp movq (%rsi), %rdx # t1 = *yp movq %rdx, (%rdi) # *xp = t1 movq %rax, (%rsi) # *yp = t0 ret
Complete Memory Addressing Modes Most General Form D(Rb,Ri,S) Mem[Reg[Rb]+S*Reg[Ri]+ D] D: Constant “displacement” 1, 2, or 4 bytes Rb: Base register: Any of 16 integer registers Ri: Index register: Any, except for %rsp Unlikely you’d use %rbp, either S: Scale: 1, 2, 4, or 8 (why these numbers?) Special Cases (Rb,Ri) Mem[Reg[Rb]+Reg[Ri]] D(Rb,Ri) Mem[Reg[Rb]+Reg[Ri]+D] (Rb,Ri,S) Mem[Reg[Rb]+S*Reg[Ri]] D(Rb,Ri,S) Mem[Reg[Rb]+S*Reg[Ri]+D]
Address Computation Examples %rdx 0xf000 %rcx 0x100 Expression Computation Address 0x8(%rdx) (%rdx,%rcx) (%rdx,%rcx,4) 0x80(,%rdx,2)
Address Computation Examples %edx 0xf000 %ecx 0x100 Expression Computation Address 0x8(%rdx) (%rdx,%rcx) (%rdx,%rcx,4) 0x80(,%rdx,2) 0xf000 + 0x8 0xf008 0xf000 + 0x100 0xf100 0xf000 + 4*0x100 0xf400 2*0xf000 + 0x80 0x1e080
Address Computation Instruction leaq Src,Dest Src is address mode expression Set Dest to address denoted by expression Format Looks like a memory access Does not actually access memory Rather, calculates the memory address, then stores in a register Uses Computing addresses without a memory reference E.g., translation of p = &x[i]; Computing arithmetic expressions of the form x + k*y k = 1, 2, 4, or 8. lea = load effective address
Example Converted to ASM by compiler: long m12(long x) { return x*12; } leaq (%rdi,%rdi,2), %rax ;t <- x+x*2 salq $2, %rax ;return t<<2 ; or t * 4
Address Computation Instruction Expression Result leaq 6(%rax), %rdx leaq (%rax, %rcx), %rdx leaq (%rax, %rcx, 4), %rdx leaq 7(%rax, %rax, 8), %rdx leaq 0xA(,%rax, 4), %rdx leaq 9(%rax,%rcx, 2), %rdx Assume %rax holds value x and %rcx holds value y * Note the leading comma in the next to last entry
Address Computation Instruction Expression Result leal 6(%rax), %rdx leal (%rax, %rcx), %rdx leal (%rax, %rcx, 4), %rdx leal 7(%rax, %rax, 8), %rdx leal 0xA(,%rax, 4), %rdx leal 9(%rax,%rcx, 2), %rdx %rdx x + 6 %rdx x + y %rdx x + (y * 4) %rdx x + (x * 8) + 7 = (x * 9) + 7 %rdx (x * 4) + 10 %rdx x + (y * 2) + 9 Assume %rax holds value x and %rcx holds value y * Note the leading comma in the next to last entry
Machine Programming II: Summary History of Intel processors and architectures Evolutionary design leads to many quirks and artifacts C, assembly, machine code New forms of visible state: program counter, registers,… Compiler must transform statements, expressions, procedures into low-level instruction sequences Assembly Basics: Registers, operands, move The x86-64 move instructions cover wide range of data movement forms Intro to x86-64 A major departure from the style of code seen in IA32