The Stack & Procedures CSE 351 Winter 2018

Slides:



Advertisements
Similar presentations
Machine-Level Programming III: Procedures Feb. 8, 2000 Topics IA32 stack Stack-based languages Stack frames Register saving conventions Creating pointers.
Advertisements

University of Washington Procedures and Stacks II The Hardware/Software Interface CSE351 Winter 2013.
Copyright 2014 – Noah Mendelsohn UM Macro Assembler Functions Noah Mendelsohn Tufts University Web:
Machine/Assembler Language Putting It All Together Noah Mendelsohn Tufts University Web:
Computer Architecture CSCE 350
University of Washington Last Time For loops  for loop → while loop → do-while loop → goto version  for loop → while loop → goto “jump to middle” version.
1 Storage Registers vs. memory Access to registers is much faster than access to memory Goal: store as much data as possible in registers Limitations/considerations:
Machine-Level Programming III: Procedures Apr. 17, 2006 Topics IA32 stack discipline Register saving conventions Creating pointers to local variables CS213.
1 Function Calls Professor Jennifer Rexford COS 217 Reading: Chapter 4 of “Programming From the Ground Up” (available online from the course Web site)
Machine-Level Programming III: Procedures Sept. 17, 2007 IA32 stack discipline Register saving conventions Creating pointers to local variablesx86-64 Argument.
– 1 – , F’02 ICS05 Instructor: Peter A. Dinda TA: Bin Lin Recitation 4.
Machine-Level Programming III: Procedures Sept. 15, 2006 IA32 stack discipline Register saving conventions Creating pointers to local variablesx86-64 Argument.
Stack Activation Records Topics IA32 stack discipline Register saving conventions Creating pointers to local variables February 6, 2003 CSCE 212H Computer.
Stacks and Frames Demystified CSCI 3753 Operating Systems Spring 2005 Prof. Rick Han.
Carnegie Mellon Introduction to Computer Systems /18-243, spring 2009 Recitation, Jan. 14 th.
University of Washington Today More on procedures, stack etc. Lab 2 due today!  We hope it was fun! What is a stack?  And how about a stack frame? 1.
Fabián E. Bustamante, Spring 2007 Machine-Level Programming III - Procedures Today IA32 stack discipline Register saving conventions Creating pointers.
Machine-Level Programming III: Procedures Topics IA32 stack discipline Register-saving conventions Creating pointers to local variables CS 105 “Tour of.
Machine-level Programming III: Procedures Topics –IA32 stack discipline –Register saving conventions –Creating pointers to local variables.
Reminder Bomb lab is due tomorrow! Attack lab is released tomorrow!!
University of Amsterdam Computer Systems – the instruction set architecture Arnoud Visser 1 Computer Systems The instruction set architecture.
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition Carnegie Mellon Instructor: San Skulrattanakulchai Machine-Level Programming.
Section 5: Procedures & Stacks
Reading Condition Codes (Cont.)
Credits and Disclaimers
CSCE 212 Computer Architecture
© Craig Zilles (adapted from slides by Howard Huang)
Recitation: Attack Lab
143A: Principles of Operating Systems Lecture 4: Calling conventions
Procedures & Executables CSE 351 Spring 2017
The Stack & Procedures CSE 351 Spring 2017
Machine-Level Programming III: Procedures
Recitation: Attack Lab
Procedures & The Stack Announcements Lab 1 graded HW 2 out
Switch & Procedures & The Stack I CSE 351 Winter 2017
x86-64 Programming III & The Stack CSE 351 Winter 2018
Machine-Level Programming 4 Procedures
Assembly Programming IV CSE 351 Spring 2017
x86-64 Programming III & The Stack CSE 351 Winter 2018
Machine-Level Programming III: Procedures /18-213/14-513/15-513: Introduction to Computer Systems 7th Lecture, September 18, 2018.
Procedures & The Stack II CSE 351 Autumn 2016
Procedures & The Stack I CSE 351 Autumn 2016
Arrays CSE 351 Winter
Carnegie Mellon Machine-Level Programming III: Procedures : Introduction to Computer Systems October 22, 2015 Instructor: Rabi Mahapatra Authors:
Procedures & The Stack II CSE 351 Winter 2017
Assembly Programming IV CSE 410 Winter 2017
Procedures & Executables CSE 351 Autumn 2017
Recitation: Attack Lab
Roadmap C: Java: Assembly language: OS: Machine code: Computer system:
x86-64 Programming III & The Stack CSE 351 Autumn 2017
Machine-Level Programming III: Procedures Sept 18, 2001
x86-64 Programming I CSE 351 Autumn 2017
Machine Level Representation of Programs (IV)
The Stack & Procedures CSE 410 Winter 2017
Roadmap C: Java: Assembly language: OS: Machine code: Computer system:
Ithaca College Machine-Level Programming VII: Procedures Comp 21000: Introduction to Computer Systems & Assembly Lang Spring 2017.
x86-64 Programming I CSE 351 Winter 2018
x86-64 Programming I CSE 351 Winter 2018
Machine-Level Representation of Programs (x86-64)
Ithaca College Machine-Level Programming VII: Procedures Comp 21000: Introduction to Computer Systems & Assembly Lang Spring 2017.
Program and memory layout
“Way easier than when we were students”
Loops, Switches, Intro to Stack & Procedures CSE 351 Winter 2019
Ithaca College Machine-Level Programming VII: Procedures Comp 21000: Introduction to Computer Systems & Assembly Lang Spring 2017.
Credits and Disclaimers
Credits and Disclaimers
© Craig Zilles (adapted from slides by Howard Huang)
Presentation transcript:

The Stack & Procedures CSE 351 Winter 2018 Instructor: Mark Wyse Teaching Assistants: Kevin Bi Parker DeWilde Emily Furst Sarah House Waylon Huang Vinny Palaniappan http://xkcd.com/648/

Administrative Homework 2 (x86) due tonight Lab 2 due Friday (2/2) Homework 3 released today On midterm material, but due after the midterm (2/9) Midterm (2/5, in-class) Find a study group! Study practice problems and past exams Must bring your UW Student ID to the exam! Topics are Lectures 1 – 12, Ch 1.0 – 3.7 Stay tuned for possible review session info; held by TA’s

x86-64 Stack Stack “Bottom” High Addresses Stack Pointer: %rsp Stack “Top” Stack “Bottom” Region of memory managed with stack “discipline” Grows toward lower addresses Customarily shown “upside-down” Register %rsp contains lowest stack address %rsp = address of top element, the most-recently-pushed item that is not-yet-popped Increasing Addresses Stack Grows Down Memory is still just an array But we treat the upper part like a stack that grows downwards rsp points at the lowest stack address, the top of the stack This will be the first thing to be popped off Remember: stacks only have 2 operations: push and pop Low Addresses 0x00…00

x86-64 Stack: Push pushq src Example: Stack “Bottom” High Addresses Stack “Bottom” pushq src Fetch operand at src Src can be reg, memory, immediate Decrement %rsp by 8 Store value at address given by %rsp Example: pushq %rcx Adjust %rsp and store contents of %rcx on the stack Increasing Addresses Stack Grows Down Stack Pointer: %rsp Stack “Top” -8 Low Addresses 0x00…00

x86-64 Stack: Pop popq dst Stack “Bottom” High Addresses Stack “Bottom” popq dst Load value at address given by %rsp Store value at dst (must be register) Increment %rsp by 8 Example: popq %rcx Stores contents of top of stack into %rcx and adjust %rsp Increasing Addresses Stack Grows Down +8 Stack Pointer: %rsp Stack “Top” Low Addresses 0x00…00 Those bits are still there; we’re just not using them.

Procedures Stack Structure Calling Conventions Passing control Passing data Managing local data Register Saving Conventions Illustration of Recursion

Procedure Call Overview Caller … <set up args> call <clean up args> <find return val> procedures Callee <create local vars> … <set up return val> <destroy local vars> ret Callee must know where to find args Callee must know where to find return address Caller must know where to find return value Caller and Callee run on same CPU, so use the same registers How do we deal with register reuse? Unneeded steps can be skipped (e.g. no arguments)

