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

writebin.c

/* writebin.c - write binary file for linker */

/* Copyright (C) 1994 Bruce Evans */

#include "syshead.h"
#include "bindef.h"
#include "const.h"
#include "obj.h"
#include "type.h"
#include "globvar.h"

#ifdef AOUT_DETECTED
#define btextoffset (text_base_value)
#define bdataoffset (data_base_value)
#define page_size() 4096

#ifdef __ELF__
#ifndef ELF_SYMS
#define ELF_SYMS 1
#endif
#endif

#ifdef EDOS
# define FILEHEADERLENGTH 0
#endif
#ifdef MINIX
# ifdef BSD_A_OUT
#  ifdef STANDARD_GNU_A_OUT
#   define HEADERLEN (sizeof(struct exec))
#  else
#   define HEADERLEN (48)
#  endif
# else
#  ifdef REL_OUTPUT
#   define HEADERLEN (reloc_output?sizeof(struct exec):A_MINHDR)
                        /* part of header not counted in offsets */
#  else
#   define HEADERLEN (A_MINHDR)
#  endif
# endif
# ifndef FILEHEADERLENGTH
#  define FILEHEADERLENGTH (headerless?0:HEADERLEN)
# endif
#endif
#define DPSEG 2

#define CM_MASK 0xC0
#define MODIFY_MASK 0x3F
#define S_MASK 0x04
#define OF_MASK 0x03

#define CM_SPECIAL 0
#define CM_ABSOLUTE 0x40
#define CM_OFFSET_RELOC 0x80
#define CM_SYMBOL_RELOC 0xC0

#define CM_EOT 0
#define CM_BYTE_SIZE 1
#define CM_WORD_SIZE 2
#define CM_LONG_SIZE 3
#define CM_1_SKIP 17
#define CM_2_SKIP 18
#define CM_4_SKIP 19
#define CM_0_SEG 32

#define ABS_TEXT_MAX 64

#define offsetof(struc, mem) ((int) &((struc *) 0)->mem)
#define memsizeof(struc, mem) sizeof(((struc *) 0)->mem)

PRIVATE bool_t bits32;        /* nonzero for 32-bit executable */
PRIVATE bin_off_t combase[NSEG];/* bases of common parts of segments */
PRIVATE bin_off_t comsz[NSEG];      /* sizes of common parts of segments */
PRIVATE fastin_t curseg;      /* current segment, 0 to $F */
PRIVATE bin_off_t edataoffset;      /* end of data */
PRIVATE bin_off_t endoffset;  /* end of bss */
PRIVATE bin_off_t etextoffset;      /* end of text */
PRIVATE bin_off_t etextpadoff;      /* end of padded text */
#ifdef REL_OUTPUT
PRIVATE unsigned ndreloc;     /* number of data relocations */
#endif
PRIVATE unsigned nsym;        /* number of symbols written */
#ifdef REL_OUTPUT
PRIVATE unsigned ntreloc;     /* number of text relocations */
extern bool_t reloc_output;   /* nonzero to leave reloc info in output */
#endif
PRIVATE unsigned relocsize;   /* current relocation size 1, 2 or 4 */
PRIVATE bin_off_t segadj[NSEG];     /* adjusts (file offset - seg offset) */
                        /* depends on zero init */
PRIVATE bin_off_t segbase[NSEG];/* bases of data parts of segments */
PRIVATE char segboundary[9] = "__seg0DH";
                        /* name of seg boundary __seg0DL to __segfCH */
PRIVATE bin_off_t segpos[NSEG];     /* segment positions for current module */
PRIVATE bin_off_t segsz[NSEG];      /* sizes of data parts of segments */
                        /* depends on zero init */
PRIVATE bool_t sepid;         /* nonzero for separate I & D */
PRIVATE bool_t stripflag;     /* nonzero to strip symbols */
PRIVATE bin_off_t spos;       /* position in current seg */
PRIVATE bool_t uzp;           /* nonzero for unmapped zero page */

#ifdef EDOS
FORWARD unsigned binheaderlength P((char *commandname));
FORWARD char *idconvert P((struct entrylist *elptr, char *commandname));
#endif
FORWARD void linkmod P((struct modstruct *modptr));
FORWARD void padmod P((struct modstruct *modptr));
FORWARD void setsym P((char *name, bin_off_t value));
FORWARD void symres P((char *name));
FORWARD void setseg P((fastin_pt newseg));
FORWARD void skip P((unsigned countsize));
#ifdef EDOS
FORWARD void writeheader P((char *commandname));
#else
FORWARD void writeheader P((void));
#endif
FORWARD void writenulls P((bin_off_t count));

