mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-23 08:24:18 +00:00
599 lines
14 KiB
C
599 lines
14 KiB
C
/******************************************************************************
|
||
*******************************************************************************
|
||
**
|
||
** 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<RBEXT ? X_RL_OFF : X_RL_XOF;
|
||
break;
|
||
|
||
case RAZSS: /* short segmented address */
|
||
type = base<RBEXT ? X_RL_SSG : X_RL_XSSG;
|
||
break;
|
||
|
||
case RAZLS: /* long segmented address */
|
||
type = base<RBEXT ? X_RL_LSG : X_RL_XLSG;
|
||
break;
|
||
|
||
default:
|
||
ferr("Illegal reloc. 0x%x at loc. 0x%x of sec. 0x%x\n",
|
||
relent, relpos, sec);
|
||
}
|
||
outrel(type, relpos, sec, base);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* ferr - Issues a fatal error message and terminates.
|
||
*/
|
||
ferr(a, b, c, d, e)
|
||
|
||
char *a;
|
||
int b, c, d, e;
|
||
|
||
{
|
||
fprintf(stderr, a, b, c, d, e);
|
||
exit(1);
|
||
}
|
||
|
||
/*
|
||
* init - Initialization.
|
||
*/
|
||
init(argc, argv)
|
||
|
||
int argc;
|
||
char *argv[];
|
||
{
|
||
char *ap;
|
||
|
||
prname = argv[0];
|
||
argv[argc] = (char *)0; /* For the benefit of UNIX Version 6 */
|
||
header.x_magic = X_NU_MAGIC;
|
||
while(*++argv != (char *)0) {
|
||
ap = *argv;
|
||
if(*ap == '-') /* options */
|
||
while(*++ap != '\0')
|
||
switch(*ap) {
|
||
|
||
case 'd': /* debug flag on */
|
||
dbgflg = 1;
|
||
break;
|
||
case 'o': /* Next argument is output file */
|
||
if((outname = *++argv) == (char *)0)
|
||
usage();
|
||
break;
|
||
|
||
case 's': /* Force segmented magic number */
|
||
header.x_magic = X_SU_MAGIC;
|
||
break;
|
||
|
||
default: /* Illegal switch */
|
||
usage();
|
||
}
|
||
else { /* object file name */
|
||
if(objname != (char *)0)
|
||
usage();
|
||
objname = ap;
|
||
}
|
||
}
|
||
|
||
if(objname==(char *)0 || strcmp(&objname[strlen(objname)-4], ".obj")!=0)
|
||
usage();
|
||
if((objiop = fopenb(objname, "r")) == NULL)
|
||
ferr("Cannot open %s\n", objname);
|
||
if(strcmp(objname, outname) == 0)
|
||
ferr("Would destroy %s\n", objname);
|
||
|
||
/*
|
||
* The 0th entry in the segment table is the absolute segment.
|
||
* We will output it only if some code is generated into it. If we
|
||
* do end up outputting it, we will hard assign it to segment number 0.
|
||
*/
|
||
segtab[0].x_sg_typ = X_SG_BSS;
|
||
}
|
||
|
||
/*
|
||
* interlude - Performs interpass processing.
|
||
*/
|
||
interlude() {
|
||
|
||
long off;
|
||
uns *extptr;
|
||
int segno;
|
||
|
||
if(exttop == exttab) { /* No undefined externals, make executable */
|
||
header.x_magic = header.x_magic==X_SU_MAGIC ? X_SX_MAGIC : X_NXN_MAGIC;
|
||
outfd = creatb(outname, 0777);
|
||
} else
|
||
outfd = creatb(outname, 0666);
|
||
if(outfd == -1)
|
||
ferr("Cannot create %s\n", outname);
|
||
|
||
if(segtab[0].x_sg_typ==X_SG_BSS || segtab[0].x_sg_typ==X_SG_STK)
|
||
/*
|
||
* There is no code going into the absolute segment, so we skip it.
|
||
*/
|
||
firstseg = 1;
|
||
|
||
off = (sizeof header) + (header.x_nseg - firstseg) * sizeof(struct x_sg);
|
||
for(segno=0 ; segno<header.x_nseg ; segno++) {
|
||
segoff[segno] = off;
|
||
if(segtab[segno].x_sg_typ!=X_SG_BSS &&
|
||
segtab[segno].x_sg_typ!=X_SG_STK) {
|
||
off += segtab[segno].x_sg_len;
|
||
header.x_init += segtab[segno].x_sg_len;
|
||
}
|
||
}
|
||
reloff = off;
|
||
symoff = reloff + header.x_reloc;
|
||
|
||
curoff = 0L;
|
||
outhdr();
|
||
outseg();
|
||
}
|
||
|
||
/*
|
||
* ofill - Reads the next object block into objbuf, and returns the block type.
|
||
*/
|
||
ofill() {
|
||
|
||
int ch;
|
||
|
||
if((objtyp = getc(objiop)) == EOF) return(0);
|
||
if((ch = getc(objiop)) == EOF) ferr("Premature EOF\n");
|
||
objtop = &objbuf[ch];
|
||
for(objpt=objbuf ; objpt<objtop ; objpt++) {
|
||
if((ch = getc(objiop)) == EOF) ferr("Premature EOF\n");
|
||
*objpt = ch;
|
||
}
|
||
objpt = objbuf;
|
||
return(objtyp);
|
||
}
|
||
|
||
/*
|
||
* ogetb - Returns the next byte from the object buffer.
|
||
*/
|
||
uns
|
||
ogetb() {
|
||
|
||
if(objpt >= 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<XNAMELN ; i++) {
|
||
outb(*name);
|
||
if(*name != '\0')
|
||
name++;
|
||
}
|
||
symoff = curoff;
|
||
}
|
||
|
||
/*
|
||
* outtxt - Outputs a block of text for the specified offset in the specified
|
||
* segment. The text comes from txtptr and has txtct bytes.
|
||
*/
|
||
outtxt(offset, segment, txtptr, txtct)
|
||
|
||
uns offset;
|
||
int segment;
|
||
char *txtptr;
|
||
int txtct;
|
||
{
|
||
long txtoff;
|
||
|
||
txtoff = segoff[segment] + (long)offset;
|
||
if(curoff != txtoff)
|
||
lseek(outfd, curoff = txtoff, 0);
|
||
write(outfd, txtptr, txtct);
|
||
curoff += txtct;
|
||
}
|
||
|
||
/*
|
||
* outw - Outputs a single word to the .out file. The word is written in
|
||
* Z8000 (MSB first) format, regardless of the host processor.
|
||
*/
|
||
outw(val)
|
||
|
||
uns val;
|
||
{
|
||
char buf[2];
|
||
|
||
buf[1] = val;
|
||
val >>= 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);
|
||
}
|