Procedure Call Overview Caller … <save regs> <set up args> call <clean up args> <restore regs> <find return val> Callee <save regs> <create local vars> … <set up return val> <destroy local vars> <restore regs> ret The convention of where to leave/find things is called the calling convention (or procedure call linkage) Details vary between systems We will see the convention for x86-64/Linux in detail What could happen if our program didn’t follow these conventions? Note: conventions are similar, but slightly different on machines running Windows OS If everyone doesn’t use the same conventions, then we can’t call each others’ libraries

Code Example (Preview) void multstore (long x, long y, long *dest) { long t = mult2(x, y); *dest = t; } Compiler Explorer: https://godbolt.org/g/cKKDZn 0000000000400540 <multstore>: 400540: push %rbx # Save %rbx 400541: movq %rdx,%rbx # Save dest 400544: call 400550 <mult2> # mult2(x,y) 400549: movq %rax,(%rbx) # Save at dest 40054c: pop %rbx # Restore %rbx 40054d: ret # Return long mult2 (long a, long b) { long s = a * b; return s; } 0000000000400550 <mult2>: 400550: movq %rdi,%rax # a 400553: imulq %rsi,%rax # a * b 400557: ret # Return Here we have a function, multstore, which calls another function, mult2 Look at call, specifies where to jump to (400550) We’ll get to each of the details for this

Procedure Control Flow Use stack to support procedure call and return Procedure call: call label Push return address on stack (why? which address?) Jump to label Call == special push

Procedure Control Flow Use stack to support procedure call and return Procedure call: call label Push return address on stack (why? which address?) Jump to label Return address: Address of instruction immediately after call instruction Example from disassembly: 400544: callq 400550 <mult2> 400549: movq %rax,(%rbx) Return address = 0x400549 Procedure return: ret Pop return address from stack Jump to address 400544: call 400550 <mult2> 400549: movq %rax,(%rbx) next instruction happens to be a move, but could be anything Ret == special pop

Procedure Call Example (step 1) 0000000000400540 <multstore>: • 400544: call 400550 <mult2> 400549: movq %rax,(%rbx) 0x120 %rsp • 0x128 0x130 0x400544 %rip 0000000000400550 <mult2>: 400550: movq %rdi,%rax • 400557: ret Push return address on stack update %rsp -> 0x118 400549 Jump to new function Update %rip

Procedure Call Example (step 2) 0000000000400540 <multstore>: • 400544: call 400550 <mult2> 400549: movq %rax,(%rbx) • 0x120 0x128 0x130 0x400549 0x118 0x118 %rsp 0000000000400550 <mult2>: 400550: movq %rdi,%rax • 400557: ret 0x400550 %rip Now return address points at where we’ll jump back to %rip is where we are executing now

Procedure Return Example (step 1) 0000000000400540 <multstore>: • 400544: call 400550 <mult2> 400549: movq %rax,(%rbx) • 0x120 0x128 0x130 0x400549 0x118 0x118 %rsp 0000000000400550 <mult2>: 400550: movq %rdi,%rax • 400557: ret 0x400557 %rip Now, after we’ve executed this function, we’re at the ret Pop return address read return address increment %rsp Jump back to return address update %rip with return address execute again starting there

Procedure Return Example (step 2) 0000000000400540 <multstore>: • 400544: call 400550 <mult2> 400549: movq %rax,(%rbx) • 0x120 0x128 0x130 0x120 %rsp 0000000000400550 <mult2>: 400550: movq %rdi,%rax • 400557: ret 0x400549 %rip

Procedures Stack Structure Calling Conventions Passing control Passing data Managing local data Register Saving Conventions Illustration of Recursion

Procedure Data Flow Registers (NOT in Memory) Stack (Memory) First 6 arguments Return value High Addresses %rdi %rsi %rdx %rcx %r8 %r9 Arg 7 • • • Arg 8 Arg n Low Addresses 0x00…00 Only allocate stack space when needed %rax

x86-64 Return Values By convention, values returned by procedures are placed in %rax Choice of %rax is arbitrary Caller must make sure to save the contents of %rax before calling a callee that returns a value Part of register-saving convention Callee places return value into %rax Any type that can fit in 8 bytes – integer, float, pointer, etc. For return values greater than 8 bytes, best to return a pointer to them Upon return, caller finds the return value in %rax Caller-saved vs callee-saved registers? Will talk about this more later Larger than 8 bytes: There’s some other part of the calling convention that dictates what to do Spoiler alert: usually it’s on the stack