/* write binary file */
#ifndef FUNCNAME 
#define FUNCNAME writebin
#endif

PUBLIC void FUNCNAME(outfilename, argsepid, argbits32, argstripflag, arguzp)
char *outfilename;
bool_pt argsepid;
bool_pt argbits32;
bool_pt argstripflag;
bool_pt arguzp;
{
    char buf4[4];
#ifdef EDOS
    char *commandname;
#endif
    char *cptr;
    struct nlist extsym;
    flags_t flags;
    struct modstruct *modptr;
    fastin_t seg;
    unsigned sizecount;
    bin_off_t tempoffset;

    sepid = argsepid;
    bits32 = argbits32;
    stripflag = argstripflag;
#ifdef REL_OUTPUT
    uzp = arguzp && !reloc_output;
#else
    uzp = arguzp;
#endif
    if (uzp)
    {
      if (btextoffset == 0)
#ifdef QMAGIC
          btextoffset = page_size()+HEADERLEN;
#else
          btextoffset = page_size();
#endif
      if (bdataoffset == 0 && sepid)
          bdataoffset = page_size();
    }
#ifdef EDOS
    commandname = stralloc(outfilename);
    if ((cptr = strchr(commandname, ':')) != NUL_PTR)
      commandname = cptr + 1;
    if ((cptr = strrchr(commandname, '.')) != NUL_PTR)
      *cptr = 0;
#endif

    /* reserve special symbols use curseg to pass parameter to symres() */
    for (curseg = 0; curseg < NSEG; ++curseg)
    {
      segboundary[5] = hexdigit[curseg];  /* to __segX?H */
      segboundary[6] = 'D';
      symres(segboundary);    /* __segXDH */
      segboundary[7] = 'L';
      symres(segboundary);    /* __segXDL */
      segboundary[6] = 'C';
      symres(segboundary);    /* __segXCL */
      segboundary[7] = 'H';
      symres(segboundary);    /* __segXCH */
#ifndef DATASEGS
        if( curseg > 3 )
      {
         segboundary[6] = 'S';
         segboundary[7] = 'O';
         symres(segboundary); /* __segXSO */
        }
#endif
    }
#ifdef EDOS
    curseg = 0;               /* data seg, s.b. variable */
#else
    curseg = 3;
#endif
    symres("__edata");
    symres("__end");
    curseg = 0;               /* text seg, s.b. variable */
    symres("__etext");
    symres("__segoff");

    /* calculate segment and common sizes (sum over loaded modules) */
    /* use zero init of segsz[] */
    /* also relocate symbols relative to starts of their segments */
    for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
      if (modptr->loadflag)
      {
          register struct symstruct **symparray;
          register struct symstruct *symptr;

          for (symparray = modptr->symparray;
             (symptr = *symparray) != NUL_PTR; ++symparray)
            if (symptr->modptr == modptr && !(symptr->flags & A_MASK))
            {
                if (!(symptr->flags & (I_MASK | SA_MASK)))
                {
                  /* relocate by offset of module in segment later */
                  /* relocate by offset of segment in memory special */
                  /* symbols get relocated improperly */
                  symptr->value += segsz[symptr->flags & SEGM_MASK];
                }
                else if (symptr->value == 0)
                {
#ifdef REL_OUTPUT
                  if (!reloc_output)
#endif
                      undefined(symptr->name);
                }
                else
                {
#ifdef REL_OUTPUT
#if 0
                  if (!reloc_output)
#else 
                  if (!reloc_output || !(symptr->flags & I_MASK))
#endif                  
#endif
                  {
                      tempoffset = ld_roundup(symptr->value, 4, bin_off_t);
                      /* temp kludge quad alignment for 386 */
                      symptr->value = comsz[seg = symptr->flags & SEGM_MASK];
                      comsz[seg] += tempoffset;
                  }
                  if (!(symptr->flags & SA_MASK))
                      symptr->flags |= C_MASK;
                }
            }
          for (seg = 0, cptr = modptr->segsize; seg < NSEG; ++seg)
          {
            segsz[seg] += cntooffset(cptr,
                    sizecount = segsizecount((unsigned) seg, modptr));
#ifndef EDOS

            /* adjust sizes to even to get quad boundaries */
            /* this should be specifiable dynamically */
            segsz[seg] = ld_roundup(segsz[seg], 4, bin_off_t);
            comsz[seg] = ld_roundup(comsz[seg], 4, bin_off_t);
#endif
            cptr += sizecount;
          }
      }

    /* calculate seg positions now their sizes are known */
    /* temp use fixed order 0D 0C 1D 1C 2D 2C ... */
    /*
#ifdef DATASEGS
     * Assume seg 0 is text and rest are data
#else
     * Assume seg 1..3 are data, Seg 0 is real text, seg 4+ are far text
#endif
     */
#ifdef EDOS
    if (btextoffset == 0)
      btextoffset = binheaderlength(commandname);
#endif
    segpos[0] = segbase[0] = spos = btextoffset;
    combase[0] = segbase[0] + segsz[0];
    segadj[1] = segadj[0] = -btextoffset;
    etextpadoff = etextoffset = combase[0] + comsz[0];
    if (sepid)
    {
      etextpadoff = ld_roundup(etextoffset, 0x10, bin_off_t);
      segadj[1] += etextpadoff - bdataoffset;
    }
#ifdef QMAGIC
    else if (uzp && bdataoffset == 0)
    {
      bdataoffset = ld_roundup(etextoffset, page_size(), bin_off_t);
      etextpadoff = ld_roundup(etextoffset, page_size(), bin_off_t);
      segadj[1] += etextpadoff - bdataoffset;
    }
#endif
    else if (bdataoffset == 0)
      bdataoffset = etextpadoff;
    segpos[1] = segbase[1] = edataoffset = bdataoffset;
    combase[1] = segbase[1] + segsz[1];
#ifndef DATASEGS
    for (seg = 4; seg < NSEG; ++seg)
    {
      segpos[seg] = segbase[seg] = 0;
      combase[seg] = segbase[seg] + segsz[seg];
      segadj[seg] = etextpadoff;

      etextpadoff += ld_roundup(segsz[seg] + comsz[seg], 0x10, bin_off_t);
      segadj[1]   += ld_roundup(segsz[seg] + comsz[seg], 0x10, bin_off_t);
    }
    for (seg = 2; seg < 4; ++seg)
#else
    for (seg = 2; seg < NSEG; ++seg)
#endif
    {
      segpos[seg] = segbase[seg] = combase[seg - 1] + comsz[seg - 1];
#ifdef MC6809
      if (seg == DPSEG)
      {
          /* temporarily have fixed DP seg */
          /* adjust if nec so it only spans 1 page */
          tempoffset = segsz[seg] + comsz[seg];
          if (tempoffset > 0x100)
            fatalerror("direct page segment too large");
          if ((((segbase[seg] + tempoffset) ^ segbase[seg])
             & ~(bin_off_t) 0xFF) != 0)
            segpos[seg] = segbase[seg] = (segbase[seg] + 0xFF)
                                   & ~(bin_off_t) 0xFF;
      }
#endif

#ifdef QMAGIC
      if(seg==3 && uzp && !stripflag) /* XXX Stripped last seek needed */
      {
         bin_off_t val;
         val = ld_roundup(segbase[seg]+segsz[seg], page_size(), bin_off_t);
         segsz[seg] = val - segbase[seg];
      }
#endif 
      combase[seg] = segbase[seg] + segsz[seg];
      segadj[seg] = segadj[seg - 1];
    }

    /* relocate symbols by offsets of segments in memory */
    for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
      if (modptr->loadflag)
      {
          register struct symstruct **symparray;
          register struct symstruct *symptr;

          for (symparray = modptr->symparray;
             (symptr = *symparray) != NUL_PTR; ++symparray)
            if (symptr->modptr == modptr && !(symptr->flags & A_MASK))
            {
                if (symptr->flags & (C_MASK | SA_MASK))
                {
#ifdef REL_OUTPUT
#if 0
                  if (!reloc_output)
#else 
                  if (!reloc_output || !(symptr->flags & I_MASK))
#endif                  
#endif
                      symptr->value += combase[symptr->flags & SEGM_MASK];
                }
                else
#ifdef REL_OUTPUT
                if (!reloc_output || !(symptr->flags & I_MASK))
#endif
                  symptr->value += segbase[symptr->flags & SEGM_MASK];
            }
      }

    /* adjust special symbols */
    for (seg = 0; seg < NSEG; ++seg)
    {
#ifdef DATASEGS
      if (segsz[seg] != 0)
          /* only count data of nonzero length */
#else
      if (segsz[seg] != 0 && seg < 4)
#endif
          edataoffset = segbase[seg] + segsz[seg];
      segboundary[5] = hexdigit[seg];           /* to __segX?H */
      segboundary[6] = 'D';
      setsym(segboundary, (tempoffset = segbase[seg]) + segsz[seg]);
                                    /* __segXDH */
      segboundary[7] = 'L';
      setsym(segboundary, tempoffset);    /* __segXDL */
      segboundary[6] = 'C';
      setsym(segboundary, tempoffset = combase[seg]);
                                    /* __segXCL */
      segboundary[7] = 'H';
      setsym(segboundary, tempoffset + comsz[seg]);
                                    /* __segXCH */
#ifndef DATASEGS
        if( seg > 3 )
      {
         segboundary[6] = 'S';
         segboundary[7] = 'O';
         setsym(segboundary, (bin_off_t)(segadj[seg]-segadj[0])/0x10);
         /* __segXSO */
        }
#endif
    }
    setsym("__etext", etextoffset);
    setsym("__edata", edataoffset);
#ifdef DATASEGS
    setsym("__end", endoffset = combase[NSEG - 1] + comsz[NSEG - 1]);
#else
    setsym("__end", endoffset = combase[3] + comsz[3]);
#endif
    setsym("__segoff", (bin_off_t)(segadj[1]-segadj[0])/0x10);
    if( !bits32 )
    {
        if( etextoffset > 65536L )
            fatalerror("text segment too large for 16bit");
        if( endoffset > 65536L )
            fatalerror("data segment too large for 16bit");
    }

    openout(outfilename);
#ifdef REL_OUTPUT
    if (reloc_output)
      seektrel(FILEHEADERLENGTH
             + (unsigned long) (etextpadoff - btextoffset)
             + (unsigned long) (edataoffset - bdataoffset));
#endif
#ifdef EDOS
    writeheader(commandname);
#else
    writeheader();
#endif
    for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
      if (modptr->loadflag)
      {
          linkmod(modptr);
          padmod(modptr);
      }

    /* dump symbol table */
#ifdef MINIX
    if (!stripflag)
    {
#ifdef BSD_A_OUT
      unsigned stringoff;
#endif

      seekout(FILEHEADERLENGTH
            + (unsigned long) (etextpadoff - btextoffset)
            + (unsigned long) (edataoffset - bdataoffset)
#ifdef REL_OUTPUT
            + ((unsigned long) ndreloc + ntreloc) * RELOC_INFO_SIZE
#endif
            );
      extsym.n_was_numaux = extsym.n_was_type = 0;
#ifdef BSD_A_OUT
      stringoff = 4;
#endif
      for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
          if (modptr->loadflag)
          {
            register struct symstruct **symparray;
            register struct symstruct *symptr;

            for (symparray = modptr->symparray;
                 (symptr = *symparray) != NUL_PTR; ++symparray)
                if (symptr->modptr == modptr)
                {
#ifdef BSD_A_OUT
                  offtocn((char *) &extsym.n_was_strx,
                        (bin_off_t) stringoff, 4);
#else
#if ELF_SYMS
                  if( symptr->name[0] == '_' && symptr->name[1] )
                     strncpy((char *) extsym.n_was_name, symptr->name+1,
                           sizeof extsym.n_was_name);
                  else
                  {
                     memcpy((char *) extsym.n_was_name, "__", 2);
                     strncpy((char *) extsym.n_was_name+2, symptr->name,
                           sizeof(extsym.n_was_name)-2);
                  }
#else
                  strncpy((char *) extsym.n_was_name, symptr->name,
                        sizeof extsym.n_was_name);
#endif
#endif
                  u4cn((char *) &extsym.n_value, (u4_t) symptr->value,
                       sizeof extsym.n_value);
                  if ((flags = symptr->flags) & A_MASK)
                      extsym.n_was_sclass = N_ABS;
                  else if (flags & (E_MASK | I_MASK))
                      extsym.n_was_sclass = C_EXT;
                  else
                      extsym.n_was_sclass = C_STAT;
                  if (!(flags & I_MASK) || (
#ifdef REL_OUTPUT
                       !reloc_output &&
#endif
                       (flags & C_MASK)))
                      switch (flags & (A_MASK | SEGM_MASK))
                      {
#ifdef DATASEGS
                      case 0:
#else
                      default:
#endif
                        extsym.n_was_sclass |= N_TEXT;
                      case A_MASK:
                        break;
#ifdef DATASEGS
                      default:
#else
                      case 1: case 2: case 3:
                      case A_MASK|1: case A_MASK|2: case A_MASK|3:
#endif
                        if (flags & (C_MASK | SA_MASK))
                            extsym.n_was_sclass |= N_BSS;
                        else
                            extsym.n_was_sclass |= N_DATA;
                        break;
                      }
                  writeout((char *) &extsym, sizeof extsym);
                  ++nsym;
#ifdef BSD_A_OUT
#if ELF_SYMS
                  stringoff += strlen(symptr->name);
                  if( symptr->name[0] != '_' || symptr->name[1] == '\0' )
                     stringoff += 3;
#else
                  stringoff += strlen(symptr->name) + 1;
#endif
#endif
                }
          }
#ifdef BSD_A_OUT
      offtocn((char *) &extsym.n_was_strx, (bin_off_t) stringoff, 4);
      writeout((char *) &extsym.n_was_strx, 4);
      for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
          if (modptr->loadflag)
          {
            register struct symstruct **symparray;
            register struct symstruct *symptr;

            for (symparray = modptr->symparray;
                 (symptr = *symparray) != NUL_PTR; ++symparray)
                if (symptr->modptr == modptr)
#if ELF_SYMS
                    {
                   if( symptr->name[0] == '_' && symptr->name[1] )
                    writeout(symptr->name + 1, strlen(symptr->name));
                   else
                   {
                      writeout("__", 2);
                    writeout(symptr->name, strlen(symptr->name) + 1);
                   }
                }
#else
                  writeout(symptr->name, strlen(symptr->name) + 1);
#endif
          }
#endif
      seekout((unsigned long) offsetof(struct exec, a_syms));
      u4cn(buf4, (u4_t) nsym * sizeof extsym,
           memsizeof(struct exec, a_syms));
      writeout(buf4, memsizeof(struct exec, a_syms));
#ifdef REL_OUTPUT
      if( FILEHEADERLENGTH >= offsetof(struct exec, a_trsize)+8)
      {
            seekout((unsigned long) offsetof(struct exec, a_trsize));
            u4cn(buf4, (u4_t) ntreloc * RELOC_INFO_SIZE,
            memsizeof(struct exec, a_trsize));
            writeout(buf4, memsizeof(struct exec, a_trsize));
            seekout((unsigned long) offsetof(struct exec, a_drsize));
            u4cn(buf4, (u4_t) ndreloc * RELOC_INFO_SIZE,
            memsizeof(struct exec, a_drsize));
            writeout(buf4, memsizeof(struct exec, a_drsize));
      }
#endif
    }
#endif /* MINIX */
    closeout();
#ifdef REL_OUTPUT
    if (!reloc_output)
#endif
      executable();
}

