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

📄 ldrdf.c

📁 一个免费的汇编语言编译器的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* ldrdf.c      RDOFF Object File linker/loader main program
 *
 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
 * Julian Hall. All rights reserved. The software is
 * redistributable under the licence given in the file "Licence"
 * distributed in the NASM archive.
 */

/*
 * TODO:
 * - enhance search of required export symbols in libraries (now depends
 *   on modules order in library)
 * - keep a cache of symbol names in each library module so
 *   we don't have to constantly recheck the file
 * - general performance improvements
 *
 * BUGS & LIMITATIONS: this program doesn't support multiple code, data
 * or bss segments, therefore for 16 bit programs whose code, data or BSS
 * segment exceeds 64K in size, it will not work. This program probably
 * won't work if compiled by a 16 bit compiler. Try DJGPP if you're running
 * under DOS. '#define STINGY_MEMORY' may help a little.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "rdoff.h"
#include "symtab.h"
#include "collectn.h"
#include "rdlib.h"
#include "segtab.h"

#define LDRDF_VERSION "1.05"

#define RDF_MAXSEGS 64
/* #define STINGY_MEMORY */

/* =======================================================================
 * Types & macros that are private to this program
 */

struct segment_infonode {
    int		dest_seg;	/* output segment to be placed into, -1 to 
				   skip linking this segment */
    long	reloc;		/* segment's relocation factor */
};


struct modulenode {
    rdffile	f;		/* the RDOFF file structure */
    struct segment_infonode seginfo[RDF_MAXSEGS]; /* what are we doing
						     with each segment? */
    void	* header;
    char	* name;
    struct modulenode * next;
    long	bss_reloc;
};

#include "ldsegs.h"

#define newstr(str) strcpy(malloc(strlen(str) + 1),str)
#define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1)+strlen(s2)+1),s1),s2)

/* ==========================================================================
 * Function prototypes of private utility functions
 */

void processmodule(const char * filename, struct modulenode * mod);
int allocnewseg(int16 type,int16 reserved);
int findsegment(int16 type,int16 reserved);
void symtab_add(const char * symbol, int segment, long offset);
int symtab_get(const char * symbol, int * segment, long * offset);

/* =========================================================================
 * Global data structures.
 */

/* a linked list of modules that will be included in the output */
struct modulenode 	* modules = NULL;
struct modulenode 	* lastmodule = NULL;

/* a linked list of libraries to be searched for unresolved imported symbols */
struct librarynode 	* libraries = NULL;
struct librarynode	* lastlib = NULL;

/* the symbol table */
void 			* symtab = NULL;

/* objects search path */
char			* objpath = NULL;

/* libraries search path */
char			* libpath = NULL;

/* file to embed as a generic record */
char			* generic_rec_file = NULL;

/* error file */
static FILE		* error_file;

/* the header of the output file, built up stage by stage */
rdf_headerbuf 		* newheader = NULL;

/* The current state of segment allocation, including information about
 * which output segment numbers have been allocated, and their types and
 * amount of data which has already been allocated inside them. 
 */
struct SegmentHeaderRec	outputseg[RDF_MAXSEGS];
int			nsegs = 0;
long			bss_length;

/* global options which affect how the program behaves */
struct ldrdfoptions {
    int		verbose;
    int		align;
    int		warnUnresolved;
    int		strip;
    int         respfile;
    int         stderr_redir;
    int         objpath;
    int         libpath;
} options;

int errorcount = 0;	/* determines main program exit status */


/* =========================================================================
 * Utility functions
 */


/*
 * initsegments()
 *
 * sets up segments 0, 1, and 2, the initial code data and bss segments
 */

void initsegments()
{
    nsegs = 3;
    outputseg[0].type = 1;
    outputseg[0].number = 0;
    outputseg[0].reserved = 0;
    outputseg[0].length = 0;
    outputseg[1].type = 2;
    outputseg[1].number = 1;
    outputseg[1].reserved = 0;
    outputseg[1].length = 0;
    outputseg[2].type = 0xFFFF;	/* reserved segment type */
    outputseg[2].number = 2;
    outputseg[2].reserved = 0;
    outputseg[2].length = 0;
    bss_length = 0;
}

/*
 * loadmodule
 *
 * Determine the characteristics of a module, and decide what to do with
 * each segment it contains (including determining destination segments and
 * relocation factors for segments that	are kept).
 */

void loadmodule(const char * filename)
{
    if (options.verbose)
	printf("loading `%s'\n", filename);

    /* allocate a new module entry on the end of the modules list */
    if (!modules)
    {
	modules = malloc (sizeof(*modules));
	lastmodule = modules;
    }
    else
    {
	lastmodule->next = malloc (sizeof(*modules));
	lastmodule = lastmodule->next;
    }

    if ( ! lastmodule)
    {
	fprintf(stderr, "ldrdf: out of memory\n");
	exit(1);
    }

    /* open the file using 'rdfopen', which returns nonzero on error */

    if (rdfopen(&lastmodule->f, filename) != 0)
    {
	rdfperror("ldrdf", filename);
	exit(1);
    }

    /* 
     * store information about the module, and determine what segments
     * it contains, and what we should do with them (determine relocation
     * factor if we decide to keep them)
     */

    lastmodule->header = NULL;
    lastmodule->name = strdup(filename);
    lastmodule->next = NULL;

    processmodule(filename, lastmodule);
}
	
/*
 * 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

}


/*
 * Look in the list for module by its name.
 */
int lookformodule(const char *name)
 {
  struct modulenode *curr=modules;

  while(curr) {
   if (!strcmp(name,curr->name)) return 1;
   curr = curr->next;
  }
  return 0;
 }


/*
 * allocnewseg()
 * findsegment()
 *
 * These functions manipulate the array of output segments, and are used
 * by processmodule(). allocnewseg() allocates a segment in the array,
 * initialising it to be empty. findsegment() first scans the array for
 * a segment of the type requested, and if one isn't found allocates a
 * new one.
 */
int allocnewseg(int16 type,int16 reserved)
{
    outputseg[nsegs].type = type;
    outputseg[nsegs].number = nsegs;
    outputseg[nsegs].reserved = reserved;
    outputseg[nsegs].length = 0;
    outputseg[nsegs].offset = 0;
    outputseg[nsegs].data = NULL;

    return nsegs++;
}

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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -