Well I am learning! (slowly bet hey, bettern nothing :grin:).
I think they are all fairly quick ones.

1>
Can the stack frame be modified on the fly to support multiple calls?

I am just curious to see if my intuition on this is way off or not. I can imagine a fairly good
speed savings on multiple API calls if you could. Say I was loading up two images...

(I have yet to start messing around with the frames yet, so maybe it should be subtraction)



WndProc proc uses ebx hWnd:dword, uMsg:dword, wParam:dword, lParam:dword
; save stack position
mov ebx, ebp

; initial API call
invoke LoadImage, hInstance, id1, IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR

; fix stack back to before last API call
add ebp, 12

; replace id1 with id2 and call again
mov [ebx+4], id2
call LoadImage

.
.
.


2>
I have an array of 22 button structures defined like so:
ToolInfo TBBUTTON 22 dup(<>)

I am having a little trouble coming up with a good way (efficient) to access an
individual elements of this. Right now I have this (which works good). Just looking
for a faster, better algo.

Note: hCurrToolInfo = index into TBBUTTON structure



; make ecx point to our structure in memory (22 TBBUTTON's)
mov eax, hCurrToolInfo
mov ecx, SIZEOF TBBUTTON
mul ecx
lea ecx, [ToolInfo]
add ecx, eax

; make eax point to the structure passed to us (TBNOTIFY)
mov eax, lParam
add eax, SIZEOF NMHDR
add eax, 4

; copy ours to thiers
invoke RtlMoveMemory, eax, ecx, SIZEOF TBBUTTON
mov eax, lParam
mov [TBNOTIFY ptr [eax]].pszText, 0

xor eax, eax
inc eax
ret


Thanks for all replies. I would try and do more with the second question, but I cant at the moment...
Posted on 2002-07-18 18:22:31 by Graebel
1) I don't see any problems with modifying the stack on the fly, but there are some things to be wary of. Namely, make sure your proc doesn't modify any of the values on the stack (I don't think any of the APIs do this) and make sure you have the same number of parameters on both calls.

I haven't done this myself, but these two things pop into my mind.

2)



mov eax,hCurrToolInfo
imul eax,sizeof TBBUTTON
lea ecx,[eax+ToolInfo]

or

mov eax,hCurrToolInfo
lea eax,[4*eax+eax]
lea ecx,[4*eax+ToolInfo]



Since TBBUTTON is 14h == 20 decimal you can use the latter version (it's bound to be faster). Also, you don't wipe out edx this way (if that matters to you). In fact, you don't really need to use eax at all, you can do it all with ecx.



mov eax,lParam
add eax,4+sizeof NMHDR


Not much of an optimation to be sure, but since sizeof NMHDR is a constant, it'll work just fine (the assembler will just add it up for you)

--Chorus
Posted on 2002-07-18 18:45:24 by chorus
Hrm, you're messing with EBP while the stack is ESP...
Parameter reuse is possible with C calling convention,
but STDCALL has the proc clean the stack. While you can
"sub esp, xx" to "get the parameters back", something could
(theoretically) have interrupted your thread and trashed
the stack parms in the meanwhile. Not too likely though,
I only think this would happen if your program is running
through a (ring3) debugger - and not even necessarily then.
I don't seee the big deal about a few pushes, though... when
you're dealing with API calls, the overhead of a few pushes
is miniscule compared to the time executing the API (most
of the time anyway). It's been said before but I'll say it
again - optimize where it matters :).

Now, with your code, you will have a standard stack frame
constructed, the usual



; auto-generated by masm
push ebp
mov ebp, esp
; your code starts here
mov ebx, ebp ; now ebx=ebp=esp = pointer-to-pushed-ebp

Later in your code, you do "mov , id2". Isn't this
going to trash your return-eip ?
Posted on 2002-07-18 20:18:44 by f0dder

Hrm, you're messing with EBP while the stack is ESP...
...
Later in your code, you do "mov , id2". Isn't this
going to trash your return-eip ?


Ahh, ESP is the stack... well like I said I havnt really looked
into it all that closely yet. I remember those two mentioned
from other posts.

Anywho I completely trashed that first example. I shouldnt
have been using EBP and I was saving the wrong stack
position to boot. If I understand everything correctly, then
the below code should be very close to what I was originally
thinking of.



