<<>> <> <> <> <<>> DIRECTORY SPARCArchitecture USING [SPARCInstruction], BreakWorldArchitecture USING [Address], Rope USING [ROPE]; SPARCManger: CEDAR DEFINITIONS ~ { <<>> <> <> <> <> <> <> <<>> <> <<>> <> << sheep ba,a patch sheep>> <> <<>> <<-- This is the easy case, we just jump to the patch to exeucte the instruction.>> <<>> <> << bicc target ba,a patch bicc target>> << delaySlot delaySlot delaySlot>> <> <<>> <<-- With a simple delay slot, we just jump to a copy (relocated) of the instruction and its delay slot. If the branch falls through, we just transfer back to the main code stream.>> << >> <> << call target call patch sethi %hi(target), %g1>> << delaySlot delaySlot jmpl %g1+%lo(target), %g0>> << noop>> <<>> <<-- The trick here is to call the patch, thus setting up the return address because the callee probably uses it (e.g. to return, or return aggregate results, etc.). We allow the instruction in the delay slot to execute (what if it messes with the return address? So be it, that's what it wanted to do.). In the manger, we move the target address to %g1 (which I think is free at this point), and then jmpl to the callee without setting the return address.>> << >> <> << jmpl target, %o7 call patch jmpl target, %g0>> << delaySlot delaySlot noop>> <<>> <<-- Again, the trick here is to call the patch, thus setting up the return address because the callee probably uses it (e.g. to return, or return aggregate results, etc.). We allow the instruction in the delay slot to execute. In the manger, we jmpl to the callee without setting the return address.>> <<>> <> << jmpl target, %g0 ba,a patch jmpl target, %g0>> << delaySlot delaySlot delaySlot>> <<>> <<-- ``jmpl target, %g0'' has a standard abbreviation of just ``jmp target'', and there are standard abbreviations of ``ret'' and ``retl'' for ``jmp %i7+8'' and ``jmp %o7+8''.>> <<-- This is just a computed delayed transfer. We branch to a copy of the instruction and it's delay slot, as in the branch instruction case, above, excpet this isn't a conditional branch.>> <<>> <> Manger: TYPE ~ MACHINE DEPENDENT RECORD [ variants: SELECT COMPUTED MangerVariant FROM <> <> normal => [ <> sheep: SPARCArchitecture.SPARCInstruction, normalContinue: SPARCArchitecture.SPARCInstruction, normalNoop: SPARCArchitecture.SPARCInstruction, tag: SPARCArchitecture.SPARCInstruction], branch => [ <> dcti: SPARCArchitecture.SPARCInstruction, branchDelay: SPARCArchitecture.SPARCInstruction, branchContinue: SPARCArchitecture.SPARCInstruction, tag: SPARCArchitecture.SPARCInstruction], call => [ <> <> callAddrHi: SPARCArchitecture.SPARCInstruction, callJmp: SPARCArchitecture.SPARCInstruction, callNoop: SPARCArchitecture.SPARCInstruction, tag: SPARCArchitecture.SPARCInstruction], jmplO7 => [ <> <> jmplO7Jmp: SPARCArchitecture.SPARCInstruction, jmplO7Noop: SPARCArchitecture.SPARCInstruction, jmplO7Pad: SPARCArchitecture.SPARCInstruction, tag: SPARCArchitecture.SPARCInstruction], jmplG0 => [ <> jmplG0Jmp: SPARCArchitecture.SPARCInstruction, jmplG0Delay: SPARCArchitecture.SPARCInstruction, jmplG0Pad: SPARCArchitecture.SPARCInstruction, tag: SPARCArchitecture.SPARCInstruction], ENDCASE ]; MangerVariant: TYPE ~ { noneOfTheAbove, normal, branch, call, jmplO7, jmplG0 }; NormalManger: TYPE ~ Manger.normal; BranchManger: TYPE ~ Manger.branch; CallManger: TYPE ~ Manger.call; JmplO7Manger: TYPE ~ Manger.jmplO7; JmplG0Manger: TYPE ~ Manger.jmplG0; <> Install: PROCEDURE [ address: BreakWorldArchitecture.Address, manger: BreakWorldArchitecture.Address, patchCode: BreakWorldArchitecture.Address] RETURNS []; Uninstall: PROCEDURE [ address: BreakWorldArchitecture.Address, manger: BreakWorldArchitecture.Address, patchCode: BreakWorldArchitecture.Address] RETURNS []; <> ErrorCode: TYPE ~ ATOM _ nullErrorCode; nullErrorCode: ErrorCode ~ NIL; ErrorMessage: TYPE ~ Rope.ROPE _ nullErrorMessage; nullErrorMessage: ErrorMessage ~ NIL; CantInstall: ERROR [code: ErrorCode, message: ErrorMessage]; CantUninstall: ERROR [code: ErrorCode, message: ErrorMessage]; }.