📄 rtld.c
字号:
else if (!strncmp(v, ld_preload, sizeof (ld_preload) - 1)) preload = v + sizeof (ld_preload); else if (!strncmp(v, ld_trace, sizeof (ld_trace) - 1)) tracing = v + sizeof (ld_trace); else if (!strncmp(v, ld_profile, sizeof (ld_profile) - 1)) profile = v + sizeof (ld_profile); else if (!strncmp(v, ld_symbols_public, sizeof (ld_symbols_public) - 1)) symbols_public = v + sizeof (ld_symbols_public); } /* * Calculate the top of stack -- avoid dependence upon USRSTACK, * but add dependence upon knowing that the stack ends with environment * strings. Note: program bootstraps already depend upon this * knowledge, and since we're sort of kind of part of the bootstrap * this isn't too much of a hack. */ for (v = *(p - 2); *v; v++) ;; top_of_stack = (caddr_t)(((int)v + PAGSIZ - 1) & ~(PAGSIZ - 1));}/* * Simple programmatic interface to the dynamic linker. * * These functions constitute a simple interface that permits programs to * add shared objects, lookup symbols in such objects, and remove those * objects -- all under program control. Such objects have special * symbol lookup interpretations, implemented by interpreter functions * such as the one immediately following. */struct nlist *dl_interpreter(lmp, s, clmp) struct link_map *lmp; char *s; struct link_map *clmp;{ if (LM2LP(lmp)->lp_dlh != LM2LP(clmp)->lp_dlh) return(0); else return(findsb(lmp, s, clmp));}/* * Add the shared object in "path" to the program. Reference count the * objects so that multiple calls actually load only one instance of * the object -- also account for objects that might have been automatically * loaded at program start-up. */struct dl_object *dlopen(path, mode) char *path; /* path name of object */ int mode; /* open mode */{ struct dl_object *dlp; /* temporary return */ /* * Jacket function for real worker routine. Establishes and * cleans up general environment. */ dlp = dlopen_worker(path, mode); if (devzero_fd != -1) { (void) close(devzero_fd); devzero_fd = -1; } return (dlp);}static struct dl_object *dlopen_worker(path, mode) char *path; /* path name of object */ int mode; /* open mode */{ struct link_map *lmp; /* link map temporary */ struct link_map *nlmp; /* newly created link maps */ struct dl_object *dlp; /* dl object temporary */ struct dl_object *wdlp; /* working dl temporary */ struct dl_object **dlpp; /* insertion pointer for dependents */ struct link_object *lop; /* dependent link objects */ char *save_error; /* error saving */ /* * Initialize error state. */ dl_error = DLE_none; /* * Currently, no modes supported. */ if (mode != 1) { dl_error = DLE_mode_error; return(NULL); } /* * If a null path, then we're operating on "main." */ if (!path) path = "main_$main_"; /* * Scan link map list looking for this object. If found, * then get a dl_object descriptor for it (creating the * descriptor if necessary.) Note that the situation in * which we find an object with a descriptor, but where * that object is either not on a dl "chain" (because * it's part of "main") or is not the head of that chain, * then we have a conflict. The conflict is the result * of having two "libraries" be depended upon by two different * shared objects, leading to confusion over how the resolution * of symbols should be handled. We simply prohibit this. */ for (lmp = hlmp; lmp; lmp = lmp->lm_next) if (!strcmp(path, lmp->lm_name)) { dlp = LM2LP(lmp)->lp_dlp; if (dlp) { if ((LM2LP(lmp)->lp_dlh != NULL) && (LM2LP(lmp)->lp_dlh != dlp)) { dl_error = DLE_conflict; return (NULL); } dlp->dl_refcnt++; } else { LM2LP(lmp)->lp_refcnt++; dlp = new_dlp(lmp); } return (dlp); } /* * No link map for it. Make one, and then make a * dl_object descriptor for it. Add it to the * address space, set it as the head of a chain. */ if (!(lmp = mapit(path, 0, 0, dl_interpreter))) { dl_error = DLE_can_not_open; return (NULL); } dlp = new_dlp(lmp); LM2LP(lmp)->lp_dlh = dlp; dlpp = &dlp->dl_dep; /* * Now, see if there are any dependent objects. For each, * load it up, get a dlp, etc. and add it to the list of * dependencies. */ for (wdlp = dlp; wdlp; wdlp = wdlp->dl_dep) { lmp = wdlp->dl_lmp; if (lmp->lm_ld) { for (lop = (struct link_object *) &TEXTBASE(lmp)[lmp->lm_ld->v2->ld_need]; lop != (struct link_object *)&TEXTBASE(lmp)[0]; lop = (struct link_object *) &TEXTBASE(lmp)[lop->lo_next]) if ((nlmp = have_we_got_it(lop, TEXTBASE(lmp))) == NULL) { if (nlmp = map_so(lmp, lop)) { *dlpp = new_dlp(nlmp); LM2LP(nlmp)->lp_interp = dl_interpreter; LM2LP(nlmp)->lp_dlh = dlp; dlpp = &(*dlpp)->dl_dep; } else { dl_error = DLE_can_not_open; break; } } else if (LM2LP(lmp)->lp_dlh) { dl_error = DLE_conflict; break; } } if (dl_error != DLE_none) break; } /* * If an error occurred, we're hosed. Close off everything we * opened including ourselves. */ if (dl_error != DLE_none) { save_error = dl_error; (void) dlclose(dlp); dl_error = save_error; return (NULL); } /* * Now, walk the list and relocate everything. */ for (wdlp = dlp; wdlp; wdlp = wdlp->dl_dep) { relocate(wdlp->dl_lmp, wdlp->dl_lmp); if (wdlp->dl_lmp->lm_rwt) { (void) mprotect(TEXTBASE(wdlp->dl_lmp), PROUND(wdlp->dl_lmp->lm_ld->v2->ld_text), PROT_READ | PROT_EXEC); wdlp->dl_lmp->lm_rwt = 0; } } return (dlp);}/* * Convert dlsym responses to appropriate address based on type of * symbol. Note that in the case of dlsym references to an unallocated * common, we have to "simulate" a reference to it in order to stimulate * the allocation process. */static caddr_tdl_absolute(sp, lmp) struct nlist *sp; /* symbol table entry of symbol */ struct link_map *lmp; /* link map that defined it */{ if (sp->n_type == N_UNDF+N_EXT && sp->n_value != 0) { sp = lookup(&LM2LP(lmp)->lp_symstr[sp->n_un.n_strx], &lmp, lmp); if (sp == NULL) return (0); } if (sp->n_type == N_COMM || sp->n_type == N_ABS+N_EXT) return ((caddr_t)sp->n_value); else return ((caddr_t)(sp->n_value + lmp->lm_addr));}#define MAX_DLSYM_SYMBOL 1024 /* maximum size of symbol we match */caddr_tdlsym(dlp, symbol) struct dl_object *dlp; char *symbol;{ int i; /* temporary */ caddr_t pc; /* caller's pc */ struct dl_object *wdlp; /* working dlp */ struct link_map *lmp; /* link map of symbol table */ struct nlist *sp; /* symbol table entry */ char *cp; /* temporary */ char buffer[MAX_DLSYM_SYMBOL + 2]; /* "_" assembly, including null pad */ /* * Initialize error. */ dl_error = DLE_none; /* * Check dl object handle -- if valid, then retrieve * symbol from appropriate object. Note that dlp of * NULL is valid, and refers to the "caller" of dlsym. */ if (dlp) { if (!valid_dl_object(dlp)) return (NULL); } else {#ifdef notdef pc = caller(); if ((lmp = pc_to_lmp(pc)) == NULL) { dl_error = DLE_bad_handle; return (NULL); }#else notdef dl_error = DLE_bad_handle; /* XXX */ return (NULL);#endif notdef } for (wdlp = dlp; wdlp; wdlp = wdlp->dl_dep) if (sp = findsb(wdlp->dl_lmp, symbol, wdlp->dl_lmp)) return (dl_absolute(sp, wdlp->dl_lmp)); /* * Symbol not found as supplied. However, most of our symbols * will be in the "C" name space, where the implementation prepends * a "_" to the symbol as it emits it. Therefore, attempt to find * the symbol with the "_" prepend. */ buffer[0] = '_'; cp = &buffer[1]; i = 1; while (i < MAX_DLSYM_SYMBOL) { if ((*cp++ = *symbol++) == '\0') { for (wdlp = dlp; wdlp; wdlp = wdlp->dl_dep) if (sp = findsb(wdlp->dl_lmp, buffer, wdlp->dl_lmp)) return (dl_absolute(sp, wdlp->dl_lmp)); break; } i++; } dl_error = DLE_undefined; return (0);}/* * Functions to retrieve a symbol from a dlopen'ed object. */static struct link_map *pc_to_lmp(pc) caddr_t pc; /* pc needing an lmp */{ int size; /* size of program */ struct link_map *lmp; /* temporary */ size = max(SIZE(*(struct exec *)lmp->lm_addr), N_SYMOFF((*(struct exec *)lmp->lm_addr)) + sizeof (struct nlist)); for (lmp = hlmp; lmp; lmp = lmp->lm_next) if (pc > lmp->lm_addr && pc < (lmp->lm_addr + size)) break; return (lmp);}/* * Remove a dynamically loaded object from the program. If it is * the last reference, then *really* remove the name -- and if the * name is the last reference to the object, then *really* remove * the object. */intdlclose(dlp) struct dl_object *dlp;{ struct link_map *lmp; /* temporary */ struct dl_object *wdlp; /* temporary */ struct dl_object *ndlp; /* where we're going next */ /* * Clear error. */ dl_error = DLE_none; /* * Validity check object handle. */ if (!valid_dl_object(dlp)) { dl_error = DLE_bad_handle; return (-1); } /* * Valid object: decrement reference count. If we've still * got any references then just leave. */ if (--dlp->dl_refcnt) return (0); /* * Reference count went to zero. By definition, that means * that the reference count on everything we loaded also * went to zero. So free them all as well. */ for (wdlp = dlp; wdlp; wdlp = ndlp) { lmp = wdlp->dl_lmp; ndlp = wdlp->dl_dep; wdlp->dl_refcnt = 0; free_dlp(wdlp); if (--LM2LP(lmp)->lp_refcnt) continue; free_lmp(lmp); } return (0);}char *dlerror() { char *error = dl_error; if (dl_error == DLE_none) return (0); dl_error = DLE_none; return (error);}/* * dl_object allocation and management. "free'ed" dl_objects are not * returned to the "heap" (because we don't have a general heap manager * at present.) So, they are kept on a list in case we need to use them * and requests for new dl_object's are allocated from this list rather * than from the heap. */static struct dl_object *new_dlp(lmp) struct link_map *lmp;{ struct dl_object *dlp; if (dlp = fdlp) fdlp = dlp->dl_next; else dlp = (struct dl_object *) rtmalloc(sizeof (struct dl_object)); dlp->dl_magic = DL_MAGIC; dlp->dl_cigam = DL_CIGAM; LM2LP(lmp)->lp_dlp = dlp; dlp->dl_lmp = lmp; dlp->dl_refcnt++; dlp->dl_next = NULL; dlp->dl_dep = NULL; *pdlpp = dlp; pdlpp = &dlp->dl_next; return (dlp);}static voidfree_dlp(dlp) struct dl_object *dlp;{ struct dl_object *tdlp; /* temporary */ struct dl_object **pdlp; /* previous pointer */ tdlp = hdlp, pdlp = &hdlp; while (tdlp) { if (tdlp == dlp) { LM2LP(dlp->dl_lmp)->lp_dlp = NULL; LM2LP(dlp->dl_lmp)->lp_dlh = NULL; dlp->dl_magic = 0; dlp->dl_cigam = 0; *pdlp = dlp->dl_next; if (pdlpp == &dlp->dl_next) pdlpp = pdlp; dlp->dl_next = fdlp; fdlp = dlp; return; } pdlp = &tdlp->dl_next; tdlp = tdlp->dl_next; } panic("ld.so: mangled dl object list.\n"); /*NOTREACHED*/}/* * Sanity check a program-provided dl_object handle. */staticvalid_dl_object(dlp) struct dl_object *dlp;{ if (dlp) if (dlp->dl_magic == DL_MAGIC && dlp->dl_cigam == DL_CIGAM && dlp->dl_refcnt != 0 && LM2LP(dlp->dl_lmp)->lp_dlh == dlp) return (1); dl_error = DLE_bad_handle; return (0);}#ifdef WHOAMI/* * This routine is only available in-house. It returns the * program name of the running process. */char *whoami(){ return(progname);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -