10/6: Lecture Topics C Brainteaser More on Procedure Call More than four arguments A recursive example Starting a Program Exercise 3.2 from H+P
A Brainteaser in C What does this program print? Why? #include <stdio.h> int* foo() { int b = 6; return &b; } void bar() { int c = 7; main() { int *a = foo(); bar(); printf(“The value at a is %d\n”, *a);
5+ Arguments Up to four arguments can be passed in registers $a0-$a3 To pass more than four, Push them on the stack Set the frame pointer ($fp) to point to them The frame pointer provides a stable base register for the duration of the procedure why not just use $sp?
Stack Allocation $sp Low address $fp $sp $sp $fp $fp Before During Local vars. Callee’s stack frame Saved $s regs. Saved $ra Saved args $fp $sp $sp Caller’s stack frame Caller’s stack frame $fp $fp Before During After High address
Activation Record For a procedure call, the activation record is the portion of the stack containing saved registers local variables Also known as stack frame or procedure frame
Recursive Procedure Call A recursive procedure calls itself With the stack, no more difficult than nested procedure call int fact(int n) { if(n < 1) return 1; else return (n * fact(n-1)); }
Factorial Implementation fact: subi $sp, $sp, 8 sw $ra, 4($sp) sw $a0, 0($sp) slt $t0, $a0, 1 beq $t0, $zero, L1 add $v0, $zero, 1 add $sp, $sp, 8 jr $ra L1: sub $a0, $a0, 1 jal fact lw $a0, 0($sp) lw $ra, 4($sp) mult $v0, $a0, $v0
Starting a Program Two phases from source code to execution Compile time compiler creates assembly assembler creates machine code linker creates an executable Run time loader moves the executable into memory and starts the program
Compile Time You’re experts on compiling from source to assembly Two parts to translating from assembly to machine language: Instruction encoding (including translating pseudoinstructions) Translating labels to addresses Label translations go in the symbol table
Symbol Table Symbols are names of global variables or labels (including procedure entry points) Symbol table associates symbols with their addresses in the object file This allows files compiled separately to be linked Label1: 0x01031ff0 bigArray 0x10006000
Modular Program Design Small projects may use only one file Any time any one line changes, recompile and reassemble the whole thing (death of Pascal) For larger projects, recompilation time is significant Solution: split project into modules compile and assemble modules separately link the object files
The Compiler + Assembler Translates high-level language source files into object files Object files Contains machine instructions (1’s & 0’s) Bookkeeping information Procedures and variables the object file defines Procedures and variables the source files use but are undefined (unresolved references) Debugging information associating machine instructions with lines of source code
Object File Example main.c area.c main.o area.o double PI = 3.14159; double A = Area( 5.0 ); } extern int ; double Area( double r ) { return PI * r * r; main.c area.c code: static data: defined symbols: undefined symbols: main.o area.o
The Linker The linker’s job is to “stitch together” the object files: 1. Place the data modules in memory 2. Determine the addresses of data and labels 3. Match up references between modules
Placing Modules in Memory Link a word processor application: text Editing text text static data Spell checking static data static data Paperclip
Determining Addresses Some addresses change during memory layout Modules were compiled in isolation Absolute addresses must be relocated Object file keeps track of instructions that use absolute addresses text text
Resolving References The editing module calls a routine from the spell checker That symbol is unresolved at compile time The linker matches unresolved symbols to locations in other modules
Linker Example main.o area.o LINKER main.exe code: main:A=area(5.0) static data: PI = 3.1415 defined symbols: main, PI undefined symbols: Area code: Area:return PI*r*r static data: defined symbols: Area undefined symbols: PI LINKER main.exe header code: main:A=area(5.0) Area:return PI*r*r static data: PI = 3.1415 defined symbols: main, PI, Area
Libraries Some code is used so often, it is bundled into libraries for common access Libraries contain most of the code you use but didn’t write: e.g., printf() Library code is (often) merged with yours at link time main.o main.exe libc.a
The Executable End result of compiling, assembling, and linking: the executable Contains: Header, listing the lengths of the other segments Text segment Static data segment Potentially other segments, depending on architecture & OS conventions
Run Time We’ll learn a lot more about this during the OS part of the course In a nutshell: Some dynamic linking may occur some symbols aren’t defined until run time Windows’ dlls (dynamic link library) why do this? The segments are loaded into memory The OS transfers control to the program and it runs
add $a1, $a1, $a1 add $v0, $zero, $zero add $t0, $zero, $zero outer: add $t4, $a0, $t0 lw $t4, 0($t4) add $t5, $zero, $zero add $t1, $zero, $zero inner: add $t3, $a0, $t1 lw $t3, 0($t3) bne $t3, $t4, skip addi $t5, $t5, 1 skip: addi $t1, $t1, 4 bne $t1, $a1, inner slt $t2, $t5, $v0 bne $t2, $zero, next add $v0, $t5, $zero add $v1, $t4, $zero next: addi $t0, $t0, 4 bne $t0, $a1, outer
int size = 5000; int values[size]; int mode = 0; int modeCount = 0; int i,j; for( i = 0; i < size; i++ ) { count = 0; for( j = 0; j < size; j++ ) { if( values[i] == values[j] ) { count++; } if( count > modeCount ) { modeCount = count; mode = values[i];