int findsegment(int16 type,int16 reserved) { int i; for (i = 0; i < nsegs; i++) if (outputseg[i].type == type) return i; return allocnewseg(type,reserved); }
/* * 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 }