/* ---------------------------------------------------------------------- */
/*                   Copyright (C) 1991 by Natrlich!                     */
/*                      This file is copyrighted!                         */
/*                Refer to the documentation for details.                 */
/* ---------------------------------------------------------------------- */
#define LINKER 1
#include "defines.h"
#include <stdio.h>
#include OSBIND
#include "nasm.h"
#include "debug.h"
#include "ldebug.h"
#include NMALLOC_H
#include "object.h"
#include "process.h"
#include "code.h"

#if ! VERSION
extern char    x1[], x2[], x3[], x4[], x5[], x6[];
#endif

byte      huge *pb;
e_dropped huge *pe;
s_dropped huge *ps;
linksymbol huge *py;
i_dropped huge *pi;
r_dropped huge *pr;
f_dropped huge *pf;
lword          magic, bytes, sbytes, ibytes, rbytes, ebytes, ybytes, fbytes;
lword          ysize;         /* hack for backwards compatibility */
static obj_h   l;

word           version,
               alignment;
#if ! VERSION
static word    revision;
#endif
static void    fix_version(), fix_sizes();
#if ! DISASM
extern int     relocatable,
               bootable,
               verbose,
               pageflag;
extern word    diff, head_off, endpc, origin, mv_offset;

extern byte huge  *ptohead;

#endif
char    trc_loss[] = "File is truncated";


#if VERSION
# define the_10seek( x, y)
#else

void the_10seek( fd, x)
char  *x;
{
   unsigned long   foo;
   static char     chkbuf[11];

   if( (foo = Fread( fd, 10L, chkbuf)) < 10L)
   {
      fprintf( stderr, "FOO = %ld\n", foo);
      ngferror( foo, trc_loss);
   }
   if( strcmp( chkbuf, x))
      nferror("Not a good object file");
}
#endif

