; Listing7-6.asm ; ; A program that demonstrates various ; forms of the try..endtry sequences. option casemap:none .nolist include aoalib.inc include aoaMacros.inc include aoaExcepts.inc includelib aoalib.lib .list .const ; Program title: align word ttlStr byte "Listing 7-6", 0 ;---------------------------------------------------------- .code ; tstSeq- ; ; Tests sequential try...endtry sequences tstSeq xproc (filterProc(tstSeq), ) local shadowStorage[56]:byte call print byte "tstSeq", nl, 0 ; Note the use of a non-volatile register here. ; This ensures that EBX's value will be preserved ; should an exception occur. Note that the tstSeq ; procedure preserves RBX (see xproc, above). ; Therefore, stack unwinding will automatically ; restore RBX's value after an exception. ; ; The following code loops through the try sequence ; four times. Three of those times generate different ; exceptions, the fourth time does not generate an ; exception. mov ebx, 0 repeatTry: try cmp ebx, 0 ja try1 call print byte "tstSeq: int 3 is next instr", nl, 0 int 3 ;Breakpoint exception try1: cmp ebx, 1 ja try2 call print byte "tstSeq: hlt is next instr", nl, 0 hlt ;Privledged Instr try2: cmp ebx, 2 ja try3 call print byte "tstSeq: memAccess on next instr", nl, 0 xor rax, rax mov rax, [rax] ;Mem Access try3: call print byte "tstSeq:End of protected section", nl, 0 exception( ex(brkpt), ex(memAccess), ex(privInstr) ) mov edx, [rax].ExceptionRecord_t.ExceptionCode call print byte "tstSeq:Brkpt/access/priv exception" byte nl byte "Exception code:%x", nl, 0 exception(ex(any)) call print byte "tstSeq:Any exception 1", nl, 0 finally call print byte "tstSeq:In finally #1", nl, 0 endtry inc ebx cmp ebx, 4 jb repeatTry call print byte "tstSeq:After first try..endtry", nl, 0 try int 3 exception(ex(any)) call print byte "tstSeq:Any exception #2", nl, 0 finally ;#2 call print byte "tstSeq:In finally 2", nl, 0 endtry call print byte "tstSeq:After 2nd try..endtry", nl, 0 ; Generate the epilog code (including ret) and end ; the procedure: tstSeq endxp() ;------------------------------------------------ ; ; tstNested- ; ; Tests nested try...endtry sequences tstNested xproc (filterProc(tstNested), <>) local shadowStorage[56]:byte call print byte "tstNested", nl, 0 try try call print byte "startTry: int 3 is next instr", nl, 0 int 3 ;Cause an exception call print byte "This should not print", nl, 0 exception(ex(brkpt)) call print byte "Brkpt exception", nl, 0 exception(ex(any)) call print byte "Any exception 1", nl, 0 finally call print byte "In finally #1", nl, 0 endtry call print byte "After first endtry", nl, 0 exception(ex(any)) call print byte "Any exception #2", nl, 0 finally ;#2 call print byte "In finally 2", nl, 0 endtry call print byte "After 2nd endtry", nl, 0 ; Generate the epilog code (including ret) and end ; the procedure: tstNested endxp() ;-------------------------------------------------- ; ; excInExc- ; ; Tests a try..endtry sequence in an exception section excInExc xproc (filterProc(excInExc), <>) local shadowStorage[56]:byte call print byte "excInExc", nl, 0 try int 3 exception(ex(any)) call print byte "excInExc: exception 1", nl, 0 try xor rax, rax ;Cause memory access mov rax, [rax] ; exception exception( ex(any) ) call print byte "excInExc:Exception 2", nl, 0 endtry finally call print byte "excInExc:In finally 1", nl, 0 endtry call print byte "excInExc:After outer endtry", nl, 0 ; Generate the epilog code (including ret) and end ; the procedure: excInExc endxp() ;-------------------------------------------------- ; ; Called- ; ; Tests a try..endtry sequence in a procedure ; that calls another procedure (that generates ; the exception). Called xproc (filterProc(Called), <>) local shadowStorage[56]:byte call print byte "Called", nl, 0 try call exInProc exception(ex(any)) call print byte "Called: exception", nl, 0 finally call print byte "Called:In finally", nl, 0 endtry call print byte "Called:After outer endtry", nl, 0 ; Generate the epilog code (including ret) and end ; the procedure: Called endxp() exInProc xproc (frame,<>) int 3 exInProc endxp() ;-------------------------------------------------- ; ; finallyAfter- ; ; Demonstrates how to execute finally code after ; an exception handler. finallyAfter xproc (filterProc(finallyAfter), <>) local shadowStorage[56]:byte call print byte "finallyAfter", nl, 0 try try int 3 exception(ex(brkpt)) call print byte "finallyAfter: exception", nl, 0 endtry finally call print byte "finallyAfter:In finally", nl, 0 endtry call print byte "finallyAfter:After outer endtry", nl, 0 ; Generate the epilog code (including ret) and end ; the procedure: finallyAfter endxp() ;-------------------------------------------------- ; ; Here is the main assembly language function. public asmMain align 8 qword ? ;Also for hot patching ; For the main assembly procedure, preserve all the ; non-volatile registers. It would be cool to save ; the XMM non-volatile registers, too, but there isn't ; room in the prolog for them. ; ; Had this code used a biased frame pointer (RBP) value, ; it could have gotten away with saving them. Epilog ; and prolog macros don't allow that, however. So this ; code preserves what it can (the general-purpose 64-bit ; non-volatile registers). asmMain xproc (frame, ) local shadowStorage[64]:byte ; Test sequential exceptions: call print byte "Calling tstSeq", nl, 0 call tstSeq call print byte "Back from tstSeq", nl, 0 ; Test nested exceptions: call print byte "Calling tstNested", nl, 0 call tstNested call print byte "Back from tstNested", nl, 0 ; Call the procedure that has nested exceptions: call print byte "Calling excInExc", nl, 0 call excInExc call print byte "Back from excInExc", nl, 0 ; Call the procedure that raises an exception ; in a called procedure: call print byte "Calling Called", nl, 0 call Called call print byte "Back from Called", nl, 0 ; Call the procedure that raises an exception ; in a called procedure: call print byte "Calling finallyAfter", nl, 0 call finallyAfter call print byte "Back from finallyAfter", nl, 0 asmMain endxp() end