📄 ld.c
字号:
sp = xsym(i); switch (sp->n_type & (N_TYPE+N_EXT)) { case N_EXT+N_UNDF: if (arflag == 0) errlev |= 01; if ((arflag==0 || dflag) && sp->n_value==0) { if (sp==p_end || sp==p_etext || sp==p_edata) continue; if (nund==0) printf("Undefined:\n"); nund++; printf("%s\n", sp->n_un.n_name); } continue; case N_EXT+N_ABS: default: continue; case N_EXT+N_TEXT: sp->n_value += torigin; continue; case N_EXT+N_DATA: sp->n_value += dorigin; continue; case N_EXT+N_BSS: sp->n_value += borigin; continue; case N_EXT+N_COMM: sp->n_type = (sp->n_type & N_STAB) | (N_EXT+N_BSS); sp->n_value += corigin; continue; } } if (sflag || xflag) ssize = 0; bsize += csize; nsym = ssize / (sizeof cursym); if (Aflag) { fixspec(p_etext,torigin); fixspec(p_edata,dorigin); fixspec(p_end,borigin); }}fixspec(sym,offset) struct nlist *sym; long offset;{ if(symx(sym) < symx(addsym) && sym!=0) sym->n_value += offset;}ldrsym(sp, val, type) register struct nlist *sp; long val;{ if (sp == 0) return; if ((sp->n_type != N_EXT+N_UNDF || sp->n_value) && !Aflag) { printf("%s: ", sp->n_un.n_name); error(0, "user attempt to redfine loader-defined symbol"); return; } sp->n_type = type; sp->n_value = val;}off_t wroff;struct biobuf toutb;setupout(){ int bss; struct stat stbuf; extern char *sys_errlist[]; extern int errno; ofilemode = 0777 & ~umask(0); biofd = creat(ofilename, 0666 & ofilemode); if (biofd < 0) { filname = ofilename; /* kludge */ archdr.ar_name[0] = 0; /* kludge */ error(1, sys_errlist[errno]); /* kludge */ /* NOT REACHED */ } fstat(biofd, &stbuf); /* suppose file exists, wrong*/ if (stbuf.st_mode & 0111) { /* mode, ld fails? */ chmod(ofilename, stbuf.st_mode & 0666); ofilemode = stbuf.st_mode; } filhdr.a_magic = nflag ? NMAGIC : (zflag ? ZMAGIC : OMAGIC); filhdr.a_mode = (ex_mode == sys_v) ? A_SYSV : ((ex_mode == posix) ? A_POSIX : A_BSD); filhdr.a_text = nflag ? tsize : round(tsize, zflag ? pagesize : sizeof (long)); filhdr.a_data = zflag ? round(dsize, pagesize) : dsize; bss = bsize - (filhdr.a_data - dsize); if (bss < 0) bss = 0; filhdr.a_bss = bss; filhdr.a_trsize = trsize; filhdr.a_drsize = drsize; if (sflag) { filhdr.a_syms = 0; } else { filhdr.a_syms = ssize + (sizeof cursym)*symx(nextsym); /* There are three extra nlist entries added at the beginning * of the symbol table containing counts (see nsline, nfun) * for dbx, if the program was linked "-lg". (vjh) */ if (gflag) { filhdr.a_syms += (3 * sizeof(struct nlist)); } } if (entrypt) { if (entrypt->n_type!=N_EXT+N_TEXT) error(0, "entry point not in text"); else filhdr.a_entry = entrypt->n_value; } else filhdr.a_entry = 0; filhdr.a_trsize = (rflag ? trsize:0); filhdr.a_drsize = (rflag ? drsize:0); tout = &toutb; bopen(tout, 0, stbuf.st_blksize); bwrite((char *)&filhdr, sizeof (filhdr), tout); if (zflag) bseek(tout, pagesize); wroff = N_TXTOFF(filhdr) + filhdr.a_text; outb(&dout, filhdr.a_data, stbuf.st_blksize); if (rflag) { outb(&trout, filhdr.a_trsize, stbuf.st_blksize); outb(&drout, filhdr.a_drsize, stbuf.st_blksize); } if (sflag==0 || xflag==0) { outb(&sout, filhdr.a_syms, stbuf.st_blksize); wroff += sizeof (offset); outb(&strout, 0, stbuf.st_blksize); if (gflag) { outstabcnt(); } }}/* Routine to output the number of functions, source lines, and * source files. These records *must* be the first three records in * the symbol table, and are used by dbx in estimating the size of * some tables that it has to build. This information is present * only if -lg was specified. (vjh) */outstabcnt(){ struct nlist stabcnt; if (sflag || xflag) return; /* 005 - vjh */ stabcnt.n_type = N_NSYMS; stabcnt.n_un.n_name = 0; stabcnt.n_desc = 0; stabcnt.n_other = 0; stabcnt.n_value = nsol; /* This will be the first record in the symbol table. */ bwrite(&stabcnt, sizeof(stabcnt), sout); stabcnt.n_value = nfun; /* This will be the second record in the symbol table. */ bwrite(&stabcnt, sizeof(stabcnt), sout); stabcnt.n_value = nsline; /* This will be the third record in the symbol table. */ bwrite(&stabcnt, sizeof(stabcnt), sout);}outb(bp, inc, bufsize) register struct biobuf **bp;{ *bp = (struct biobuf *)malloc(sizeof (struct biobuf)); if (*bp == 0) error(1, "ran out of memory (outb)"); bopen(*bp, wroff, bufsize); wroff += inc;}load2arg(acp)char *acp;{ register char *cp; off_t loc; cp = acp; if (getfile(cp) == 0) { while (*cp) cp++; while (cp >= acp && *--cp != '/'); mkfsym(++cp); load2(0L); } else { /* scan archive members referenced */ for (;;) { if (clibseg->li_used2 == clibseg->li_used) { if (clibseg->li_used < NROUT) error(1, "libseg botch"); clibseg++; } loc = clibseg->li_first[clibseg->li_used2++]; if (loc == -1) break; dseek(&text, loc, (long)sizeof(archdr)); getarhdr(); mkfsym(archdr.ar_name); load2(loc + (long)sizeof(archdr)); } } close(infil);}load2(loc)long loc;{ int size; register struct nlist *sp; register struct local *lp; register int symno, i; int type; readhdr(loc); if (!funding) { ctrel = torigin; cdrel += dorigin; cbrel += borigin; } /* * Reread the symbol table, recording the numbering * of symbols for fixing external references. */ for (i = 0; i < LHSIZ; i++) lochash[i] = 0; clocseg = locseg; clocseg->lo_used = 0; symno = -1; loc += N_TXTOFF(filhdr); dseek(&text, loc+filhdr.a_text+filhdr.a_data+ filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms, sizeof(off_t)); mget(&size, sizeof(size), &text); dseek(&text, loc+filhdr.a_text+filhdr.a_data+ filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms+sizeof(off_t), size - sizeof(off_t)); curstr = (char *)malloc(size); if (curstr == NULL) error(1, "out of space reading string table (pass 2)"); mget(curstr+sizeof(off_t), size-sizeof(off_t), &text); dseek(&text, loc+filhdr.a_text+filhdr.a_data+ filhdr.a_trsize+filhdr.a_drsize, filhdr.a_syms); while (text.size > 0) { symno++; mget((char *)&cursym, sizeof(struct nlist), &text); if (cursym.n_un.n_strx) { if (cursym.n_un.n_strx<sizeof(size) || cursym.n_un.n_strx>=size) error(1, "bad string table index (pass 2)"); cursym.n_un.n_name = curstr + cursym.n_un.n_strx; }/* inline expansion of symreloc() */ switch (cursym.n_type & 017) { case N_TEXT: case N_EXT+N_TEXT: cursym.n_value += ctrel; break; case N_DATA: case N_EXT+N_DATA: cursym.n_value += cdrel; break; case N_BSS: case N_EXT+N_BSS: cursym.n_value += cbrel; break; case N_EXT+N_UNDF: break; default: if (cursym.n_type&N_EXT) cursym.n_type = N_EXT+N_ABS; }/* end inline expansion of symreloc() */ type = cursym.n_type; if (yflag && cursym.n_un.n_name) for (i = 0; i < yflag; i++) /* fast check for 2d character! */ if (ytab[i][1] == cursym.n_un.n_name[1] && !strcmp(ytab[i], cursym.n_un.n_name)) { tracesym(); break; } if ((type&N_EXT) == 0) { if (!sflag&&!xflag&& /* SLR001 */ (!Xflag||type&N_STAB||cursym.n_un.n_name[0]!='L')) symwrite(&cursym, sout); continue; } if (funding) continue; if ((sp = *lookup()) == 0) error(1, "internal error: symbol not found"); if (cursym.n_type == N_EXT+N_UNDF) { if (clocseg->lo_used == NSYMPR) { if (++clocseg == &locseg[NSEG]) error(1, "local symbol overflow"); clocseg->lo_used = 0; } if (clocseg->lo_first == 0) { clocseg->lo_first = (struct local *) malloc(NSYMPR * sizeof (struct local)); if (clocseg->lo_first == 0) error(1, "out of memory (clocseg)"); } lp = &clocseg->lo_first[clocseg->lo_used++]; lp->l_index = symno; lp->l_symbol = sp; lp->l_link = lochash[symno % LHSIZ]; lochash[symno % LHSIZ] = lp; continue; } if (cursym.n_type & N_STAB) continue; if (cursym.n_type!=sp->n_type || cursym.n_value!=sp->n_value) { printf("%s: ", cursym.n_un.n_name); error(0, "multiply defined"); } } if (funding) return; dseek(&text, loc, filhdr.a_text); dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize); load2td(ctrel, torigin - textbase, tout, trout); dseek(&text, loc+filhdr.a_text, filhdr.a_data); dseek(&reloc, loc+filhdr.a_text+filhdr.a_data+filhdr.a_trsize, filhdr.a_drsize); load2td(cdrel, dorigin - database, dout, drout); while (filhdr.a_data & (sizeof(long)-1)) { bputc(0, dout); filhdr.a_data++; } torigin += filhdr.a_text; dorigin += round(filhdr.a_data, sizeof (long)); borigin += round(filhdr.a_bss, sizeof (long)); free(curstr);}struct tynames { int ty_value; char *ty_name;} tynames[] = { N_UNDF, "undefined", N_ABS, "absolute", N_TEXT, "text", N_DATA, "data", N_BSS, "bss", N_COMM, "common", 0, 0,};tracesym(){ register struct tynames *tp; if (cursym.n_type & N_STAB) return; printf("%s", filname); if (archdr.ar_name[0]) printf("(%s)", archdr.ar_name); printf(": "); if ((cursym.n_type&N_TYPE) == N_UNDF && cursym.n_value) { printf("definition of common %s size %d\n", cursym.n_un.n_name, cursym.n_value); return; } for (tp = tynames; tp->ty_name; tp++) if (tp->ty_value == (cursym.n_type&N_TYPE)) break; printf((cursym.n_type&N_TYPE) ? "definition of" : "reference to"); if (cursym.n_type&N_EXT) printf(" external"); if (tp->ty_name) printf(" %s", tp->ty_name); printf(" %s\n", cursym.n_un.n_name);}/* * This routine relocates the single text or data segment argument. * Offsets from external symbols are resolved by adding the value * of the external symbols. Non-external reference are updated to account * for the relative motion of the segments (ctrel, cdrel, ...). If * a relocation was pc-relative, then we update it to reflect the * change in the positioning of the segments by adding the displacement * of the referenced segment and subtracting the displacement of the * current segment (creloc). * * If we are saving the relocation information, then we increase * each relocation datum address by our base position in the new segment. */load2td(creloc, position, b1, b2) long creloc, position; /* DLB002 */ struct biobuf *b1, *b2;{ register struct nlist *sp; register struct local *lp; long tw; register struct relocation_info *rp, *rpend; struct relocation_info *relp; char *codep; register char *cp; int relsz, codesz; relsz = reloc.size; relp = (struct relocation_info *)malloc(relsz); codesz = text.size; codep = (char *)malloc(codesz); if (relp == 0 || codep == 0) error(1, "out of memory (load2td)"); mget((char *)relp, relsz, &reloc); rpend = &relp[relsz / sizeof (struct relocation_info)]; mget(codep, codesz, &text); for (rp = relp; rp < rpend; rp++) { cp = codep + rp->r_address; /* * Pick up previous value at location to be relocated. */ switch (rp->r_length) { case 0: /* byte */ tw = *cp; break; case 1: /* word */ tw = *(short *)cp; break; case 2: /* long */ tw = *(long *)cp; break; default: error(1, "load2td botch: bad length"); } /* * If relative to an external which is defined, * resolve to a simpler kind of reference in the * result file. If the external is undefined, just * convert the symbol number to the number of the * symbol in the result file and leave it undefined. */ if (rp->r_extern) { /* * Search the hash table which maps local * symbol numbers to symbol tables entries * in the new a.out file. */ lp = lochash[rp->r_symbolnum % LHSIZ]; while (lp->l_index != rp->r_symbolnum) { lp = lp->l_link; if (lp == 0) error(1, "local symbol botch"); } sp = lp->l_symbol; if (sp->n_type == N_EXT+N_UNDF) rp->r_symbolnum = nsym+symx(sp); else { rp->r_symbolnum = sp->n_type & N_TYPE; tw += sp->n_value; rp->r_extern = 0; } } else switch (rp->r_symbolnum & N_TYPE) { /* * Relocation is relative to the loaded position * of another segment. Update by the change in position * of that segment. */ case N_TEXT: tw += ctrel; break; case N_DATA: tw += cdrel; break; case N_BSS: tw += cbrel; break; case N_ABS: break; default: error(1, "relocation format botch (symbol type))"); } /* * Relocation is pc relative, so decrease the relocation * by the amount the current segment is displaced. * (E.g if we are a relative reference to a text location * from data space, we added the increase in the text address * above, and subtract the increase in our (data) address * here, leaving the net change the relative change in the * positioning of our text and data segments.) */ if (rp->r_pcrel) tw -= creloc; /* * Put the value back in the segment, * while checking for overflow. */ switch (rp->r_length) { case 0: /* byte */ if (tw < -128 || tw > 127) error(0, "byte displacement overflow"); *cp = tw; break; case 1: /* word */ if (tw < -32768 || tw > 32767) error(0, "word displacement overflow"); *(short *)cp = tw; break; case 2: /* long */ *(long *)cp = tw; break; } /* * If we are saving relocation information, * we must convert the address in the segment from * the old .o file into an address in the segment in * the new a.out, by adding the position of our * segment in the new larger segment. */ if (rflag) rp->r_address += position; } bwrite(codep, codesz, b1); if (rflag) bwrite(relp, relsz, b2); free((char *)relp); free(codep);}finishout(){ register int i; int nsymt; if (sflag==0) { nsymt = symx(nextsym); for (i = 0; i < nsymt; i++) symwrite(xsym(i), sout); bwrite(&offset, sizeof offset, sout); } if (!ofilfnd) { unlink("a.out"); if (link("l.out", "a.out") < 0) error(1, "cannot move l.out to a.out"); ofilename = "a.out"; } delarg = errlev; delexit();}mkfsym(s)char *s;{ if (sflag || xflag) return; cursym.n_un.n_name = s; cursym.n_type = N_TEXT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -