summaryrefslogtreecommitdiff
path: root/ld/writebin.c
diff options
context:
space:
mode:
authorRobert de Bath <rdebath@poboxes.com>2002-07-27 09:23:57 +0200
committerLubomir Rintel <lkundrak@v3.sk>2013-10-23 23:16:11 +0200
commita7aba15e8efffb1c5d3097656f1a93955a64f01f (patch)
tree4bb9d6d1d1528bc5647670d510aca6cc5fb300a8 /ld/writebin.c
downloaddev86-a7aba15e8efffb1c5d3097656f1a93955a64f01f.tar.gz
Import origs.tar.gzorigs
Diffstat (limited to 'ld/writebin.c')
-rw-r--r--ld/writebin.c989
1 files changed, 989 insertions, 0 deletions
diff --git a/ld/writebin.c b/ld/writebin.c
new file mode 100644
index 0000000..a95280c
--- /dev/null
+++ b/ld/writebin.c
@@ -0,0 +1,989 @@
+extern long text_base_address;
+#define btextoffset text_base_address
+static long bdataoffset;
+#define page_size() 4096
+
+/* writebin.c - write binary file for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#ifdef A_OUT_H
+# include A_OUT_H
+#else
+# ifdef BSD_A_OUT
+# ifdef STANDARD_GNU_A_OUT
+# include <a.out.h>
+# define RELOC_INFO_SIZE 8 /* unportable bitfields - bcc doesn't pack */
+# else
+# include "bsd-a.out.h"
+# define RELOC_INFO_SIZE (sizeof (struct relocation_info))
+# endif
+# define C_EXT N_EXT
+# define C_STAT 0
+# define n_was_name n_un.n_name
+# define n_was_numaux n_other
+# define n_was_other n_numaux
+# define n_was_sclass n_type
+# define n_was_strx n_un.n_strx
+# define n_was_type n_desc
+# else /* not BSD_A_OUT */
+# include "a.out.h" /* maybe local copy of <a.out.h> for X-link */
+# define n_was_name n_name
+# define n_was_numaux n_numaux
+# define n_was_other n_other
+# define n_was_sclass n_sclass
+# define n_was_strx n_value
+# define n_was_type n_type
+# endif /* BSD_A_OUT */
+#endif
+
+#include "const.h"
+#include "obj.h"
+#include "type.h"
+#undef EXTERN
+#include "globvar.h"
+
+#ifdef STDC_HEADERS_MISSING
+void *memset P((void *s, int c, unsigned n));
+#else
+#undef NULL
+#include <string.h>
+#endif
+
+#ifdef EDOS
+# define FILEHEADERLENGTH 0
+#endif
+#ifdef MINIX
+# ifdef BSD_A_OUT
+# ifdef STANDARD_GNU_A_OUT
+# define FILEHEADERLENGTH 32
+# else
+# define FILEHEADERLENGTH 48
+# endif
+# else
+# define FILEHEADERLENGTH A_MINHDR
+ /* part of header not counted in offsets */
+# 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 offset_t combase[NSEG]; /* bases of common parts of segments */
+PRIVATE offset_t comsz[NSEG]; /* sizes of common parts of segments */
+PRIVATE fastin_t curseg; /* current segment, 0 to $F */
+PRIVATE offset_t edataoffset; /* end of data */
+PRIVATE offset_t endoffset; /* end of bss */
+PRIVATE offset_t etextoffset; /* end of text */
+PRIVATE offset_t etextpadoff; /* end of padded text */
+#ifdef BSD_A_OUT
+PRIVATE unsigned ndreloc; /* number of data relocations */
+#endif
+PRIVATE unsigned nsym; /* number of symbols written */
+#ifdef BSD_A_OUT
+PRIVATE unsigned ntreloc; /* number of text relocations */
+PRIVATE bool_t reloc_output; /* nonzero to leave reloc info in output */
+#endif
+PRIVATE unsigned relocsize; /* current relocation size 1, 2 or 4 */
+PRIVATE offset_t segadj[NSEG]; /* adjusts (file offset - seg offset) */
+ /* depends on zero init */
+PRIVATE offset_t segbase[NSEG]; /* bases of data parts of segments */
+PRIVATE char segboundary[9] = "__seg0DH";
+ /* name of seg boundary __seg0DL to __segfCH */
+PRIVATE offset_t segpos[NSEG]; /* segment positions for current module */
+PRIVATE offset_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 offset_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 linkrefs P((struct modstruct *modptr));
+FORWARD void padmod P((struct modstruct *modptr));
+FORWARD void setsym P((char *name, offset_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((offset_t count));
+
+/* link all symbols connected to entry symbols */
+
+PUBLIC void linksyms(argreloc_output)
+bool_pt argreloc_output;
+{
+ char needlink;
+ struct entrylist *elptr;
+ struct modstruct *modptr;
+ struct symstruct *symptr;
+
+#ifdef BSD_A_OUT
+ reloc_output = argreloc_output;
+ if (argreloc_output)
+ {
+ if (modfirst->modnext != NULL)
+ fatalerror("relocatable output only works for one input file");
+ for (modptr = modfirst; modptr != NULL; modptr = modptr->modnext)
+ modptr->loadflag = TRUE;
+ return;
+ }
+#endif
+ if ((symptr = findsym("_main")) != NULL)
+ entrysym(symptr);
+ do
+ {
+ if ((elptr = entryfirst) == NULL)
+ fatalerror("no start symbol");
+ for (modptr = modfirst; modptr != NULL; modptr = modptr->modnext)
+ modptr->loadflag = FALSE;
+ for (; elptr != NULL; elptr = elptr->elnext)
+ linkrefs(elptr->elsymptr->modptr);
+ if ((symptr = findsym("start")) != NULL)
+ linkrefs(symptr->modptr);
+ needlink = FALSE;
+ {
+ struct redlist *prlptr;
+ struct redlist *rlptr;
+
+ for (rlptr = redfirst; rlptr != NULL;
+ rlptr = (prlptr = rlptr)->rlnext)
+ if (rlptr->rlmodptr->loadflag &&
+ rlptr->rlmodptr->class > rlptr->rlsymptr->modptr->class)
+ {
+ rlptr->rlsymptr->modptr = rlptr->rlmodptr;
+ rlptr->rlsymptr->value = rlptr->rlvalue;
+ if (rlptr == redfirst)
+ redfirst = rlptr->rlnext;
+ else
+ prlptr->rlnext = rlptr->rlnext;
+ needlink = TRUE;
+ }
+ }
+ }
+ while (needlink);
+}
+
+/* write binary file */
+
+PUBLIC void writebin(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;
+ offset_t tempoffset;
+
+ sepid = argsepid;
+ bits32 = argbits32;
+ stripflag = argstripflag;
+#ifdef BSD_A_OUT
+ uzp = arguzp && !reloc_output;
+#else
+ uzp = arguzp;
+#endif
+ if (uzp)
+ {
+ if (btextoffset == 0)
+ btextoffset = page_size();
+ if (bdataoffset == 0 && sepid)
+ bdataoffset = page_size();
+ }
+#ifdef EDOS
+ commandname = stralloc(outfilename);
+ if ((cptr = strchr(commandname, ':')) != NULL)
+ commandname = cptr + 1;
+ if ((cptr = strrchr(commandname, '.')) != NULL)
+ *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 */
+ }
+#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");
+
+ /* 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 != NULL; modptr = modptr->modnext)
+ if (modptr->loadflag)
+ {
+ register struct symstruct **symparray;
+ register struct symstruct *symptr;
+
+ for (symparray = modptr->symparray;
+ (symptr = *symparray) != NULL; ++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 BSD_A_OUT
+ if (!reloc_output)
+#endif
+ undefined(symptr->name);
+ }
+ else
+ {
+#ifdef BSD_A_OUT
+#if 0
+ if (!reloc_output)
+#else
+ if (!reloc_output || !(symptr->flags & I_MASK))
+#endif
+#endif
+ {
+ tempoffset = roundup(symptr->value, 4, offset_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] = roundup(segsz[seg], 4, offset_t);
+ comsz[seg] = roundup(comsz[seg], 4, offset_t);
+#endif
+ cptr += sizecount;
+ }
+ }
+
+ /* calculate seg positions now their sizes are known */
+ /* temp use fixed order 0D 0C 1D 1C 2D 2C ... */
+ /* assume seg 0 is text and rest are data */
+#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 = roundup(etextoffset, 0x10, offset_t);
+ segadj[1] += etextpadoff - bdataoffset;
+ }
+ else if (bdataoffset == 0)
+ bdataoffset = etextpadoff;
+ segpos[1] = segbase[1] = edataoffset = bdataoffset;
+ combase[1] = segbase[1] + segsz[1];
+ for (seg = 2; seg < NSEG; ++seg)
+ {
+ segpos[seg] = segbase[seg] = combase[seg - 1] + comsz[seg - 1];
+ 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])
+ & ~(offset_t) 0xFF) != 0)
+ segpos[seg] = segbase[seg] = (segbase[seg] + 0xFF)
+ & ~(offset_t) 0xFF;
+ }
+ combase[seg] = segbase[seg] + segsz[seg];
+ segadj[seg] = segadj[seg - 1];
+ }
+
+ /* relocate symbols by offsets of segments in memory */
+ for (modptr = modfirst; modptr != NULL; modptr = modptr->modnext)
+ if (modptr->loadflag)
+ {
+ register struct symstruct **symparray;
+ register struct symstruct *symptr;
+
+ for (symparray = modptr->symparray;
+ (symptr = *symparray) != NULL; ++symparray)
+ if (symptr->modptr == modptr && !(symptr->flags & A_MASK))
+ {
+ if (symptr->flags & (C_MASK | SA_MASK))
+ {
+#ifdef BSD_A_OUT
+#if 0
+ if (!reloc_output)
+#else
+ if (!reloc_output || !(symptr->flags & I_MASK))
+#endif
+#endif
+ symptr->value += combase[symptr->flags & SEGM_MASK];
+ }
+ else
+#ifdef BSD_A_OUT
+ if (!reloc_output || !(symptr->flags & I_MASK))
+#endif
+ symptr->value += segbase[symptr->flags & SEGM_MASK];
+ }
+ }
+
+ /* adjust special symbols */
+ for (seg = 0; seg < NSEG; ++seg)
+ {
+ if (segsz[seg] != 0)
+ /* only count data of nonzero length */
+ 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 */
+ }
+ setsym("__etext", etextoffset);
+ setsym("__edata", edataoffset);
+ setsym("__end", endoffset = combase[NSEG - 1] + comsz[NSEG - 1]);
+
+ openout(outfilename);
+#ifdef BSD_A_OUT
+ 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 != NULL; 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 BSD_A_OUT
+ + ((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 != NULL; modptr = modptr->modnext)
+ if (modptr->loadflag)
+ {
+ register struct symstruct **symparray;
+ register struct symstruct *symptr;
+
+ for (symparray = modptr->symparray;
+ (symptr = *symparray) != NULL; ++symparray)
+ if (symptr->modptr == modptr)
+ {
+#ifdef BSD_A_OUT
+ offtocn((char *) &extsym.n_was_strx,
+ (offset_t) stringoff, 4);
+#else
+ strncpy((char *) &extsym.n_was_name, symptr->name,
+ sizeof extsym.n_was_name);
+#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 BSD_A_OUT
+ !reloc_output &&
+#endif
+ flags & C_MASK)
+ switch (flags & (A_MASK | SEGM_MASK))
+ {
+ case 0:
+ extsym.n_was_sclass |= N_TEXT;
+ case A_MASK:
+ break;
+ default:
+ 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
+ stringoff += strlen(symptr->name) + 1;
+#endif
+ }
+ }
+#ifdef BSD_A_OUT
+ offtocn((char *) &extsym.n_was_strx, (offset_t) stringoff, 4);
+ writeout((char *) &extsym.n_was_strx, 4);
+ for (modptr = modfirst; modptr != NULL; modptr = modptr->modnext)
+ if (modptr->loadflag)
+ {
+ register struct symstruct **symparray;
+ register struct symstruct *symptr;
+
+ for (symparray = modptr->symparray;
+ (symptr = *symparray) != NULL; ++symparray)
+ if (symptr->modptr == modptr)
+ writeout(symptr->name, strlen(symptr->name) + 1);
+ }
+#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 BSD_A_OUT
+ 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 BSD_A_OUT
+ 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 != NULL; elptr = elptr->elnext)
+ {
+ name = idconvert(elptr, commandname);
+ count += strlen(name) + 1 + 2 + 1; /* nul off flg */
+ ourfree(name);
+ if (startptr != NULL)
+ 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;
+ offset_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)
+ offset -= (spos + relocsize);
+ offtocn(buf, segbase[modify & SEGM_MASK] + offset, relocsize);
+ writeout(buf, relocsize);
+#ifdef BSD_A_OUT
+ 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 /* BSD_A_OUT */
+ 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)
+ offset -= (spos + relocsize);
+#ifdef BSD_A_OUT
+ if (!reloc_output || !(symptr->flags & I_MASK))
+#endif
+ offset += symptr->value;
+ offtocn(buf, offset, relocsize);
+ writeout(buf, relocsize);
+#ifdef BSD_A_OUT
+ 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 /* BSD_A_OUT */
+ spos += relocsize;
+ }
+ }
+}
+
+PRIVATE void linkrefs(modptr)
+struct modstruct *modptr;
+{
+ register struct symstruct **symparray;
+ register struct symstruct *symptr;
+
+ modptr->loadflag = TRUE;
+ for (symparray = modptr->symparray;
+ (symptr = *symparray) != NULL; ++symparray)
+ if (symptr->modptr->loadflag == FALSE)
+ linkrefs(symptr->modptr);
+}
+
+PRIVATE void padmod(modptr)
+struct modstruct *modptr;
+{
+ offset_t count;
+ fastin_t seg;
+ offset_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 = roundup(segpos[seg], 4, offset_t) - segpos[seg]) != 0)
+ {
+ setseg(seg);
+ writenulls(size);
+ segpos[seg] = spos;
+ }
+ segbase[seg] = segpos[seg];
+ }
+}
+
+PRIVATE void setsym(name, value)
+char *name;
+offset_t value;
+{
+ struct symstruct *symptr;
+
+#ifdef BSD_A_OUT
+ if (!reloc_output)
+#endif
+ if ((symptr = findsym(name)) != NULL)
+ symptr->value = value;
+}
+
+PRIVATE void symres(name)
+register char *name;
+{
+ register struct symstruct *symptr;
+
+ if ((symptr = findsym(name)) != NULL)
+ {
+ if ((symptr->flags & SEGM_MASK) == SEGM_MASK)
+ symptr->flags &= ~SEGM_MASK | curseg;
+ if (symptr->flags != (I_MASK | curseg) || symptr->value != 0)
+ reserved(name);
+#ifdef BSD_A_OUT
+ 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((offset_t) readsize(countsize));
+}
+
+#ifdef EDOS
+
+PRIVATE void writeheader(commandname)
+char *commandname;
+{
+ char buf[MAX_OFFSET_SIZE];
+ offset_t offset;
+ unsigned headlength;
+ char *name;
+ struct entrylist *elptr;
+ struct symstruct *startptr;
+
+ headlength = binheaderlength(commandname);
+ for (elptr = entryfirst; elptr != NULL; 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 != NULL; elptr = elptr->elnext)
+ {
+ name = idconvert(elptr, commandname);
+ writeout(name, (unsigned) strlen(name) + 1);
+ ourfree(name);
+ offtocn(buf, startptr == NULL ? 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 != NULL)
+ {
+ offset = headlength + 3; /* over 1st LBSR */
+ for (elptr = entryfirst; elptr != NULL; 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
+ 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 BSD_A_OUT
+ 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
+ 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 BSD_A_OUT
+ if (!reloc_output)
+#endif
+ {
+ if (uzp)
+ offtocn((char *) &header.a_entry, page_size(),
+ sizeof header.a_entry);
+#ifndef STANDARD_GNU_A_OUT
+ offtocn((char *) &header.a_total, (offset_t)
+ (endoffset < 0x00010000L ? 0x00010000L : endoffset + 0x0008000L),
+ sizeof header.a_total);
+#endif
+ }
+ writeout((char *) &header, FILEHEADERLENGTH);
+}
+
+#endif /* MINIX */
+
+PRIVATE void writenulls(count)
+offset_t count;
+{
+ spos += count;
+ while (count--)
+ writechar(0);
+}