void  do_load( fd)
{
   long  foo;

   ENTER("do_load");
   INTEGRITY_CHECK();
   if( Fread( fd, sizeof( obj_h), &l) != sizeof( obj_h))
      nferror("File is too short to be an object file");
   IMESS("Sizeof( obj_h) = %ld", sizeof( obj_h), 4);
   magic    = lbeek( &l.magic);
   version  = dbeek( &l.version);
#if ! VERSION
   revision = dbeek( &l.revision);
#endif
   alignment= dbeek( &l.alignment);
   bytes    = (lword) dbeek( &l.codesize);
   sbytes   = lbeek( &l.segsize);
   ibytes   = lbeek( &l.immsize);
   rbytes   = lbeek( &l.relsize);
   ebytes   = lbeek( &l.expsize);
   ybytes   = ysize = lbeek( &l.symsize);
   fbytes   = lbeek( &l.fixsize);
   if( magic != OBJMAGIC)
      nferror("This is not an object file");
   if( version < (word) OBJ_READ_COMP)
      nferror("Object file was created with an obsolete version");
   if( version > DVERSION)
      nferror("I am too oldfashioned to understand this object format");
#if ! VERSION
   if( revision != ASMREVISION)
      nferror("Object was created by a different revision");
#endif
   if( version != DVERSION)
      fix_sizes( version);

#if ! DISASM
   if( __p - __program + bytes >= MAXMODULE)
      nferror("Objects overflow the program buffer");
#endif
   MESS("[ 0] --- Fread ---");
   pb = nmalloc( bytes);
   if( (foo = Fread( fd, bytes, pb)) != bytes)
      ngferror( foo, trc_loss);

   MESS("[ 1] --- Fseek ---");
   the_10seek( fd, x1);
   INTEGRITY_CHECK();
   MESS("[ 2] --- Sbytes ---");
   if( sbytes)
   {
      ps = nmalloc( sbytes);
      if( (foo = Fread( fd, sbytes, ps)) != sbytes)
         ngferror( foo, trc_loss);
   }

   MESS("[ 3] --- Fseek ---");
   INTEGRITY_CHECK();
   the_10seek( fd, x2);
   MESS("[ 4] --- Ibytes ---");
   if( ibytes)
   {
      pi = nmalloc( ibytes);
      if( (foo = Fread( fd, ibytes, pi)) != ibytes)
         ngferror( foo, trc_loss);
   }

   MESS("[ 5] --- Fseek ---");
   INTEGRITY_CHECK();
   the_10seek( fd, x3);
   MESS("[ 6] --- Rbytes ---");
   if( rbytes)
   {
      pr = nmalloc( rbytes);
      if( (foo = Fread( fd, rbytes, pr)) != rbytes)
         ngferror( foo, trc_loss);
   }

   MESS("[ 7] --- Fseek ---");
   INTEGRITY_CHECK();
   the_10seek( fd, x4);
   MESS("[ 8] --- Ebytes ---");
   if( ebytes)
   {
      pe = nmalloc( ebytes);
      if( (foo = Fread( fd, ebytes, pe)) != ebytes)
         ngferror( foo, trc_loss);
   }

   MESS("[ 9] --- Fseek ---");
   the_10seek( fd, x5);
   MESS("[10] --- Ybytes ---");
   if( ybytes)
   {
      py = nmalloc( ysize);
      if( (foo = Fread( fd, ybytes, py)) != ybytes)
         ngferror( foo, trc_loss);
   }

   the_10seek( fd, x6);
   INTEGRITY_CHECK();
   MESS("[11] --- Fbytes ---");
   if( fbytes)
   {
      pf = nmalloc( fbytes);
      if( (foo = Fread( fd, fbytes, pf)) != fbytes)
         ngferror( foo, trc_loss);
   }

   ADD_WATCH( &pb, sizeof( char *), "pb");
   ADD_WATCH( &pe, sizeof( char *), "pe");
   ADD_WATCH( &ps, sizeof( char *), "ps");
   ADD_WATCH( &py, sizeof( char *), "py");      
   ADD_WATCH( &pi, sizeof( char *), "pi");
   ADD_WATCH( &pr, sizeof( char *), "pr");
   ADD_WATCH( &pf, sizeof( char *), "pf");

   if( version != DVERSION)
   {
      fix_version( version);        /* fix up old style object files */
   }

   ybytes /= sizeof( linksymbol);
   ebytes /= sizeof( e_dropped);
   sbytes /= sizeof( s_dropped);
   ibytes /= sizeof( i_dropped);
   rbytes /= sizeof( r_dropped);
   fbytes /= sizeof( f_dropped);


   INTEGRITY_CHECK();
# if BIGENDIAN
   flipstructs();
# endif
   INTEGRITY_CHECK();
#if ! DISASM
   {
      word  oldpc,
            val = 0;

      diff  = __pc - DEFORG + mv_offset;
      oldpc = __pc;
      if( alignment)
         if( ! pageflag && relocatable)
            nferror("Conflict between -m option and requested alignment");
         else
            if( val = __pc & alignment)
            {
               dpoke( ptohead, __pc - 1);
               __pc += (val = (~val & alignment) + 1);
               diff += val;
               if( bootable)
               {
                  register int   i;

                  for( i = val; i; i--)
                     *__p++ = 0;
               }
               else
               {
                  dpoke( __p, __pc);
                  _advance( 4);
                  ptohead = __p - 2;
               }
            }
      endpc = DEFORG;

      INTEGRITY_CHECK();
      seg_link();
      INTEGRITY_CHECK();
      MESS("code_reloc");
      code_reloc();
      INTEGRITY_CHECK();
      MESS("imm_link");
      imm_link();
      INTEGRITY_CHECK();
      MESS("ref_link");
      ref_link();
      INTEGRITY_CHECK();
      MESS("exp_link");
      exp_link();
      INTEGRITY_CHECK();
      MESS("sym_link");
      sym_link();
      INTEGRITY_CHECK();
      MESS("sym2_link");
      sym2_link();
      INTEGRITY_CHECK();
      DEL_WATCH( &pb);
      DEL_WATCH( &pe);
      DEL_WATCH( &ps);
      DEL_WATCH( &py);
      DEL_WATCH( &pi);
      DEL_WATCH( &pr);
      DEL_WATCH( &pf);
      wrapup();

      if( verbose)
         if( alignment)
            printf("Start: $%04X  Size:%5ld bytes  Alignment loss: %3d bytes\n",
                     oldpc, (lword) __pc - oldpc, val);
         else
            printf("Start: $%04X  Size:%5ld bytes\n", oldpc, bytes);

   }
#endif
   LEAVE();
}