#ifdef EDOS

PRIVATE unsigned binheaderlength(commandname)
char *commandname;
{
    unsigned count;
    char *name;
    struct entrylist *elptr;
    struct symstruct *startptr;

    count = 2 + 2 + 1;        /* len len nul */
    startptr = findsym("start");
    for (elptr = entryfirst; elptr != NUL_PTR; elptr = elptr->elnext)
    {
      name = idconvert(elptr, commandname);
      count += strlen(name) + 1 + 2 + 1;  /* nul off flg */
      ourfree(name);
      if (startptr != NUL_PTR)
          count += 6;         /* LBSR $xxxx and LBRA $xxxx */
    }
    return count;
}

/* convert name of symbol (entry) list element to a Basic identifier */
/* new name is built in storage obtained from stralloc() */
/* the special name  _main  is converted to the command name first */
/* copy upper case and numerals, convert lower case to upper, ignore rest */

PRIVATE char *idconvert(elptr, commandname)
struct entrylist *elptr;
char *commandname;
{
    char *name;
    char *newname;

    if (strcmp(name = elptr->elsymptr->name, "_main") == 0)
      name = commandname;
    newname = stralloc(name);
    {
      register char *t;
      register char *s;

      t = newname;
      s = name;
      do
      {
          if (*s >= '0' && *s <= '9' || *s >= 'A' && *s <= 'Z')
            *t++ = *s;
          if (*s >= 'a' && *s <= 'z')
            *t++ = *s + ('A' - 'a');
      }
      while (*s++);
      *t = 0;
    }
    if (*newname < 'A')       /* numeral or null */
      fatalerror("bad entry name");
    return newname;
}

