GP2X How To Get Stack Pointer And Stack Base Pointer


synkro

0xdeadbeef
Joined
Aug 26, 2003
Messages
823
Location
Germany
Website
Visit site
I need the Stack Pointer and the Stack Base Pointer. To get the Stack Pointer I just dereferenciate the last local variable. This should work on all machines (as I want to run my code on GP2X and my PC as most GP2X devs do....) Is there a ARM specific (faster) way? R13 maybe?

To get the Stack Base Pointer I increment the Stack Pointer (as the stack grows down toward the heap) till I get a SIGSEGV or SIGBUSS. This happens when I derefernenciate the mem location right after the Stack Base Addr.

On my PC I get on every run differrent address as I have stuff running in the background using the stack, so this should be alright. But on the GP2X I get 0xbffffffc as Stack Base Pointer. That seems to be WAAAY to far...

What am I doing wrong? Are there better (more elegant) ways to get those pointers (on my Linux PC _and_ GP2X) ?

Source with syntax highlightning

Code:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>

// non-local jump env
static jmp_buf g_jump_buffer;

// prototypes
void handleSignal(int value);
void *getStackBasePtr(void);

int main(void)
{
	printf("stack base pointer: %p\n", getStackBasePtr());
	return 1;
}

/*
** gets called when we leave the stack into the limbo
** SIGBUS or SIGSEV
*/
void handleSignal(int value)
{
	longjmp(g_jump_buffer, 1);
}

/*
** Returns the stacl base pointer
*/
void *getStackBasePtr(void)
{
	int *base_ptr, stack_top, deref;
	
	// get one of the top stack entries
	base_ptr = &stack_top;
	
	// non-local exit
	if(setjmp(g_jump_buffer)!=0)
    {
        // we left the stack by one
  return base_ptr - 1;
    }
	
	// follow the stakc till we leave it
	while(1)
    {
  // move towards the first/oldest element on the stack
  base_ptr++;
  // if we dereference an invalid pointer, signal will be thrown
  deref = *base_ptr;
        if( (signal(SIGBUS, handleSignal) == SIG_ERR) || (signal(SIGSEGV, handleSignal) == SIG_ERR) )
        {
            // error with signal handler
            fprintf(stderr,"ERROR! SIGNAL HANDLER FAILED!\n");
            exit(1);
        }
    }
	return base_ptr - 1;	
}
 
synkro posted on Mar 30 2006 at 06:03 PM said:
On my PC I get on every run differrent address as I have stuff running in the background using the stack, so this should be alright. But on the GP2X I get 0xbffffffc as Stack Base Pointer. That seems to be WAAAY to far...
0xbfff fffc is the last 32bit word of addressable RAM, it makes sense to use that as the stack base. However, due to virtual memory, you don't know where it really exists in physical memory, and without searching through the kernel source you won't know how much space is allocated.
 
Last edited by a moderator:
I don't need to know the physical location. So in other words, my approach seems to be correct then? I was just wondering if that addr was valid. Does that also meant that the minimum alignment of a pointer is 32bit?
 
Linux can map any address within the cpu's 4GB address space to any physical memory location with a granuality of about 1KB. There doesn't have to be any physical memory at those addresses, the MMU translates all addresses coming from the 920 into physical addresses in a wholy transparent manner.
Pointers to 32bit data have to be 32bit aligned, 16bit data has to be 16bit aligned. The stack pointer is always 32bit aligned.
 
What do you mean with 1KB granularity? does it means that malloc allocates at least 1KB? Or that between two subsequent virtual addr are alsways 1KB in physical mem?

I assumed that all pointers are 4byte (32bit) aligned. The following code mallocs severalnumbers of chars and the pointers it returns are always (on multiple runs) are 4 bytes aligned (last number is the printf is always 0 --> addr is dividedable by 4 bytes)

Code:
#include <stdlib.h>
#include <stdio.h>

int main(void)
{
	int i;
	char *x;
	
	for(i=1; i<24; i++)
	{
  x = (char*) malloc(i * sizeof(char));
  printf("%i\tBytes malloc'd @ addr: %p, %u\n", i, x, ((unsigned int)x % 4) );
	}
	return 1;
}
 
yeah, what gfoot said .. i've been trying to think of a reason you'd need this but can't really come up with anything other than 'fast hash???' or some such glib thing ..
 
you guys leave me alone....

okay I found another way I haven't tested but seems to be WAAAAY simpler... This should also return the Stack Base Pointer. But I have a feeling this might not work on all versions of libc :(

Code:
extern void* __libc_stack_end;
main () { printf ("%p\n", __libc_stack_end); }

I also assume that it might be possible to get the Stack Base Pointer from
Code:
/proc/self/stat
but I don't know how yet.
 
Assuming the stack always grows downwards (usually true), you could just note the stack pointer at the start of the main function. main has two parameters, but you're unlikely to need to consider those in garbage collection.

I've never heard of doing garbage collection based on a plain stack with no data type information - nice one if you can make it work, I would have thought it would be too unreliable though. Unless you have a good way to locate pointers to other objects, you'll have to treat pretty much everything as a pointer. It'd be much simpler if functions registered their stack data layout (particularly where their gc-able pointers are) - you'd probably want to go for a much more .NET-like system, only garbage collecting managed pointers and restricting conversion between managed and unmanaged pointers.
 
gfoot posted on Mar 31 2006 at 06:41 AM said:
I've never heard of doing garbage collection based on a plain stack with no data type information - nice one if you can make it work, I would have thought it would be too unreliable though.  Unless you have a good way to locate pointers to other objects, you'll have to treat pretty much everything as a pointer.
Boehm-Dehmers-Weiler (already mentioned above) works without any meta-data. And yes, everything that looks like a pointer into heap memory is treated as such.

Edit: Obviously, this was the wrong pointer; MzScheme uses the Boehm collector. I'll send a pointer to the right code if I find it.

- HM
 
Last edited by a moderator:
I need to check the stack because it may contain valid pointers to data on the heap, what would mark them as alive.
 
Did you try reading the current stack pointer on startup, storing it globally and using that as the base? I don't see any problem with that - it would only fail if there were relevant pointers further up the stack, but if you avoid using any local variables in 'main' then you should be fine.
 
gfoot posted on Apr 6 2006 at 11:20 AM said:
Did you try reading the current stack pointer on startup, storing it globally and using that as the base? I don't see any problem with that - it would only fail if there were relevant pointers further up the stack, but if you avoid using any local variables in 'main' then you should be fine.

This is of course a solution but I try to avoid that, because that way I have to hope the GC's init function is called as the very first. This needs further testing, maybe I get a better solution. I also can't force the user not using any local variables in main(). The stack base pointer must be stored SOMEWHERE...
 
Last edited by a moderator:
You don't have to know that it's called absolutely first, you could have main() read it as a first step, and if the user really wants to put stuff in local vars in "main", make a wrapper function with the actual main() code - you can't have any pointers to heap memory before it on the stack, right?
 
BradN posted on Apr 6 2006 at 02:48 PM said:
You don't have to know that it's called absolutely first, you could have main() read it as a first step, and if the user really wants to put stuff in local vars in "main", make a wrapper function with the actual main() code - you can't have any pointers to heap memory before it on the stack, right?

That is even worse, it should be a transparent as possible. Everything on the stack before my assumed base pointer won't be checked, that is too dangerous.
 
Last edited by a moderator:
Back
Top