📄 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 + -