#endif /* EDOS */

PRIVATE void linkmod(modptr)
struct modstruct *modptr;
{
    char buf[ABS_TEXT_MAX];
    int command;
    unsigned char modify;
    bin_off_t offset;
    int symbolnum;
    struct symstruct **symparray;
    struct symstruct *symptr;

    setseg(0);
    relocsize = 2;
    symparray = modptr->symparray;
    openin(modptr->filename); /* does nothing if already open */
    seekin(modptr->textoffset);
    while (TRUE)
    {
      if ((command = readchar()) < 0)
          prematureeof();
      modify = command & MODIFY_MASK;
      switch (command & CM_MASK)
      {
      case CM_SPECIAL:
          switch (modify)
          {
          case CM_EOT:
            segpos[curseg] = spos;
            return;
          case CM_BYTE_SIZE:
            relocsize = 1;
            break;
          case CM_WORD_SIZE:
            relocsize = 2;
            break;
          case CM_LONG_SIZE:
#ifdef LONG_OFFSETS
            relocsize = 4;
            break;
#else
            fatalerror("relocation by long offsets not implemented");
#endif
          case CM_1_SKIP:
            skip(1);
            break;
          case CM_2_SKIP:
            skip(2);
            break;
          case CM_4_SKIP:
            skip(4);
            break;
          default:
            if ((modify -= CM_0_SEG) >= NSEG)
                inputerror("bad data in");
            setseg(modify);
            break;
          }
          break;
      case CM_ABSOLUTE:
          if (modify == 0)
            modify = ABS_TEXT_MAX;
          readin(buf, (unsigned) modify);
          writeout(buf, (unsigned) modify);
          spos += (int) modify;
          break;
      case CM_OFFSET_RELOC:
          offset = readsize(relocsize);
          if (modify & R_MASK)
          {
#ifndef DATASEGS
                int m = (modify & SEGM_MASK);
              if( curseg != m && m != SEGM_MASK )
                 interseg(modptr->filename, modptr->archentry, (char*)0);
#endif
            offset -= (spos + relocsize);
            }
          offtocn(buf, segbase[modify & SEGM_MASK] + offset, relocsize);
          writeout(buf, relocsize);
#ifdef REL_OUTPUT
          if (reloc_output)
          {
            u4_t bitfield;

            if (curseg == 0)
            {
                ++ntreloc;
                offtocn(buf, spos, 4);
                writetrel(buf, 4);
            }
            else
            {
                ++ndreloc;
                offtocn(buf, spos - segbase[1], 4);
                writedrel(buf, 4);
            }
            if ((modify & SEGM_MASK) == 0)
                bitfield = N_TEXT;
            else
                bitfield = N_DATA;
            if (modify & R_MASK)
                bitfield |= 1L << 24;
            if (relocsize == 2)
                bitfield |= 1L << 25;
            else if (relocsize == 4)
                bitfield |= 1L << 26;
            u4cn(buf, bitfield, 4);
            if (curseg == 0)
                writetrel(buf, 4);
            else
                writedrel(buf, 4);
          }
#endif /* REL_OUTPUT */
          spos += relocsize;
          break;
      case CM_SYMBOL_RELOC:
          symptr = symparray[symbolnum = readconvsize((unsigned)
                                  (modify & S_MASK ? 2 : 1))];
          offset = readconvsize((unsigned) modify & OF_MASK);
          if (modify & R_MASK)
          {
#ifndef DATASEGS
                int m = (symptr->flags & SEGM_MASK);
              if( curseg != m && m != SEGM_MASK )
                 interseg(modptr->filename, modptr->archentry, symptr->name);
#endif
            offset -= (spos + relocsize);
          }
#ifdef REL_OUTPUT
          if (!reloc_output || !(symptr->flags & I_MASK))
#endif
            offset += symptr->value;          
          offtocn(buf, offset, relocsize);
          writeout(buf, relocsize);
#ifdef REL_OUTPUT
          if (reloc_output)
          {
            u4_t bitfield;

            if (curseg == 0)
            {
                ++ntreloc;
                offtocn(buf, spos, 4);
                writetrel(buf, 4);
            }
            else
            {
                ++ndreloc;
                offtocn(buf, spos - segbase[1], 4);
                writedrel(buf, 4);
            }
            if (symptr->flags & I_MASK)
                bitfield = (1L << 27) | symbolnum;
            else if ((symptr->flags & SEGM_MASK) == 0)
                bitfield = N_TEXT;
            else if (symptr->flags & (C_MASK | SA_MASK))
                bitfield = N_BSS;
            else
                bitfield = N_DATA;
            if (modify & R_MASK)
                bitfield |= 1L << 24;
            if (relocsize == 2)
                bitfield |= 1L << 25;
            else if (relocsize == 4)
                bitfield |= 1L << 26;
            u4cn(buf, bitfield, 4);
            if (curseg == 0)
                writetrel(buf, 4);
            else
                writedrel(buf, 4);
          }
#endif /* REL_OUTPUT */
          spos += relocsize;
      }
    }
}

