aboutsummaryrefslogtreecommitdiffstats
path: root/rdoff/rdoff.c
diff options
context:
space:
mode:
Diffstat (limited to 'rdoff/rdoff.c')
-rw-r--r--rdoff/rdoff.c356
1 files changed, 235 insertions, 121 deletions
diff --git a/rdoff/rdoff.c b/rdoff/rdoff.c
index 96620ecc..7f4937ac 100644
--- a/rdoff/rdoff.c
+++ b/rdoff/rdoff.c
@@ -4,11 +4,19 @@
* Julian Hall. All rights reserved. The software is
* redistributable under the licence given in the file "Licence"
* distributed in the NASM archive.
+ *
+ * Permission to use this file in your own projects is granted, as long
+ * as acknowledgement is given in an appropriate manner to its authors,
+ * with instructions of how to obtain a copy via ftp.
*/
/* TODO: The functions in this module assume they are running
* on a little-endian machine. This should be fixed to
* make it portable.
+ *
+ * This module no longer supports RDOFF1. If anybody *really*
+ * needs the functionality of supporting both types at the
+ * same time, I'll add it back in.
*/
#include <stdio.h>
@@ -22,115 +30,146 @@
#define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1) + strlen(s2) + 1), \
s1),s2)
+/*
+ * Comment this out to allow the module to read & write header record types
+ * that it isn't aware of. With this defined, unrecognised header records
+ * will generate error number 8, reported as 'unknown extended header record'.
+ */
+
+#define STRICT_ERRORS
+
/* ========================================================================
* Code for memory buffers (for delayed writing of header until we know
* how long it is).
* ======================================================================== */
-memorybuffer * newmembuf(){
- memorybuffer * t;
+memorybuffer * newmembuf()
+{
+ memorybuffer * t;
- t = malloc(sizeof(memorybuffer));
+ t = malloc(sizeof(memorybuffer));
- t->length = 0;
- t->next = NULL;
- return t;
+ t->length = 0;
+ t->next = NULL;
+ return t;
}
-void membufwrite(memorybuffer *b, void *data, int bytes) {
- int16 w;
- long l;
-
- if (b->next) { /* memory buffer full - use next buffer */
- membufwrite(b->next,data,bytes);
- return;
- }
- if ((bytes < 0 && b->length - bytes > BUF_BLOCK_LEN)
- || (bytes > 0 && b->length + bytes > BUF_BLOCK_LEN)) {
-
- /* buffer full and no next allocated... allocate and initialise next
- * buffer */
+void membufwrite(memorybuffer *b, void *data, int bytes)
+{
+ int16 w;
+ long l;
- b->next = newmembuf();
- membufwrite(b->next,data,bytes);
- }
+ if (b->next) { /* memory buffer full - use next buffer */
+ membufwrite(b->next,data,bytes);
+ return;
+ }
- switch(bytes) {
- case -4: /* convert to little-endian */
- l = * (long *) data ;
- b->buffer[b->length++] = l & 0xFF;
- l >>= 8 ;
- b->buffer[b->length++] = l & 0xFF;
- l >>= 8 ;
- b->buffer[b->length++] = l & 0xFF;
- l >>= 8 ;
- b->buffer[b->length++] = l & 0xFF;
- break;
+ if ((bytes < 0 && b->length - bytes > BUF_BLOCK_LEN)
+ || (bytes > 0 && b->length + bytes > BUF_BLOCK_LEN))
+ {
+
+ /* buffer full and no next allocated... allocate and initialise next
+ * buffer */
+ b->next = newmembuf();
+ membufwrite(b->next,data,bytes);
+ return;
+ }
- case -2:
- w = * (int16 *) data ;
- b->buffer[b->length++] = w & 0xFF;
- w >>= 8 ;
- b->buffer[b->length++] = w & 0xFF;
- break;
+ switch(bytes) {
+ case -4: /* convert to little-endian */
+ l = * (long *) data ;
+ b->buffer[b->length++] = l & 0xFF;
+ l >>= 8 ;
+ b->buffer[b->length++] = l & 0xFF;
+ l >>= 8 ;
+ b->buffer[b->length++] = l & 0xFF;
+ l >>= 8 ;
+ b->buffer[b->length++] = l & 0xFF;
+ break;
- default:
- while(bytes--) {
- b->buffer[b->length++] = *(* (unsigned char **) &data);
+ case -2:
+ w = * (int16 *) data ;
+ b->buffer[b->length++] = w & 0xFF;
+ w >>= 8 ;
+ b->buffer[b->length++] = w & 0xFF;
+ break;
- (* (unsigned char **) &data)++ ;
+ default:
+ while(bytes--) {
+ b->buffer[b->length++] = *(* (unsigned char **) &data);
+
+ (* (unsigned char **) &data)++ ;
+ }
+ break;
}
- break;
- }
}
void membufdump(memorybuffer *b,FILE *fp)
{
- if (!b) return;
+ if (!b) return;
- fwrite (b->buffer, 1, b->length, fp);
+ fwrite (b->buffer, 1, b->length, fp);
- membufdump(b->next,fp);
+ membufdump(b->next,fp);
}
int membuflength(memorybuffer *b)
{
- if (!b) return 0;
- return b->length + membuflength(b->next);
+ if (!b) return 0;
+ return b->length + membuflength(b->next);
}
void freemembuf(memorybuffer *b)
{
- if (!b) return;
- freemembuf(b->next);
- free(b);
+ if (!b) return;
+ freemembuf(b->next);
+ free(b);
}
/* =========================================================================
General purpose routines and variables used by the library functions
========================================================================= */
-long translatelong(long in) { /* translate from little endian to
- local representation */
- long r;
- unsigned char *i;
+/*
+ * translatelong() and translateshort()
+ *
+ * translate from little endian to local representation
+ */
+long translatelong(long in)
+{
+ long r;
+ unsigned char *i;
- i = (unsigned char *)&in;
- r = i[3];
- r = (r << 8) + i[2];
- r = (r << 8) + i[1];
- r = (r << 8) + *i;
+ i = (unsigned char *)&in;
+ r = i[3];
+ r = (r << 8) + i[2];
+ r = (r << 8) + i[1];
+ r = (r << 8) + *i;
- return r;
+ return r;
}
-const char *RDOFFId = "RDOFF1"; /* written to the start of RDOFF files */
+int16 translateshort(int16 in)
+{
+ int16 r;
+ unsigned char * i;
+
+ i = (unsigned char *)&in;
+ r = (i[1] << 8) + i[0];
+
+ return r;
+}
+
+const char *RDOFFId = "RDOFF2"; /* written to the start of RDOFF files */
-const char *rdf_errors[7] = {
+const char *rdf_errors[11] = {
"no error occurred","could not open file","invalid file format",
"error reading file","unknown error","header not read",
- "out of memory"};
+ "out of memory", "RDOFF v1 not supported",
+ "unknown extended header record",
+ "header record of known type but unknown length",
+ "no such segment"};
int rdf_errno = 0;
@@ -145,13 +184,15 @@ int rdfopen(rdffile *f, const char *name)
fp = fopen(name,"rb");
if (!fp) return rdf_errno = 1; /* error 1: file open error */
- return rdfopenhere(f,fp,NULL,"");
+ return rdfopenhere(f,fp,NULL,name);
}
-int rdfopenhere(rdffile *f, FILE *fp, int *refcount, char *name)
+int rdfopenhere(rdffile *f, FILE *fp, int *refcount, const char *name)
{
char buf[8];
long initpos;
+ long l;
+ int16 s;
if (translatelong(0x01020304) != 0x01020304)
{ /* fix this to be portable! */
@@ -168,38 +209,61 @@ int rdfopenhere(rdffile *f, FILE *fp, int *refcount, char *name)
if (strcmp(buf,RDOFFId)) {
fclose(f->fp);
+ if (!strcmp(buf,"RDOFF1"))
+ return rdf_errno = 7; /* error 7: RDOFF 1 not supported */
return rdf_errno = 2; /* error 2: invalid file format */
}
- if (fread(&f->header_len,1,4,f->fp) != 4) {
+ if (fread(&l,1,4,f->fp) != 4 ||
+ fread(&f->header_len,1,4,f->fp) != 4) {
fclose(f->fp);
return rdf_errno = 3; /* error 3: file read error */
}
f->header_ofs = ftell(f->fp);
+ f->eof_offset = f->header_ofs + translatelong(l) - 4;
if (fseek(f->fp,f->header_len,SEEK_CUR)) {
fclose(f->fp);
return rdf_errno = 2; /* seek past end of file...? */
}
- if (fread(&f->code_len,1,4,f->fp) != 4) {
- fclose(f->fp);
- return rdf_errno = 3;
+ if (fread(&s,1,2,f->fp) != 2) {
+ fclose(f->fp);
+ return rdf_errno = 3;
}
- f->code_ofs = ftell(f->fp);
- if (fseek(f->fp,f->code_len,SEEK_CUR)) {
- fclose(f->fp);
- return rdf_errno = 2;
- }
+ f->nsegs = 0;
- if (fread(&f->data_len,1,4,f->fp) != 4) {
- fclose(f->fp);
- return rdf_errno = 3;
+ while (s != 0)
+ {
+ f->seg[f->nsegs].type = s;
+ if (fread(&f->seg[f->nsegs].number,1,2,f->fp) != 2 ||
+ fread(&f->seg[f->nsegs].reserved,1,2,f->fp) != 2 ||
+ fread(&f->seg[f->nsegs].length,1,4,f->fp) != 4)
+ {
+ fclose(f->fp);
+ return rdf_errno = 3;
+ }
+
+ f->seg[f->nsegs].offset = ftell(f->fp);
+ if (fseek(f->fp,f->seg[f->nsegs].length,SEEK_CUR)) {
+ fclose(f->fp);
+ return rdf_errno = 2;
+ }
+ f->nsegs++;
+
+ if (fread(&s,1,2,f->fp) != 2) {
+ fclose(f->fp);
+ return rdf_errno = 3;
+ }
}
- f->data_ofs = ftell(f->fp);
+ if (f->eof_offset != ftell(f->fp) + 8) /* +8 = skip null segment header */
+ {
+ fprintf(stderr, "warning: eof_offset [%ld] and actual eof offset "
+ "[%ld] don't match\n", f->eof_offset, ftell(f->fp) + 8);
+ }
fseek(f->fp,initpos,SEEK_SET);
f->header_loc = NULL;
@@ -211,7 +275,7 @@ int rdfopenhere(rdffile *f, FILE *fp, int *refcount, char *name)
int rdfclose(rdffile *f)
{
- if (! f->refcount || ! *--f->refcount)
+ if (! f->refcount || ! --(*f->refcount))
fclose(f->fp);
free(f->name);
@@ -228,6 +292,14 @@ void rdfperror(const char *app,const char *name)
}
+int rdffindsegment(rdffile * f, int segno)
+{
+ int i;
+ for (i = 0; i < f->nsegs; i++)
+ if (f->seg[i].number == segno) return i;
+ return -1;
+}
+
int rdfloadseg(rdffile *f,int segment,void *buffer)
{
long fpos;
@@ -235,22 +307,20 @@ int rdfloadseg(rdffile *f,int segment,void *buffer)
switch(segment) {
case RDOFF_HEADER:
- fpos = f->header_ofs;
- slen = f->header_len;
- f->header_loc = (char *)buffer;
- f->header_fp = 0;
- break;
- case RDOFF_CODE:
- fpos = f->code_ofs;
- slen = f->code_len;
- break;
- case RDOFF_DATA:
- fpos = f->data_ofs;
- slen = f->data_len;
- break;
+ fpos = f->header_ofs;
+ slen = f->header_len;
+ f->header_loc = (byte *)buffer;
+ f->header_fp = 0;
+ break;
default:
- fpos = 0;
- slen = 0;
+ if (segment < f->nsegs) {
+ fpos = f->seg[segment].offset;
+ slen = f->seg[segment].length;
+ f->seg[segment].data = (byte *)buffer;
+ }
+ else {
+ return rdf_errno = 10; /* no such segment */
+ }
}
if (fseek(f->fp,fpos,SEEK_SET))
@@ -291,8 +361,15 @@ rdfheaderrec *rdfgetheaderrec(rdffile *f)
if (f->header_fp >= f->header_len) return 0;
RI8(r.type);
+ RI8(r.g.reclen);
+
switch(r.type) {
case 1: /* Relocation record */
+ case 6:
+ if (r.r.reclen != 8) {
+ rdf_errno = 9;
+ return NULL;
+ }
RI8(r.r.segment);
RI32(r.r.offset);
RI8(r.r.length);
@@ -300,6 +377,7 @@ rdfheaderrec *rdfgetheaderrec(rdffile *f)
break;
case 2: /* Imported symbol record */
+ case 7:
RI16(r.i.segment);
RS(r.i.label,32);
break;
@@ -315,12 +393,21 @@ rdfheaderrec *rdfgetheaderrec(rdffile *f)
break;
case 5: /* BSS reservation record */
+ if (r.r.reclen != 4) {
+ rdf_errno = 9;
+ return NULL;
+ }
RI32(r.b.amount);
break;
default:
- rdf_errno = 2; /* invalid file */
+#ifdef STRICT_ERRORS
+ rdf_errno = 8; /* unknown header record */
return NULL;
+#else
+ for (i = 0; i < r.g.reclen; i++)
+ RI8(r.g.data[i]);
+#endif
}
return &r;
}
@@ -333,65 +420,92 @@ void rdfheaderrewind(rdffile *f)
rdf_headerbuf * rdfnewheader(void)
{
- return newmembuf();
+ rdf_headerbuf * hb = malloc(sizeof(hb));
+ if (hb == NULL) return NULL;
+
+ hb->buf = newmembuf();
+ hb->nsegments = 0;
+ hb->seglength = 0;
+
+ return hb;
}
int rdfaddheader(rdf_headerbuf * h, rdfheaderrec * r)
{
+#ifndef STRICT_ERRORS
+ int i;
+#endif
+ membufwrite(h->buf,&r->type,1);
+ membufwrite(h->buf,&r->g.reclen,1);
+
switch (r->type)
{
case 1:
- membufwrite(h,&r->type,1);
- membufwrite(h,&r->r.segment,1);
- membufwrite(h,&r->r.offset,-4);
- membufwrite(h,&r->r.length,1);
- membufwrite(h,&r->r.refseg,-2); /* 9 bytes written */
+ case 6:
+ membufwrite(h->buf,&r->r.segment,1);
+ membufwrite(h->buf,&r->r.offset,-4);
+ membufwrite(h->buf,&r->r.length,1);
+ membufwrite(h->buf,&r->r.refseg,-2); /* 9 bytes written */
break;
case 2: /* import */
- membufwrite(h,&r->type,1);
- membufwrite(h,&r->i.segment,-2);
- membufwrite(h,&r->i.label,strlen(r->i.label) + 1);
+ case 7:
+ membufwrite(h->buf,&r->i.segment,-2);
+ membufwrite(h->buf,&r->i.label,strlen(r->i.label) + 1);
break ;
case 3: /* export */
- membufwrite(h,&r->type,1);
- membufwrite(h,&r->e.segment,1);
- membufwrite(h,&r->e.offset,-4);
- membufwrite(h,&r->e.label,strlen(r->e.label) + 1);
+ membufwrite(h->buf,&r->e.segment,1);
+ membufwrite(h->buf,&r->e.offset,-4);
+ membufwrite(h->buf,&r->e.label,strlen(r->e.label) + 1);
break ;
case 4: /* DLL */
- membufwrite(h,&r->type,1);
- membufwrite(h,&r->d.libname,strlen(r->d.libname) + 1);
+ membufwrite(h->buf,&r->d.libname,strlen(r->d.libname) + 1);
break ;
case 5: /* BSS */
- membufwrite(h,&r->type,1);
- membufwrite(h,&r->b.amount,-4);
+ membufwrite(h->buf,&r->b.amount,-4);
break ;
default:
- return (rdf_errno = 2);
+#ifdef STRICT_ERRORS
+ return (rdf_errno = 8);
+#else
+ for (i = 0; i < r->g.reclen; i++)
+ membufwrite(h->buf, r->g.data[i], 1);
+#endif
}
return 0;
}
+int rdfaddsegment(rdf_headerbuf *h, long seglength)
+{
+ h->nsegments ++;
+ h->seglength += seglength;
+ return 0;
+}
+
int rdfwriteheader(FILE * fp, rdf_headerbuf * h)
{
- long l;
+ long l, l2;
fwrite (RDOFFId, 1, strlen(RDOFFId), fp) ;
- l = translatelong ( membuflength (h) );
- fwrite (&l, 4, 1, fp);
+ l = membuflength (h->buf);
+ l2 = l + 14 + 10*h->nsegments + h->seglength;
+ l = translatelong(l);
+ l2 = translatelong(l2);
+ fwrite (&l2, 4, 1, fp); /* object length */
+ fwrite (&l, 4, 1, fp); /* header length */
- membufdump(h, fp);
+ membufdump(h->buf, fp);
return 0; /* no error handling in here... CHANGE THIS! */
}
void rdfdoneheader(rdf_headerbuf * h)
{
- freemembuf(h);
+ freemembuf(h->buf);
+ free(h);
}