Files
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

599 lines
14 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/******************************************************************************
*******************************************************************************
**
** 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);
}