/* _cygwin_crt0_common.cc: common crt0 function for cygwin crt0's.

   Copyright 2000, 2001, 2002, 2003, 2004, 2009 Red Hat, Inc.

This file is part of Cygwin.

This software is a copyrighted work licensed under the terms of the
Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
details. */

#include "winsup.h"
#include "crt0.h"
#include "cygwin-cxx.h"

/* Weaken these declarations so the references don't pull in C++ dependencies 
   unnecessarily.  */
#define WEAK __attribute__ ((weak))

/* Use asm names to bypass the --wrap that is being applied to redirect all other
   references to these operators toward the redirectors in the Cygwin DLL; this
   way we can record what definitions were visible at final link time but still
   send all calls to the redirectors.  */
extern WEAK void *operator new(std::size_t sz) throw (std::bad_alloc)
			__asm__ ("___real__Znwj");
extern WEAK void *operator new[](std::size_t sz) throw (std::bad_alloc)
			__asm__ ("___real__Znaj");
extern WEAK void operator delete(void *p) throw()
			__asm__ ("___real__ZdlPv ");
extern WEAK void operator delete[](void *p) throw()
			__asm__ ("___real__ZdaPv");
extern WEAK void *operator new(std::size_t sz, const std::nothrow_t &nt) throw()
			__asm__ ("___real__ZnwjRKSt9nothrow_t");
extern WEAK void *operator new[](std::size_t sz, const std::nothrow_t &nt) throw()
			__asm__ ("___real__ZnajRKSt9nothrow_t");
extern WEAK void operator delete(void *p, const std::nothrow_t &nt) throw()
			__asm__ ("___real__ZdlPvRKSt9nothrow_t");
extern WEAK void operator delete[](void *p, const std::nothrow_t &nt) throw()
			__asm__ ("___real__ZdaPvRKSt9nothrow_t");

/* Avoid an info message from linker when linking applications.  */
extern __declspec(dllimport) struct _reent *_impure_ptr;

/* Initialised in _cygwin_dll_entry. */
extern int __dynamically_loaded;

#undef environ

extern "C"
{
char **environ;
int _fmode;
void _pei386_runtime_relocator (void);

extern char __RUNTIME_PSEUDO_RELOC_LIST__;
extern char __RUNTIME_PSEUDO_RELOC_LIST_END__;
extern char _image_base__;

struct per_process_cxx_malloc __cygwin_cxx_malloc = 
{
  &(operator new), &(operator new[]),
  &(operator delete), &(operator delete[]),
  &(operator new), &(operator new[]),
  &(operator delete), &(operator delete[])
};

/* Set up pointers to various pieces so the dll can then use them,
   and then jump to the dll.  */

int __stdcall
_cygwin_crt0_common (MainFunc f, per_process *u)
{
  per_process *newu = (per_process *) cygwin_internal (CW_USER_DATA);
  bool uwasnull;

  /* u is non-NULL if we are in a DLL, and NULL in the main exe.
     newu is the Cygwin DLL's internal per_process and never NULL.  */
  if (u != NULL)
    uwasnull = false;	/* Caller allocated space for per_process structure.  */
  else
    {
      u = newu;		/* Using DLL built-in per_process.  */
      uwasnull = true;	/* Remember for later.  */
    }

  /* The version numbers are the main source of compatibility checking.
     As a backup to them, we use the size of the per_process struct.  */
  u->magic_biscuit = sizeof (per_process);

  /* cygwin.dll version number in effect at the time the app was created.  */
  u->dll_major = CYGWIN_VERSION_DLL_MAJOR;
  u->dll_minor = CYGWIN_VERSION_DLL_MINOR;
  u->api_major = CYGWIN_VERSION_API_MAJOR;
  u->api_minor = CYGWIN_VERSION_API_MINOR;

  u->ctors = &__CTOR_LIST__;
  u->dtors = &__DTOR_LIST__;
  u->envptr = &environ;
  if (uwasnull)
    _impure_ptr = u->impure_ptr;	/* Use field initialized in newer DLLs. */
  else
    u->impure_ptr_ptr = &_impure_ptr;	/* Older DLLs need this. */

  u->main = f;

  /* These functions are executed prior to main.  They are just stubs unless the
     user overrides them. */
  u->premain[0] = cygwin_premain0;
  u->premain[1] = cygwin_premain1;
  u->premain[2] = cygwin_premain2;
  u->premain[3] = cygwin_premain3;
  u->fmode_ptr = &_fmode;

  /* This is used to record what the initial sp was.  The value is needed
     when copying the parent's stack to the child during a fork.  */
  u->initial_sp = (char *) __builtin_frame_address (1);

  /* Remember whatever the user linked his application with - or
     point to entries in the dll.  */
  u->malloc = &malloc;
  u->free = &free;
  u->realloc = &realloc;
  u->calloc = &calloc;

  /* Likewise for the C++ memory operators, if any, but not if we
     were dlopen()'d, as we might get dlclose()'d and that would
     leave stale function pointers behind.    */
  if (newu && newu->cxx_malloc && !__dynamically_loaded)
    {
      /* Inherit what we don't override.  */
#define CONDITIONALLY_OVERRIDE(MEMBER) \
      if (!__cygwin_cxx_malloc.MEMBER) \
	__cygwin_cxx_malloc.MEMBER = newu->cxx_malloc->MEMBER;
      CONDITIONALLY_OVERRIDE(oper_new);
      CONDITIONALLY_OVERRIDE(oper_new__);
      CONDITIONALLY_OVERRIDE(oper_delete);
      CONDITIONALLY_OVERRIDE(oper_delete__);
      CONDITIONALLY_OVERRIDE(oper_new_nt);
      CONDITIONALLY_OVERRIDE(oper_new___nt);
      CONDITIONALLY_OVERRIDE(oper_delete_nt);
      CONDITIONALLY_OVERRIDE(oper_delete___nt);
      /* Now update the resulting set into the global redirectors.  */
      *newu->cxx_malloc = __cygwin_cxx_malloc;
    }

  /* Setup the module handle so fork can get the path name.  */
  u->hmodule = GetModuleHandle (0);

  /* variables for fork */
  u->data_start = &_data_start__;
  u->data_end = &_data_end__;
  u->bss_start = &_bss_start__;
  u->bss_end = &_bss_end__;
  u->pseudo_reloc_start = &__RUNTIME_PSEUDO_RELOC_LIST__;
  u->pseudo_reloc_end = &__RUNTIME_PSEUDO_RELOC_LIST_END__;
  u->image_base = &_image_base__;
  /* This is actually a dummy call to force the linker to load this
     symbol for older apps which need it.  */
  _pei386_runtime_relocator ();
  return 1;
}
} /* "C" */
