void ex_asgn() { SymTabEntry* p; struct item* q; SymTabEntry* symtabLhsEntry; int i; p = (SymTabEntry*)sp[-1]; q = (struct item *) sp[-1]; /* just to get item->index * further down, q is reassigned */ switch (p->entryType) { case QV: i = q->index; /* get the pointer to applicable quad service routine */ (*exop[i])(1); return; case LV: symtabLhsEntry = symtabFind(p->namep); if (symtabLhsEntry == NULL) { symtabLhsEntry = symtabInsert(p->namep); } if (symtabLhsEntry != NULL) { symtabLhsEntry->entryType = LV; } if (p->itemp != NULL && p->itemp->itemType == LBL) error(ERR_implicit, "attempt to reassign a label value"); if (symtabLhsEntry == NULL) { error(ERR, "asgn - panic"); } break; default: error(ERR, "asgn - panic"); } if (p->entryUse != UNKNOWN && p->entryUse != DA) { error(ERR_domain, "asgn"); } sp--; q = fetch1(); erase(p); symtabLhsEntry->entryUse = DA; symtabLhsEntry->itemp = q; sp[-1] = (struct item*) symtabLhsEntry; if (vars_trace) { vars_dump(); } }
/* * symtab_get() * * Retrieves the values associated with a symbol. Undefined symbols * are assumed to have -1:0 associated. Returns 1 if the symbol was * successfully located. */ int symtab_get(const char *symbol, int *segment, long *offset) { symtabEnt *ste = symtabFind(symtab, symbol); if (!ste) { *segment = -1; *offset = 0; return 0; } else { *segment = ste->segment; *offset = ste->offset; return 1; } }
/* * symtab_add() * * inserts a symbol into the global symbol table, which associates symbol * names either with addresses, or a marker that the symbol hasn't been * resolved yet, or possibly that the symbol has been defined as * contained in a dynamic [load time/run time] linked library. * * segment = -1 => not yet defined * segment = -2 => defined as dll symbol * * If the symbol is already defined, and the new segment >= 0, then * if the original segment was < 0 the symbol is redefined, otherwise * a duplicate symbol warning is issued. If new segment == -1, this * routine won't change a previously existing symbol. It will change * to segment = -2 only if the segment was previously < 0. */ void symtab_add(const char *symbol, int segment, long offset) { symtabEnt *ste; ste = symtabFind(symtab, symbol); if (ste) { if (ste->segment >= 0) { /* * symbol previously defined */ if (segment < 0) return; fprintf(error_file, "warning: `%s' redefined\n", symbol); return; } /* * somebody wanted the symbol, and put an undefined symbol * marker into the table */ if (segment == -1) return; /* * we have more information now - update the symbol's entry */ ste->segment = segment; ste->offset = offset; ste->flags = 0; return; } /* * this is the first declaration of this symbol */ ste = malloc(sizeof(symtabEnt)); if (!ste) { fprintf(stderr, "ldrdf: out of memory\n"); exit(1); } ste->name = strdup(symbol); ste->segment = segment; ste->offset = offset; ste->flags = 0; symtabInsert(symtab, ste); }
/* * 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); }
/* * processmodule() * * step through each segment, determine what exactly we're doing with * it, and if we intend to keep it, determine (a) which segment to * put it in and (b) whereabouts in that segment it will end up. * (b) is fairly easy, because we're now keeping track of how big each * segment in our output file is... */ void processmodule(const char *filename, struct modulenode *mod) { struct segconfig sconf; int seg, outseg; void *header; rdfheaderrec *hr; long bssamount = 0; int bss_was_referenced = 0; for (seg = 0; seg < mod->f.nsegs; seg++) { /* * get the segment configuration for this type from the segment * table. getsegconfig() is a macro, defined in ldsegs.h. */ getsegconfig(sconf, mod->f.seg[seg].type); if (options.verbose > 1) { printf("%s %04x [%04x:%10s] ", filename, mod->f.seg[seg].number, mod->f.seg[seg].type, sconf.typedesc); } /* * sconf->dowhat tells us what to do with a segment of this type. */ switch (sconf.dowhat) { case SEG_IGNORE: /* * Set destination segment to -1, to indicate that this segment * should be ignored for the purpose of output, ie it is left * out of the linked executable. */ mod->seginfo[seg].dest_seg = -1; if (options.verbose > 1) printf("IGNORED\n"); break; case SEG_NEWSEG: /* * The configuration tells us to create a new segment for * each occurrence of this segment type. */ outseg = allocnewseg(sconf.mergetype, mod->f.seg[seg].reserved); mod->seginfo[seg].dest_seg = outseg; mod->seginfo[seg].reloc = 0; outputseg[outseg].length = mod->f.seg[seg].length; if (options.verbose > 1) printf("=> %04x:%08lx (+%04lx)\n", outseg, mod->seginfo[seg].reloc, mod->f.seg[seg].length); break; case SEG_MERGE: /* * The configuration tells us to merge the segment with * a previously existing segment of type 'sconf.mergetype', * if one exists. Otherwise a new segment is created. * This is handled transparently by 'findsegment()'. */ outseg = findsegment(sconf.mergetype, mod->f.seg[seg].reserved); mod->seginfo[seg].dest_seg = outseg; /* * We need to add alignment to these segments. */ if (outputseg[outseg].length % options.align != 0) outputseg[outseg].length += options.align - (outputseg[outseg].length % options.align); mod->seginfo[seg].reloc = outputseg[outseg].length; outputseg[outseg].length += mod->f.seg[seg].length; if (options.verbose > 1) printf("=> %04x:%08lx (+%04lx)\n", outseg, mod->seginfo[seg].reloc, mod->f.seg[seg].length); } } /* * extract symbols from the header, and dump them into the * symbol table */ header = malloc(mod->f.header_len); if (!header) { fprintf(stderr, "ldrdf: not enough memory\n"); exit(1); } if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) { rdfperror("ldrdf", filename); exit(1); } while ((hr = rdfgetheaderrec(&mod->f))) { switch (hr->type) { case RDFREC_IMPORT: /* imported symbol */ case RDFREC_FARIMPORT: /* Define with seg = -1 */ symtab_add(hr->i.label, -1, 0); break; case RDFREC_GLOBAL:{ /* exported symbol */ int destseg; long destreloc; if (hr->e.segment == 2) { bss_was_referenced = 1; destreloc = bss_length; if (destreloc % options.align != 0) destreloc += options.align - (destreloc % options.align); destseg = 2; } else { if ((destseg = mod->seginfo[(int)hr->e.segment].dest_seg) == -1) continue; destreloc = mod->seginfo[(int)hr->e.segment].reloc; } symtab_add(hr->e.label, destseg, destreloc + hr->e.offset); break; } case RDFREC_BSS: /* BSS reservation */ /* * first, amalgamate all BSS reservations in this module * into one, because we allow this in the output format. */ bssamount += hr->b.amount; break; case RDFREC_COMMON:{ /* Common variable */ symtabEnt *ste = symtabFind(symtab, hr->c.label); /* Is the symbol already in the table? */ if (ste) break; /* Align the variable */ if (bss_length % hr->c.align != 0) bss_length += hr->c.align - (bss_length % hr->c.align); if (options.verbose > 1) { printf("%s %04x common '%s' => 0002:%08lx (+%04lx)\n", filename, hr->c.segment, hr->c.label, bss_length, hr->c.size); } symtab_add(hr->c.label, 2, bss_length); mod->bss_reloc = bss_length; bss_length += hr->c.size; break; } } } if (bssamount != 0 || bss_was_referenced) { /* * handle the BSS segment - first pad the existing bss length * to the correct alignment, then store the length in bss_reloc * for this module. Then add this module's BSS length onto * bss_length. */ if (bss_length % options.align != 0) bss_length += options.align - (bss_length % options.align); mod->bss_reloc = bss_length; if (options.verbose > 1) { printf("%s 0002 [ BSS] => 0002:%08lx (+%04lx)\n", filename, bss_length, bssamount); } bss_length += bssamount; } #ifdef STINGY_MEMORY /* * we free the header buffer here, to save memory later. * this isn't efficient, but probably halves the memory usage * of this program... */ mod->f.header_loc = NULL; free(header); #endif }
/* * 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); }