Logo Search packages:      
Sourcecode: linux86 version File versions  Download package

genobj.c

/* genobj.c - object code generation routines for assembler */

#include "syshead.h"
#include "const.h"
#include "type.h"
#include "address.h"
#include "file.h"
#include "globvar.h"

#define OBJBUFSIZE 512        /* size of object code output buffer */
#define isge2byteoffset(offset) ((offset) >= 0x100)
#define isge4byteoffset(offset) ((offset) >= 0x10000L)

PRIVATE char hid_absbuf[OBJ_MAX_ABS_LEN]; /* absolute object code buf */
PRIVATE char *absbuf;         /* start */
PRIVATE char *absbufend;      /* last location + 1 */
PRIVATE char *absbufptr;      /* current location */
PRIVATE struct sym_s **arrext;      /* array of external symbol ptrs */
PRIVATE char hid_objbuf[OBJBUFSIZE];      /* object code buffer */
PRIVATE unsigned numext;      /* number of external symbols */
PRIVATE char *objbuf;         /* start */
PRIVATE char *objbufend;      /* last location + 1 */
PRIVATE char *objbufptr;      /* current location */
PRIVATE unsigned char relsize;      /* current relocation size, 0 init */
                        /* local to genobjadr, but here */
                        /* because of static re-init bug */
PRIVATE offset_t rmbcount;    /* accumulator for repeated RMB's */

FORWARD void flushabs P((void));
FORWARD void flushrmb P((void));
FORWARD void genobjadr P((struct address_s *adrptr, int size));
FORWARD void putobj1 P((opcode_pt ch));
FORWARD void putobj4 P((u32_T offset));
FORWARD void putobjoffset P((offset_t offset, count_t size));
FORWARD void putobjword P((unsigned word));
FORWARD void writeobj P((char *buf, unsigned count));

/* accumulate RMB requests into 1 (so + and - requests cancel) */

PUBLIC void accumulate_rmb(offset)
offset_t offset;
{
    if (objectc)
    {
      flushabs();
      rmbcount += offset;
    }
}

/* flush absolute object code buffer to object code buffer if necessary */

PRIVATE void flushabs()
{
    if (absbufptr > absbuf)
    {
      putobj1((absbufptr - absbuf) | OBJ_ABS);
      {
          register char *bufptr;

          bufptr = absbuf;
          do
            putobj1(*bufptr);
          while (++bufptr < absbufptr);
          absbufptr = absbuf;
      }
    }
}

/* flush object code buffer if necessary */

PUBLIC void flushobj()
{
    int ntowrite;

    if ((ntowrite = objbufptr - objbuf) > 0)
    {
      if (write(objfil, objbuf, (unsigned) ntowrite) != ntowrite)
      {
          error(OBJOUT);
          listline();
          finishup();
      }
      objbufptr = objbuf;
    }
}

/* flush RMB count if necessary */

PRIVATE void flushrmb()
{
    count_t size;

    if (rmbcount != 0)
    {
#if SIZEOF_OFFSET_T > 2
      if (isge4byteoffset(rmbcount))
      {
          putobj1(OBJ_SKIP_4);
          size = 4;
      }
      else
#endif
      if (isge2byteoffset(rmbcount))
      {
          putobj1(OBJ_SKIP_2);
          size = 2;
      }
      else
      {
          putobj1(OBJ_SKIP_1);
          size = 1;
      }
      putobjoffset(rmbcount, size);
      rmbcount = 0;
    }
}

/* generate object code for current line */

/*
  any address parameter is (regrettably) in lastexp
  any immediate parameter is (corectly) in immadr
*/

PUBLIC void genobj()
{
    struct address_s *adrptr;
    char *bufptr;
    unsigned char remaining;

    if (objectc && mcount != 0)
    {
      if (popflags)
      {
          if (fcflag)
          {
            bufptr = databuf.fcbuf;
            remaining = mcount;
            do
                putabs(*bufptr++);
            while (--remaining != 0);
          }
          if (fdflag)
          {
            adrptr = databuf.fdbuf;
            remaining = mcount;
            do
                genobjadr(adrptr++, 2);
            while ((remaining -= 2) != 0);
          }
#if SIZEOF_OFFSET_T > 2
          if (fqflag)
          {
            adrptr = databuf.fqbuf;
            remaining = mcount;
            do
                genobjadr(adrptr++, 4);
            while ((remaining -= 4) != 0);
          }
#endif
      }
      else
      {
          remaining = mcount - 1;   /* count opcode immediately */
#ifdef I80386
          if (aprefix != 0)
          {
            putabs(aprefix);
            --remaining;
          }
          if (oprefix != 0)
          {
            putabs(oprefix);
            --remaining;
          }
          if (sprefix != 0)
          {
            putabs(sprefix);
            --remaining;
          }
#endif
          if (page != 0)
          {
            putabs(page);
            --remaining;
          }
          putabs(opcode);
          if (remaining != 0)
          {
            if (postb != 0)
            {
                putabs(postb);
                --remaining;
            }
#ifdef I80386
            if (sib != NO_SIB)
            {
                putabs(sib);
                --remaining;
            }
#endif
            if (remaining != 0)
                genobjadr(&lastexp, remaining);
          }
      }
#ifdef I80386
      if (immcount != 0)
          genobjadr(&immadr, immcount);
#endif
    }
}

