Machine Programming III: Procedures
Mechanisms in Procedures
-
Passing control
- To beginning of procedure code
- Back to return point
-
Passing data
- Procedure arguments
- Return value
-
Memory management
-
Allocate during procedure execution
-
Mechanisms all implemented with machine instructions
-
-
x86-64 implementation of a procedure uses only those mechanisms required
Stack Structure
x86-64 Stack
- Region of memory managed with stack discipline
- Grows toward lower addresses
- Register %rsp contains lowest stack address
- address of “top” element
- pushq Src
- Fetch operand at Src
- Decrement %rsp by 8
- Write operand at address given by %rsp
- popq Dest
- Read value at address given by %rsp
- Increment %rsp by 8
- Store value at Dest (must be register)
Calling Conventions
Passing control
Code Example
void multstore (long x, long y, long *dest)
{
long t = mult2(x, y);
*dest = t;
}
000000000400540 <multstore>:
400540: push %rbx # Save %rbx
400541: mov %rdx, %rbx # Save dest
400544: callq 400550 <mult2> # mult2(x, y)
400549: mov %rax, (%rbx) # Save at dest
40054c: pop %rbx # Restore %rbx
50054d: retq # Return
long mult2 (long a, long b)
{
long s = a * b;
return s;
}
000000000400550 <mult2>:
400550: mov %rdi, %rax
400553: imul %rsi, %rax
400557: retq
Procedure Control Flow
- Use stack to support procedure call and return
- Procedure call: call label
- Push return address on stack
- Jump to label
- Return address:
- Address of the next instruction right after call
- Example from disassembly
Control Flow Example #1
Control Flow Example #2
Control Flow Example #3
Control Flow Example #4
Passing data
Procedure Data Flow
-
Register
- First 6 argument %rdi %rsi %rdx %rcx %r8 %r9
-
Stack
- Argn … Arg8 Arg7
-
Return Value
- %rax
-
Only allocate stack space when needed
Data Flow Example
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: mov %rdx, %rbx # Save dest
400544: callq 400550 <mullt2> # mult2(x, y)
# t in %rax
400549: mov %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: mov %rdi,%rax # a
400553: imul %rsi,%rax # a*b
# s in %rax # Return
400557: retq
Managing local data
Stack-Based Languages
- Languages that support recursion
- e.g, C, Pascal, Java
- Code must be “Reentrant”
- Multiple simultaneous instantiations of single procedure
- Need some place to store state of each instantiation
- Arguments
- Local variables
- Return pointer
- Stack discipline
- State for given procedure needed for limited time
- From when called to when return
- Callee returns before caller does
- State for given procedure needed for limited time
- Stack allocated in Frames
- state for single procedure instantiation
x86-64/Linux Stack Frame
-
Current Stack Frame (“Top” to Bottom)
-
“argument build:”
Parameters for function about to call
-
Local variables
If can’t keep in registers
-
Saved register context
-
Old frame pointer (optional)
-
-
Caller Stack Frame
- Return address
- Pushed by call instruction
- Arguments for this call
- Return address
Register Saving Conventions
-
When procedure yoo call who:
- yoo is the caller
- who is the callee
-
Can register be used for temporary storage?
yoo: • • • movq $15213, %rdx call who addq %rdx, %rax • • • ret
who: • • • subq $18213, %rdx • • • ret
- Contents of register %rdx overwritten by who
- This could be trouble -> something should be done!
- Need some coordination
x86-64 Linux Register Usage
- %rax
- Return value
- Also caller-saved
- Can be modified by procedure
- %rdi, …, %r9
- Arguments
- Also caller-saved
- Can be modified by procedure
- %r10, %r11
- Caller-saved
- Can be modified by procedure
- %rbx, %r12, %r13, %r14
- Callee-saved
- Callee must save & restore
- %rbp
- Callee-saved
- Callee must save & store
- May be used as frame pointer
- Can mix & match
- %rsp
- Special form of callee save
- Restored to original value upon exit from procedure
Illustration of Recursion
Recursive Function
/* Recursive popcount */
long pcount_r(unsigned long x) {
if (x == 0)
return 0;
else
return (x & 1)
+ pcount_r(x >> 1);
}
pcount_r:
movl $0, %eax
testq %rdi, %rdi
je .L6
pushq %rbx
movq %rdi, %rbx
andl $1, %ebx
shrq %rdi
call pcount_r
addq %rbx, %rax
popq %rbx
.L6:
rep; ret
Observations About Recursion
- Handled Without Special Consideration
- Stack frames mean that each function call has private storage
- Saved registers & local variables
- Saved return pointer
- Register saving conventions prevent one function call from corrupting another’s data
- Unless the C code explicitly does so (e.g., buffer overflow in Lecture 9)
- Stack discipline follows call/return pattern
- If P calls Q, then Q returns before P
- Last-In, First-Out
- Stack frames mean that each function call has private storage
- Also works for mutual recursion
- P calls Q; Q calls P
x86-64 Procedure Summary
- Important Points
- Stack is the right data structure for procedure call / return
- If P calls Q, then Q returns before P
- Recursion(& mutual recursion) handled by normal calling conventions
- Can safely store values in local stack frame and in callee-saved registers
- Put function arguments at top of stack
- Result return in %rax
- Pointers are addresses of values
- On stack or global
- On stack or global
Machine Programming IV: Data
Summary
- Arrays
- Elements packed into contiguous region of memory
- Use index arithmetic to locate individual elements
- Structure
- Elements packed into single region of memory
- Access using offsets determined by compiler
- Possible require internal and external padding to ensure alignment
- Combinations
- Can nest structure and array code arbitrarily
- Floating Point
- Data held and operated on in XMM registers