News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Negative offset in structure

Started by peter_asm, June 24, 2014, 05:17:27 AM

Previous topic - Next topic

jj2007

Quote from: qWord on June 25, 2014, 12:10:49 AM
Just as side note, jWasm has the option stackbase, which allows to omit EBP as frame pointer.

Déjà vu, in a different context. Locals relative to esp aren't any faster but [esp+n] is one byte longer than [ebp+n]. However, "frameless" seems a magic word for assembler programmers ;-)

dedndave

CPU manufacturers have optimized use of EBP for a stack frame

however, the MASM stack frames (default prologue and epilogue) are less than ideal
i often find myself writing my own stack frame code to get what i want   :P

i may use ESP, but only if i access the stack frame a few times

nidud

#17
deleted

RuiLoureiro

These are the results:

Test for correctness:
Frame OFF: 123456       61728
Frame  ON: 123456       123456

Timings:
1831    cycles for 100*call stack_frame_on
1810    cycles for 100*stack_frame_OFF

Code sizes:
Frame on:       136
Frame off:      142
--- ok ---  :t

dedndave

#19
a well-managed stack frame is a thing of beauty   :biggrin:

        OPTION  PROLOGUE:None
        OPTION  EPILOGUE:None

FrameFunc PROC dwArg1:DWORD,dwArg2:DWORD

;-----------------------------------------------------

;use TEXTQU to create labels
;if you want to add or remove locals, just change the offsets here
;it also gives you a nice "graphic" view of the overall stack frame

_dwArg2    TEXTEQU <dword ptr [ebp+28]>  ;dwArg2
_dwArg1    TEXTEQU <dword ptr [ebp+24]>  ;dwArg1
;                             [ebp+20]   ;RETurn address
;                             [ebp+16]   ;preserved EBX
;                             [ebp+12]   ;preserved ESI
;                             [ebp+8]    ;preserved EDI
_dwEaxRet  TEXTEQU <dword ptr [ebp+4]>   ;return value for EAX
;                             [ebp]      ;preserved EBP
_dwLocal1  TEXTEQU <dword ptr [ebp-4]>   ;dwLocal1
_dwLocal2  TEXTEQU <dword ptr [ebp-8]>   ;dwLocal2
_dwLocal3  TEXTEQU <dword ptr [ebp-12]>  ;dwLocal3
_lpBuff1   TEXTEQU <dword ptr [ebp-16]>  ;lpBuff1
_lpBuff2   TEXTEQU <dword ptr [ebp-20]>  ;lpBuff2

;-----------------------------------------------------

        xor     edx,edx
        push    ebx
        push    esi
        push    edi
        push    edx
        push    ebp
        mov     ebp,esp

;code to calculate the initial value of dwLocal1 in EAX

        push    eax                      ;[EBP-4] = _dwLocal1

;code to calculate the initial value of dwLocal2 in EAX

        push    eax                      ;[EBP-8] = _dwLocal2

;code to calculate the initial value of dwLocal3 in EAX

        push    eax                      ;[EBP-12] = _dwLocal3

;create placeholders for the local buffer pointers

        push    edx                      ;[EBP-16] = _lpBuff1
        push    edx                      ;[EBP-20] = _lpBuff2

;now, we want to calculate the size of the "buffers"
;they might be string buffers, structures, or local arrays
;their sizes should create 4-aligned addresses

        mov     edx,esp

;code to calculate the size of Buff1 in EAX

        sub     edx,eax
        mov     _lpBuff1,edx             ;_lpBuff1 = address of Buff1

;code to calculate the size of Buff2 in EAX

        sub     edx,eax
        mov     _lpBuff2,edx             ;_lpBuff2 = address of Buff2

;probe the stack down to create the buffers

        ASSUME  FS:Nothing

stack_probe_loop:
        push    eax
        mov     esp,fs:[8]               ;FS:[8] = TEB.StackLimit
        cmp     edx,esp
        jb      stack_probe_loop

        ASSUME  FS:ERROR

        mov     esp,edx

;at this point, the stack frame is all set up - no need to use "[ebp-xx]"
;the local dwords may be accessed by using labels like "_dwLocal1"
;the local buffer address may be accessed by using labels like "_lpBuff1"
;the value to be returned in EAX may be accessed by "_dwEaxRet"


;body of function code


;when it comes time to exit, just execute LEAVE
;that discards all the local dwords and buffers
;the return value for EAX is set up for exit
;EBP, EDI, ESI, and EBX are restored

        leave
        pop     eax
        pop     edi
        pop     esi
        pop     ebx
        ret     8

FrameFunc ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef


EDIT: of course, if you have a fixed-size buffer, you can add that before the variable-sized ones, as well   :P

RuiLoureiro

Hey Dave,
                 we have more things to do  :biggrin:

RuiLoureiro

Quote from: nidud on June 25, 2014, 02:06:37 AM
It depends on what the aim of the test was, but since it included negative values I assumed locals where used, and arguments was used, so you have to take into account usage as well as calling convention
note: i have not negative values.

My point of view is this:
i prefer to test a particular well defined procedure or set of
code that we need to do something than to get a general
rule (?) from a general test...
It seems that you prefer to use your tests to show what
you want to show.
This is why i don't follow your point of view.


Zen

DAVE !!!
Really appreciate the a well-managed stack frame is a thing of beauty post. :icon_cool:
I've always wondered how to identify stack frames,...assuming that I could actually find the stack,... :biggrin:

dedndave

this one adds a fixed-size buffer (or structure, array)

        OPTION  PROLOGUE:None
        OPTION  EPILOGUE:None

FrameFunc PROC dwArg1:DWORD,dwArg2:DWORD

;-----------------------------------------------------

;use TEXTQU to create labels
;if you want to add or remove locals, just change the offsets here
;it also gives you a nice "graphic" view of the overall stack frame

_dwArg2    TEXTEQU <dword ptr [ebp+28]>  ;dwArg2
_dwArg1    TEXTEQU <dword ptr [ebp+24]>  ;dwArg1
;                             [ebp+20]   ;RETurn address
;                             [ebp+16]   ;preserved EBX
;                             [ebp+12]   ;preserved ESI
;                             [ebp+8]    ;preserved EDI
_dwEaxRet  TEXTEQU <dword ptr [ebp+4]>   ;return value for EAX
;                             [ebp]      ;preserved EBP
_dwLocal1  TEXTEQU <dword ptr [ebp-4]>   ;dwLocal1
_dwLocal2  TEXTEQU <dword ptr [ebp-8]>   ;dwLocal2
_dwLocal3  TEXTEQU <dword ptr [ebp-12]>  ;dwLocal3
_lpBuff2   TEXTEQU <dword ptr [ebp-16]>  ;lpBuff2
_lpBuff3   TEXTEQU <dword ptr [ebp-20]>  ;lpBuff3
_Buff1     TEXTEQU           <[ebp-60]>  ;Buff1 = 40 byte fixed size buffer

;-----------------------------------------------------

        xor     edx,edx
        push    ebx
        push    esi
        push    edi
        push    edx
        push    ebp
        mov     ebp,esp

;code to calculate the initial value of dwLocal1 in EAX

        push    eax                      ;[EBP-4] = _dwLocal1

;code to calculate the initial value of dwLocal2 in EAX

        push    eax                      ;[EBP-8] = _dwLocal2

;code to calculate the initial value of dwLocal3 in EAX

        push    eax                      ;[EBP-12] = _dwLocal3

;create placeholders for the variable-size local buffer pointers

        push    edx                      ;[EBP-16] = _lpBuff2
        push    edx                      ;[EBP-20] = _lpBuff3

;now, we want to calculate the size of the "buffers"
;they might be string buffers, structures, or local arrays
;their sizes should create 4-aligned addresses

        lea     edx,_Buff1               ;start with the address of the lowest fixed-size buffer

;code to calculate the size of Buff2 in EAX

        sub     edx,eax
        mov     _lpBuff2,edx             ;_lpBuff2 = address of Buff2

;code to calculate the size of Buff3 in EAX

        sub     edx,eax
        mov     _lpBuff3,edx             ;_lpBuff3 = address of Buff3

;probe the stack down to create the buffers

        ASSUME  FS:Nothing

stack_probe_loop:
        push    eax
        mov     esp,fs:[8]               ;FS:[8] = TEB.StackLimit
        cmp     edx,esp
        jb      stack_probe_loop

        ASSUME  FS:ERROR

        mov     esp,edx

;at this point, the stack frame is all set up - no need to use "[ebp-xx]"
;the local dwords may be accessed by using labels like "_dwLocal1"
;the local fixed-size buffer may be addressed directly by _Buff1, perhaps using LEA
;the local variable-size buffer addresses may be accessed by using labels like "_lpBuff2"
;the value to be returned in EAX may be accessed by "_dwEaxRet"


;body of function code


;when it comes time to exit, just execute LEAVE
;that discards all the local dwords and buffers
;the return value for EAX is set up for exit
;EBP, EDI, ESI, and EBX are restored

        leave
        pop     eax
        pop     edi
        pop     esi
        pop     ebx
        ret     8

FrameFunc ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

nidud

#24
deleted

nidud

#25
deleted

RuiLoureiro

Yes, i see it and i see your posts, bidud.
but i don't follow your sol. also
but nothing wrong. It seems that you
didnt see what i wrote, but you do
exactly what you want to do.

EDIT: i got some results in milliseconds
         where esp is better.
         But it says nothing to me as i said
         before. That´s all.

nidud

#27
deleted

jj2007

Quote from: nidud on June 25, 2014, 02:06:37 AMUsing ESP is slower than using other register but the call is faster if EBP is not used as base pointer.
No difference here, except for fastcall, of course:

Intel(R) Celeron(R) M CPU        420  @ 1.60GHz (SSE3)
------------------------------------------------------
3235176 cycles - 0: standard (ebp)
3231541 cycles - 1: no pro/epilogue (esp)
3229054 cycles - 2: no pro/epilogue (eax)
2223710 cycles - 3: fastcall(eax,edx)


btw your code builds only with JWasm.

nidud

#29
deleted