/* generate object code for current address */

PRIVATE void genobjadr(adrptr, size)
struct address_s *adrptr;
smallcount_t size;
{
    unsigned char byte;
    unsigned symnum;

    if (!(adrptr->data & RELBIT))
    {
      /* absolute address */

      char buf[sizeof(offset_t)];

#if SIZEOF_OFFSET_T > 2
      u4cn(buf, adrptr->offset, size);
#else
      u2cn(buf, adrptr->offset, size);
#endif
      putabs(buf[0]);
      if (size > 1)
          putabs(buf[1]);
      if (size > 2)
      {
          putabs(buf[2]);
          putabs(buf[3]);
      }
    }
    else
    {
      /* relocatable address */
      if (size != relsize)
          /* set reloc size index |00|0000xx| */
          putobj((relsize = size) == 4 ? 0x03 : relsize);
      if (!(adrptr->data & IMPBIT))
      {
          /* offset relocation (known offset) */
          putobj((adrptr->data & SEGM) | OBJ_OFFSET_REL | pcrflag);
          putobjoffset(adrptr->offset, size);
      }
      else
      {
          /* symbol relocation (imported symbol + offset) */
          {
            register struct sym_s **copyptr;

            for (copyptr = arrext, symnum = 0;
                 symnum < numext && *copyptr++ != adrptr->sym; ++symnum)
                ;
          }
          byte = OBJ_SYMBOL_REL;
          if (isge2byteoffset(symnum))
            byte = OBJ_SYMBOL_REL | OBJ_S_MASK;
#if SIZEOF_OFFSET_T > 2
          if (isge4byteoffset(adrptr->offset))
          {
            byte |= 0x03;     /* 4 byte offset */
            size = 4;
          }
          else
#endif
          if (isge2byteoffset(adrptr->offset))
          {
            byte |= 0x02;     /* 2 byte offset */
            size = 2;
          }
          else if (adrptr->offset != 0)
          {
            byte |= 0x01;     /* 1 byte offset */
            size = 1;
          }
          else
            size = 0;
          putobj(byte | pcrflag);
          if (isge2byteoffset(symnum))
            putobjword(symnum);
          else
            putobj1((opcode_pt) symnum);
          if (adrptr->offset != 0)
            putobjoffset(adrptr->offset, size);
      }
    }
}

/* initialise private variables */

PUBLIC void initobj()
{
    absbufend = (absbufptr = absbuf = hid_absbuf) + sizeof hid_absbuf;
    objbufend = (objbufptr = objbuf = hid_objbuf) + sizeof hid_objbuf;
}

/*
  write header to object file
  also build array of imported/exported symbols
*/

