int rdfopenhere(rdffile *f, FILE *fp, int *refcount, char *name) { char buf[8]; long initpos; if (translatelong(0x01020304) != 0x01020304) { /* fix this to be portable! */ fputs("*** this program requires a little endian machine\n",stderr); fprintf(stderr,"01020304h = %08lxh\n",translatelong(0x01020304)); exit(3); } f->fp = fp; initpos = ftell(fp); fread(buf,6,1,f->fp); /* read header */ buf[6] = 0; if (strcmp(buf,RDOFFId)) { fclose(f->fp); return rdf_errno = 2; /* error 2: invalid file format */ } if (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); 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; } f->code_ofs = ftell(f->fp); if (fseek(f->fp,f->code_len,SEEK_CUR)) { fclose(f->fp); return rdf_errno = 2; } if (fread(&f->data_len,1,4,f->fp) != 4) { fclose(f->fp); return rdf_errno = 3; } f->data_ofs = ftell(f->fp); fseek(f->fp,initpos,SEEK_SET); f->header_loc = NULL; f->name = newstr(name); f->refcount = refcount; if (refcount) (*refcount)++; return 0; }
void print_header(long length) { char buf[129],t,s,l; long o,ll; short rs; while (length > 0) { fread(&t,1,1,infile); switch(t) { case 1: /* relocation record */ fread(&s,1,1,infile); fread(&o,4,1,infile); fread(&l,1,1,infile); fread(&rs,2,1,infile); printf(" relocation: location (%04x:%08lx), length %d, " "referred seg %04x\n",(int)s,translatelong(o),(int)l, translateshort(rs)); length -= 9; break; case 2: /* import record */ fread(&rs,2,1,infile); ll = 0; do { fread(&buf[ll],1,1,infile); } while (buf[ll++]); printf(" import: segment %04x = %s\n",translateshort(rs),buf); length -= ll + 3; break; case 3: /* export record */ fread(&s,1,1,infile); fread(&o,4,1,infile); ll = 0; do { fread(&buf[ll],1,1,infile); } while (buf[ll++]); printf(" export: (%04x:%08lx) = %s\n",(int)s,translatelong(o),buf); length -= ll + 6; break; case 4: /* DLL record */ ll = 0; do { fread(&buf[ll],1,1,infile); } while (buf[ll++]); printf(" dll: %s\n",buf); length -= ll + 1; break; case 5: /* BSS reservation */ fread(&ll,4,1,infile); printf(" bss reservation: %08lx bytes\n",translatelong(ll)); length -= 5; break; default: printf(" unrecognised record (type %d)\n",(int)t); length --; } } }
int rdfwriteheader(FILE * fp, rdf_headerbuf * h) { long l, l2; fwrite (RDOFFId, 1, strlen(RDOFFId), 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->buf, fp); return 0; /* no error handling in here... CHANGE THIS! */ }
int rdfwriteheader(FILE * fp, rdf_headerbuf * h) { long l; fwrite (RDOFFId, 1, strlen(RDOFFId), fp) ; l = translatelong ( membuflength (h) ); fwrite (&l, 4, 1, fp); membufdump(h, fp); return 0; /* no error handling in here... CHANGE THIS! */ }
/* * write_output() * * this takes the linked list of modules, and walks through it, merging * all the modules into a single output module, and then writes this to a * file. */ void write_output(const char *filename) { FILE *f; rdf_headerbuf *rdfheader; struct modulenode *cur; int i, availableseg, seg, localseg, isrelative; void *header; rdfheaderrec *hr, newrec; symtabEnt *se; segtab segs; long offset; byte *data; if ((f = fopen(filename, "wb")) == NULL) { fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename); exit(1); } if ((rdfheader = rdfnewheader()) == NULL) { fprintf(stderr, "ldrdf: out of memory\n"); exit(1); } /* * If '-g' option was given, first record in output file will be a * `generic' record, filled with a given file content. * This can be useful, for example, when constructing multiboot * compliant kernels. */ if (generic_rec_file) { FILE *ff; if (options.verbose) printf("\nadding generic record from binary file %s\n", generic_rec_file); hr = (rdfheaderrec *) malloc(sizeof(struct GenericRec)); if ((ff = fopen(generic_rec_file, "r")) == NULL) { fprintf(stderr, "ldrdf: couldn't open %s for input\n", generic_rec_file); exit(1); } i = fread(hr->g.data, 1, sizeof(hr->g.data), ff); fseek(ff, 0, SEEK_END); if (ftell(ff) > sizeof(hr->g.data)) { fprintf(error_file, "warning: maximum generic record size is %d, rest of file ignored\n", sizeof(hr->g.data)); } fclose(ff); hr->g.type = 0; hr->g.reclen = i; rdfaddheader(rdfheader, hr); free(hr); } if (options.verbose) printf("\nbuilding output module (%d segments)\n", nsegs); /* * Allocate the memory for the segments. We may be better off * building the output module one segment at a time when running * under 16 bit DOS, but that would be a slower way of doing this. * And you could always use DJGPP... */ for (i = 0; i < nsegs; i++) { outputseg[i].data = NULL; if (!outputseg[i].length) continue; outputseg[i].data = malloc(outputseg[i].length); if (!outputseg[i].data) { fprintf(stderr, "ldrdf: out of memory\n"); exit(1); } } /* * initialise availableseg, used to allocate segment numbers for * imported and exported labels... */ availableseg = nsegs; /* * Step through the modules, performing required actions on each one */ for (cur = modules; cur; cur = cur->next) { /* * Read the actual segment contents into the correct places in * the newly allocated segments */ for (i = 0; i < cur->f.nsegs; i++) { int dest = cur->seginfo[i].dest_seg; if (dest == -1) continue; if (rdfloadseg(&cur->f, i, outputseg[dest].data + cur->seginfo[i].reloc)) { rdfperror("ldrdf", cur->name); exit(1); } } /* * Perform fixups, and add new header records where required */ header = malloc(cur->f.header_len); if (!header) { fprintf(stderr, "ldrdf: out of memory\n"); exit(1); } if (cur->f.header_loc) rdfheaderrewind(&cur->f); else if (rdfloadseg(&cur->f, RDOFF_HEADER, header)) { rdfperror("ldrdf", cur->name); exit(1); } /* * we need to create a local segment number -> location * table for the segments in this module. */ init_seglocations(&segs); for (i = 0; i < cur->f.nsegs; i++) { add_seglocation(&segs, cur->f.seg[i].number, cur->seginfo[i].dest_seg, cur->seginfo[i].reloc); } /* * and the BSS segment (doh!) */ add_seglocation(&segs, 2, 2, cur->bss_reloc); while ((hr = rdfgetheaderrec(&cur->f))) { switch (hr->type) { case RDFREC_RELOC: /* relocation record - need to do a fixup */ /* * First correct the offset stored in the segment from * the start of the segment (which may well have changed). * * To do this we add to the number stored the relocation * factor associated with the segment that contains the * target segment. * * The relocation could be a relative relocation, in which * case we have to first subtract the amount we've relocated * the containing segment by. */ if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) { fprintf(stderr, "%s: reloc to undefined segment %04x\n", cur->name, (int)hr->r.refseg); errorcount++; break; } isrelative = (hr->r.segment & RDOFF_RELATIVEMASK) == RDOFF_RELATIVEMASK; hr->r.segment &= (RDOFF_RELATIVEMASK - 1); if (hr->r.segment == 2 || (localseg = rdffindsegment(&cur->f, hr->r.segment)) == -1) { fprintf(stderr, "%s: reloc from %s segment (%d)\n", cur->name, hr->r.segment == 2 ? "BSS" : "unknown", hr->r.segment); errorcount++; break; } if (hr->r.length != 1 && hr->r.length != 2 && hr->r.length != 4) { fprintf(stderr, "%s: nonstandard length reloc " "(%d bytes)\n", cur->name, hr->r.length); errorcount++; break; } /* * okay, now the relocation is in the segment pointed to by * cur->seginfo[localseg], and we know everything else is * okay to go ahead and do the relocation */ data = outputseg[cur->seginfo[localseg].dest_seg].data; data += cur->seginfo[localseg].reloc + hr->r.offset; /* * data now points to the reference that needs * relocation. Calculate the relocation factor. * Factor is: * offset of referred object in segment [in offset] * (- relocation of localseg, if ref is relative) * For simplicity, the result is stored in 'offset'. * Then add 'offset' onto the value at data. */ if (isrelative) offset -= cur->seginfo[localseg].reloc; switch (hr->r.length) { case 1: offset += *data; if (offset < -127 || offset > 128) fprintf(error_file, "warning: relocation out of range " "at %s(%02x:%08lx)\n", cur->name, (int)hr->r.segment, hr->r.offset); *data = (char)offset; break; case 2: offset += *(short *)data; if (offset < -32767 || offset > 32768) fprintf(error_file, "warning: relocation out of range " "at %s(%02x:%08lx)\n", cur->name, (int)hr->r.segment, hr->r.offset); *(short *)data = (short)offset; break; case 4: *(long *)data += offset; /* we can't easily detect overflow on this one */ break; } /* * If the relocation was relative between two symbols in * the same segment, then we're done. * * Otherwise, we need to output a new relocation record * with the references updated segment and offset... */ if (!isrelative || cur->seginfo[localseg].dest_seg != seg) { hr->r.segment = cur->seginfo[localseg].dest_seg; hr->r.offset += cur->seginfo[localseg].reloc; hr->r.refseg = seg; if (isrelative) hr->r.segment += RDOFF_RELATIVEMASK; rdfaddheader(rdfheader, hr); } break; case RDFREC_IMPORT: /* import symbol */ case RDFREC_FARIMPORT: /* * scan the global symbol table for the symbol * and associate its location with the segment number * for this module */ se = symtabFind(symtab, hr->i.label); if (!se || se->segment == -1) { if (!options.dynalink && !(hr->i.flags & SYM_IMPORT)) { fprintf(error_file, "error: unresolved reference to `%s'" " in module `%s'\n", hr->i.label, cur->name); errorcount++; } /* * we need to allocate a segment number for this * symbol, and store it in the symbol table for * future reference */ if (!se) { se = malloc(sizeof(*se)); if (!se) { fprintf(stderr, "ldrdf: out of memory\n"); exit(1); } se->name = strdup(hr->i.label); se->flags = 0; se->segment = availableseg++; se->offset = 0; symtabInsert(symtab, se); } else { se->segment = availableseg++; se->offset = 0; } /* * output a header record that imports it to the * recently allocated segment number... */ newrec = *hr; newrec.i.segment = se->segment; rdfaddheader(rdfheader, &newrec); } add_seglocation(&segs, hr->i.segment, se->segment, se->offset); break; case RDFREC_GLOBAL: /* export symbol */ /* * need to insert an export for this symbol into the new * header, unless we're stripping symbols. Even if we're * stripping, put the symbol if it's marked as SYM_GLOBAL. */ if (options.strip && !(hr->e.flags & SYM_GLOBAL)) break; if (hr->e.segment == 2) { seg = 2; offset = cur->bss_reloc; } else { localseg = rdffindsegment(&cur->f, hr->e.segment); if (localseg == -1) { fprintf(stderr, "%s: exported symbol `%s' from " "unrecognised segment\n", cur->name, hr->e.label); errorcount++; break; } offset = cur->seginfo[localseg].reloc; seg = cur->seginfo[localseg].dest_seg; } hr->e.segment = seg; hr->e.offset += offset; rdfaddheader(rdfheader, hr); break; case RDFREC_MODNAME: /* module name */ /* * Insert module name record if export symbols * are not stripped. * If module name begins with '$' - insert it anyway. */ if (options.strip && hr->m.modname[0] != '$') break; rdfaddheader(rdfheader, hr); break; case RDFREC_DLL: /* DLL name */ /* * Insert DLL name if it begins with '$' */ if (hr->d.libname[0] != '$') break; rdfaddheader(rdfheader, hr); break; case RDFREC_SEGRELOC: /* segment fixup */ /* * modify the segment numbers if necessary, and * pass straight through to the output module header * * *** FIXME *** */ if (hr->r.segment == 2) { fprintf(stderr, "%s: segment fixup in BSS section\n", cur->name); errorcount++; break; } localseg = rdffindsegment(&cur->f, hr->r.segment); if (localseg == -1) { fprintf(stderr, "%s: segment fixup in unrecognised" " segment (%d)\n", cur->name, hr->r.segment); errorcount++; break; } hr->r.segment = cur->seginfo[localseg].dest_seg; hr->r.offset += cur->seginfo[localseg].reloc; if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) { fprintf(stderr, "%s: segment fixup to undefined " "segment %04x\n", cur->name, (int)hr->r.refseg); errorcount++; break; } hr->r.refseg = seg; rdfaddheader(rdfheader, hr); break; case RDFREC_COMMON: /* Common variable */ /* Is this symbol already in the table? */ se = symtabFind(symtab, hr->c.label); if (!se) { printf("%s is not in symtab yet\n", hr->c.label); break; } /* Add segment location */ add_seglocation(&segs, hr->c.segment, se->segment, se->offset); break; } } free(header); done_seglocations(&segs); } /* * combined BSS reservation for the entire results */ newrec.type = RDFREC_BSS; newrec.b.reclen = 4; newrec.b.amount = bss_length; rdfaddheader(rdfheader, &newrec); /* * Write the header */ for (i = 0; i < nsegs; i++) { if (i == 2) continue; rdfaddsegment(rdfheader, outputseg[i].length); } rdfwriteheader(f, rdfheader); rdfdoneheader(rdfheader); /* * Step through the segments, one at a time, writing out into * the output file */ for (i = 0; i < nsegs; i++) { uint16 s; long l; if (i == 2) continue; s = translateshort(outputseg[i].type); fwrite(&s, 2, 1, f); s = translateshort(outputseg[i].number); fwrite(&s, 2, 1, f); s = translateshort(outputseg[i].reserved); fwrite(&s, 2, 1, f); l = translatelong(outputseg[i].length); fwrite(&l, 4, 1, f); fwrite(outputseg[i].data, outputseg[i].length, 1, f); } fwrite("\0\0\0\0\0\0\0\0\0\0", 10, 1, f); }
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! */ fputs("*** this program requires a little endian machine\n",stderr); fprintf(stderr,"01020304h = %08lxh\n",translatelong(0x01020304)); exit(3); } f->fp = fp; initpos = ftell(fp); fread(buf,6,1,f->fp); /* read header */ buf[6] = 0; 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(&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(&s,1,2,f->fp) != 2) { fclose(f->fp); return rdf_errno = 3; } f->nsegs = 0; 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; } } 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; f->name = newstr(name); f->refcount = refcount; if (refcount) (*refcount)++; return 0; }
void print_header(long length, int rdf_version) { char buf[129],t,s,l,flags; unsigned char reclen; long o,ll; int16 rs; struct tMultiBootHeader *mb; while (length > 0) { fread(&t,1,1,infile); if (rdf_version >= 2) { fread(&reclen,1,1,infile); } switch(t) { case 1: /* relocation record */ case 6: /* segment relocation */ fread(&s,1,1,infile); fread(&o,4,1,infile); fread(&l,1,1,infile); fread(&rs,2,1,infile); printf(" %s: location (%04x:%08lx), length %d, " "referred seg %04x\n", t == 1 ? "relocation" : "seg relocation", (int)s,translatelong(o),(int)l, translateshort(rs)); if (rdf_version >= 2 && reclen != 8) printf(" warning: reclen != 8\n"); if (rdf_version == 1) length -= 9; if (rdf_version == 1 && t == 6) printf(" warning: seg relocation not supported in RDOFF1\n"); break; case 2: /* import record */ case 7: /* import far symbol */ fread(&rs,2,1,infile); ll = 0; if (rdf_version == 1) { do { fread(&buf[ll],1,1,infile); } while (buf[ll++]); } else { for (;ll < reclen - 2; ll++) fread(&buf[ll],1,1,infile); } printf(" %simport: segment %04x = %s\n",t == 7 ? "far " : "", translateshort(rs),buf); if (rdf_version == 1) length -= ll + 3; if (rdf_version == 1 && t == 7) printf (" warning: far import not supported in RDOFF1\n"); break; case 3: /* export record */ fread(&flags,1,1,infile); fread(&s,1,1,infile); fread(&o,4,1,infile); ll = 0; if (rdf_version == 1) { do { fread(&buf[ll],1,1,infile); } while (buf[ll++]); } else { for (; ll < reclen - 6; ll ++) fread(&buf[ll],1,1,infile); } if (flags & SYM_GLOBAL) printf(" export"); else printf(" global"); if (flags & SYM_FUNCTION) printf(" proc"); if (flags & SYM_DATA) printf(" data"); printf(": (%04x:%08lx) = %s\n",(int)s,translatelong(o),buf); if (rdf_version == 1) length -= ll + 6; break; case 4: /* DLL and Module records */ case 8: ll = 0; if (rdf_version == 1) { do { fread(&buf[ll],1,1,infile); } while (buf[ll++]); } else { for (; ll < reclen; ll++) fread(&buf[ll],1,1,infile); } if (t==4) printf(" dll: %s\n",buf); else printf(" module: %s\n",buf); if (rdf_version == 1) length -= ll + 1; break; case 5: /* BSS reservation */ fread(&ll,4,1,infile); printf(" bss reservation: %08lx bytes\n",translatelong(ll)); if (rdf_version == 1) length -= 5; if (rdf_version > 1 && reclen != 4) printf(" warning: reclen != 4\n"); break; case 9: /* MultiBoot header record */ fread(buf,reclen,1,infile); mb = (struct tMultiBootHeader *)buf; printf(" multiboot header: load address=0x%X, size=0x%X, entry=0x%X\n", mb->LoadAddr, mb->LoadEndAddr - mb->LoadAddr, mb->Entry); break; default: printf(" unrecognised record (type %d",(int)t); if (rdf_version > 1) { printf(", length %d",(int)reclen); fseek(infile,reclen,SEEK_CUR); } printf(")\n"); if (rdf_version == 1) length --; } if (rdf_version != 1) length -= 2 + reclen; } }
int main(int argc,char **argv) { char id[7]; long l; int16 s; int verbose = 0; long offset; int foundnullsegment = 0; int version; long segmentcontentlength = 0; int nsegments = 0; long headerlength = 0; long objectlength = 0; puts("RDOFF Dump utility v2.1\n(c) Copyright 1996,99,2000 Julian R Hall, Yuri M Zaporogets"); if (argc < 2) { fputs("Usage: rdfdump [-v] <filename>\n",stderr); exit(1); } if (! strcmp (argv[1], "-v") ) { verbose = 1; if (argc < 3) { fputs("required parameter missing\n",stderr); exit(1); } argv++; } infile = fopen(argv[1],"rb"); if (! infile) { fprintf(stderr,"rdfdump: Could not open %s\n",argv[1]); exit(1); } fread(id,6,1,infile); if (strncmp(id,"RDOFF",5)) { fputs("rdfdump: File does not contain valid RDOFF header\n",stderr); exit(1); } printf("File %s: RDOFF version %c\n\n",argv[1],id[5]); if (id[5] < '1' || id[5] > '2') { fprintf(stderr,"rdfdump: unknown RDOFF version '%c'\n",id[5]); exit(1); } version = id[5] - '0'; if (version > 1) { fread(&l, 4, 1, infile); objectlength = translatelong(l); printf("Object content size: %ld bytes\n", objectlength); } fread(&l,4,1,infile); headerlength = translatelong(l); printf("Header (%ld bytes):\n",headerlength); print_header(headerlength, version); if (version == 1) { fread(&l,4,1,infile); l = translatelong(l); printf("\nText segment length = %ld bytes\n",l); offset = 0; while(l--) { fread(id,1,1,infile); if (verbose) { if (offset % 16 == 0) printf("\n%08lx ", offset); printf(" %02x",(int) (unsigned char)id[0]); offset++; } } if (verbose) printf("\n\n"); fread(&l,4,1,infile); l = translatelong(l); printf("Data segment length = %ld bytes\n",l); if (verbose) { offset = 0; while (l--) { fread(id,1,1,infile); if (offset % 16 == 0) printf("\n%08lx ", offset); printf(" %02x",(int) (unsigned char) id[0]); offset++; } printf("\n"); } } else { do { fread(&s,2,1,infile); s = translateshort(s); if (!s) { printf("\nNULL segment\n"); foundnullsegment = 1; break; } printf("\nSegment:\n Type = %04X (%s)\n",(int)s, translatesegmenttype(s)); nsegments++; fread(&s,2,1,infile); printf(" Number = %04X\n",(int)translateshort(s)); fread(&s,2,1,infile); printf(" Resrvd = %04X\n",(int)translateshort(s)); fread(&l,4,1,infile); l = translatelong(l); printf(" Length = %ld bytes\n",l); segmentcontentlength += l; offset = 0; while(l--) { fread(id,1,1,infile); if (verbose) { if (offset % 16 == 0) printf("\n%08lx ", offset); printf(" %02x",(int) (unsigned char)id[0]); offset++; } } if (verbose) printf("\n"); } while (!feof(infile)); if (! foundnullsegment) printf("\nWarning: unexpected end of file - " "NULL segment not found\n"); printf("\nTotal number of segments: %d\n", nsegments); printf("Total segment content length: %ld bytes\n",segmentcontentlength); /* calculate what the total object content length should have been */ l = segmentcontentlength + 10 * (nsegments+1) + headerlength + 4; if (l != objectlength) printf("Warning: actual object length (%ld) != " "stored object length (%ld)\n", l, objectlength); } fclose(infile); return 0; }
/* * write_output() * * this takes the linked list of modules, and walks through it, merging * all the modules into a single output module, and then writes this to a * file. */ void write_output(const char * filename) { FILE * f = fopen(filename, "wb"); rdf_headerbuf * rdfheader = rdfnewheader(); struct modulenode * cur; int i, availableseg, seg, localseg, isrelative; void * header; rdfheaderrec * hr, newrec; symtabEnt * se; segtab segs; long offset; byte * data; if (!f) { fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename); exit(1); } if (!rdfheader) { fprintf(stderr, "ldrdf: out of memory\n"); exit(1); } if (options.verbose) printf ("\nbuilding output module (%d segments)\n", nsegs); /* * Allocate the memory for the segments. We may be better off * building the output module one segment at a time when running * under 16 bit DOS, but that would be a slower way of doing this. * And you could always use DJGPP... */ for (i = 0; i < nsegs; i++) { outputseg[i].data = malloc(outputseg[i].length); if (!outputseg[i].data) { fprintf(stderr, "ldrdf: out of memory\n"); exit(1); } } /* * initialise availableseg, used to allocate segment numbers for * imported and exported labels... */ availableseg = nsegs; /* * Step through the modules, performing required actions on each one */ for (cur = modules; cur; cur=cur->next) { /* * Read the actual segment contents into the correct places in * the newly allocated segments */ for (i = 0; i < cur->f.nsegs; i++) { int dest = cur->seginfo[i].dest_seg; if (dest == -1) continue; if (rdfloadseg(&cur->f, i, outputseg[dest].data + cur->seginfo[i].reloc)) { rdfperror("ldrdf", cur->name); exit(1); } } /* * Perform fixups, and add new header records where required */ header = malloc(cur->f.header_len); if (!header) { fprintf(stderr, "ldrdf: out of memory\n"); exit(1); } if (cur->f.header_loc) rdfheaderrewind(&cur->f); else if (rdfloadseg(&cur->f, RDOFF_HEADER, header)) { rdfperror("ldrdf", cur->name); exit(1); } /* * we need to create a local segment number -> location * table for the segments in this module. */ init_seglocations(&segs); for (i = 0; i < cur->f.nsegs; i++) { add_seglocation(&segs, cur->f.seg[i].number, cur->seginfo[i].dest_seg, cur->seginfo[i].reloc); } /* * and the BSS segment (doh!) */ add_seglocation (&segs, 2, 2, cur->bss_reloc); while ((hr = rdfgetheaderrec(&cur->f))) { switch(hr->type) { case 1: /* relocation record - need to do a fixup */ /* * First correct the offset stored in the segment from * the start of the segment (which may well have changed). * * To do this we add to the number stored the relocation * factor associated with the segment that contains the * target segment. * * The relocation could be a relative relocation, in which * case we have to first subtract the amount we've relocated * the containing segment by. */ if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) { fprintf(stderr, "%s: reloc to undefined segment %04x\n", cur->name, (int) hr->r.refseg); errorcount++; break; } isrelative = (hr->r.segment & 64) == 64; hr->r.segment &= 63; if (hr->r.segment == 2 || (localseg = rdffindsegment(&cur->f, hr->r.segment)) == -1) { fprintf(stderr, "%s: reloc from %s segment (%d)\n", cur->name, hr->r.segment == 2 ? "BSS" : "unknown", hr->r.segment); errorcount++; break; } if (hr->r.length != 1 && hr->r.length != 2 && hr->r.length!=4) { fprintf(stderr, "%s: nonstandard length reloc " "(%d bytes)\n", cur->name, hr->r.length); errorcount++; break; } /* * okay, now the relocation is in the segment pointed to by * cur->seginfo[localseg], and we know everything else is * okay to go ahead and do the relocation */ data = outputseg[cur->seginfo[localseg].dest_seg].data; data += cur->seginfo[localseg].reloc + hr->r.offset; /* * data now points to the reference that needs * relocation. Calculate the relocation factor. * Factor is: * offset of referred object in segment [in offset] * (- relocation of localseg, if ref is relative) * For simplicity, the result is stored in 'offset'. * Then add 'offset' onto the value at data. */ if (isrelative) offset -= cur->seginfo[localseg].reloc; switch (hr->r.length) { case 1: offset += *data; if (offset < -127 || offset > 128) fprintf(stderr, "warning: relocation out of range " "at %s(%02x:%08lx)\n", cur->name, (int)hr->r.segment, hr->r.offset); *data = (char) offset; break; case 2: offset += * (short *)data; if (offset < -32767 || offset > 32768) fprintf(stderr, "warning: relocation out of range " "at %s(%02x:%08lx)\n", cur->name, (int)hr->r.segment, hr->r.offset); * (short *)data = (short) offset; break; case 4: * (long *)data += offset; /* we can't easily detect overflow on this one */ break; } /* * If the relocation was relative between two symbols in * the same segment, then we're done. * * Otherwise, we need to output a new relocation record * with the references updated segment and offset... */ if (! isrelative || cur->seginfo[localseg].dest_seg != seg) { hr->r.segment = cur->seginfo[localseg].dest_seg; hr->r.offset += cur->seginfo[localseg].reloc; hr->r.refseg = seg; rdfaddheader(rdfheader, hr); } break; case 2: /* import symbol */ case 7: /* * scan the global symbol table for the symbol * and associate its location with the segment number * for this module */ se = symtabFind(symtab, hr->i.label); if (!se || se->segment == -1) { if (options.warnUnresolved) { fprintf(stderr, "warning: unresolved reference to `%s'" " in module `%s'\n", hr->i.label, cur->name); } /* * we need to allocate a segment number for this * symbol, and store it in the symbol table for * future reference */ if (!se) { se=malloc(sizeof(*se)); if (!se) { fprintf(stderr, "ldrdf: out of memory\n"); exit(1); } se->name = strdup(hr->i.label); se->flags = 0; se->segment = availableseg++; se->offset = 0; symtabInsert(symtab, se); } else { se->segment = availableseg++; se->offset = 0; } /* * output a header record that imports it to the * recently allocated segment number... */ newrec = *hr; newrec.i.segment = se->segment; rdfaddheader(rdfheader, &newrec); } add_seglocation(&segs, hr->i.segment, se->segment, se->offset); break; case 3: /* export symbol */ /* * need to insert an export for this symbol into the new * header, unless we're stripping symbols [unless this * symbol is in an explicit keep list]. *** FIXME *** */ if (options.strip) break; if (hr->e.segment == 2) { seg = 2; offset = cur->bss_reloc; } else { localseg = rdffindsegment(&cur->f, hr->e.segment); if (localseg == -1) { fprintf(stderr, "%s: exported symbol `%s' from " "unrecognised segment\n", cur->name, hr->e.label); errorcount++; break; } offset = cur->seginfo[localseg].reloc; seg = cur->seginfo[localseg].dest_seg; } hr->e.segment = seg; hr->e.offset += offset; rdfaddheader(rdfheader, hr); break; case 6: /* segment fixup */ /* * modify the segment numbers if necessary, and * pass straight through to the output module header * * *** FIXME *** */ if (hr->r.segment == 2) { fprintf(stderr, "%s: segment fixup in BSS section\n", cur->name); errorcount++; break; } localseg = rdffindsegment(&cur->f, hr->r.segment); if (localseg == -1) { fprintf(stderr, "%s: segment fixup in unrecognised" " segment (%d)\n", cur->name, hr->r.segment); errorcount++; break; } hr->r.segment = cur->seginfo[localseg].dest_seg; hr->r.offset += cur->seginfo[localseg].reloc; if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) { fprintf(stderr, "%s: segment fixup to undefined " "segment %04x\n", cur->name, (int)hr->r.refseg); errorcount++; break; } hr->r.refseg = seg; rdfaddheader(rdfheader, hr); break; } } free(header); done_seglocations(&segs); } /* * combined BSS reservation for the entire results */ newrec.type = 5; newrec.b.reclen = 4; newrec.b.amount = bss_length; rdfaddheader(rdfheader, &newrec); /* * Write the header */ for (i = 0; i < nsegs; i++) { if (i == 2) continue; rdfaddsegment (rdfheader, outputseg[i].length); } rdfwriteheader(f, rdfheader); rdfdoneheader(rdfheader); /* * Step through the segments, one at a time, writing out into * the output file */ for (i = 0; i < nsegs; i++) { int16 s; long l; if (i == 2) continue; s = translateshort(outputseg[i].type); fwrite(&s, 2, 1, f); s = translateshort(outputseg[i].number); fwrite(&s, 2, 1, f); s = translateshort(outputseg[i].reserved); fwrite(&s, 2, 1, f); l = translatelong(outputseg[i].length); fwrite(&l, 4, 1, f); fwrite(outputseg[i].data, outputseg[i].length, 1, f); } fwrite("\0\0\0\0\0\0\0\0\0\0", 10, 1, f); }
int main(int argc,char **argv) { char id[7]; long l; int verbose = 0; long offset; puts("RDOFF Dump utility v1.1 (C) Copyright 1996 Julian R Hall"); if (argc < 2) { fputs("Usage: rdfdump [-v] <filename>\n",stderr); exit(1); } if (! strcmp (argv[1], "-v") ) { verbose = 1; if (argc < 3) { fputs("required parameter missing\n",stderr); exit(1); } argv++; } infile = fopen(argv[1],"rb"); if (! infile) { fprintf(stderr,"rdfdump: Could not open %s",argv[1]); exit(1); } fread(id,6,1,infile); if (strncmp(id,"RDOFF",5)) { fputs("rdfdump: File does not contain valid RDOFF header\n",stderr); exit(1); } printf("File %s: RDOFF version %c\n\n",argv[1],id[5]); if (id[5] < '1' || id[5] > '1') { fprintf(stderr,"rdfdump: unknown RDOFF version '%c'\n",id[5]); exit(1); } fread(&l,4,1,infile); l = translatelong(l); printf("Header (%ld bytes):\n",l); print_header(l); fread(&l,4,1,infile); l = translatelong(l); printf("\nText segment length = %ld bytes\n",l); offset = 0; while(l--) { fread(id,1,1,infile); if (verbose) { if (offset % 16 == 0) printf("\n%08lx ", offset); printf(" %02x",(int) (unsigned char)id[0]); offset++; } } if (verbose) printf("\n\n"); fread(&l,4,1,infile); l = translatelong(l); printf("Data segment length = %ld bytes\n",l); if (verbose) { offset = 0; while (l--) { fread(id,1,1,infile); if (offset % 16 == 0) printf("\n%08lx ", offset); printf(" %02x",(int) (unsigned char) id[0]); offset++; } printf("\n"); } fclose(infile); return 0; }