📄 ldrdf.c
字号:
{
/* we're only interested in exports, so skip others: */
if (hr->type != 3) continue;
/*
* Find the symbol 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);
processmodule(f.name, lastmodule);
break;
}
if (!keepfile)
rdfclose(&f);
}
if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND)
rdl_perror("ldrdf", cur->name);
cur = cur->next;
}
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 = 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);
}
/* =========================================================================
* Main program
*/
void usage()
{
printf("usage:\n");
printf(" ldrdf [options] object modules ... [-llibrary ...]\n");
printf(" ldrdf -r\n");
printf("options:\n");
printf(" -v[=n] increases verbosity by 1, or sets it to n\n");
printf(" -a nn sets segment alignment value (default 16)\n");
printf(" -s strips exported symbols\n");
printf(" -x warn about unresolved symbols\n");
printf(" -o name write output in file 'name'\n");
printf("\n");
printf("Note: no library searching is performed. Please specify full\n");
printf("paths to all files referenced.\n");
exit(0);
}
int main(int argc, char ** argv)
{
char * outname = "aout.rdf";
int moduleloaded = 0;
options.verbose = 0;
options.align = 16;
options.warnUnresolved = 0;
options.strip = 0;
argc --, argv ++;
if (argc == 0) usage();
while (argc && **argv == '-' && argv[0][1] != 'l')
{
switch(argv[0][1]) {
case 'r':
printf("ldrdf (linker for RDF files) version " LDRDF_VERSION "\n");
printf( _RDOFF_H "\n");
exit(0);
case 'v':
if (argv[0][2] == '=') {
options.verbose = argv[0][3] - '0';
if (options.verbose < 0 || options.verbose > 9) {
fprintf(stderr, "ldrdf: verbosity level must be a number"
" between 0 and 9\n");
exit(1);
}
}
else
options.verbose++;
break;
case 'a':
options.align = atoi(argv[1]);
if (options.align <= 0) {
fprintf(stderr,
"ldrdf: -a expects a positive number argument\n");
exit(1);
}
argv++, argc--;
break;
case 's':
options.strip = 1;
break;
case 'x':
options.warnUnresolved = 1;
break;
case 'o':
outname = argv[1];
argv++, argc--;
break;
default:
usage();
}
argv++, argc--;
}
if (options.verbose > 4) {
printf("ldrdf invoked with options:\n");
printf(" section alignment: %d bytes\n", options.align);
printf(" output name: `%s'\n", outname);
if (options.strip)
printf(" strip symbols\n");
if (options.warnUnresolved)
printf(" warn about unresolved symbols\n");
printf("\n");
}
symtab = symtabNew();
initsegments();
if (!symtab) {
fprintf(stderr, "ldrdf: out of memory\n");
exit(1);
}
while (argc)
{
if (!strncmp(*argv, "-l", 2)) /* library */
add_library(*argv + 2);
else {
loadmodule(*argv);
moduleloaded = 1;
}
argv++, argc--;
}
if (! moduleloaded) {
printf("ldrdf: nothing to do. ldrdf -h for usage\n");
return 0;
}
search_libraries();
if (options.verbose > 2)
{
printf ("symbol table:\n");
symtabDump(symtab, stdout);
}
write_output(outname);
if (errorcount > 0)
exit(1);
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -