News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

How to properly make prologue and epilogue?

Started by vogelsang, December 21, 2013, 10:34:36 PM

Previous topic - Next topic

vogelsang

hi,

I have a problem with understanding SEH directives. I've read about this issue on MSDN, but i'm not sure do i understood it correctly. As far as i know SEH directives are for handling exceptions. They write informations about procedure frames to xdata and pdata sections. And SEH directives are needed only for procs that are calling other procs.

For example if got proc Main which calls other proc that takes 8 params and Main uses its own params i think that proper prologue and epilogue should look like this:


.data
qwResult dq 0
.code

Main PROC FRAME 1st:QWORD, 2nd:QWORD

push rbp
.pushreg rbp
push rbx
.pushreg rbx
push rdi
.pushreg rdi
mov rbp, rsp
.setframe rbp, 0
sub rsp, 8*8
.allocstack 8*8
.endprolog

mov 1st, rcx
mov 2nd, rdx

xor ebx, ebx
mov qword ptr [rsp+7*8], rbx
mov qword ptr [rsp+6*8], rbx
mov qword ptr [rsp+5*8], rbx
mov qword ptr [rsp+4*8], rbx
mov r9, 100000h
mov r8, 10000h
mov rdx, 1000h
mov rcx, 100h
call EightParamProc

add rax, 1st
add rax, 2nd
mov qwResult, rax

add rsp, 8*8
pop rdi
pop rbx
pop rbp
ret

Main ENDP
END


Could someone correct me if wrong?
Thanks in advance.
"How beautiful this world ruled by dibs, not a gun!"
...

Gunther

Quote from: vogelsang on December 21, 2013, 10:34:36 PM
hi,

I have a problem with understanding SEH directives. I've read about this issue on MSDN, but i'm not sure do i understood it correctly. As far as i know SEH directives are for handling exceptions. They write informations about procedure frames to xdata and pdata sections. And SEH directives are needed only for procs that are calling other procs.

you could check the following link. It's NASM/YASM code, but should be easy to convert. Furthermore, JWasm has a 64 bit SEH example inside the Samples directory (Win64_3.asm). I hope that helps.

Gunther
You have to know the facts before you can distort them.

vogelsang

I saw those examples but i have many lacks in nasm syntax and one example from jwasm is too little for me. I'll try to convert nasm example. Thanks for help.
"How beautiful this world ruled by dibs, not a gun!"
...

Gunther

Quote from: vogelsang on December 22, 2013, 12:18:50 AM
I saw those examples but i have many lacks in nasm syntax and one example from jwasm is too little for me. I'll try to convert nasm example. Thanks for help.

There's another JWasm example (Win64_3e.asm). The translation from NASM to MASM isn't hard. That'll give you enough help.

Gunther
You have to know the facts before you can distort them.

japheth

Quote from: vogelsang on December 21, 2013, 10:34:36 PM
Could someone correct me if wrong?

I'd say your code looks good.

You can make jwasm tell in the listing file what it writes into .xdata and .pdata by adding the -Sg cmdline option.

vogelsang

Quote
I'd say your code looks good.

You write little about my understaning SEH directives, so i guess it's fine. I'll look at file listing. Maybe there i'll find out about that for sure. Thanks.
"How beautiful this world ruled by dibs, not a gun!"
...

japheth

Quote from: vogelsang on December 22, 2013, 05:01:46 PM
You write little about my understaning SEH directives, so i guess it's fine.

Yes.

However, a second glance at your code reveals an error:


mov _1st, rcx
mov _2nd, rdx


If you setup your own frame AND want to access the proc's parameters by name, you have to comply to the rule that the frame pointer register has to point to the location where the old value is saved, immediately followed by the proc's return address and the proc's arguments.

That means, in your sample you should move the "push rbx" and "push rdi" lines BEHIND the "mov rbp, rsp".

vogelsang

#7

SomeProc PROC
push    rbp
mov     rbp, rsp
...


True, i saw that piece of code at the start of procs in other sources. I need to complete my knowledge about stack frame. Thanks for pointing this.