Data Flow Examples void multstore (long x, long y, long *dest) { long t = mult2(x, y); *dest = t; } 0000000000400540 <multstore>: # x in %rdi, y in %rsi, dest in %rdx • • • 400541: movq %rdx,%rbx # Save dest 400544: call 400550 <mult2> # mult2(x,y) # t in %rax 400549: movq %rax,(%rbx) # Save at dest long mult2 (long a, long b) { long s = a * b; return s; } 0000000000400550 <mult2>: # a in %rdi, b in %rsi 400550: movq %rdi,%rax # a 400553: imulq %rsi,%rax # a * b # s in %rax 400557: ret # Return How do we get data into and out of procedures? x -> a, y -> b, so no need to change those registers! Don’t need to save because we don’t use x or y after mult2 returns but, we do need to save %rdx, need it after mult2

Procedures Stack Structure Calling Conventions Passing control Passing data Managing local data Register Saving Conventions Illustration of Recursion

Stack-Based Languages Languages that support recursion e.g. C, Java, most modern languages Code must be re-entrant Multiple simultaneous instantiations of single procedure Need some place to store state of each instantiation Arguments, local variables, return pointer Stack allocated in frames State for a single procedure instantiation Stack discipline State for a given procedure needed for a limited time Starting from when it is called to when it returns Callee always returns before caller does Re-entrant means we need to be able to call the same function more than once Could be from within the function! or from another called function Execute a new copy Each time we call it, need somewhere to keep the local variables, and arguments The Stack gives us a place to put state while a function is executing only need state for the currently executing copy callee returns, and we can pop off its temporary data

Procedure amI is recursive (calls itself) Call Chain Example Example Call Chain yoo(…) { • who(); } yoo who amI who(…) { • amI(); } amI(…) { • if(…){ amI() } Procedure amI is recursive (calls itself)

1) Call to yoo Stack main yoo yoo yoo(…) { • who(); who %rbp } amI %rsp

