📄 ldrdf.c
字号:
}/* * 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);}/* * 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; }}/* * add_library() * * checks that a library can be opened and is in the correct format, * then adds it to the linked list of libraries. */void add_library(const char * name){ if (rdl_verify(name)) { rdl_perror("ldrdf", name); errorcount++; return; } if (! libraries) { lastlib = libraries = malloc(sizeof(*libraries)); if (! libraries) { fprintf(stderr, "ldrdf: out of memory\n"); exit(1); } } else { lastlib->next = malloc(sizeof(*libraries)); if (!lastlib->next) { fprintf(stderr, "ldrdf: out of memory\n"); exit(1); } lastlib = lastlib->next; } lastlib->next = NULL; if (rdl_open(lastlib, name)) { rdl_perror("ldrdf", name); errorcount++; return; }}/* * search_libraries() * * scans through the list of libraries, attempting to match symbols * defined in library modules against symbols that are referenced but * not defined (segment = -1 in the symbol table) * * returns 1 if any extra library modules are included, indicating that * another pass through the library list should be made (possibly). */int search_libraries(){ struct librarynode * cur; rdffile f; int i; void * header; int segment; long offset; int doneanything = 0, pass = 1, keepfile; rdfheaderrec * hr; cur = libraries; while (cur) { if (options.verbose > 2) printf("scanning library `%s', pass %d...\n", cur->name, pass); for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++) { if (pass == 2 && lookformodule(f.name)) continue; if (options.verbose > 3) printf(" looking in module `%s'\n", f.name); header = malloc(f.header_len); if (!header) { fprintf(stderr, "ldrdf: not enough memory\n"); exit(1); } if (rdfloadseg(&f, RDOFF_HEADER, header)) { rdfperror("ldrdf", f.name); errorcount++; return 0; } keepfile = 0; while ((hr = rdfgetheaderrec (&f))) { /* We're only interested in exports, so skip others */ if (hr->type != RDFREC_GLOBAL) continue; /* * If the symbol is marked as SYM_GLOBAL, somebody will be * definitely interested in it.. */ if ((hr->e.flags & SYM_GLOBAL) == 0) { /* * otherwise the symbol is just public. Find it in * the symbol table. If the symbol isn't defined, we * aren't interested, so go on to the next. * If it is defined as anything but -1, we're also not * interested. But if it is defined as -1, insert this * module into the list of modules to use, and go * immediately on to the next module... */ if (!symtab_get(hr->e.label, &segment, &offset) || segment != -1) continue; } doneanything = 1; keepfile = 1; /* * as there are undefined symbols, we can assume that * there are modules on the module list by the time * we get here. */ lastmodule->next = malloc(sizeof(*lastmodule->next)); if (!lastmodule->next) { fprintf(stderr, "ldrdf: not enough memory\n"); exit(1); } lastmodule = lastmodule->next; memcpy(&lastmodule->f, &f, sizeof(f)); lastmodule->name = strdup(f.name); lastmodule->next = NULL; processmodule(f.name, lastmodule); break; } if (!keepfile) { free(f.name); f.name = NULL; f.fp = NULL; } } if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND) rdl_perror("ldrdf", cur->name); cur = cur->next; if (cur == NULL && pass == 1) { cur = libraries; pass++; } } return doneanything;}/* * 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 & 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -