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

📄 rtld.c

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