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

📄 ldrdf.c

📁 开源的nasm编译器源码,研究编译器原理很有帮且
💻 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 + -