2) Call to who Stack yoo who yoo yoo(…) { • who(…) { who(); who • amI yoo who yoo(…) { • who(); } who(…) { • amI(); } %rbp %rsp

3) Call to amI (1) Stack yoo who amI1 yoo yoo(…) { • who(…) { who(); } who(…) { • amI(); } amI(…) { • if(){ amI() } %rbp %rsp

4) Recursive call to amI (2) Stack yoo who amI yoo who amI1 amI2 yoo(…) { • who(); } who(…) { • amI(); } amI(…) { • if(){ amI() } amI(…) { • if(){ amI() } %rbp %rsp

5) (another) Recursive call to amI (3) Stack yoo who amI yoo who amI1 amI2 amI3 yoo(…) { • who(); } who(…) { • amI(); } amI(…) { • if(){ amI() } amI(…) { • if(){ amI() } amI(…) { • if(){ amI() } Let’s say this time, the if condition is false, so we don’t recurse again %rbp %rsp

6) Return from (another) recursive call to amI Stack yoo who amI yoo who amI1 amI2 amI3 yoo(…) { • who(); } who(…) { • amI(); } amI(…) { • if(){ amI() } amI(…) { • if(){ amI() } %rbp %rsp Start popping our way back up the stack frames

7) Return from recursive call to amI Stack yoo who amI yoo who amI1 amI2 amI3 yoo(…) { • who(); } who(…) { • amI(); } amI(…) { • if(){ amI() } %rbp %rsp

8) Return from call to amI Stack yoo who amI yoo who amI1 amI2 amI3 yoo(…) { • who(); } who(…) { • amI(); } %rbp %rsp At this point, we’re back up to who, which calls amI twice

9) (second) Call to amI (4) Stack yoo who amI yoo who amI4 amI2 amI3 yoo(…) { • who(); } who(…) { • amI(); } amI(…) { • if(){ amI() } %rbp %rsp Looks similar to Step 3, but it’s NOT! Let’s assume if condition is false.

10) Return from (second) call to amI Stack yoo who amI yoo who amI4 amI2 amI3 yoo(…) { • who(); } who(…) { • amI(); } %rbp %rsp

11) Return from call to who Stack yoo who amI yoo who amI4 amI2 amI3 yoo(…) { • who(); } %rbp %rsp Main calls yoo() Blue frame is main’s stack frame Total stack frames created: 7 Maximum stack depth: 6 frames

x86-64/Linux Stack Frame Caller’s Stack Frame Extra arguments (if > 6 args) for this call Return address Pushed by call instruction Current/Callee Stack Frame Old frame pointer (optional) Saved register context (when reusing registers) Local variables (If can’t be kept in registers) “Argument build” area (If callee needs to call another function -parameters for function about to call, if needed) Caller Frame Arguments 7+ Frame pointer %rbp Return Addr Old %rbp (Optional) Saved Registers + Local Variables Note: some consider the Return Addr to be part of the Callee stack frame Argument Build (Optional) Stack pointer %rsp

Example: increment CSE351 Lecture 12 long increment(long *p, long val) { long x = *p; long y = x + val; *p = y; return x; } Register Use(s) %rdi 1st arg (p) %rsi 2nd arg (val), y %rax x, return value increment: movq (%rdi), %rax addq %rax, %rsi movq %rsi, (%rdi) ret (on handout)

Procedure Call Example (initial state) CSE351 Lecture 12 Procedure Call Example (initial state) Initial Stack Structure long call_incr() { long v1 = 351; long v2 = increment(&v1, 100); return v1+v2; } • • • Return addr <main+8> ⟵%rsp call_incr: subq $16, %rsp movq $351, 8(%rsp) movl $100, %esi leaq 8(%rsp), %rdi call increment addq 8(%rsp), %rax addq $16, %rsp ret Return address on stack is the address of instruction immediately following the call to “call_incr” Shown here as main, but could be anything) Pushed onto stack by call call_incr (on handout) We’re at the beginning of call_incr, let’s say it was called from main, so we already have some stuff up further in the stack, and the last thing, because we just started call_incr, is the return address to jump back into main

Procedure Call Example (step 1) CSE351 Lecture 12 Procedure Call Example (step 1) Stack Structure long call_incr() { long v1 = 351; long v2 = increment(&v1, 100); return v1+v2; } • • • Return addr <main+8> 351 Unused ⟵old %rsp call_incr: subq $16, %rsp movq $351, 8(%rsp) movl $100, %esi leaq 8(%rsp), %rdi call increment addq 8(%rsp), %rax addq $16, %rsp ret ⟵%rsp+8 Allocate space for local vars ⟵%rsp Setup space for local variables Only v1 needs space on the stack Compiler allocated extra space Often does this for a variety of reasons, including alignment Remember back to when everyone was asking how we know where our variables live… Here, the compiler has created v1 on the stack…

Procedure Call Example (step 2) CSE351 Lecture 12 Procedure Call Example (step 2) Stack Structure long call_incr() { long v1 = 351; long v2 = increment(&v1, 100); return v1+v2; } • • • Return addr <main+8> 351 Unused call_incr: subq $16, %rsp movq $351, 8(%rsp) movl $100, %esi leaq 8(%rsp), %rdi call increment addq 8(%rsp), %rax addq $16, %rsp ret ⟵%rsp+8 ⟵%rsp Set up parameters for call to increment Register Use(s) %rdi &v1 %rsi 100 Now, we set up the arguments for our call to increment First parameter: &v1 8(%rsp) is the address of that value on our stack Second parameter: 100 use movl because 100 is a small positive value that will fit in 32 bits. The high order bits of %rsi get set to zero for us automatically. Next will be the actual call Aside: movl is used because 100 is a small positive value that fits in 32 bits. High order bits of rsi get set to zero automatically. It takes one less byte to encode a movl than a movq.

Procedure Call Example (step 3) CSE351 Lecture 12 Procedure Call Example (step 3) Stack Structure long call_incr() { long v1 = 351; long v2 = increment(&v1, 100); return v1+v2; } • • • Return addr <main+8> 351 Unused Return addr <call_incr+?> call_incr: subq $16, %rsp movq $351, 8(%rsp) movl $100, %esi leaq 8(%rsp), %rdi call increment addq 8(%rsp), %rax addq $16, %rsp ret ⟵%rsp State while inside increment Return address on top of stack is address of the addq instruction immediately following call to increment Register Use(s) %rdi &v1 %rsi 100 %rax increment: movq (%rdi), %rax addq %rax, %rsi movq %rsi, (%rdi) ret Push address of next instruction onto the stack In this case it’s the addq Then jump to the increment label Like push %rip+? Execute increment Read initial value where %rdi points Save that in %rax, that’s our return value do increment 100 with addq update what’s in memory

Procedure Call Example (step 4) CSE351 Lecture 12 Procedure Call Example (step 4) Stack Structure long call_incr() { long v1 = 351; long v2 = increment(&v1, 100); return v1+v2; } • • • Return addr <main+8> 451 Unused Return addr <call_incr+?> call_incr: subq $16, %rsp movq $351, 8(%rsp) movl $100, %esi leaq 8(%rsp), %rdi call increment addq 8(%rsp), %rax addq $16, %rsp ret ⟵%rsp State while inside increment After code in body has been executed Register Use(s) %rdi &v1 %rsi 451 %rax 351 increment: movq (%rdi), %rax # x = *p addq %rax, %rsi # y = x+100 movq %rsi, (%rdi) # *p = y ret Return Pop return address from stack Jump Like pop %rip

Procedure Call Example (step 5) Stack Structure long call_incr() { long v1 = 351; long v2 = increment(&v1, 100); return v1+v2; } • • • Return addr <main+8> 451 Unused call_incr: subq $16, %rsp movq $351, 8(%rsp) movl $100, %esi leaq 8(%rsp), %rdi call increment addq 8(%rsp), %rax addq $16, %rsp ret ⟵%rsp+8 ⟵%rsp After returning from call to increment Registers and memory have been modified and return address has been popped off stack Register Use(s) %rdi &v1 %rsi 451 %rax 351 V1 = 451 V2 = 351

Procedure Call Example (step 6) Stack Structure long call_incr() { long v1 = 351; long v2 = increment(&v1, 100); return v1+v2; } • • • Return addr <main+8> 451 Unused call_incr: subq $16, %rsp movq $351, 8(%rsp) movl $100, %esi leaq 8(%rsp), %rdi call increment addq 8(%rsp), %rax addq $16, %rsp ret ⟵%rsp+8 ⟵%rsp Update %rax to contain v1+v2 Register Use(s) %rdi &v1 %rsi 451 %rax 451+351

Procedure Call Example (step 7) Stack Structure long call_incr() { long v1 = 351; long v2 = increment(&v1, 100); return v1+v2; } • • • Return addr <main+8> 451 Unused ⟵%rsp call_incr: subq $16, %rsp movq $351, 8(%rsp) movl $100, %esi leaq 8(%rsp), %rdi call increment addq 8(%rsp), %rax addq $16, %rsp ret ⟵old %rsp De-allocate space for local vars Register Use(s) %rdi &v1 %rsi 451 %rax 802

Procedure Call Example (step 8) Stack Structure long call_incr() { long v1 = 351; long v2 = increment(&v1, 100); return v1+v2; } • • • Return addr <main+8> ⟵%rsp call_incr: subq $16, %rsp movq $351, 8(%rsp) movl $100, %esi leaq 8(%rsp), %rdi call increment addq 8(%rsp), %rax addq $16, %rsp ret State just before returning from call to call_incr Register Use(s) %rdi &v1 %rsi 451 %rax 802

Procedure Call Example (step 9) Final Stack Structure long call_incr() { long v1 = 351; long v2 = increment(&v1, 100); return v1+v2; } • • • ⟵%rsp call_incr: subq $16, %rsp movq $351, 8(%rsp) movl $100, %esi leaq 8(%rsp), %rdi call increment addq 8(%rsp), %rax addq $16, %rsp ret State immediately after returning from call to call_incr Return addr has been popped off stack Control has returned to the instruction immediately following the call to call_incr (not shown here) Register Use(s) %rdi &v1 %rsi 451 %rax 802