Page 1 of 1

Flat assembler thread

Posted: July 6th, 2021, 8:20 am
by PHPBB12345
For example, Win64 SEH implementation:

Code: Select all

UNW_FLAG_NHANDLER = 0
UNW_FLAG_EHANDLER = 1
UNW_FLAG_UHANDLER = 2
UNW_FLAG_CHAININFO = 4

__SEH64_REG.rax = 0
__SEH64_REG.rcx = 1
__SEH64_REG.rdx = 2
__SEH64_REG.rbx = 3
__SEH64_REG.rsp = 4
__SEH64_REG.rbp = 5
__SEH64_REG.rsi = 6
__SEH64_REG.rdi = 7
__SEH64_REG.r8  = 8
__SEH64_REG.r9  = 9
__SEH64_REG.r10 = 10
__SEH64_REG.r11 = 11
__SEH64_REG.r12 = 12
__SEH64_REG.r13 = 13
__SEH64_REG.r14 = 14
__SEH64_REG.r15 = 15

virtual at -510
  __SEH64_UNWIND_CODE::
        dw 255 dup(?)
        assert ($ = 0)
end virtual

; The UNWIND_INFO structure tells how the portion of code should be handled. Here's the declaration I found on MSDN:
; typedef union _UNWIND_CODE {
;     struct {
;         UBYTE CodeOffset;
;         UBYTE UnwindOp : 4;
;         UBYTE OpInfo   : 4;
;     };
;     USHORT FrameOffset;
; } UNWIND_CODE, *PUNWIND_CODE;
;
; typedef struct _UNWIND_INFO {
;     UBYTE Version       : 3;
;     UBYTE Flags         : 5;
;     UBYTE SizeOfProlog;
;     UBYTE CountOfCodes;
;     UBYTE FrameRegister : 4;
;     UBYTE FrameOffset   : 4;
;     UNWIND_CODE UnwindCode[1];
; /*  UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
;  *  union {
;  *      OPTIONAL ULONG ExceptionHandler;
;  *      OPTIONAL ULONG FunctionEntry;
;  *  };
;  *  OPTIONAL ULONG ExceptionData[];
;  */

macro .seh_proc func {
        local ..flags, ..frameptr, ..funcptr, ..funclabel, ..ucodes
        ..flags = 0
        ..frameptr = 0
        ..ucodes = 0
        macro .seh_handler handler, flags \{
                ..flags = flags
                ..funcptr = rva handler
        \}
        macro .seh_pushreg reg \{
                ; UWOP_PUSH_NONVOL
                \local ..label
          ..label:
                ..ucodes = ..ucodes + 1
                store byte (..label - func) at __SEH64_UNWIND_CODE:(-2*..ucodes)
                store byte (__SEH64_REG.\#reg * 16) at __SEH64_UNWIND_CODE:(-2*..ucodes+1)
        \}
        macro .seh_stackalloc size \{
                \local ..label
          ..label:
                if size <= 128
                        ; UWOP_ALLOC_SMALL
                        ..ucodes = ..ucodes + 1
                        store byte (..label - func) at __SEH64_UNWIND_CODE:(-2*..ucodes)
                        store byte ((size) * 2 - 14) at __SEH64_UNWIND_CODE:(-2*..ucodes+1)
                else if size < 524288
                        ; UWOP_ALLOC_LARGE (OpInfo = 0)
                        ..ucodes = ..ucodes + 2
                        store byte (..label - func) at __SEH64_UNWIND_CODE:(-2*..ucodes)
                        store byte 1 at __SEH64_UNWIND_CODE:(-2*..ucodes+1)
                        store word ((size) / 8) at __SEH64_UNWIND_CODE:(-2*..ucodes+2)
                else
                        ; UWOP_ALLOC_LARGE (OpInfo = 1)
                        ..ucodes = ..ucodes + 3
                        store byte (..label - func) at __SEH64_UNWIND_CODE:(-2*..ucodes)
                        store byte 17 at __SEH64_UNWIND_CODE:(-2*..ucodes+1)
                        store dword (size) at __SEH64_UNWIND_CODE:(-2*..ucodes+2)
                end if
        \}
        macro .seh_setframe reg, offset \{
                ; UWOP_SET_FPREG
                \local ..label
          ..label:
                ..ucodes = ..ucodes + 1
                ..frameptr = __SEH64_REG.\#reg + offset
                store byte (..label - func) at __SEH64_UNWIND_CODE:(-2*..ucodes)
                store byte (__SEH64_REG.\#reg * 16 + 3) at __SEH64_UNWIND_CODE:(-2*..ucodes+1)
        \}
        macro .seh_endprologue \{
                \local ..endp, ..tmp
          ..endp:
                virtual at 0
                  ..funclabel#.uinfo::
                        db 1 + (..flags * 8)
                        db ..endp - func
                        db ..ucodes
                        db ..frameptr
                        repeat ..ucodes
                                load ..tmp word from __SEH64_UNWIND_CODE:((-..ucodes + % - 1) * 2)
                                dw ..tmp
                        end repeat
                        align 4
                        if ..flags <> UNW_FLAG_NHANDLER
                                dd ..funcptr
                        end if

                  ..funclabel#.uinfo.size = $
                end virtual
        \}
        macro .seh_endproc \{
                \local ..endp
                purge .seh_handler
                purge .seh_pushreg
                purge .seh_stackalloc
                purge .seh_setframe
                purge .seh_endprologue
                purge .seh_endproc
          ..endp:
                virtual at 0
                  ..funclabel::
                        dd rva func, rva ..endp, rva ..funclabel#.uinfo.ptr
                end virtual
                __SEH64_FUNCTABL equ ..funclabel
        \}
  func:
}

macro .seh_fixup {
        local sym, cmd, mem, i, t
        data 3
        irpv sym, __SEH64_FUNCTABL \{
                irp mem, sym \\{
                        load t dword from mem:0
                        dd t
                        load t dword from mem:4
                        dd t
                        load t dword from mem:8
                        dd t
                \\}
        \}
        end data
        irpv sym, __SEH64_FUNCTABL \{
                irp mem, sym \\{
                        i = 0
                  mem\\#.uinfo.ptr:
                        while i < mem\\#.uinfo.size
                                load t dword from mem\\#.uinfo:i
                                dd t
                                i = i + 4
                        end while
                \\}
        \}
}