Flat assembler thread

A forum where anything goes. Introduce yourselves to other members of the forums, discuss how your name evolves when written out in the Game of Life, or just tell us how you found it. This is the forum for "non-academic" content.
Post Reply
User avatar
PHPBB12345
Posts: 871
Joined: August 5th, 2015, 11:55 pm
Contact:

Flat assembler thread

Post by PHPBB12345 » July 6th, 2021, 8:20 am

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
                \\}
        \}
}

Post Reply