📄 rtld.c
字号:
fprintf(stderr, "word displacement overflow at %#x", rp->r_address); *(short *)where = what; break; case RELOC_22: case RELOC_BASE22: what += *where & MASK(22); if (!IN_RANGE(what,22)) fprintf(stderr, "sethi displacement overflow at %#x", rp->r_address); *(long *)where = (*(long *)where & ~MASK(22)) | (what & MASK(22)); break; case RELOC_HI22: what += (*where<<32-22) & MASK(22); *(long *)where = (*(long *)where & ~MASK(22)) | ((what>>(32-22)) & MASK(22)); break; case RELOC_WDISP22: what += *where & MASK(22); if (what & MASK(2) ) fprintf(stderr, "odd word displacement at %#x", rp->r_address); what >>= 2; if (!IN_RANGE(what,22)) fprintf(stderr, "branch displacement overflow at %#x", rp->r_address); *(long *)where = (*(long *)where & ~MASK(22)) | (what & MASK(22)); break; case RELOC_WDISP30: what += *where & MASK(30); if (what & MASK(2) ) fprintf(stderr, "odd word displacement at %#x", rp->r_address); what >>= 2; *(long *)where = (*(long *)where & ~MASK(30)) | (what&MASK(30)); break; case RELOC_32: case RELOC_GLOB_DAT: case RELOC_DISP32: what += *where; *(long *)where = what; break; default: fprintf(stderr, "unknown relocation type %d", rp->r_type); break; }#endif #if TARGET==SUN3 || TARGET==SUN2 /* * Put the value back in the segment, * while checking for overflow. */ what += *where; *(long *)where = what; /* ++++ need to add this switch (rp->r_length) { case 0: if (what < -128 || what > 127) fprintf(stderr, "byte displacement overflow at %#x", rp->r_address); *where = what; break; case 1: if (what < -32768 || what > 32767) fprintf(stderr, "word displacement overflow at %#x", rp->r_address); *(short *)where = what; break; case 2: *(long *)where = what; break; } */#endif}/* * Calculate hash value for symbol being looked up. */static intgethashv(sn) char *sn;{ int val; /* accumulator for hash value */ /* * Calculate hash value for symbol being looked up. */ for (val = 0; *sn;) val = (val<<1) + *sn++; return(val);}static struct nlist *ldsofindsb(lmp, sn, clmp) struct link_map *lmp; char *sn; struct link_map *clmp;{ struct nlist *sp; if ((sp = findsb(lmp, sn, clmp)) == 0) return (0); if ((sp->n_value == 0) || (sp->n_type == N_EXT+N_UNDF)) return (0); LM2LP(lmp)->lp_symbol_base = ld_lmp->lm_addr; return (findsb(ld_lmp, sn, clmp));}#define HASHMASK 0x7fffffffstatic struct nlist *findsb(lmp, sn, clmp) struct link_map *lmp; char *sn; struct link_map *clmp;{ register char *cp; /* temporary */ register char *s1; /* string handling pointers */ struct fshash *p; /* working pointer to .so symbols */ int i; /* temporary */ struct nlist *sp; /* symbol entry pointer */ static int hashval; /* cache hash value of last symbol */ static char *lp; /* cache last symbol pointer */ /* * this is a questionable cache since the same pointer may * pointed to a different symbol. ++++ */ if (lp != sn) hashval = gethashv(sn); if (LM2LP(lmp)->lp_hash == (struct fshash *)&lmp->lm_addr[0]) return(0); /* not found */ i = (hashval & HASHMASK) % (lmp->lm_ld->v2->ld_buckets == 0 ? RTHS : lmp->lm_ld->v2->ld_buckets); p = LM2LP(lmp)->lp_hash + i; if (p->fssymbno != -1) do { sp = &LM2LP(lmp)->lp_symtab[p->fssymbno]; s1 = sn; cp = &LM2LP(lmp)->lp_symstr[sp->n_un.n_strx]; while (*s1 == *cp++) if (*s1++=='\0') { return(sp); /* found */ } if (p->next == 0) return(0); /* not found */ else continue; /* next symbol */ } while (p = &LM2LP(lmp)->lp_hash[p->next]); return(0);}/* * Lookup symbol with name (s). Return pointer to symbol table entry * representing it as well as index to dynamic object which defines it. */staticstruct nlist *lookup(s, lmpp, clmp) char *s; struct link_map **lmpp; struct link_map *clmp;{ register struct link_map *lmp; /* working pointer */ register char *cp; /* string handling pointers */ register char *s1; /* string handling pointers */ struct nlist *sp; /* symbol table entry */ struct nlist *savesp; /* save common data symbol entry */ int msize = 0; /* common maximum size */ struct rtc_symb *rs; /* new common */ struct rtc_symb *trs; /* temporary for new common */ static struct nlist *lsp; /* cached copy of last symbol found */ static struct link_map *lmpc; /* cached link map pointer */ /* * Heuristic: if this symbol is the same as the last one, then * just skip all this work. * XXX should count this to see how effective it is. */ if (cached_symbol) if (!strcmp(cached_symbol, s)) { *lmpp = lmpc; return(lsp); } cached_symbol = s; /* * Over all loaded objects, determine find the hash entry corresponding * to this value, and search for a definition for this symbol. */ for (lmp = hlmp; lmp; lmp = lmp->lm_next) { lmpc = lmp; if (lsp = sp = (*(LM2LP(lmp)->lp_interp))(lmp, s, clmp)) { /* * We found a match. If it is simply a reference * and not a definition we proceed to the next object. * If it is a definition, and not a common then we * have found what we're looking for so return it. * Otherwise, determine whether the common has already * been allocated, and if so, return that pointer. */ if (sp->n_value == 0) continue; if (sp->n_type != N_EXT+N_UNDF) { if (msize == 0) { *lmpp = lmp; return (sp); } } else { /* * look up the runtime allocated commom * symbol table */ savesp = sp; trs = rtcp; while (trs) { s1 = s; cp = trs->rtc_sp->n_un.n_name; while (*s1 == *cp++) if (*s1++=='\0') return (lsp = trs->rtc_sp); trs = trs->rtc_next; } /* * It's an unallocated common, * accumulate size information. */ if (msize < sp->n_value) msize = sp->n_value; continue; } } } /* * If we got this far, we either have found nothing suitable or * else have a common. In the former, punt, otherwise we now * know enough to allocate the common so do so. */ if (msize == 0) { return (0); } else { rs = (struct rtc_symb *) rtmalloc(sizeof (struct rtc_symb)); rs->rtc_sp = (struct nlist *)rtmalloc(sizeof (struct nlist)); trs = rtcp; rtcp = rs; rs->rtc_next = trs; *(rs->rtc_sp) = *savesp; rs->rtc_sp->n_un.n_name = rtmalloc(strlen(s) + 1); strcpy(rs->rtc_sp->n_un.n_name, s); rs->rtc_sp->n_type = N_COMM; rs->rtc_sp->n_value = (long)rtmalloc(msize); *lmpp = lmpc = hlmp; return (lsp = rs->rtc_sp); }}/* * Procedure call binding. Called on initial call reference to a global * unbound symbol. */intbinder(pc, relocindex) caddr_t pc; int relocindex;{ int address; /* target address */ register struct link_map *lmp; /* link_map describing calling obj */ register struct /* working relocation pointer */ relocation_info *rp; register struct nlist *sp; /* entry for symbol being referenced */ register char *symbol; /* symbol being searched for */ struct link_map *llmp; /* link_map in which symbol is found */ /* * Find the object that our caller came from. */ for (lmp = hlmp; lmp; lmp = lmp->lm_next) if (pc > (caddr_t)(LM2LP(lmp)->lp_plt) && pc < (caddr_t)((int)LM2LP(lmp)->lp_plt + lmp->lm_ld->v2->ld_plt_sz)) goto gotit; /* * If no object can be found, we can't understand how we got * here, so we panic. */ if (lmp == NULL) panic("ld.so: unidentifiable procedure reference at 0x%x\n", pc);gotit: /* * Need to know which link_dynamic version for plt handling. * This interface will be revised post 4.0 ++++++ */#if TARGET==SUN4#define LAST22BITS 0x3fffff version_no = lmp->lm_ld->ld_version; if (version_no == 3) relocindex = *(int *)(pc + 4) & LAST22BITS;#endif /* * Find the symbol being referenced, and then find a definition for it. * If the latter can not be found, then terminate the program. */ /* * N.B. Different error handling possibilities are a CASE * opportunity: namely, incremental program construction and * calls to debuggers. */ rp = &LM2LP(lmp)->lp_rp[relocindex]; sp = &LM2LP(lmp)->lp_symtab[rp->r_symbolnum]; symbol = &LM2LP(lmp)->lp_symstr[sp->n_un.n_strx]; if ((sp = lookup(symbol, &llmp, lmp)) == NULL) panic("ld.so: call to undefined procedure %s from 0x%x\n", symbol, pc); /* * Rebuild the relocation entry to direct future calls directly * to the target procedure. Return the address to which this call * should ultimately return. */ /* * N.B. Much opportunity here for: * - call graph profiling. * - alternative procedure call implementation (RPC). * - value-added interposing. */ address = (int)&LM2LP(llmp)->lp_symbol_base[sp->n_value]; stuffit((long *)&lmp->lm_addr[rp->r_address], address); return (address);}/* * Rebuild a _PLT_ entry after initial binding. */stuffit(where, what) long *where; int what;{#if TARGET==SUN4 long *i = where; switch (version_no) { case 3: *i = SETHI; *i = (*i & ~MASK(22)) | ((what>>(32-22)) & MASK(22)); i++; *i = JMPI; *i = (*i & ~MASK(10)) | (what & MASK(10)); break; default: *i = SETHI; *i = (*i & ~MASK(22)) | ((what>>(32-22)) & MASK(22)); i++; *i = ORIT; *i = (*i & ~MASK(10)) | (what & MASK(10)); *i++; *i++ = JMPI; *i = NOP; break; }#endif#if TARGET==SUN3 || TARGET==SUN2 char *i = (char *)where; *where = what; *(short *)(i - 2) = JUMP;#endif}/* * Utility function to round "v" to the next "r" boundary. */round(v, r) u_int v; u_int r;{ r--; v += r; v &= ~(long)r; return (v);}/* * Make sure we have a source of heap. */staticget_zero_object(){ int zfd; if (devzero_fd == -1) devzero_fd = open("/dev/zero", O_RDONLY); return (devzero_fd != -1);}/* * Local heap allocator. Very simple, does not support storage freeing. * XXX Should be upgraded to support multiple heaps. Should also handle * /dev/zero allocation errors. */caddr_trtmalloc(nb) int nb;{ static caddr_t cp = 0; static caddr_t sp = 0; caddr_t tp; struct rlimit rlimit; int sl; if (cp == 0) { getrlimit(RLIMIT_STACK, &rlimit); sl = rlimit.rlim_cur - (rlimit.rlim_cur % PAGSIZ); sp = cp = (caddr_t)(top_of_stack - sl); } if (cp + round(nb, (long)sizeof (double)) >= sp) { if (!get_zero_object()) map_error("map heap", "/dev/zero"); if ((sp = mmap(sp, round(nb, PAGSIZ), PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, devzero_fd, 0)) == (caddr_t)-1) map_error("map heap", "/dev/zero"); sp += round(nb,PAGSIZ); } tp = cp; cp += round(nb, sizeof (double)); return (tp);} /* * Run-time link editor private getenv system call. Scans for our * special strings, and also calculates top of stack. */char ld_library_path[] = "LD_LIBRARY_PATH";char ld_trace[] = "LD_TRACE_LOADED_OBJECTS";char ld_profile[] = "LD_PROFILE";char ld_preload[] = "LD_PRELOAD";char ld_symbols_public[]= "LD_SYMBOLS_PUBLIC";staticrtgetenv(){ register char **p = environ; register char *v; /* * Guard against no environment. This seems practically impossible, * as the variable "environ" is initialized in crt0 with an address * on the stack. However, if it actually does happen, we need to * fake out the top of user_stack. */ if ((p == NULL) || (*p == NULL)) { top_of_stack = (caddr_t)(((int)&p + PAGSIZ - 1) & ~(PAGSIZ - 1)); return; } /* * Scan for LD_ environment variables that affect our behavior. */ while (v = *p++) { if (strncmp(v, "LD_", 3)) continue; if (!strncmp(v, ld_library_path, sizeof (ld_library_path) - 1)) library_path = v + sizeof (ld_library_path);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -