**** Local variables Local variables has a lifetime of a single function call or a single program block. Local variables may be saved either in the call's stack frame or in a register. Function arguments are a special case of local variables and they are usually passed in registers. However, sometimes there will just be too many arguments to pass in registers. In this case, some argumnets must be passed on the stack. Either the compiler or the assembly-language programmer or the ABI (Application Binary Interface) allocates registers and stack locations to local variables. Suppose N is a local variable. Let's look at how the statement N += 7 can be implemented in the MIP32 architecture. If register $t5 has been allocated to N, the statement can be implemented as a single instruction. addi $t5,$t5,7 However, if N is implemented on the stack, say at offset 30, up to three instructions are required. lw $t0,40($sp) addi $t0,$t0,7 sw $t0,40($sp) **** Caller and callee saved However, what happens if N is allocated to $t5 and than a call is made to a subfunction. How can the programmer be sure that the subfunction doesn’t use $t5 and "lose" the value of N. Following the common terminology, we'll can the calling function the caller and the called function the callee. (Sometime calling and called is also used. The MIPS32 ABI states that the temporary registers $t0 to $t9 are caller saved. This means that the callee is free to use these registers and that the caller better save them. The argument ($a0 to $a3) and value ($v0 to $v1) are also caller saved. On the other hand, the saved registers $s0 to $s7 are callee saved. This means that the callee can use these registers only if their original values are saved before use and restored befor return. The caller is guaranteed that the saved registers are unchanged by the call. Global variables Global or external variables are a bit messier. The address of a global variables cannot be determined by the compiler or assembler. This is the job of the linker (called ld in the Unix world). The best the compiler can do is generate a table containing the names of all external variables and the many references, both instructions and data, to these variables in the object module that it produces. The linker tries to resolve these references. This requires the use of the global pointer ($gp) register. An assembly language program may write a statement similar to lw $t0,x If x has been allocated within 215 bytes of $gp (most precisely with the range $gp-32768 to $gp+32767), the lw can be implemented with code similar to lw $t0,OFFSET_x($gp) where OFFSETx is computed by the linker. However, sometimes it is simply imposible to put all global variables in 216 bytes. In this case, it is necessary to place the addresses of globals in the global offset table or GOT. Effectively, the global offset table is an vector of pointers and global variable access is implemented by a two-instruction sequence similar to lw $t0,OFFSET_GOT_N($gp) lw $t0,0($t0) By the way, shared librarys (DLL) add yet more complexity. Addresses (Pointers) If N is a variable stored in memory, how do you get its address? If N is stored at 40 bytes from the begining of the stack pointer, you use something like the following: addi $t0,40($sp) If N is a global it will be referenced using the global pointer, $gp. Fortunately the assembler has a little hack allows you to write use a idiom like la $t0,N which is magically translated to something like addi $t0,$gp,OFFSET_N or, when a global offset table is used, to lw $t0,OFFSET_GOT_N($gp) Don't ask questions, just us la to load address. **** Array access Remember that A[i] is really just *(A+i) but keep in mind that the addition must be implemented as A+i*sizeof(*A). So, if A is an array of 4-byte integers, then something like the following is requred on a MIPS32 computer to load A[0] into a register. la $t0,A lw $t1,i sll $t1,$t1,2 add $t0,$t0,$t1 lw $t0,0($t0) As it turns out the Intel architecture can do this in a couple of instructions mov i, %rax movl A(,%rax,4), %eax ;; %edx stored in H[v] It's not at all clear that the Intel two will be faster than the MIPS five. Ultimately, both require the same number of adds and shifts. The faster solution, for both MIPS and Intel, is to use a compiler that transforms a loop like for (int i=0; i