PUBLIC void objheader()
{
    static char module_header[] =
    {
#ifdef I80386
      0xA3, 0x86,
      1, 0,
      (char) (0xA3 + 0x86 + 1 + 0),
#endif
#ifdef MC6809
      'S', '1',         /* 2 byte magic number */
      0, 1,             /* 2 byte number of modules in file */
      'S' + '1' + 0 + 1,      /* 1 byte checksum */
#endif
    };
    static char seg_max_sizes[] =
    {
      0x55,             /* all segments have maximum size 2^16 */
      0x55,             /* this is encoded by 0b01 4 times per byte */
      0x55,             /* other codes are 0b00 = max size 2^8 */
      0x55,             /* 0b10 = max size 2^24, 0b11 = max 2^32 */
    };
    unsigned char byte;
    register struct sym_s **copyptr;
    struct sym_s **copytop;
    struct sym_s **hashptr;
    struct lc_s *lcp;
    char module_name[FILNAMLEN + 1];
    char *nameptr;
    unsigned offset;
    unsigned segsizebytes;
    unsigned size;
    unsigned char sizebits;
    unsigned strsiz;          /* size of object string table */
    unsigned symosiz;         /* size of object symbol table */
    register struct sym_s *symptr;
    u32_T textlength;
    int symcount = 0;

    if ((objectc = objectg) == 0)
      return;
    writeobj(module_header, sizeof module_header);

    /* calculate number of imported/exported symbols */
    /* and lengths of symbol and string tables */
    /* build array of imported/exported symbols */

    symosiz = 0;
    if (truefilename == NUL_PTR)
      truefilename = filnamptr;
    nameptr = strrchr(truefilename, DIRCHAR);
    strcpy(module_name, nameptr != NUL_PTR ? nameptr + 1 : truefilename);
    if ((nameptr = strrchr(module_name, '.')) != NUL_PTR)
      *nameptr = 0;
    strsiz = strlen(module_name) + 1;
    
    for (hashptr = spt; hashptr < spt_top;)
      if ((symptr = *hashptr++) != NUL_PTR)
          do
          {
            if ((symptr->type & EXPBIT || symptr->data & IMPBIT) ||
                (!globals_only_in_obj && symptr->name[0] != '.' &&
                !(symptr->type & (MNREGBIT | MACBIT | VARBIT))))
            {
                symcount ++;
            }
          }
          while ((symptr = symptr->next) != NUL_PTR);
    arrext = copyptr = asalloc( sizeof(struct sym_s *) * symcount);

    for (hashptr = spt; hashptr < spt_top;)
      if ((symptr = *hashptr++) != NUL_PTR)
          do
          {
            if ((symptr->type & EXPBIT || symptr->data & IMPBIT) ||
                (!globals_only_in_obj && symptr->name[0] != '.' &&
                !(symptr->type & (MNREGBIT | MACBIT | VARBIT))))
            {
                *copyptr++ = symptr;
                strsiz += symptr->length + 1;
                if (textseg>=0 && (symptr->data & SEGM) == textseg)
                   strsiz+=2;
#if SIZEOF_OFFSET_T > 2
                if (isge4byteoffset(symptr->value_reg_or_op.value))
                  size = 4 + 4;
                  /* 4 is size of offset into string table and flags */
                  /* 2nd 4 is for 4 byte offset */
                else
#endif
                if (isge2byteoffset(symptr->value_reg_or_op.value))
                  size = 4 + 2;
                else if (symptr->value_reg_or_op.value != 0)
                  size = 4 + 1;
                else
                  size = 4;
                symosiz += size;
                ++numext;
            }
          }
          while ((symptr = symptr->next) != NUL_PTR);
    copytop = copyptr;

    /* calculate length of text, and number of seg size bytes in header */

    textlength = segsizebytes = 0;
    lcp = lctab;
    do
      if (lcp->lc != 0)
      {
          textlength += lcp->lc;    /* assuming text starts at 0 */
#if SIZEOF_OFFSET_T > 2
          if (isge4byteoffset(lcp->lc))
            segsizebytes += 4;
          else
#endif
            segsizebytes += 2;      /* use 2 byte size if possible */
      }
    while (++lcp < lctabtop);

/*
  offset to text = length of header since only 1 module
  header consists of:
  module header               sizeof module_header
  offset to start of text     4
  length of text        4
  length of string area       2
  class                       1
  revision              1
  seg max sizes               sizeof seg_max_sizes
  seg size descriptors        4
  seg sizes             segsizebytes
  symbol count                2
  symbol offsets and types    symosiz
  strings               strsiz
*/

    /* offset to start of text */

    putobj4((u32_T) (sizeof module_header + 4 + 4 + 2 + 1 + 1 +
                 sizeof seg_max_sizes + 4 + segsizebytes + 2 +
                 symosiz) + strsiz);

    /* length of text */

    putobj4((u32_T) textlength);

    /* length of string area */

    putobjword(strsiz);

    /* class and revision */

    putobj1(0);
    putobj1(0);

    /* segment max sizes (constant) */

    writeobj(seg_max_sizes, sizeof seg_max_sizes);

    /* segment size descriptors */
    /* produce only 0 and 2 byte sizes */

    lcp = lctabtop;
    byte = 0;
    sizebits = OBJ_SEGSZ_TWO << 6;
    do
    {
      --lcp;
      if (lcp->lc != 0)
      {
          byte |= sizebits;
#if SIZEOF_OFFSET_T > 2
          if (isge4byteoffset(lcp->lc))
            byte |= sizebits >> 1;  /* XXX - convert size 2 to size 4 */
#endif
      }
      if ((sizebits >>= 2) == 0)
      {
          putobj1(byte);
          byte = 0;
          sizebits = OBJ_SEGSZ_TWO << 6;
      }
    }
    while (lcp > lctab);

    /* segment sizes */

    do                        /* lcp starts at lctab */
      if (lcp->lc != 0)
      {
#if SIZEOF_OFFSET_T > 2
          if (isge4byteoffset(lcp->lc))
            putobj4(lcp->lc);
          else
#endif
            putobjword((unsigned) lcp->lc);
      }
    while (++lcp < lctabtop);

    /* symbol count */

    putobjword(numext);

    /* symbol offsets and types */

    offset = strlen(module_name) + 1;     /* 1st symbol begins after name */
    for (copyptr = arrext; copyptr < copytop;)
    {
      putobjword(offset);
      symptr = *copyptr++;
      byte = symptr->type & OBJ_N_MASK;
#if SIZEOF_OFFSET_T > 2
      if (isge4byteoffset(symptr->value_reg_or_op.value))
      {
          byte |= OBJ_SZ_FOUR;
          size = 4;
      }
      else
#endif
      if (isge2byteoffset(symptr->value_reg_or_op.value))
      {
          byte |= OBJ_SZ_TWO;
          size = 2;
      }
      else if (symptr->value_reg_or_op.value != 0)
      {
          byte |= OBJ_SZ_ONE;
          size = 1;
      }
      else
          size = 0;
      if ((symptr->type & (COMMBIT | REDBIT)) == (COMMBIT | REDBIT))
      {
          byte |= OBJ_SA_MASK;
          symptr->data &= ~OBJ_I_MASK;
      }
      putobjword((unsigned)
               (byte << 0x8) |
               (symptr->type & OBJ_E_MASK) |    /* |E|0000000| */
             ((symptr->data & (OBJ_I_MASK | OBJ_A_MASK | OBJ_SEGM_MASK)) ^
      /* |0|I|0|A|SEGM| */
            RELBIT));   /* RELBIT by negative logic */
      if ((symptr->type & (COMMBIT | REDBIT)) == (COMMBIT | REDBIT))
          symptr->data |= OBJ_I_MASK;
      if (size != 0)
          putobjoffset(symptr->value_reg_or_op.value, size);
      offset += symptr->length + 1;
      if (textseg>=0 && (symptr->data & SEGM) == textseg)
         offset+=2;
    }

    /* strings */

    writeobj(module_name, strlen(module_name));
    putobj1(0);
    for (copyptr = arrext; copyptr < copytop;)
    {
      symptr = *copyptr++;
      writeobj(symptr->name, symptr->length);
      if (textseg>=0 && (symptr->data & SEGM) == textseg)
      {
         putobj1('.');
         putobj1(hexdigit[textseg]);
      }
      putobj1(0);
    }
    putobj1(OBJ_SET_SEG | 0); /* default segment 0, |0010|SEGM| */
}