PRIVATE void padmod(modptr)
struct modstruct *modptr;
{
    bin_off_t count;
    fastin_t seg;
    bin_off_t size;
    unsigned sizecount;
    char *sizeptr;

    for (seg = 0, sizeptr = modptr->segsize; seg < NSEG; ++seg)
    {
      size = cntooffset(sizeptr,
                    sizecount = segsizecount((unsigned) seg, modptr));
      sizeptr += sizecount;
      if ((count = segpos[seg] - segbase[seg]) != size)
          size_error(seg, count, size);

      /* pad to quad boundary */
      /* not padding in-between common areas which sometimes get into file */
      if ((size = ld_roundup(segpos[seg], 4, bin_off_t) - segpos[seg]) != 0)
      {
          setseg(seg);
          writenulls(size);
          segpos[seg] = spos;
      }
      segbase[seg] = segpos[seg];
    }
}

PRIVATE void setsym(name, value)
char *name;
bin_off_t value;
{
    struct symstruct *symptr;

#ifdef REL_OUTPUT
    if (!reloc_output)
#endif
      if ((symptr = findsym(name)) != NUL_PTR)
          symptr->value = value;
}

PRIVATE void symres(name)
register char *name;
{
    register struct symstruct *symptr;

    if ((symptr = findsym(name)) != NUL_PTR)
    {
      if ((symptr->flags & SEGM_MASK) == SEGM_MASK)
          symptr->flags &= ~SEGM_MASK | curseg;
      if (symptr->flags != (I_MASK | curseg) || symptr->value != 0)
          reserved(name);
#ifdef REL_OUTPUT
      if (!reloc_output)
#endif
          symptr->flags = E_MASK | curseg;      /* show defined, not common */
    }
}

