⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtld.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 4 页
字号:
		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 + -