Other thing, i've looked at file listing and found this fragment of code where is something about xdata and pdata sections. But i don't understand what this numbers mean. This is too advanced stuff for me but i'm curious. Could you explain a bit? Source is similiar to that from first post but not the same:


                                ;--------MAKE-------------------------------------------------------------------------
                                ;
                                ; assembling:
                                ; jwasm -win64 -Zp8 -Fl -Sg SEH.asm
                                ; linking:
                                ; link /SUBSYSTEM:CONSOLE SEH.obj
                                ;
                                ;--------DATA-------------------------------------------------------------------------

                                .DATA
00000000                    *   _DATA segment
                            *   assume cs:ERROR
00000000  0000000000000000      qwResult dq 0

                                ;--------CODE-------------------------------------------------------------------------
00000000                        .CODE
00000008                    *   _DATA ends
00000000                    *   _TEXT segment
                            *   assume cs:FLAT

00000000                        mainCRTStartup PROC FRAME

00000000  4883EC28              sub rsp, 5*8
                                .allocstack 5*8
                                .endprolog

00000004  48C7C20A000000        mov rdx, 10
0000000B  48C7C11E000000        mov rcx, 30
00000012  E808000000            call TwoParamProc
00000017  33C9                  xor ecx, ecx
00000019  FF1500000000          call __imp_ExitProcess

00000000                    *   .xdata segment align(8) flat read 'DATA'
00000000                    *   $xdatasym label near
00000000  01040100          *   db 1t + (00h shl 3), 4t, 1t, 00h + (00h shl 4)
00000004  0442              *   dw 04204h
00000006  0000              *   align 4
00000008                    *   .xdata ends
00000000                    *   .pdata segment align(4) flat read 'DATA'
00000000  000000001F00000000*   dd imagerel mainCRTStartup, imagerel mainCRTStartup+01Fh, imagerel $xdatasym+00h
0000000C                    *   .pdata ends
0000001F                        mainCRTStartup ENDP

0000001F                        TwoParamProc PROC FRAME first:QWORD, second:QWORD
                               
0000001F  55                    push rbp
                                .pushreg rbp
00000020  488BEC                mov rbp, rsp
                                .setframe rbp, 0

00000023  53                    push rbx
                                .pushreg rbx
00000024  57                    push rdi
                                .pushreg rdi

00000025  4883EC40              sub rsp, 8*8
                                .allocstack 8*8
                                .endprolog

00000029  48894D10              mov first, rcx
0000002D  48895518              mov second, rdx

00000031  33DB                  xor ebx, ebx
00000033  48895C2438            mov qword ptr [rsp+7*8], rbx
00000038  48895C2430            mov qword ptr [rsp+6*8], rbx
0000003D  48895C2428            mov qword ptr [rsp+5*8], rbx
00000042  48895C2420            mov qword ptr [rsp+4*8], rbx
00000047  49C7C100001000        mov r9, 100000h
0000004E  49C7C000000100        mov r8, 10000h
00000055  48C7C200100000        mov rdx, 1000h
0000005C  48C7C100010000        mov rcx, 100h
00000063  E817000000            call EightParamProc

00000068  48034510              add rax, first
0000006C  48034518              add rax, second
00000070  48890500000000        mov qwResult, rax

00000077  4883C440              add rsp, 8*8
0000007B  5F                    pop rdi
0000007C  5B                    pop rbx
0000007D  5D                    pop rbp
0000007E                        ret
0000007E  C3                *   retn
                               
00000008                    *   .xdata segment
00000008  010A0505          *   db 1t + (00h shl 3), 10t, 5t, 05h + (00h shl 4)
0000000C  0A7206700530045301*   dw 0720ah, 07006h, 03005h, 05304h, 05001h
00000016  0000              *   align 4
00000018                    *   .xdata ends
0000000C                    *   .pdata segment
0000000C  000000006000000008*   dd imagerel TwoParamProc, imagerel TwoParamProc+060h, imagerel $xdatasym+08h
00000018                    *   .pdata ends
0000007F                        TwoParamProc ENDP

0000007F                        EightParamProc PROC p1:QWORD, p2:QWORD, p3:QWORD, p4:QWORD, p5:QWORD, p6:QWORD, p7:QWORD, p8:QWORD
                               