/* set new segment */

PRIVATE void setseg(newseg)
fastin_pt newseg;
{
    if (newseg != curseg)
    {
      segpos[curseg] = spos;
      spos = segpos[curseg = newseg];
      seekout(FILEHEADERLENGTH + (unsigned long) spos
            + (unsigned long) segadj[curseg]);
    }
}

PRIVATE void skip(countsize)
unsigned countsize;
{
    writenulls((bin_off_t) readsize(countsize));
}

#ifdef EDOS

PRIVATE void writeheader(commandname)
char *commandname;
{
    char buf[MAX_OFFSET_SIZE];
    bin_off_t offset;
    unsigned headlength;
    char *name;
    struct entrylist *elptr;
    struct symstruct *startptr;

    headlength = binheaderlength(commandname);
    for (elptr = entryfirst; elptr != NUL_PTR; elptr = elptr->elnext)
      headlength -= 6;
    offset = headlength;
    startptr = findsym("start");
    offtocn(buf, edataoffset, 2);
    writeout(buf, 2);
    writechar(0xFF);          /* dummy data length 0xFFFF takes everything */
    writechar(0xFF);
    for (elptr = entryfirst; elptr != NUL_PTR; elptr = elptr->elnext)
    {
      name = idconvert(elptr, commandname);
      writeout(name, (unsigned) strlen(name) + 1);
      ourfree(name);
      offtocn(buf, startptr == NUL_PTR ? elptr->elsymptr->value : offset, 2);
      writeout(buf, 2);
      writechar(0x82);  /* 8 = set flags from here, 2 = cmd line */
      offset += 6;            /* LBSR $xxxx and LBRA $xxxx */
    }
    writechar(0);
    if (startptr != NUL_PTR)
    {
      offset = headlength + 3;      /* over 1st LBSR */
      for (elptr = entryfirst; elptr != NUL_PTR; elptr = elptr->elnext)
      {
          writechar(0x17);    /* LBSR */
          offtocn(buf, startptr->value - offset, 2);
          writeout(buf, 2);
          writechar(0x16);    /* LBRA */
          offtocn(buf, elptr->elsymptr->value - offset - 3, 2);
          writeout(buf, 2);
          offset += 6;
      }
    }
}

#endif /* EDOS */

#ifdef MINIX

PRIVATE void writeheader()
{
    struct exec header;

    memset(&header, 0, sizeof header);
#ifdef STANDARD_GNU_A_OUT
#ifdef N_SET_MAGIC
#ifdef QMAGIC
    if(uzp)
       N_SET_MAGIC(header, QMAGIC);
    else
#endif
    N_SET_MAGIC(header, OMAGIC);
#else
    *(unsigned short *) &header.a_magic = OMAGIC;  /* XXX - works for 386BSD */
#endif
#else
    header.a_magic[0] = A_MAGIC0;
    header.a_magic[1] = A_MAGIC1;
#endif
#ifdef REL_OUTPUT
    if (!reloc_output)
#endif
    {
#ifdef STANDARD_GNU_A_OUT
#ifdef N_SET_FLAGS
      N_SET_FLAGS(header, 0);
#else
      /* XXX - works for 386BSD */
#endif
#else
      header.a_flags = sepid ? A_SEP : A_EXEC;
      if (uzp)
          header.a_flags |= A_UZP;
#endif
    }
#ifdef BSD_A_OUT
#ifdef STANDARD_GNU_A_OUT
#ifdef N_SET_FLAGS
    N_SET_MACHTYPE(header, M_386);
#else
      /* XXX - works for 386BSD which doesn't define its own machtype :-( */
#endif
#else
    header.a_cpu = (bits32 || reloc_output) ? A_I80386 : A_I8086;
#endif
#else
    header.a_cpu = bits32 ? A_I80386 : A_I8086;
#endif
#ifndef STANDARD_GNU_A_OUT
    header.a_hdrlen = FILEHEADERLENGTH;
#endif
#ifdef QMAGIC
    if (uzp)
       offtocn((char *) &header.a_text, etextpadoff - btextoffset+HEADERLEN,
             sizeof header.a_text);
    else
#endif
    offtocn((char *) &header.a_text, etextpadoff - btextoffset,
          sizeof header.a_text);
    offtocn((char *) &header.a_data, edataoffset - bdataoffset,
          sizeof header.a_data);
    offtocn((char *) &header.a_bss, endoffset - edataoffset,
          sizeof header.a_bss);

#ifdef REL_OUTPUT
    if (!reloc_output)
#endif
    {
      offtocn((char *) &header.a_entry, btextoffset,
                sizeof header.a_entry);
#ifndef STANDARD_GNU_A_OUT
      offtocn((char *) &header.a_total, (bin_off_t)
          (endoffset < 0x00010000L ? 0x00010000L : endoffset + 0x0008000L),
            sizeof header.a_total);
#endif
    }
    if( FILEHEADERLENGTH )
       writeout((char *) &header, FILEHEADERLENGTH);
}

#endif /* MINIX */

PRIVATE void writenulls(count)
bin_off_t count;
{
    long lcount = count;
    if( lcount < 0 )
      fatalerror("org command requires reverse seek");
    spos += count;
    while (count-- > 0)
      writechar(0);
}
#else

#ifndef FUNCNAME
#define FUNCNAME writebin
#endif

PUBLIC void FUNCNAME(outfilename, argsepid, argbits32, argstripflag, arguzp)
char *outfilename;
bool_pt argsepid;
bool_pt argbits32;
bool_pt argstripflag;
bool_pt arguzp;
{
    char * s  = "WARNING: Native a.out generation not included, sorry\n";
    write(2, s, strlen(s));
    write_elks(outfilename, argsepid, argbits32, argstripflag, arguzp, 0);
}
#endif

Generated by  Doxygen 1.6.0   Back to index