Page 1 of 1

Stack issues

Posted: Tue May 01, 2007 3:06 am
by pcmattman
I have a working stack setup in my kernel thread generation code, that pushes a return address onto the stack that points to a 'die()' function to delete the process when it returns. The problem is, I can't have anything on the stack between the process entry point and the 'die()' entry point. I wrote this to push the arguments onto the stack:

Code: Select all

	// start the va_list
	va_list pushargs;
	va_start( pushargs, arglist );
	
	// parse it
	i = 0;
	while( arglist[i] != 0 )
	{
		if( arglist[i] == '%' )
		{
			// get each part of it
			if( arglist[i+1] == 'd' )
			{
				// decimal (int)
				i += 2;
				int val = va_arg( pushargs, int );
				*esp-- = val;
			}
			else if( arglist[i+1] == 'u' )
			{
				// unsigned (look at next char)
				if( arglist[i+2] == 'd' )
				{
					// unsigned int
					i += 3;
					unsigned int val = va_arg( pushargs, unsigned int );
					*esp-- = val;
				}
				else
				{
					i++;
				}
			}
			else if( arglist[i+1] == 's' )
			{
				// string pointer (always char*)
				i += 2;
				char* val = va_arg( pushargs, char* );
				*esp-- = (unsigned int) val;
			}
			else
			{
				// unknown format specifier
				i++;
			}
		}
	}
	
	// all done
	va_end( pushargs );
It works, processes spawned can read the arguments and use them etc...

But they can't return without crashing, because, I think, they are trying to return to an address that is pushed by the above code. The main reason, I think, is that C doesn't pop arguments off the stack when it handles them, that's the job of the caller. In that case, how do I pop the arguments off the stack?

I tried this, to sum up the size of all the arguments and add that value to ESP:

Code: Select all

unsigned int stacksize = sizeof( arg1 ) + sizeof( arg2 ) + sizeof( unsigned int );
__asm__ __volatile__ ( "addl %0,%%esp" : : "r" (stacksize) );
It didn't work.

Posted: Tue May 01, 2007 4:01 am
by senaus
Do you push the entry point into die() after the arguments or before? By C calling convention, it should be pushed afterwards - this is the return address.

That way, your process's 'main()' or equivalent will pop the entry point to 'die()' and return to that.

Also, is the die() routine in kernel mode or user mode?

Cheers,
Senaus

Posted: Tue May 01, 2007 4:08 am
by pcmattman
I honestly completely forgot that the return address goes first on the stack...

Posted: Tue May 01, 2007 4:10 am
by senaus
Aaaah, so is it working now?

Posted: Tue May 01, 2007 4:11 am
by pcmattman
Yes.

I also forgot a(nother) very important thing: arguments must be pushed in reverse...