/* write trailer to object file */

PUBLIC void objtrailer()
{
    if (objectc)
    {
      putobj(0);        /* end of object file */
      flushobj();
    }
}

/* write char to absolute object code buffer, flush if necessary */

PUBLIC void putabs(ch)
opcode_pt ch;
{
    if (objectc)
    {
      if (rmbcount != 0)
          flushrmb();
      if (absbufptr >= absbufend)
          flushabs();
      *absbufptr++ = ch;
    }
}

/* write char to object code buffer, flush if necessary */

PUBLIC void putobj(ch)
opcode_pt ch;
{
    if (objectc)
    {
      flushabs();
      flushrmb();
      putobj1(ch);
    }
}

/* write char to object code buffer assuming nothing in absolute & rmb bufs */

PRIVATE void putobj1(ch)
opcode_pt ch;
{
    if (objbufptr >= objbufend)
      flushobj();
    *objbufptr++ = ch;
}

/* write 32 bit offset to object code buffer assuming ... */

PRIVATE void putobj4(offset)
u32_T offset;
{
    char buf[sizeof offset];

    u4c4(buf, offset);
    writeobj(buf, 4);
}

/* write sized offset to object code buffer assuming ... */

PRIVATE void putobjoffset(offset, size)
offset_t offset;
count_t size;
{
    char buf[sizeof offset];

#if SIZEOF_OFFSET_T > 2
    u4cn(buf, offset, size);
#else
    u2cn(buf, offset, size);
#endif
    putobj1(buf[0]);
    if (size > 1)
      putobj1(buf[1]);
    if (size > 2)
    {
      putobj1(buf[2]);
      putobj1(buf[3]);
    }
}

/* write word to object code buffer assuming ... */

PRIVATE void putobjword(word)
unsigned word;
{
    char buf[sizeof word];

    u2c2(buf, word);
    putobj1(buf[0]);
    putobj1(buf[1]);
}

/* write several bytes to object code buffer assuming ... */

PRIVATE void writeobj(buf, count)
char *buf;
unsigned count;
{
    do
      putobj1(*buf++);
    while (--count);
}

Generated by  Doxygen 1.6.0   Back to index