The Daily Click ::. Forums ::. Non-Klik Coding Help ::. Anyone know ASM?
 

Post Reply  Post Oekaki 
 

Posted By Message

DeadmanDines

Best Article Writer

Registered
  27/04/2006
Points
  4758
10th April, 2011 at 13:21:50 -

Hi guys,

I'm trying to make a variable-argument function in inline ASM (inline with C++) which conforms to _stdcall, except that every article that talks about _stdcall at an ASM level is written in nerd, so I'm having a nightmare trying to understand it.

I can write a _stdcall in inline ASM okay within a naked C++ function, and even read a variable number of params (a global structure advises how big the variables are, etc). But it dies when it finishes (just after my epilogue code) so I suspect I'm not popping the stack properly.

However, as I don't fully understand what the caller has done to the stack, I can't really envisage how to change it back again.

My code:



bool _declspec(naked) __stdcall CallBackFunction( ... ){
// Setup
int eaxVal; // To transfer value of eax register
int i; // General purpose iterator
int iOffs; // Similar to above, but a note of the offset in conjunction with iterator
int pSize; // Size of params region

// Prologue
_asm {
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
}

// Fill in parameters field
pSize = lpgRdPtr->nParams * sizeof(long); // lpgRdPtr = long global pointer to Rundata.
lpgRdPtr->pParams = (char*)malloc(pSize);

// Loop through and transfer params from stack to pParams
iOffs = 8; // Start offset at 8 in the stack
for(i=0; i<pSize; i=i+4){
// Go one dword at a time
// Get variable value from stack
_asm{
mov edx, iOffs // The offset
mov eax, [ebp + edx] // Gets dword at iAdd offset
mov eaxVal, eax
}

lpgRdPtr->pParams[i] = ((char*)&eaxVal)[3];
lpgRdPtr->pParams[i+1] = ((char*)&eaxVal)[2];
lpgRdPtr->pParams[i+2] = ((char*)&eaxVal)[1];
lpgRdPtr->pParams[i+3] = ((char*)&eaxVal)[0];

iOffs = iOffs + 4; // Inc offset by 4
}

// Trigger event
lpgRdPtr->rRd->GenerateEvent(1);

free( lpgRdPtr->pParams );

// Epilogue
_asm{
mov esp, ebp
pop ebp
ret 10h // <-- Currently assumes params are 16 bytes long, but I don't seem able to specify a dynamic value here
}
}



So yeah, the objective is to allow the user to define their own callback function in MMF so a function like EnumWindows() can run an event as if that event were a callback formatted like an EnumWindowsProc().

It's supposed to create a dummy _stdcall function for the EnumWindowsProc and read the params into a structure in Rundata, then trigger the event in MMF.

All this goes perfectly until it tries to close the function and step back up into the caller, at which point it goes 'Ka-Puff!!' and dies.

Yeah. Ka-Puff.

 
191 / 9999 * 7 + 191 * 7

Hagar

Administrator
Old klik fart

Registered
  20/02/2002
Points
  1692

You've Been Circy'd!Teddy Bear
2nd May, 2011 at 17:09:04 -

Hi Dines,

I do some assembly on the Texas Instruments series of Digital Signal Processors - so my knowledge may not be terribly useful or applicable - but apart from some possible speed advantages of writing assembly (that said beating compiler optimisation takes some thinking in the DSP world, but it can be done) is there not easier ways to pass variable length arguments, preferably in C/C++?

Just off the top of my head, a system consisting of 2 pointers and an integer springs to mind. The first pointer could be the address of a beginning piece of dynamically allocated RAM. The second pointer could point to an another piece of dynamically allocated RAM which indicates what each byte's purpose is. The thrid and final argument, could be the number of bytes you wish to pass as an argument.

You could then have some system to figure out what variable accounts to what memory in your dynamically allocated memory and then memcpy into whatever variables you wish.

This maybe a complent tangent but I thought I would try to help in whatever way I could .

TI have a great framework for making assembly functions, arguments are mapped into certain registers (either values or pointers, it does not matter), and so is your return address to branch to after running your assembly code. It really does make life easy.

 
n/a

DeadmanDines

Best Article Writer

Registered
  27/04/2006
Points
  4758
9th May, 2011 at 12:38:23 -

My problem is that I have no control over the caller.

I was trying to make an extension object that would let you set a series of events up as a callback function.

So in DLL Object I could call the EnumWindows() function from the WinAPI and pass it the address of my callback function in the parameters.

Then using a static variable, tell the Callback Object's function what setup the callback needs (return type, number and types of params, etc) so that the callback function when executed can load these into a structure, pass a pointer to the structure to Rundata, and then trigger a condition which will run your MMF events.

That was the idea, and Stack Overflow's comments helped a lot, but I'm still struggling because my code executes fine, but still somehow messes up the stack in a way that I can't figure out.

Bummer.



 
191 / 9999 * 7 + 191 * 7

Hagar

Administrator
Old klik fart

Registered
  20/02/2002
Points
  1692

You've Been Circy'd!Teddy Bear
16th May, 2011 at 19:55:52 -

Bogus dude

Might be worth getting in touch with some of the clickteam extension developers. They do a lot more Windows based cpp development than I have ever done.

 
n/a
   

Post Reply



 



Advertisement

Worth A Click