0000007F  55                *   push rbp
00000080  488BEC            *   mov rbp, rsp
00000083  48C7C00A000000        mov rax, 10
0000008A                        ret
0000008A  C9                *   leave
0000008B  C3                *   retn

0000008C                        EightParamProc ENDP
                                END
0000008C                    *   _TEXT ends


Edit 06:05:46 PM

Here was some code added, but I have some delusions :biggrin: and deleted it.






"How beautiful this world ruled by dibs, not a gun!"
...

japheth

Quote from: vogelsang on December 23, 2013, 03:21:04 AM
Other thing, i've looked at file listing and found this fragment of code where is something about xdata and pdata sections. But i don't understand what this numbers mean. ... Could you explain a bit?

I forgot most of this stuff. But see file win64seh.h from jwasm's source:



/* some structures for Win64 SEH */

/* .pdata items */

typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY
{
    uint_32 BeginAddress;
    uint_32 EndAddress;
    uint_32 UnwindData; /* RVA of UNWIND_INFO */
} IMAGE_RUNTIME_FUNCTION_ENTRY;

/* .xdata items */

enum {
    UWOP_PUSH_NONVOL     = 0, /* .PUSHREG    - push nonvolative gpr */
    UWOP_ALLOC_LARGE     = 1, /* .ALLOCSTACK - alloc large-sized area on stack */
    UWOP_ALLOC_SMALL     = 2, /* .ALLOCSTACK - alloc small-sized area (8-128) on stack */
    UWOP_SET_FPREG       = 3, /* .SETFRAME   - set frame pointer */
    UWOP_SAVE_NONVOL     = 4, /* .SAVEREG    - save nonvolative gpr using MOV instead of PUSH */
    UWOP_SAVE_NONVOL_FAR = 5, /* .SAVEREG    - save nonvolative gpr using MOV instead of PUSH */
    UWOP_SAVE_XMM        = 6, /* */
    UWOP_SAVE_XMM_FAR    = 7, /* */
    UWOP_SAVE_XMM128     = 8, /* .SAVEXMM128 - save all 128bits of nonvolative XMM register on stack */
    UWOP_SAVE_XMM128_FAR = 9, /* .SAVEXMM128 - save all 128bits of nonvolative XMM register on stack */
    UWOP_PUSH_MACHFRAME  = 10 /* .PUSHFRAME  - push a machine frame ( SS, RSP, EFL, CS, RIP [ERRCODE] ) */
};

typedef union _UNWIND_CODE {
    struct {
        uint_8 CodeOffset;    /* offset within prolog */
        uint_8 UnwindOp : 4;  /* see UWOP_ values */
        uint_8 OpInfo   : 4;
    };
    uint_16 FrameOffset;
} UNWIND_CODE;

enum {
    UNW_FLAG_NHANDLER = 0,
    UNW_FLAG_EHANDLER = 1, /* function to examine exceptions */
    UNW_FLAG_UHANDLER = 2, /* function to unwind an exception */
    UNW_FLAG_FHANDLER = 3, /* inofficial, is E+U */
    UNW_FLAG_CHAININFO = 4
};

typedef struct _UNWIND_INFO {
    uint_8 Version       : 3; /* is 1 */
    uint_8 Flags         : 5; /* see UNW_FLAG_ values */
    uint_8 SizeOfProlog;      /* size of prolog in bytes */
    uint_8 CountOfCodes;      /* number of UNWIND_CODE entries */
    uint_8 FrameRegister : 4; /* if nonzero, function uses a frame pointer */
    uint_8 FrameOffset   : 4; /* offset frame reg from RSP * 16 */
#if 0
    UNWIND_CODE UnwindCode[1]; /* unwind codes array */
    union {
        uint_32 ExceptionHandler; /* if UNW_FLAG_EHANDLER or UNW_FLAG_UHANDLER is set: RVA of language specific handler */
        uint_32 FunctionEntry;    /* if UNW_FLAG_CHAININFO is set: see IMAGE_RUNTIME_FUNCTION_ENTRY */
    };
    uint_32 ExceptionData[];
#endif
} UNWIND_INFO;

#define UNW_VERSION 1



If you google some of the symbolic constants ( i.e. "UWOP_PUSH" ) I bet that some more detailed info may be found.