#if BIGENDIAN
void  flipstructs()
{
   register word huge   *q;
   register lword       i;
   {
      register linksymbol huge *p;

      for( p = py, i = ybytes; i--; p++)
      {
         q  = (word huge *) p;
         dswap( q); q++;
         dswap( q); q++;
         dswap( q); q += 2;
         lswap( q);
         POINTER_CHECK( q);
      }
   }
   {
      for( q = (word huge *) pe, i = ebytes; i--;)
      {
         dswap( q); q++;      /* val      */
         dswap( q); q++;      /* aux      */
         dswap( q);           /* label    */
         q += 2;              /* op & fix */
         dswap( q); q++;      /* t        */
         dswap( q); q++;      /* l        */
         POINTER_CHECK( q);
         dswap( q); q++;      /* r        */
      }
   }
   {
      for( q = (word huge *) pi, i = ibytes; i--;)
      {
         dswap( q); q++;      /* block */
         dswap( q); q++;      /* type  */
         dswap( q); q++;      /* offset*/
         POINTER_CHECK( q);
         dswap( q); q++;      /* val   */
      }
   }
   {
      for( q = (word huge *) ps, i = sbytes; i--;)
      {
         dswap( q); q++;      /* type  */
         dswap( q); q++;      /* index */
         POINTER_CHECK( q);
         dswap( q); q++;      /* size  */
      }
   }
   {
      for( q = (word huge *) pf, i = fbytes; i--;)
      {
         dswap( q); q++;         /* poof  */
         dswap( q); q++;         /* imm   */
         POINTER_CHECK( q);
         dswap( q); q++;         /* index */
      }
   }
   {
      register r_dropped huge  *p;

      for( p = pr, i = rbytes; i--; p++)
      {
         dswap( p);
         POINTER_CHECK( p);
      }
   }
}
#endif

#if VERSION == 2 || VERSION == 0
# define V1_SIGNIFICANT 8
# define V1_SIGNDIFF    (SIGNIFICANT - V1_SIGNIFICANT)
# define V1_L_DIFF      (V1_SIGNDIFF + sizeof( word))
# define V1_SIZE        (sizeof( linksymbol) - V1_L_DIFF)
#endif

static void    fix_sizes( version)
{
   switch( version)
   {
#if VERSION == 2 || VERSION == 0   
      case 1 :
         ysize = ybytes / V1_SIZE * sizeof( linksymbol);
         break;
#endif
      default  :
         nferror( "Sorry, but that's an object file version I can't cope with");
   }
}


static void    fix_version( version)
{
   switch( version)
   {
#if VERSION == 2 || VERSION == 0
      case 1 :
      {
         word       huge      *p;
         linksymbol huge      *q;
         register word        i, j;
         register char huge   *dst;

         i = ybytes /= V1_SIZE;           /* calc # symbols */
         q = &py[ i];                     /* move to end of */
         p = (word huge *) ((char huge *) q - i * V1_L_DIFF);

         while( --q, i--)
         {
            for( dst = &q->name[ j = SIGNIFICANT]; j-- > V1_SIGNIFICANT;)
               *--dst = 0;
# if PHILOSOPHICAL_PROBLEM
            do
            {
               p = (word huge *) ((char huge *) p - 1);
               *--dst = *p;
            }
            while( j--);
            p -= sizeof( lword) / sizeof( word);
            q->refs = (ref huge *) *(lword huge *)p;
# else
            do
               *--dst = *--(char huge *)p;
            while( j--);
            q->refs = (ref huge *) *(--(lword huge *)p);
# endif
            q->type = *--p;
            q->no   = *--p;
            q->val  = *--p;
            POINTER_CHECK( p);
            POINTER_CHECK( q);
         }
         ybytes *= sizeof( linksymbol);
         break;
      }
#endif

      default  :
         nferror( "Sorry, but that's an object file version I can't cope with");
   }
}


