SPARC, Intel Subroutines
- SPARC:
- save and restore
- Pointer Arguments
- Intel:
- Stack Frames
- call
- ret and ret n
- saving registers: push and pop
- saving registers: pusha and popa
- Homework
save
- save %r1, r2/imm, %r3:
- reads the value of %r1
- reads/loads the value of r2/imm
- increases the "current window pointer" (CWP)
- then stores the result in %r3.
- save %sp, -64, %sp:
- reads the value of %sp
- gets the value -64 (from the instruction encoding)
- increases the "current window pointer" (CWP), transforming
%sp into %fp.
- then stores the result into the new %sp.
restore
- restore with no arguments is the same as
restore %r0, %r0, %r0:
- like save, restore adds its arguments and,
after updating the CWP, stores the result
- restore with no arguments simply updates the CWP
- restore with arguments could be used to place return values
into caller's registers
- especially if the value returned is the sum of two
integers... (optimization)
Pointer Arguments
- sometimes the arguments to a subroutine are pointers
- e.g. swap(int * x, int * y)
- a pointer is a memory address
- what if x, y are in the caller's registers?
- write an "open macro" which doesn't use pointers, e.g.
#define swap(x, y) {int tmp = (x);\
(x) = (y); \
(y) = tmp; }
- rewrite the subroutine (e.g. swap) to swap two registers
- store x, y into the stack before calling swap
(only possible solution when compiling)
Intel Subroutine Calls
- No register windows
- Only 8 32-bit registers to save and restore
- All registers are callee-save (called function should save them
before using them)
- call and ret
- return address is saved on stack, not in register
Stack Frames
- (figure):
- local variables for caller (including saved registers)
- parameters for called procedure
- return address
- SS (stack segment) is segment register for all stack operations
- EBP normally points to return address (set to ESP by callee)
- stack alignment should be 32 bits (4 bytes)
Subroutine definition
Caller:
...
call foo
...
Callee (note, old value of EBP is lost):
foo: mov EBP, ESP
...
ret
call
- save EIP:
- near call (same code segment): EIP pushed onto stack
- far call (different code segment): CS and EIP pushed onto stack
- reload EIP:
- near call (same code segment): load EIP
- far call (different code segment): load new CS and EIP
ret
- pop top of stack into EIP
- for far return, pops CS from stack
- if argument is given ( ret n), adds n to ESP
push
and {\tt pop}
- push decrements ESP, then puts argument into [ESP]
- pop loads from [ESP], then increments ESP
- subroutines (esp. leaf subroutines) can use
push and pop to save just the registers they will use
pusha
and {\tt popa}
- pusha pushes AX, CX, DX, BX, (original) SP, BP, SI, DI.
- popa pops DI, SI, BP, throw-away, BX, DX, CX, AX
- pushad pushes EAX, ECX, EDX, EBX, (original) ESP, EBP, ESI, EDI.
- popad pops EDI, ESI, EBP, throw-away, EBX, EDX, ECX, EAX
- note ESP restored automatically to correct value
- subroutines can use pusha/d and popa/d to save all
the registers into the stack frame (32 bytes for pushad and
16 bytes for pusha)
Homework
- Assigned by e-mail to mailing list (last Wed.)
- due Oct 14th
- 5-3
- 5-6
- 6-5
- 7-9 (for 7-9, the book doesn't specify explicitly, so use m4+assembly).