diff options
Diffstat (limited to 'rdoff/rdoff.c')
-rw-r--r-- | rdoff/rdoff.c | 356 |
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 *)∈ - r = i[3]; - r = (r << 8) + i[2]; - r = (r << 8) + i[1]; - r = (r << 8) + *i; + i = (unsigned char *)∈ + 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 *)∈ + 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); } |