/*
 *  Pilot startup code for use with gcc.  This code was written 
 *  by Kresten Krab Thorup, and is in the public domain.
 *  It is *not* under the GPL or the GLPL, you can freely link it
 *  into your programs.
 */

#include <Common.h>
#include <System/SysAll.h>
#define NON_PORTABLE
#include <SystemPrv.h>

void GccRelocateData ();

ULong start ()
{
  SysAppInfoPtr appInfo;
  Ptr prevGlobals;
  Ptr globalsPtr;
  ULong result;
  
  if (SysAppStartup (&appInfo, &prevGlobals, &globalsPtr) != 0)
    {
      SndPlaySystemSound (sndError);
      return -1;
    }
  else
    {
      GccRelocateData ();
      PilotMain (appInfo->cmd, appInfo->cmdPBP, appInfo->launchFlags);
      SysAppExit (appInfo, prevGlobals, globalsPtr);
      return 0;
    }
}

struct pilot_reloc {
  UChar  type;
  UChar  section;  
  UInt   offset;
  ULong  value ;
};

#define TEXT_SECTION 't'
#define DATA_SECTION 'd'
#define BSS_SECTION  'b'

#define RELOC_ABS_32       0xbe

/*
 *  This function should be called from 
 */
void GccRelocateData ()
{
  extern long data_start, bss_start;
  unsigned long data = (unsigned long)&data_start;
  unsigned long bss  = (unsigned long)&bss_start;
  unsigned long text = (unsigned long)&start;

  VoidHand relocH;
  char *relocPtr;
  struct pilot_reloc *relocs;
  UInt count, i;

  static int done = 0;
  
  if (done) return;
  else done = 1;

  asm ("sub.l #start, %0" : "=g" (text) : "0" (text));
  asm ("sub.l #bss_start, %0" : "=g" (bss) : "0" (bss));
  asm ("sub.l #data_start, %0" : "=g" (data) : "0" (data));
  
  relocH = DmGet1Resource ('rloc', 0);
  if (relocH == 0)
    return;

  relocPtr = MemHandleLock (relocH);
  count = *(UInt*)relocPtr;
  relocs = (struct pilot_reloc*) (relocPtr + 2);

#if DEBUG
  printf ("count=%d\n", count);
#endif /* DEBUG */

  for (i = 0; i < count; i++)
    {
      unsigned long *loc;
#if DEBUG
      printf ("reloc[%d].type = %x\n", i, (UInt) relocs[i].type);
#endif /* DEBUG */
      ErrFatalDisplayIf (relocs[i].type != RELOC_ABS_32, \
			 "unknown reloc.type");

      loc = (unsigned long*) ((char*)&data_start + relocs[i].offset);

      switch (relocs[i].section)
	{
	case TEXT_SECTION:
	  *loc += text;
	  break;

	case DATA_SECTION:
	  *loc += data;
	  break;

	case BSS_SECTION:
	  *loc += bss;
	  
	default:
	  ErrDisplay ("Unknown reloc.section");
	}
    }
  MemHandleUnlock (relocH);
  DmReleaseResource (relocH);
}
