📄 rtld.c
字号:
PROUND(lmp->lm_ld->v2->ld_text), PROT_READ | PROT_EXEC) == -1) panic( "ld.so: write protect error %d\n", errno); lmp->lm_rwt = 0; } /* * Get rid of /dev/zero */ (void) close(devzero_fd); devzero_fd = -1;#ifdef HRC_TIME etime = hrc_time(); time4 = etime - stime; stime = etime; /* +++ time in misc stuff after relocate loop */ fprintf(stderr, "before mainloop %x main loop %x relocate %x misc %x\n", time1, time2, time3, time4); fprintf(stderr, " total %x\n", etime - ftime);#endif}/* * Indicate whether a given link_object has already been mapped into the * address space. */static struct link_map *have_we_got_it(lop, ba) struct link_object *lop; caddr_t ba;{ struct link_map *lmp; for (lmp = hlmp; lmp; lmp = lmp->lm_next) if (lmp->lm_lop) if (!strcmp(&ba[lop->lo_name], &lmp->lm_lob[lmp->lm_lop->lo_name])) return (lmp); return (0);}/* * Handle mapping error. */static voidmap_error(s, cp) char *s; /* type of mapping */ char *cp; /* object being mapped */{ if (errno == ENOMEM) { fprintf(stderr, "ld.so: swap space exhausted for %s of %s\n", s, cp); _exit(EX_TEMPFAIL); } else panic("ld.so: %s error (%d) for %s\n", s, errno, cp);}static struct link_map *mapit(s, lop, lob, intp) char *s; /* object name */ struct link_object *lop; /* link object that derived file */ caddr_t lob; /* base address for link object */ struct nlist *(*intp)(); /* interpreter for link map */{ struct exec exec; /* working area for object headers */ int fd; /* file descriptor temporary */ caddr_t addr; /* mmap result temporary */ struct link_dynamic *dp; /* dynamic pointer of object mapped */ int size; /* size of object */ if ((fd = open(s, O_RDONLY)) == -1) return(0); /* * Verify the object's header. */ if (read(fd, (char *)&exec, sizeof (struct exec)) != sizeof (struct exec)) panic("ld.so: can't read struct exec for %s\n", s); if #if TARGET == SUN2 (exec.a_machtype != M_68010) #endif#if TARGET == SUN3 ((exec.a_machtype != M_68010) && (exec.a_machtype != M_68020)) #endif#if TARGET == SUN4 (exec.a_machtype != M_SPARC) #endif panic("ld.so: %s is not for this machine type\n", s); /* * Map text and allocate enough address space to fit the whole * library. Note that we map enough to catch the first symbol * in the symbol table and thereby avoid an "lseek" & "read" * pair to pick it up. */ /* XXX need to fail in ways besides "panic". */ size = max(SIZE(exec), N_SYMOFF(exec) + sizeof (struct nlist)); if ((addr = mmap(0, size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0)) == (caddr_t)-1) map_error("mmap", s); /* * Grab the first symbol entry while we've got it mapped aligned * to file addresses. We assume that this symbol describes the * object's link_dynamic. */ dp = (struct link_dynamic *)&addr[ ((struct nlist *)&addr[N_SYMOFF(exec)])->n_value]; /* * Map the initialized data portion of the file to the correct * point in the range of allocated addresses. This will leave * some portion of the data segment "doubly mapped" on machines * where the text/data relocation alignment is not on a page * boundaries. However, leaving the file mapped has the double * advantage of both saving the munmap system call and of leaving * us a contiguous chunk of address space devoted to the object -- * in case we need to unmap it all later. */ if (mmap((caddr_t)(addr+SROUND(exec.a_text)), (int) exec.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, (off_t) exec.a_text) == (caddr_t)-1) map_error("mmap data", s); /* * Allocate pages for the object's bss, if necessary. */ if (exec.a_bss != 0) { if (!get_zero_object()) map_error("mmap bss", s); if (mmap(addr + SROUND(exec.a_text) + exec.a_data, (int) exec.a_bss, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, devzero_fd, (off_t) 0) == (caddr_t)-1) map_error("mmap bss", s); } /* * Finished with shared object mapping, get rid of descriptor. */ dp->v2 = (struct link_dynamic_2 *)((int)dp->v2 + (int)addr); (void) close(fd); return(new_lmp(s, lop, lob, addr, dp, intp));}/* * Map in a link object, return its link_map. */static struct link_map *map_so(lmp, lop) struct link_map *lmp; /* link_map from which lop came */ struct link_object *lop; /* object to be mapped */{ caddr_t cp; /* work pointer */ static int flushed = 0; /* only flush cache once */ struct link_map *nlmp; /* new link map for mapped object */ /* * Determine the absolute name of the object to be mapped. */ for (;;) { cp = lop->lo_library ? lo_lookup(lop, lmp) : &TEXTBASE(lmp)[lop->lo_name]; if (!cp) { if (!tracing) panic("ld.so: lib%s.so.%d: not found\n", &TEXTBASE(lmp)[lop->lo_name], lop->lo_major); return (new_lmp(NULL, lop, TEXTBASE(lmp), 0, 0, findsb)); } /* * Open object. If we can not, see if flushing the cache * and retrying helps. There is special handling for the * "programmer's interface", embodied in libdl -- which * is really just an alias for some of our own symbols. * Note that this allows for special handling ONLY for * a libdl installed with /usr/lib/ld.so -- i.e., the * one *in* /usr/lib. */ if ((nlmp = mapit(cp, lop, TEXTBASE(lmp), (!strcmp(cp, "/usr/lib/libdl.so.1.0") ? ldsofindsb : findsb))) == 0) { if (flushed) { if (!tracing) panic("ld.so: open error %d for %s\n", errno, cp); return (new_lmp(NULL, lop, TEXTBASE(lmp), 0, 0, findsb)); } else { lo_flush(); flushed++; } } else break; } /* * Process dynamic interface we just loaded, including * list of objects on which this one depends. */ return (nlmp);}/* * Allocate a new link map for file "f", loaded at "addr" from link_object * "lop", with a dynamic at "dp". Manage a free list of "link maps" -- as * we have no way to reclaim one into a "heap" when one is made free. */static struct link_map *new_lmp(f, lop, lob, addr, dp, intp) char *f; /* file name */ struct link_object *lop; /* link object that derived file */ caddr_t lob; /* base address for link object */ caddr_t addr; /* address where mapped */ struct link_dynamic *dp; /* link_dynamic for file */ struct nlist *(*intp)(); /* interpreter for link map */{ caddr_t offset; /* hack for "main" */ struct link_map *lmp; /* link map we built */ /* * For the "main" program, addresses in the link_dynamic structure * are "broken" (text relocated to "0" rather than MAIN_BASE). * We "know" which these are, and deal with them especially here. * XXX */ offset = f == main_program ? (caddr_t)MAIN_BASE : addr; /* * Allocate link_map structure, and private data structure. * Add the new link_map to the list of link_map's. */ if (lmp = flmp) flmp = lmp->lm_next; else { lmp = (struct link_map *)rtmalloc(sizeof (struct link_map)); lmp->lm_lpd = rtmalloc(sizeof (struct ld_private)); } lmp->lm_next = *plmpp; *plmpp = lmp; plmpp = &lmp->lm_next; /* * Fill in the fields in the new link_map. Load the private * data cache with pre-relocated information from the object's * unrelocated link_dynamic. */ LM2LP(lmp)->lp_symbol_base = lmp->lm_addr = addr; if (f) { lmp->lm_name = rtmalloc(strlen(f) + 1); strcpy(lmp->lm_name, f); } else lmp->lm_name = f; lmp->lm_lop = lop; lmp->lm_lob = lob; lmp->lm_ld = dp; /* * Fill in fields from target's dynamic structure -- if there is * one. (There might not be because we are "tracing.") */ if (dp) { if (dp->ld_version < VERSION2) panic("ld.so: __DYNAMIC version %d not supported\n", dp->ld_version); LM2LP(lmp)->lp_plt = (struct jbind *)(&addr[JMPOFF(dp)]); LM2LP(lmp)->lp_rp = (struct relocation_info *)(&offset[RELOCOFF(dp)]); LM2LP(lmp)->lp_hash = (struct fshash *)(&offset[HASHOFF(dp)]); LM2LP(lmp)->lp_symtab = (struct nlist *)(&offset[SYMOFF(dp)]); LM2LP(lmp)->lp_symstr = &offset[STROFF(dp)]; LM2LP(lmp)->lp_textbase = offset; LM2LP(lmp)->lp_interp = intp; LM2LP(lmp)->lp_refcnt++; LM2LP(lmp)->lp_dlh = LM2LP(lmp)->lp_dlp = NULL; } return (lmp);}static voidfree_lmp(lmp) struct link_map *lmp;{ struct link_map *tlmp; /* temporary */ struct link_map **plmp; /* previous pointer */ tlmp = hlmp, plmp = &hlmp; while (tlmp) { if (tlmp == lmp) { cached_symbol = NULL; (void) munmap(lmp->lm_addr, max(SIZE(*(struct exec *)lmp->lm_addr), N_SYMOFF((*(struct exec *)lmp->lm_addr)) + sizeof (struct nlist))); *plmp = lmp->lm_next; if (plmpp == &lmp->lm_next) plmpp = plmp; lmp->lm_next = flmp; flmp = lmp; return; } plmp = &tlmp->lm_next; tlmp = tlmp->lm_next; } panic("ld.so: mangled lm object list.\n"); /*NOTREACHED*/}/* * Relocate an object. */static voidrelocate(lmp, clmp) register struct link_map *lmp; /* object to be relocated */ register struct link_map *clmp; /* calling link map */{ int k; /* loop temporary */ int nr; /* number of relocations */ char *symbol; /* symbol being searched for */ caddr_t et; /* cached _etext of object */ register long j; /* relocation temporary */ register caddr_t ra; /* cached relocation address */ register struct /* current relocation */ relocation_info *rp; struct nlist *sp; /* symbol table of "symbol" */ struct link_map *llmp; /* lmp of source of "symbol" */ /* * Cache some invariants. */ rp = LM2LP(lmp)->lp_rp; et = &TEXTBASE(lmp)[lmp->lm_ld->v2->ld_text]; nr = GETRELSZ(lmp->lm_ld) / sizeof (struct relocation_info); /* * Initialize _PLT_, if any. */ if (lmp->lm_ld->v2->ld_plt_sz) {#if TARGET==SUN4 int *inst = LM2LP(lmp)->lp_plt->jb_inst; int tmp = (int) rtbinder; *inst++ |= ((tmp >> (32-22)) & MASK(22)); *inst |= (tmp & MASK(10)); #endif#if TARGET==SUN3 || TARGET==SUN2 LM2LP(lmp)->lp_plt->cl_hi = (int) rtbinder >> 16; LM2LP(lmp)->lp_plt->cl_low = (int) rtbinder & 0xffff;#endif } /* * Loop over all relocations. */ for (k = 0; k < nr; k++, rp++) { /* * Check to see if we're relocating in the text segment * and turn off the write protect if necessary. */ if ((ra = &lmp->lm_addr[rp->r_address]) < et) if (lmp->lm_rwt == 0) { if (mprotect(TEXTBASE(lmp), PROUND((long)(et - TEXTBASE(lmp))), PROT_READ | PROT_WRITE | PROT_EXEC) == -1) map_error("text write-enable", lmp->lm_name); lmp->lm_rwt = 1; } /* * Perform the relocation. */ if (rp->r_extern == 0) {#if TARGET==SUN4 upd_reloc(rp, (long *)ra, (long) lmp->lm_addr);#endif#if TARGET==SUN3 || TARGET==SUN2 *(long *)(ra) += (int)lmp->lm_addr;#endif } else {#if TARGET==SUN4 if (rp->r_type == RELOC_JMP_SLOT)#endif#if TARGET==SUN3 || TARGET==SUN2 if (rp->r_jmptable)#endif continue; sp = &LM2LP(lmp)->lp_symtab[rp->r_symbolnum]; symbol = &LM2LP(lmp)->lp_symstr[sp->n_un.n_strx]; if ((sp = lookup(symbol, &llmp, clmp)) == NULL) panic("ld.so: Undefined symbol: %s\n", symbol); #if TARGET==SUN4 j = sp->n_value + (long) (sp->n_type==N_COMM || sp->n_type==N_ABS+N_EXT ? 0 : llmp->lm_addr) + rp->r_addend; if (isitpcrel(rp))#endif#if TARGET==SUN3 || TARGET==SUN2 j = sp->n_value + (long) (sp->n_type==N_COMM || sp->n_type==N_ABS+N_EXT ? 0 : llmp->lm_addr); if (rp->r_pcrel)#endif j -= (long)lmp->lm_addr;#if TARGET==SUN4 upd_reloc(rp, (long *)ra, j);#endif TARGET==SUN4#if TARGET==SUN3 || TARGET==SUN2 /* * Optimize out the call to upd_reloc. Note * that upd_reloc has unimplemented sanity checking * that, when implemented, may require removing * or otherwise altering this optimization. */ *(long *)ra += j;#endif TARGET==SUN3 || TARGET==SUN2 } }}/* * Perform a specific relocation operation. */static voidupd_reloc(rp, where, what) struct relocation_info *rp; long *where; long what;{#if TARGET==SUN4 switch (rp->r_type) { case RELOC_RELATIVE: what += *where << (32-22); *(long *)where = (*(long *)where & ~MASK(22)) | ((what >> (32-22)) & MASK(22)); where++; what += (*where & MASK(10)); *(long *)where = (*(long *)where & ~MASK(10)) | (what & MASK(10)); break; case RELOC_8: case RELOC_DISP8: what += *where & MASK(8); if (!IN_RANGE(what,8)) fprintf(stderr, "byte displacement overflow at %#x", rp->r_address); *where = what; break; case RELOC_LO10: case RELOC_BASE10: what += *where & MASK(10); *(long *)where = (*(long *)where & ~MASK(10)) | (what & MASK(10)); break; case RELOC_BASE13: case RELOC_13: what += *where & MASK(13); *(long *)where = (*(long *)where & ~MASK(13)) | (what & MASK(13)); break; case RELOC_16: case RELOC_DISP16: what += *where & MASK(16); if (!IN_RANGE(what,16))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -