📄 ld.c
字号:
/* * Copyright (c) 1980 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */#ifndef lintchar copyright[] ="@(#) Copyright (c) 1980 Regents of the University of California.\n\ All rights reserved.\n";#endif#ifndef lintstatic char *sccsid = "@(#)ld.c 4.4 ULTRIX 9/17/90";#endif/************************************************************************ * * * Copyright (c) 1985, 1987, 1988 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//************************************************************************ * * * Modification History * * * * 014 Ken Lesniak, 05-Dec-89 * * Added Bflag to tell ld to force BSS to start on a 512 byte * * (hardware page) boundary. * * * * 013 Mark Parenti, 08-Jun-88 * * Changed signal handlers to void. * * * * 012 Jon Reeves, 24-Nov-87 * * Add logic for execution mode (a_mode field). * * * * 011 Jon Reeves, 05-Aug-87 * * Don't scribble on start of string table when the link includes * * a null file by name. * * * * 010 Jon Reeves, 01-Jun-87 * * Incorporate 4.3 changes (mostly -L option) * * * * 009 Jon Reeves, 01-Jun-87 * * Don't make -r output executable unless -d present. Avoids * * user errors and increases X/OPEN compliance. * * * * 008 Victoria Holt, 01-Jul-86 * * Now output 3 N_NSYMS records, using stabcnt.n_value field only, * * to avoid possible overflow. * * * * 007 Victoria Holt, 23-Dec-85 * * Bug fix: increment nfun counter for local routines (see * * vjh007 in source). * * * * 006 Robert Rodriguez, 15-Sep-85 * * Add 4.3 speed ups (subsumed in 010) * * * * 005 Victoria Holt, 29-Aug-85 * * Big fix: ld output N_NSYMS record when -x switch was specified.* * Harmless, but shouldn't have been there by definition of the * * switch. * * * * 004 Victoria Holt, 14-Jun-85 * * ld will now count the number of functions, source lines, and * * source files; this information is output in a stab record of * * type N_NSYMS for use by dbx. It must be the first stab entry * * in the symbol table. * * * * David L Ballenger, 17-May-1985 * * 003 Fix for QPR-00078. The -H option did not work properly. The * * size argument was being used to increase the base address for * * the data section, but the textsize written to the a.out header * * was not increased accordingly. * * * * 002- David L Ballenger, 07-Sep-84 * * Fix error with definiton of "position" formal parameter for * * load2td function. * * * * Stephen Reilly, 15-Feb-84 * * 001- Fix some dereferencing of NULL pointers (partially subsumed in * * 010). * * * ************************************************************************//* * ld - string table version for VAX */#include <sys/param.h>#include <signal.h>#include <strings.h>#include <stdio.h>#include <ctype.h>#include <ar.h>#include <a.out.h>#include <stab.h>#include <ranlib.h>#include <sys/stat.h>#include <sys/file.h>/* * Basic strategy: * * The loader takes a number of files and libraries as arguments. * A first pass examines each file in turn. Normal files are * unconditionally loaded, and the (external) symbols they define and require * are noted in the symbol table. Libraries are searched, and the * library members which define needed symbols are remembered * in a special data structure so they can be selected on the second * pass. Symbols defined and required by library members are also * recorded. * * After the first pass, the loader knows the size of the basic text * data, and bss segments from the sum of the sizes of the modules which * were required. It has computed, for each ``common'' symbol, the * maximum size of any reference to it, and these symbols are then assigned * storage locations after their sizes are appropriately rounded. * The loader now knows all sizes for the eventual output file, and * can determine the final locations of external symbols before it * begins a second pass. * * On the second pass each normal file and required library member * is processed again. The symbol table for each such file is * reread and relevant parts of it are placed in the output. The offsets * in the local symbol table for externally defined symbols are recorded * since relocation information refers to symbols in this way. * Armed with all necessary information, the text and data segments * are relocated and the result is placed in the output file, which * is pasted together, ``in place'', by writing to it in several * different places concurrently. *//* * Internal data structures * * All internal data structures are segmented and dynamically extended. * The basic structures hold 1103 (NSYM) symbols, ~~200 (NROUT) * referenced library members, and 100 (NSYMPR) private (local) symbols * per object module. For large programs and/or modules, these structures * expand to be up to 40 (NSEG) times as large as this as necessary. */#define NSEG 40 /* Number of segments, each data structure */#define NSYM 1103 /* Number of symbols per segment */#define NROUT 250 /* Number of library references per segment */#define NSYMPR 100 /* Number of private symbols per segment *//* * Structure describing each symbol table segment. * Each segment has its own hash table. We record the first * address in and first address beyond both the symbol and hash * tables, for use in the routine symx and the lookup routine respectively. * The symfree routine also understands this structure well as it used * to back out symbols from modules we decide that we don't need in pass 1. * * Csymseg points to the current symbol table segment; * csymseg->sy_first[csymseg->sy_used] is the next symbol slot to be allocated, * (unless csymseg->sy_used == NSYM in which case we will allocate another * symbol table segment first.) */struct symseg { struct nlist *sy_first; /* base of this alloc'ed segment */ struct nlist *sy_last; /* end of this segment, for n_strx */ int sy_used; /* symbols used in this seg */ struct nlist **sy_hfirst; /* base of hash table, this seg */ struct nlist **sy_hlast; /* end of hash table, this seg */} symseg[NSEG], *csymseg;/* * The lookup routine uses quadratic rehash. Since a quadratic rehash * only probes 1/2 of the buckets in the table, and since the hash * table is segmented the same way the symbol table is, we make the * hash table have twice as many buckets as there are symbol table slots * in the segment. This guarantees that the quadratic rehash will never * fail to find an empty bucket if the segment is not full and the * symbol is not there. */#define HSIZE (NSYM*2)/* * Xsym converts symbol table indices (ala x) into symbol table pointers. * Symx (harder, but never used in loops) inverts pointers into the symbol * table into indices using the symseg[] structure. */#define xsym(x) (symseg[(x)/NSYM].sy_first+((x)%NSYM))/* symx() is a function, defined below */struct nlist cursym; /* current symbol */struct nlist *lastsym; /* last symbol entered */struct nlist *nextsym; /* next available symbol table entry */struct nlist *addsym; /* first sym defined during incr load */int nsym; /* pass2: number of local symbols in a.out *//* nsym + symx(nextsym) is the symbol table size during pass2 */struct nlist **lookup(), **slookup();struct nlist *p_etext, *p_edata, *p_end, *entrypt;/* * Definitions of segmentation for library member table. * For each library we encounter on pass 1 we record pointers to all * members which we will load on pass 2. These are recorded as offsets * into the archive in the library member table. Libraries are * separated in the table by the special offset value -1. */off_t li_init[NROUT];struct libseg { off_t *li_first; int li_used; int li_used2;} libseg[NSEG] = { li_init, 0, 0,}, *clibseg = libseg;/* * In processing each module on pass 2 we must relocate references * relative to external symbols. These references are recorded * in the relocation information as relative to local symbol numbers * assigned to the external symbols when the module was created. * Thus before relocating the module in pass 2 we create a table * which maps these internal numbers to symbol table entries. * A hash table is constructed, based on the local symbol table indices, * for quick lookup of these symbols. */#define LHSIZ 31struct local { int l_index; /* index to symbol in file */ struct nlist *l_symbol; /* ptr to symbol table */ struct local *l_link; /* hash link */} *lochash[LHSIZ], lhinit[NSYMPR];struct locseg { struct local *lo_first; int lo_used;} locseg[NSEG] = { lhinit, 0}, *clocseg;/* * Libraries are typically built with a table of contents, * which is the first member of a library with special file * name __.SYMDEF and contains a list of symbol names * and with each symbol the offset of the library member which defines * it. The loader uses this table to quickly tell which library members * are (potentially) useful. The alternative, examining the symbol * table of each library member, is painfully slow for large archives. * * See <ranlib.h> for the definition of the ranlib structure and an * explanation of the __.SYMDEF file format. */int tnum; /* number of symbols in table of contents */int ssiz; /* size of string table for table of contents */struct ranlib *tab; /* the table of contents (dynamically allocated) */char *tabstr; /* string table for table of contents *//* * We open each input file or library only once, but in pass2 we * (historically) read from such a file at 2 different places at the * same time. These structures are remnants from those days, * and now serve only to catch ``Premature EOF''. * In order to make I/O more efficient, we provide routines which * use the optimal block size returned by stat(). */#define BLKSIZE 1024typedef struct { short *fakeptr; int bno; int nibuf; int nuser; char *buff; int bufsize;} PAGE;PAGE page[2];int p_blksize;int p_blkshift;int p_blkmask;struct { short *fakeptr; int bno; int nibuf; int nuser;} fpage;typedef struct { char *ptr; int bno; int nibuf; long size; long pos; PAGE *pno;} STREAM;STREAM text;STREAM reloc;/* * Header from the a.out and the archive it is from (if any). */struct exec filhdr;struct ar_hdr archdr;#define OARMAG 0177545/* * Options. */int trace;int xflag; /* discard local symbols */int Xflag; /* discard locals starting with 'L' */int Sflag; /* discard all except locals and globals*/int rflag; /* preserve relocation bits, don't define common */int arflag; /* original copy of rflag */int sflag; /* discard all symbols */int Mflag; /* print rudimentary load map */int nflag; /* pure procedure */int dflag; /* define common even with rflag */int zflag; /* demand paged */long hsize; /* size of hole at beginning of data to be squashed */int Bflag; /* set if want 512 byte alignment on BSS */int Aflag; /* doing incremental load */int Nflag; /* want impure a.out */int funding; /* reading fundamental file for incremental load */int yflag; /* number of symbols to be traced */int gflag; /* link for debugging */char **ytab; /* the symbols */enum Mode { sys_v, posix, bsd} ex_mode = bsd; /* 012 - execution mode; changed by -Y/PROG_ENV *//* * These are the cumulative sizes, set in pass 1, which * appear in the a.out header when the loader is finished. */off_t tsize, dsize, bsize, trsize, drsize, ssize;/* Number of functions (estimate), number of source lines, and * number of source files. This information is provided for dbx. * and is used when gflag is true (when linking -lg). (vjh) */unsigned long nsline;unsigned long nfun;unsigned long nsol;/* * Symbol relocation: c?rel is a scale factor which is * added to an old relocation to convert it to new units; * i.e. it is the difference between segment origins. * (Thus if we are loading from a data segment which began at location * 4 in a .o file into an a.out where it will be loaded starting at * 1024, cdrel will be 1020.) */long ctrel, cdrel, cbrel;/* * Textbase is the start address of all text, 0 unless given by -T. * Database is the base of all data, computed before and used during pass2. */long textbase, database;/* * The base addresses for the loaded text, data and bss from the * current module during pass2 are given by torigin, dorigin and borigin. */long torigin, dorigin, borigin;/* * Errlev is nonzero when errors have occured. * Delarg is an implicit argument to the routine delexit * which is called on error. We do ``delarg = errlev'' before normal * exits, and only if delarg is 0 (i.e. errlev was 0) do we make the * result file executable. */int errlev;int delarg = 4;/* * The biobuf structure and associated routines are used to write * into one file at several places concurrently. Calling bopen * with a biobuf structure sets it up to write ``biofd'' starting * at the specified offset. You can then use ``bwrite'' and/or ``bputc'' * to stuff characters in the stream, much like ``fwrite'' and ``fputc''. * Calling bflush drains all the buffers and MUST be done before exit. */struct biobuf { short b_nleft; /* Number free spaces left in b_buf *//* Initialize to be less than b_bufsize initially, to boundary align in file */ char *b_ptr; /* Next place to stuff characters */ char *b_buf; /* Pointer to the buffer */ int b_bufsize; /* Size of the buffer */ off_t b_off; /* Current file offset */ struct biobuf *b_link; /* Link in chain for bflush() */} *biobufs;#define bputc(c,b) ((b)->b_nleft ? (--(b)->b_nleft, *(b)->b_ptr++ = (c)) \ : bflushc(b, c))int biofd;off_t boffset;struct biobuf *tout, *dout, *trout, *drout, *sout, *strout;/* * Offset is the current offset in the string file. * Its initial value reflects the fact that we will * eventually stuff the size of the string table at the * beginning of the string table (i.e. offset itself!). */off_t offset = sizeof (off_t);int ofilfnd; /* -o given; otherwise move l.out to a.out */char *ofilename = "l.out";int ofilemode; /* respect umask even for unsucessful ld's */int infil; /* current input file descriptor */char *filname; /* and its name */#define NDIRS 25#define NDEFDIRS 3 /* number of default directories in dirs[] */char *dirs[NDIRS]; /* directories for library search */int ndir; /* number of directories *//* * Base of the string table of the current module (pass1 and pass2). */char *curstr;/* * System software page size, as returned by getpagesize. */int pagesize;char get();void delexit();char *savestr();char *malloc();char *getenv();main(argc, argv)char **argv;{ register int c, i; int num; register char *ap, **p; char *pep; char save; if (signal(SIGINT, SIG_IGN) != SIG_IGN) { signal(SIGINT, delexit); signal(SIGTERM, delexit); } if (argc == 1) exit(4); pagesize = getpagesize(); if ( strcmp("SYSTEM_FIVE",pep=getenv("PROG_ENV")) == 0) ex_mode = sys_v; else if ( strcmp("POSIX",pep) == 0) ex_mode = posix; else if ( strcmp("BSD",pep) == 0) ex_mode = bsd; /* * Pull out search directories. */ for (c = 1; c < argc; c++) { ap = argv[c]; if (ap[0] == '-' && ap[1] == 'L') { if (ap[2] == 0) error(1, "-L: pathname missing"); if (ndir >= NDIRS - NDEFDIRS) error(1, "-L: too many directories"); dirs[ndir++] = &ap[2]; } } /* add default search directories */ dirs[ndir++] = "/lib"; dirs[ndir++] = "/usr/lib"; dirs[ndir++] = "/usr/local/lib"; p = argv+1; /* * Scan files once to find where symbols are defined. */ for (c=1; c<argc; c++) { if (trace) printf("%s:\n", *p); filname = 0; ap = *p++; if (*ap != '-') { load1arg(ap); continue; } for (i=1; ap[i]; i++) switch (ap[i]) { case 'o': if (++c >= argc) error(1, "-o where?"); ofilename = *p++; ofilfnd++; continue; case 'u': case 'e': if (++c >= argc) error(1, "-u or -e: arg missing"); enter(slookup(*p++)); if (ap[i]=='e') entrypt = lastsym; continue; case 'H': if (++c >= argc) error(1, "-H: arg missing"); if (tsize!=0) error(1, "-H: too late, some text already loaded"); hsize = atoi(*p++); continue; case 'B': Bflag++; continue; case 'A': if (++c >= argc) error(1, "-A: arg missing"); if (Aflag) error(1, "-A: only one base file allowed"); Aflag = 1; nflag = 0; funding = 1; load1arg(*p++); trsize = drsize = tsize = dsize = bsize = 0; ctrel = cdrel = cbrel = 0; funding = 0; addsym = nextsym; continue; case 'D': if (++c >= argc) error(1, "-D: arg missing"); num = htoi(*p++); if (dsize > num) error(1, "-D: too small"); dsize = num; continue; case 'T': if (++c >= argc) error(1, "-T: arg missing"); if (tsize!=0) error(1, "-T: too late, some text already loaded"); textbase = htoi(*p++); continue; case 'l': save = ap[--i]; ap[i]='-'; load1arg(&ap[i]); ap[i]=save; goto next; case 'M': Mflag++; continue;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -