; Listing7-4.asm ; ; A program that demonstrates handling ; an exception in pure (no macros) ; assembly language. option casemap:none .nolist include aoalib.inc include aoaExcepts.inc includelib aoalib.lib .list .const ; Program title: align word ttlStr byte "Listing 7-4", 0 .code ; The following is a procedure-specific handler ; for the tstSEH procedure. procSpec proc lea r10, tstSEH$scopeTable jmp genericLSH procSpec endp ; tstSEH- ; ; This procedure tests exception handling code in ; assembly language. option prologue:none option epilogue:none tstSEH proc frame:procSpec local endTryPtr:qword local shadowStorage[48]:byte push rbp mov rbp, rsp push rax .allocstack 8 push rbx .pushreg rbx push rcx .allocstack 8 sub rsp, 56 .allocstack 56 .setframe rbp, 80 .endprolog ; Begin the protected block: ; ; try startTry:: 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 ; This will never execute, but inlucde the code just ; to show the structure of the try..except..endtry ; code. call finallyCode ;Execute finally block jmp endTryCode endProtected: ; Generate the scopeTable entry for the ; following breakpoint except block: option dotname .xdata segment read align(8) tstSEH$scopeTable dword 1 dword ex(brkpt) dword 0 qword startTry qword endProtected qword brkPtExc qword finallyCode .xdata ends ; Here's the code that executes whenever a memory ; access violation occurs in the protected block. ; ; Note that the call to the finallyCode can happen ; before or after the body of the exception handler. ; Normally, it's best if it happens first (to ; guarantee execution). ; exception( ex(brkpt) ) brkPtExc: push rax ;Preserve RAX across call push rax ;Keep 16-byte alignment call finallyCode pop rax pop rax ; Upon entry into this code, RAX contains a pointer ; to the DispatcherContext record. Print a couple ; of useful values from that record: mov edx, [rax].ExceptionRecord_t.ExceptionCode call print byte "Breakpoint encountered (0x%x)", nl, 0 jmp endTryCode ; Here's the finally code; This corresponds to the ; finallyCode: call print byte "Executed finally code", nl, 0 ret 0 ;Must be RET 0! ; This is where the code exits the protected loop. ; ; endtry endTryCode: ; Generate the epilog code (including ret) and end ; the procedure: add rsp, 56 pop rcx pop rbx pop rax leave ret 0 tstSEH endp ;-------------------------------------------------- ; ; Here is the main assembly language function. public asmMain ; 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 proc frame local shadowStorage[56]:byte push rbp mov rbp, rsp push rbx .pushreg rbx push rsi .pushreg rsi push rdi .pushreg rdi push r12 .pushreg r12 push r13 .pushreg r13 push r14 .pushreg r14 push r15 .pushreg r15 sub rsp, 56 .allocstack 56 .setframe rbp, 112 .endprolog ; Call the procedure the demonstrates exception handling: call print byte "Calling tstSEH", nl, 0 ; Call the procedure that raises an exception: call tstSEH call print byte "Back from tstSEH", nl, 0 add rsp, 56 pop r15 pop r14 pop r13 pop r12 pop rdi pop rsi pop rbx leave ret 0 asmMain endp end