WndProc proc uses ebx hWnd:dword, uMsg:dword, wParam:dword, lParam:dword
; initial api call
push LR_DEFAULTCOLOR
push 0
push 0
push IMAGE_BITMAP
push id1
push hInstance
; <-- save ESP here
mov ebx, esp
call LoadImage

; fix stack back to before last API call
mov esp, ebx

; replace id1 with id2 and call again
mov [ebx+4], id2
call LoadImage
.
.
.


And yeah, its just a few pushes, but if I dont mess around enough
with this kind of code I wont have a clue as to how to really optimize
the code that really needs it. In my book the more tricks you can
pull from your hat, the better off you will be in the long run :alright:.


...something could (theoretically) have interrupted your thread and
trashed the stack parms in the meanwhile


Hmm, actuall I dont understand this point. If something interrupts my
thread, how does that affect my stack? Would not the same
argument apply for regular based calls? Like take the 1st example and
dont mess with the stack, but force an interrupt:

push LR_DEFAULTCOLOR
push 0
push 0
push IMAGE_BITMAP
push id1
push hInstance
; <-- interrupt
call LoadImage

Could not the same thing happen here as well? If not whats the
difference between this and the one that modifies the stack? Looks
to me like they both do...
Posted on 2002-07-18 21:44:49 by Graebel
Well... it wouldn't happen with a "normal" program, because there you only have
data at "esp+xx" - while your method of stackfiddling has a (very small) timeframe
where you have data at "esp-xx" ("unallocated" stack space). Now I don't really
think that windows will mess with your stack, interrupts should have their own
ring0 stacks and such, and I don't think debuggers these days have a need to
store stuff temporarily in the user stack - but one never knows :).
Posted on 2002-07-18 22:24:11 by f0dder
Well I can kindof understand what your saying. However I guess I dont yet
see where the problem might be. Consider:



WndProc proc uses ebx hWnd:dword, uMsg:dword, wParam:dword, lParam:dword
; initial api call
push LR_DEFAULTCOLOR
push 0
push 0
push IMAGE_BITMAP
push id1
push hInstance
<POINT1>
; <-- save ESP here
mov ebx, esp
call LoadImage

; fix stack back to before last API call
; <POINT2>
mov esp, ebx
; <POINT3>

; replace id1 with id2 and call again
mov [ebx+4], id2
call LoadImage


If I get interrupted right before I modify the stack <POINT2> then it would be the
same as if it was interrupted in any normal program and nothing should happen
because the stack is balanced.

If I get interrupted right after at <POINT3> then to the other program it would look
the same as if I had been interupted at <POINT1> right? To me this looks like it
could happen even if I was not modifying the stack at all.

To me, either way, this type of code looks the same as any other normal series
of events a program goes through so if it works in one dont see a reason why it
wouldnt in the other...
:confused:
Posted on 2002-07-18 22:41:01 by Graebel
If you get interrupted at POINT1, no harm done, as all the
values on your stack are above the stack pointer. Other code
pushing values will not interfere with your stack contents.
If you get interrupted at POINT2, you have data on the stack
that are below the stack pointer - other code doing push would
trash your values on the stack. Perhaps this isn't very likely
to happen (was in the DOS days though), but I'm not taking any
chances in *my* code :). Also, what if the proc you're calling
has modified the parms on the stack? It's quite legal to do so,
and I do it often in my code to avoid temporary local variables
etc. And just because API calls don't do it now, nobody says
they can't do it in the future - save a few clocks but risk
your app breaking on a different windows build, is it worth it?
Of course it can be done when calling your own procs where you
know time is critical, but imho if time is so critical, you ought
to not be calling a proc, but rather using a macro, or restructure
your program.
Posted on 2002-07-18 22:50:26 by f0dder
Ahh, I had not considered the case where the API (or other) might
modify the stack variables itself. I can see where this would be
both practical and useful.

Thanks f0dder, learned a good deal on the inner workings of things
and I did end up with a new trick :grin:

Oh yes, and thank you also chorus. I have not had alot of luck in
understanding lea. I knew the bare basics on it but was never able
to use it to its full potential. And whats even better, after a couple
of minutes of running those variables around in my head, I actually
understood both of those. I like the second example better myself.
Posted on 2002-07-18 23:12:52 by Graebel