⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ldrdf.c

📁 一个免费的汇编语言编译器的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
}

/*
 * 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 + -