/****************************************************************************** ******************************************************************************* ** ** Unidot object format to x.out convertor. ** ** Usage is: ** ** xcon [-o outfile] [-s] file.obj ** ** The input file (file.obj) must be in the standard Unidot object file format, ** and its name must end with ".obj". The input file is converted into the ** x.out format, and the result is put in the output file specified by the ** "-o" switch. If no "-o" switch is given, the file "x.out" is created as ** a default. ** ** The "-s" switch will force the output to be marked as segmented, for ** those rare cases where xcon cannot determine that from the input file. ** ** Care has been taken to ensure machine independence. The output file ** generated by this program will be correct for a Z8000 regardless of ** the processor on which this program is run. In particular, this program ** may be run on a PDP-11 or on a VAX without any byte swap problems in the ** output file. One consequence of this policy is that routines are used ** to output the various structures defined in "xout.h". If the x.out ** file format is changed, or if "xout.h" is changed, the corresponding ** routines will probably need changing too. The routines to check are ** outhdr(), outrel(), outseg(), outsym(), and outtxt(). ** ** John D. Polstra ** September 13, 1982 ** ******************************************************************************* ******************************************************************************/ #include "stdio.h" #include "xout.h" #include "obj.h" /* * Constants. */ #define EXTMAX (RBMSK+1-RBEXT) /* Maximum number of external symbols allowed */ #define SEGMAX 128 /* Maximum number of segments allowed */ /* * Type definitions. */ typedef unsigned short uns; /* * Global variables. */ uns exttab[EXTMAX]; /* Mapping from external # to symbol # */ uns *exttop = exttab; /* Pointer to top of exttab */ struct x_sg segtab[SEGMAX]; /* Table of information about segments */ struct x_hdr header; /* Header for x.out file */ long curoff; /* Current x.out file offset */ long reloff; /* X.out file offset for next reloc. entry */ long segoff[SEGMAX]; /* X.out file offsets for segments */ long symoff; /* X.out file offset for next symbol */ uns symct; /* Number of symbols for the x.out file */ char dbgflg = 0; /* Debug output flag on =1 off =0 */ char objbuf[255]; /* Buffer holding body of current .obj block */ FILE *objiop; /* Standard I/O pointer for .obj file */ char *objname; /* Name of .obj file */ char *objpt, *objtop; /* Pointers into objbuf */ int objtyp; /* Type of current .obj block */ int outfd; /* File descriptor for x.out file */ char *outname = "x.out"; /* Name of x.out file */ int firstseg; /* First segment (0 or 1) actually output */ char pass2; /* Flag set for second pass over .obj file */ char *prname; /* Name of this program */ /* * Here is a brief description of our section / segment numbering * scheme. The tables segtab[] and segoff[] are indexed by the Unidot * section number; thus they always have a slot for the absolute section * (number 0) whether it is used or not. However, we do not want to * output a segment descriptor for the absolute section unless it is * really used. So in the interlude we set the variable firstseg to * one iff the absolute section is used. Within the various x.out * outputting routines (outrel, outsym, etc.) we adjust the section numbers * according to the value of firstseg. The general philosophy is that * the outputting routines are called with Unidot section numbers; they * perform the necessary adjustments to produce the required x.out * segment numbers in the output file. * * Got it? */ /* * Function declarations. */ long lseek(); /* Move I/O pointer to new file position */ uns ogetb(); /* Get next byte from object block */ long ogetl(); /* Get next long from object block */ char *ogets(); /* Get next string from object block */ uns ogetw(); /* Get next word from object block */ /* * main - The main program consists simply of some initialization followed * by two processing passes, with some interlude processing in between * the two passes. */ main(argc, argv) int argc; char *argv[]; { init(argc, argv); dopass(); interlude(); pass2 = 1; rewind(objiop); dopass(); close(outfd); fclose(objiop); return(0); } /* * dopass - Performs a scan of the .obj file. */ dopass() { uns action; uns adr; uns base; uns len; uns relent; uns relpos; uns sec; char *sym; int type; uns val; header.x_nseg = 1; /* We always leave room for an absolute segment */ if(ofill() != OBOST) ferr("Bad .obj file format\n"); while(ofill() != OBOND) { switch(objtyp) { case OBSEC: /* Sections block */ while(objpt < objtop) { ogetb(); /* Discard alignment */ ogetb(); /* Discard extent */ ogetb(); /* Discard attributes */ sym = ogets(); /* Get section name */ if(pass2 && dbgflg) printf("sections %s\n",sym); if(!pass2) { /* * Enter a new segment into segtab. * Increment the number of segments * in the header. Also increase * the symbol table size to account * for the segment name symbol. */ segtab[header.x_nseg].x_sg_no = 255; if (strcmp(sym,"__text")== 0) segtab[header.x_nseg].x_sg_typ = X_SG_COD; if (strcmp(sym,"__con")== 0) segtab[header.x_nseg].x_sg_typ = X_SG_CON; if (strcmp(sym,"__data")== 0) segtab[header.x_nseg].x_sg_typ = X_SG_DAT; if (strcmp(sym,"__bss")== 0) segtab[header.x_nseg].x_sg_typ = X_SG_BSS; header.x_symb += sizeof(struct x_sym); symct++; } else outsym(sym, X_SY_SEG, 0, header.x_nseg); header.x_nseg++; } break; case OBGLO: /* Global symbols block */ if(pass2 && dbgflg) printf("global "); case OBLOC: /* Local symbols block */ if(pass2 && dbgflg) printf("symbols block\n"); while(objpt < objtop) { val = (uns)ogetl(); sec = ogetb(); sym = ogets(); if(!pass2) { if(sec == RBUND) /* Enter symbol # of new external */ *exttop++ = symct; header.x_symb += sizeof(struct x_sym); symct++; } else { type = objtyp==OBGLO ? X_SY_GLB : X_SY_LOC; if(sec == RBUND) type = X_SY_UNX; outsym(sym, type, val, sec); } } break; case OBTXT: /* Text block */ adr = (uns)ogetl(); sec = ogetb(); len = ogetb(); if(pass2 && dbgflg) printf("text section[%x] at %x for %x bytes\n",sec,adr,len); if(!pass2) { if(adr+len > segtab[sec].x_sg_len) segtab[sec].x_sg_len = adr+len; objpt += len; while(objpt < objtop) { ogetb(); /* Relocation byte number */ relent = ogetw(); /* Relocation entry */ header.x_reloc += sizeof(struct x_rel); relent &= RAMSK; if(relent==RAZLS || relent==RAZSS || relent==RAZOF) header.x_magic = X_SU_MAGIC; } } else { outtxt(adr, sec, objpt, len); objpt += len; while(objpt < objtop) { relpos = adr + ogetb() - 6; relent = ogetw(); action = relent & RAMSK; base = relent & RBMSK; switch(action) { case RAA32M: /* absolute 32-bit address */ /* * The loader can only relocate the least * significant half of a 32-bit item. */ relpos += 2; /* Fall through to next case */ case RAA16M: /* absolute 16-bit address */ case RAZOF: /* segmented offset */ type = base= objtop) { ferr("Off the end of objbuf\n"); } return(*objpt++&0377); } /* * ogetl - Returns the next long word from the object buffer. */ long ogetl() { long l; l = ogetw(); return((long)ogetw()<<16|l); } /* * ogets - Returns a pointer to the next string in the object buffer. */ char * ogets() { char *s; s = objpt; while(ogetb()); return(s); } /* * ogetw - Returns the next word from the object buffer. */ uns ogetw() { uns w; w = ogetb(); return(ogetb()<<8|w); } /* * outb - Outputs a single byte to the .out file. */ outb(val) char val; { write(outfd, &val, 1); curoff++; } /* * outhdr - Outputs the header section of the .out file. */ outhdr() { outw(header.x_magic); outw(header.x_nseg - firstseg); outl(header.x_init); outl(header.x_reloc); outl(header.x_symb); } /* * outl - Outputs a single long word to the .out file. The long word is * written in Z8000 (MSB first) format, regardless of the host processor. */ outl(val) long val; { char buf[4]; buf[3] = val; val >>= 8; buf[2] = val; val >>= 8; buf[1] = val; val >>= 8; buf[0] = val; write(outfd, buf, 4); curoff += 4; } /* * outrel - Outputs a relocation entry with the specified type, offset, * segment, and relocation base. */ outrel(type, offset, segment, base) int type; uns offset; int segment; uns base; { if(curoff != reloff) lseek(outfd, curoff = reloff, 0); if(base >= RBEXT) base = exttab[base-RBEXT]; else base -= firstseg; outb(segment - firstseg); outb(type); outw(offset); outw(base); reloff = curoff; } /* * outseg - Outputs the segments section of the .out file. */ outseg() { struct x_sg *p; for(p = &segtab[firstseg] ; p < &segtab[header.x_nseg] ; p++) { outb(p->x_sg_no); outb(p->x_sg_typ); outw(p->x_sg_len); } } /* * outsym - Outputs a symbol table entry with the specified name, * type, value, and segment. */ outsym(name, type, value, segment) register char *name; int type; unsigned short value; int segment; { register int i; if(curoff != symoff) lseek(outfd, curoff = symoff, 0); if(segment==RBABS || segment==RBUND) segment = 255; else segment -= firstseg; outb(segment); outb(type); outw(value); for(i=0 ; i>= 8; buf[0] = val; write(outfd, buf, 2); curoff += 2; } /* * usage - Issues a fatal error message for incorrect usage. */ usage() { ferr("Usage: %s [-o x.out] [-s] file.obj\n", prname); }