コード例 #1
0
ファイル: resolve.c プロジェクト: sofuture/bitrig
/*
 * Add a new dynamic object to the object list.
 */
void
_dl_add_object(elf_object_t *object)
{
	/* if a .so is marked nodelete, then add a reference */
	if (object->obj_flags & DF_1_NODELETE &&
	    (object->status & STAT_NODELETE) == 0) {
		DL_DEB(("objname %s is nodelete\n", object->load_name));
		object->refcount++;
		object->status |= STAT_NODELETE;
	}

	/*
	 * if this is a new object, prev will be NULL
	 * != NULL if an object already in the list
	 * prev == NULL for the first item in the list, but that will
	 * be the executable.
	 */
	if (object->prev != NULL)
		return;

	if (_dl_objects == NULL) {			/* First object ? */
		_dl_last_object = _dl_objects = object;
	} else {
		_dl_last_object->next = object;
		object->prev = _dl_last_object;
		_dl_last_object = object;
	}
}
コード例 #2
0
ファイル: resolve.c プロジェクト: ajinkya93/OpenBSD
/*
 * Add a new dynamic object to the object list.
 */
void
_dl_add_object(elf_object_t *object)
{
	/*
	 * If a .so is marked nodelete, then the entire load group that it's
	 * in needs to be kept around forever, so add a reference there.
	 * XXX It would be better if we tracked inter-object dependencies
	 * from relocations and didn't leave dangling pointers when a load
	 * group was partially unloaded.  That would render this unnecessary.
	 */
	if (object->obj_flags & DF_1_NODELETE &&
	    (object->load_object->status & STAT_NODELETE) == 0) {
		DL_DEB(("objname %s is nodelete\n", object->load_name));
		object->load_object->opencount++;
		object->load_object->status |= STAT_NODELETE;
	}

	/*
	 * if this is a new object, prev will be NULL
	 * != NULL if an object already in the list
	 * prev == NULL for the first item in the list, but that will
	 * be the executable.
	 */
	if (object->prev != NULL)
		return;

	if (_dl_objects == NULL) {			/* First object ? */
		_dl_last_object = _dl_objects = object;
	} else {
		_dl_last_object->next = object;
		object->prev = _dl_last_object;
		_dl_last_object = object;
	}
}
コード例 #3
0
ファイル: library.c プロジェクト: enukane/openbsd-work
void
_dl_unload_shlib(elf_object_t *object)
{
	struct dep_node *n;
	DL_DEB(("unload_shlib called on %s\n", object->load_name));
	if (OBJECT_REF_CNT(object) == 0 &&
	    (object->status & STAT_UNLOADED) == 0) {
		object->status |= STAT_UNLOADED;
		TAILQ_FOREACH(n, &object->child_list, next_sib)
			_dl_unload_shlib(n->data);
		TAILQ_FOREACH(n, &object->grpref_list, next_sib)
			_dl_unload_shlib(n->data);
		DL_DEB(("unload_shlib unloading on %s\n", object->load_name));
		_dl_load_list_free(object->load_list);
		_dl_munmap((void *)object->load_base, object->load_size);
		_dl_remove_object(object);
	}
}
コード例 #4
0
ファイル: rtld_machine.c プロジェクト: sofuture/bitrig
/*
 * Resolve a symbol at run-time.
 */
Elf_Addr
_dl_bind(elf_object_t *object, int reloff)
{
	Elf_RelA *rela;
	Elf_Addr *addr, ooff;
	const Elf_Sym *sym, *this;
	const char *symn;
	sigset_t savedmask;

	rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL] + reloff);

	addr = (Elf_Addr *)(object->obj_base + rela->r_offset);
	if (object->plt_size != 0 && !(*addr >=  object->plt_start &&
	    *addr < (object->plt_start + object->plt_size ))) {
		/* something is broken, relocation has already occurred */
#if 0
		DL_DEB(("*addr doesn't point into plt %p obj %s\n", 
		    *addr, object->load_name));
#endif
		return *addr;
	}

	sym = object->dyn.symtab;
	sym += ELF64_R_SYM(rela->r_info);
	symn = object->dyn.strtab + sym->st_name;

	this = NULL;
	ooff = _dl_find_symbol(symn, &this,
	    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym,
	    object, NULL);
	if (this == NULL) {
		_dl_printf("lazy binding failed!\n");
		*((int *)0) = 0;	/* XXX */
	}

	/* if PLT is protected, allow the write */
	if (object->plt_size != 0) {
		_dl_thread_bind_lock(0, &savedmask);
		_dl_mprotect(addr, sizeof(Elf_Addr),
		    PROT_READ|PROT_WRITE);
	}

	*addr = ooff + this->st_value + rela->r_addend;

	/* if PLT is (to be protected, change back to RO/X  */
	if (object->plt_size != 0) {
		_dl_mprotect(addr, sizeof(Elf_Addr),
		    PROT_READ);
		_dl_thread_bind_lock(1, &savedmask);
	}

	return *addr;
}
コード例 #5
0
/*
 * Resolve a symbol at run-time.
 */
uint64_t
_dl_bind(elf_object_t *object, int reloff)
{
	const elf_object_t *sobj;
	const Elf_Sym *sym, *this;
	Elf_Addr *addr, ooff;
	const char *symn;
	Elf_Addr value;
	Elf_RelA *rela;
	sigset_t savedmask;

	rela = (Elf_RelA *)object->dyn.jmprel + reloff;

	sym = object->dyn.symtab;
	sym += ELF_R_SYM(rela->r_info);
	symn = object->dyn.strtab + sym->st_name;

	addr = (Elf_Addr *)(object->obj_base + rela->r_offset);
	this = NULL;
	ooff = _dl_find_symbol(symn, &this,
	    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym, object, &sobj);
	if (this == NULL) {
		_dl_printf("lazy binding failed!\n");
		*(volatile int *)0 = 0;		/* XXX */
	}
	DL_DEB(("%s: %s\n", symn, sobj->load_name));

	value = ooff + this->st_value + rela->r_addend;

	if (sobj->traced && _dl_trace_plt(sobj, symn))
		return ((uint64_t)value << 32) | (Elf_Addr)sobj->dyn.pltgot;

	/* if PLT+GOT is protected, allow the write */
	if (object->got_size != 0) {
		_dl_thread_bind_lock(0, &savedmask);
		/* mprotect the actual modified region, not the whole plt */
		_dl_mprotect((void*)addr, sizeof (Elf_Addr) * 2,
		    PROT_READ|PROT_WRITE|PROT_EXEC);
	}

	addr[0] = value;
	addr[1] = (Elf_Addr)sobj->dyn.pltgot;

	/* if PLT is (to be protected, change back to RO */
	if (object->got_size != 0) {
		/* mprotect the actual modified region, not the whole plt */
		_dl_mprotect((void*)addr, sizeof (Elf_Addr) * 3,
		    PROT_READ|PROT_EXEC);
		_dl_thread_bind_lock(1, &savedmask);
	}

	return ((uint64_t)addr[0] << 32) | addr[1];
}
コード例 #6
0
/*
 * Initialize a new dynamic object.
 */
elf_object_t *
_dl_finalize_object(const char *objname, Elf_Dyn *dynp, Elf_Phdr *phdrp,
    int phdrc, const int objtype, const long lbase, const long obase)
{
	elf_object_t *object;
#if 0
	_dl_printf("objname [%s], dynp %p, objtype %x lbase %lx, obase %lx\n",
	    objname, dynp, objtype, lbase, obase);
#endif
	object = _dl_malloc(sizeof(elf_object_t));
	object->prev = object->next = NULL;

	object->load_dyn = dynp;
	while (dynp->d_tag != DT_NULL) {
		if (dynp->d_tag < DT_NUM)
			object->Dyn.info[dynp->d_tag] = dynp->d_un.d_val;
		else if (dynp->d_tag >= DT_LOPROC &&
		    dynp->d_tag < DT_LOPROC + DT_PROCNUM)
			object->Dyn.info[dynp->d_tag + DT_NUM - DT_LOPROC] =
			    dynp->d_un.d_val;
		if (dynp->d_tag == DT_TEXTREL)
			object->dyn.textrel = 1;
		if (dynp->d_tag == DT_SYMBOLIC)
			object->dyn.symbolic = 1;
		if (dynp->d_tag == DT_BIND_NOW)
			object->obj_flags = RTLD_NOW;
		dynp++;
	}

	/*
	 *  Now relocate all pointer to dynamic info, but only
	 *  the ones which have pointer values.
	 */
	if (object->Dyn.info[DT_PLTGOT])
		object->Dyn.info[DT_PLTGOT] += obase;
	if (object->Dyn.info[DT_HASH])
		object->Dyn.info[DT_HASH] += obase;
	if (object->Dyn.info[DT_STRTAB])
		object->Dyn.info[DT_STRTAB] += obase;
	if (object->Dyn.info[DT_SYMTAB])
		object->Dyn.info[DT_SYMTAB] += obase;
	if (object->Dyn.info[DT_RELA])
		object->Dyn.info[DT_RELA] += obase;
	if (object->Dyn.info[DT_SONAME])
		object->Dyn.info[DT_SONAME] += obase;
	if (object->Dyn.info[DT_RPATH])
		object->Dyn.info[DT_RPATH] += object->Dyn.info[DT_STRTAB];
	if (object->Dyn.info[DT_REL])
		object->Dyn.info[DT_REL] += obase;
	if (object->Dyn.info[DT_INIT])
		object->Dyn.info[DT_INIT] += obase;
	if (object->Dyn.info[DT_FINI])
		object->Dyn.info[DT_FINI] += obase;
	if (object->Dyn.info[DT_JMPREL])
		object->Dyn.info[DT_JMPREL] += obase;

	if (object->Dyn.info[DT_HASH] != 0) {
		Elf_Word *hashtab = (Elf_Word *)object->Dyn.info[DT_HASH];

		object->nbuckets = hashtab[0];
		object->nchains = hashtab[1];
		object->buckets = hashtab + 2;
		object->chains = object->buckets + object->nbuckets;
	}

	object->phdrp = phdrp;
	object->phdrc = phdrc;
	object->obj_type = objtype;
	object->load_base = lbase;
	object->obj_base = obase;
	object->load_name = _dl_strdup(objname);
	if (_dl_loading_object == NULL) {
		/*
		 * no loading object, object is the loading object,
		 * as it is either executable, or dlopened()
		 */
		_dl_loading_object = object->load_object = object;
		DL_DEB(("head %s\n", object->load_name ));
	} else {
		object->load_object = _dl_loading_object;
	}
	DL_DEB(("obj %s has %s as head\n", object->load_name,
	    _dl_loading_object->load_name ));
	object->refcount = 0;
	TAILQ_INIT(&object->child_list);
	object->opencount = 0;	/* # dlopen() & exe */
	object->grprefcount = 0;
	/* default dev, inode for dlopen-able objects. */
	object->dev = 0;
	object->inode = 0;
	TAILQ_INIT(&object->grpsym_list);
	TAILQ_INIT(&object->grpref_list);

	return(object);
}
コード例 #7
0
int
_dl_md_reloc(elf_object_t *object, int rel, int relasz)
{
	Elf_RelA	*rela;
	Elf_Addr	loff;
	int	i, numrela, fails = 0;
	size_t	size;

	loff = object->obj_base;
	numrela = object->Dyn.info[relasz] / sizeof(Elf_RelA);
	rela = (Elf_RelA *)(object->Dyn.info[rel]);

#ifdef DEBUG
	DL_DEB(("object %s relasz %x, numrela %x loff %x\n",
	    object->load_name, object->Dyn.info[relasz], numrela, loff));
#endif

	if (rela == NULL)
		return (0);

	/* either it's an ld bug or a wacky hpux abi */
	if (!object->dyn.pltgot)
		object->Dyn.info[DT_PLTGOT] += loff;

	if (object->dyn.init && !((Elf_Addr)object->dyn.init & 2)) {
		Elf_Addr addr = _dl_md_plabel((Elf_Addr)object->dyn.init,
		    object->dyn.pltgot);
#ifdef DEBUG
		DL_DEB(("PLABEL32: %p:%p(_init) -> 0x%x in %s\n",
		    object->dyn.init, object->dyn.pltgot,
		    addr, object->load_name));
#endif
		object->dyn.init = (void *)addr;
	}

	if (object->dyn.fini && !((Elf_Addr)object->dyn.fini & 2)) {
		Elf_Addr addr = _dl_md_plabel((Elf_Addr)object->dyn.fini,
		    object->dyn.pltgot);
#ifdef DEBUG
		DL_DEB(("PLABEL32: %p:%p(_fini) -> 0x%x in %s\n",
		    object->dyn.fini, object->dyn.pltgot,
		    addr, object->load_name));
#endif
		object->dyn.fini = (void *)addr;
	}

	/*
	 * this is normally done by the crt0 code but we have to make
	 * sure it's set here to allow constructors to call functions
	 * that are overridden in the user binary (that are un-pic)
	 */
	if (object->obj_type == OBJTYPE_EXE)
		_hppa_dl_set_dp(object->dyn.pltgot);

	for (i = 0; i < numrela; i++, rela++) {
		const elf_object_t *sobj;
		const Elf_Sym *sym, *this;
		Elf_Addr *pt, ooff;
		const char *symn;
		int type;

		type = ELF_R_TYPE(rela->r_info);
		if (type == RELOC_NONE)
			continue;

		sym = object->dyn.symtab + ELF_R_SYM(rela->r_info);
		sobj = object;
		symn = object->dyn.strtab + sym->st_name;
		pt = (Elf_Addr *)(rela->r_offset + loff);

		ooff = 0;
		this = NULL;
		if (ELF_R_SYM(rela->r_info) && sym->st_name) {
			ooff = _dl_find_symbol_bysym(object,
			    ELF_R_SYM(rela->r_info), &this,
			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|
			    ((type == RELOC_IPLT) ? SYM_PLT: SYM_NOTPLT),
			    sym, &sobj);
			if (this == NULL) {
				if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
					fails++;
				continue;
			}
		}

#ifdef DEBUG
		DL_DEB(("*pt=%x r_addend=%x r_sym=%x\n",
		    *pt, rela->r_addend, ELF_R_SYM(rela->r_info)));
#endif

		switch (type) {
		case RELOC_DIR32:
			if (ELF_R_SYM(rela->r_info) && sym->st_name) {
				*pt = ooff + this->st_value + rela->r_addend;
#ifdef DEBUG
				DL_DEB(("[%x]DIR32: %s:%s -> 0x%x in %s\n",
				    i, symn, object->load_name,
				    *pt, sobj->load_name));
#endif
			} else {
				/*
				 * XXX should objects ever get their
				 * sections loaded insequential this
				 * would have to get a section number
				 * (ELF_R_SYM(rela->r_info))-1 and then:
				 *    *pt = sect->addr + rela->r_addend;
				 */
				if (ELF_R_SYM(rela->r_info))
					*pt += loff;
				else
					*pt += loff + rela->r_addend;
#ifdef DEBUG
				DL_DEB(("[%x]DIR32: %s @ 0x%x\n", i,
				    object->load_name, *pt));
#endif
			}
			break;

		case RELOC_PLABEL32:
			if (ELF_R_SYM(rela->r_info)) {
				if (ELF_ST_TYPE(this->st_info) != STT_FUNC) {
					DL_DEB(("[%x]PLABEL32: bad\n", i));
					break;
				}
				*pt = _dl_md_plabel(sobj->obj_base +
				    this->st_value + rela->r_addend,
				    sobj->dyn.pltgot);
#ifdef DEBUG
				DL_DEB(("[%x]PLABEL32: %s:%s -> 0x%x in %s\n",
				    i, symn, object->load_name,
				    *pt, sobj->load_name));
#endif
			} else {
				*pt = loff + rela->r_addend;
#ifdef DEBUG
				DL_DEB(("[%x]PLABEL32: %s @ 0x%x\n", i,
				    object->load_name, *pt));
#endif
			}
			break;

		case RELOC_IPLT:
			if (ELF_R_SYM(rela->r_info)) {
				pt[0] = ooff + this->st_value + rela->r_addend;
				pt[1] = (Elf_Addr)sobj->dyn.pltgot;
#ifdef DEBUG
				DL_DEB(("[%x]IPLT: %s:%s -> 0x%x:0x%x in %s\n",
				    i, symn, object->load_name,
				    pt[0], pt[1], sobj->load_name));
#endif
			} else {
				pt[0] = loff + rela->r_addend;
				pt[1] = (Elf_Addr)object->dyn.pltgot;
#ifdef DEBUG
				DL_DEB(("[%x]IPLT: %s @ 0x%x:0x%x\n", i,
				    object->load_name, pt[0], pt[1]));
#endif
			}
			break;

		case RELOC_COPY:
		{
			const Elf32_Sym *cpysrc = NULL;
			size = sym->st_size;
			ooff = _dl_find_symbol(symn, &cpysrc,
			    SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT,
			    sym, object, NULL);
			if (cpysrc) {
				_dl_bcopy((void *)(ooff + cpysrc->st_value),
				    pt, sym->st_size);
#ifdef DEBUG
				DL_DEB(("[%x]COPY: %s[%x]:%s -> %p[%x] in %s\n",
				    i, symn, ooff + cpysrc->st_value,
				    object->load_name, pt, sym->st_size,
				    sobj->load_name));
#endif
			} else
				DL_DEB(("[%x]COPY: no sym\n", i));
			break;
		}
		default:
			DL_DEB(("[%x]UNKNOWN(%d): type=%d off=0x%lx "
			    "addend=0x%lx rel=0x%x\n", i, type,
			    ELF_R_TYPE(rela->r_info), rela->r_offset,
			    rela->r_addend, *pt));
			break;
		}
	}

	return (fails);
}
コード例 #8
0
ファイル: rtld_machine.c プロジェクト: sofuture/bitrig
int
_dl_md_reloc(elf_object_t *object, int rel, int relsz)
{
	int	i;
	int	numrel;
	int	fails = 0;
	struct load_list *load_list;
	Elf64_Addr loff;
	Elf64_Addr ooff;
	Elf64_Addr got_start, got_end;
	Elf64_Rel  *relocs;
	const Elf64_Sym *sym, *this;

	loff = object->obj_base;
	numrel = object->Dyn.info[relsz] / sizeof(Elf64_Rel);
	relocs = (Elf64_Rel *)(object->Dyn.info[rel]);

	if (relocs == NULL)
		return(0);

	/*
	 * Change protection of all write protected segments in the
	 * object so we can do relocations in the .rodata section.
	 * After relocation restore protection.
	 */
	load_list = object->load_list;
	while (load_list != NULL) {
		if ((load_list->prot & PROT_WRITE) == 0)
			_dl_mprotect(load_list->start, load_list->size,
			    load_list->prot|PROT_WRITE);
		load_list = load_list->next;
	}

	/* XXX We need the got limits to know if reloc is in got. */
	/* XXX Relocs against the got should not include the STUB address! */
	this = NULL;
	got_start = 0;
	got_end = 0;
	ooff = _dl_find_symbol("__got_start", &this,
	    SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL);
	if (this != NULL)
		got_start = ooff + this->st_value;
	this = NULL;
	ooff = _dl_find_symbol("__got_end", &this,
	    SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL);
	if (this != NULL)
		got_end = ooff + this->st_value;

	DL_DEB(("relocating %d\n", numrel));
	for (i = 0; i < numrel; i++, relocs++) {
		Elf64_Addr r_addr = relocs->r_offset + loff;
		const char *symn;
		int type;

		if (ELF64_R_SYM(relocs->r_info) == 0xffffff)
			continue;

		ooff = 0;
		sym = object->dyn.symtab;
		sym += ELF64_R_SYM(relocs->r_info);
		symn = object->dyn.strtab + sym->st_name;
		type = ELF64_R_TYPE(relocs->r_info);

		this = NULL;
		if (ELF64_R_SYM(relocs->r_info) &&
		    !(ELF64_ST_BIND(sym->st_info) == STB_LOCAL &&
		    ELF64_ST_TYPE (sym->st_info) == STT_NOTYPE)) {
			ooff = _dl_find_symbol(symn, &this,
			SYM_SEARCH_ALL | SYM_WARNNOTFOUND | SYM_PLT,
			sym, object, NULL);

			if (this == NULL) {
				if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
					fails++;
				continue;
			}
		}

		switch (ELF64_R_TYPE(relocs->r_info)) {
			/* XXX Handle non aligned relocs. .eh_frame
			 * XXX in libstdc++ seems to have them... */
			u_int64_t robj;

		case R_MIPS_REL32_64:
			if (ELF64_ST_BIND(sym->st_info) == STB_LOCAL &&
			    (ELF64_ST_TYPE(sym->st_info) == STT_SECTION ||
			    ELF64_ST_TYPE(sym->st_info) == STT_NOTYPE) ) {
				if ((long)r_addr & 7) {
					_dl_bcopy((char *)r_addr, &robj, sizeof(robj));
					robj += loff + sym->st_value;
					_dl_bcopy(&robj, (char *)r_addr, sizeof(robj));
				} else {
					*(u_int64_t *)r_addr += loff + sym->st_value;
				}
			} else if (this && ((long)r_addr & 7)) {
				_dl_bcopy((char *)r_addr, &robj, sizeof(robj));
				robj += this->st_value + ooff;
				_dl_bcopy(&robj, (char *)r_addr, sizeof(robj));
			} else if (this) {
				*(u_int64_t *)r_addr += this->st_value + ooff;
			}
			break;

		case R_MIPS_NONE:
			break;

		default:
			_dl_printf("%s: unsupported relocation '%d'\n",
			    _dl_progname, ELF64_R_TYPE(relocs->r_info));
			_dl_exit(1);
		}
	}
	DL_DEB(("done %d fails\n", fails));
	load_list = object->load_list;
	while (load_list != NULL) {
		if ((load_list->prot & PROT_WRITE) == 0)
			_dl_mprotect(load_list->start, load_list->size,
			    load_list->prot);
		load_list = load_list->next;
	}
	return(fails);
}
コード例 #9
0
ファイル: rtld_machine.c プロジェクト: sofuture/bitrig
/*
 *	Relocate the Global Offset Table (GOT). Currently we don't
 *	do lazy evaluation here because the GNU linker doesn't
 *	follow the ABI spec which says that if an external symbol
 *	is referenced by other relocations than CALL16 and 26 it
 *	should not be given a stub and have a zero value in the
 *	symbol table. By not doing so, we can't use pointers to
 *	external functions and use them in comparisons...
 */
int
_dl_md_reloc_got(elf_object_t *object, int lazy)
{
	int	i, n;
	Elf64_Addr loff;
	Elf64_Addr ooff;
	Elf64_Addr *gotp;
	const Elf64_Sym  *symp;
	const Elf64_Sym  *this;
	const char *strt;

	if (object->status & STAT_GOT_DONE)
		return (0);

	loff = object->obj_base;
	strt = object->dyn.strtab;
	gotp = object->dyn.pltgot;
	n = object->Dyn.info[DT_MIPS_LOCAL_GOTNO - DT_LOPROC + DT_NUM];

	DL_DEB(("loff: '%p'\n", loff));
	/*
	 *  Set up pointers for run time (lazy) resolving.
	 */
	gotp[0] = (long)_dl_bind_start;
	gotp[1] = (long)object;

	/*  First do all local references. */
	for (i = 2; i < n; i++) {
		gotp[i] += loff;
	}

	gotp += n;

	symp =  object->dyn.symtab;
	symp += object->Dyn.info[DT_MIPS_GOTSYM - DT_LOPROC + DT_NUM];
	n =  object->Dyn.info[DT_MIPS_SYMTABNO - DT_LOPROC + DT_NUM] -
	    object->Dyn.info[DT_MIPS_GOTSYM - DT_LOPROC + DT_NUM];

	this = NULL;
	object->plt_size = 0;
	object->got_size = 0;
	ooff = _dl_find_symbol("__got_start", &this,
	    SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL);
	if (this != NULL)
		object->got_start = ooff + this->st_value;

	this = NULL;
	ooff = _dl_find_symbol("__got_end", &this,
	    SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL);
	if (this != NULL)
		object->got_size = ooff + this->st_value  - object->got_start;

	/*
	 *  Then do all global references according to the ABI.
	 *  Quickstart is not yet implemented.
	 */
	while (n--) {
		if (symp->st_shndx == SHN_UNDEF &&
		    ELF64_ST_TYPE(symp->st_info) == STT_FUNC) {
			if (symp->st_value == 0 || !lazy) {
				this = NULL;
				ooff = _dl_find_symbol(strt + symp->st_name,
				    &this,
				    SYM_SEARCH_ALL|SYM_NOWARNNOTFOUND|SYM_PLT,
				    symp, object, NULL);
				if (this)
					*gotp = this->st_value + ooff;
			} else
				*gotp = symp->st_value + loff;
		} else if (symp->st_shndx == SHN_COMMON ||
			symp->st_shndx == SHN_UNDEF) {
			this = NULL;
			ooff = _dl_find_symbol(strt + symp->st_name, &this,
			    SYM_SEARCH_ALL|SYM_NOWARNNOTFOUND|SYM_PLT,
			    symp, object, NULL);
			if (this)
				*gotp = this->st_value + ooff;
		} else if (ELF64_ST_TYPE(symp->st_info) == STT_FUNC &&
			symp->st_value != *gotp) {
			*gotp += loff;
		} else {	/* Resolve all others immediately */
			this = NULL;
			ooff = _dl_find_symbol(strt + symp->st_name, &this,
			    SYM_SEARCH_ALL|SYM_NOWARNNOTFOUND|SYM_PLT,
			    symp, object, NULL);
			if (this)
				*gotp = this->st_value + ooff;
			else
				*gotp = symp->st_value + loff;
		}
		gotp++;
		symp++;
	}
	object->status |= STAT_GOT_DONE;

	DL_DEB(("got: %x, %x\n", object->got_start, object->got_size));
	if (object->got_size != 0)
		_dl_mprotect((void*)object->got_start, object->got_size,
		    PROT_READ);

	return (0);
}
コード例 #10
0
ファイル: library.c プロジェクト: appleorange1/bitrig
elf_object_t *
_dl_tryload_shlib(const char *libname, int type, int flags)
{
	int	libfile, i;
	struct load_list *next_load, *load_list = NULL;
	Elf_Addr maxva = 0, minva = ELFDEFNNAME(NO_ADDR);
	Elf_Addr libaddr, loff, align = _dl_pagesz - 1;
	elf_object_t *object;
	char	hbuf[4096];
	Elf_Dyn *dynp = 0;
	Elf_Ehdr *ehdr;
	Elf_Phdr *phdp;
	Elf_Phdr *ptls = 0;
	struct stat sb;
	void *prebind_data;

#define ROUND_PG(x) (((x) + align) & ~(align))
#define TRUNC_PG(x) ((x) & ~(align))

	libfile = _dl_open(libname, O_RDONLY);
	if (libfile < 0) {
		_dl_errno = DL_CANT_OPEN;
		return(0);
	}

	if ( _dl_fstat(libfile, &sb) < 0) {
		_dl_errno = DL_CANT_OPEN;
		return(0);
	}

	for (object = _dl_objects; object != NULL; object = object->next) {
		if (object->dev == sb.st_dev &&
		    object->inode == sb.st_ino) {
			object->obj_flags |= flags & DF_1_GLOBAL;
			_dl_close(libfile);
			if (_dl_loading_object == NULL)
				_dl_loading_object = object;
			if (object->load_object != _dl_objects &&
			    object->load_object != _dl_loading_object) {
				_dl_link_grpref(object->load_object,
				    _dl_loading_object);
			}
			return(object);
		}
	}

	_dl_read(libfile, hbuf, sizeof(hbuf));
	ehdr = (Elf_Ehdr *)hbuf;
	if (ehdr->e_ident[0] != ELFMAG0  || ehdr->e_ident[1] != ELFMAG1 ||
	    ehdr->e_ident[2] != ELFMAG2 || ehdr->e_ident[3] != ELFMAG3 ||
	    ehdr->e_type != ET_DYN || ehdr->e_machine != MACHID) {
		_dl_close(libfile);
		_dl_errno = DL_NOT_ELF;
		return(0);
	}

	/*
	 *  Alright, we might have a winner!
	 *  Figure out how much VM space we need.
	 */
	phdp = (Elf_Phdr *)(hbuf + ehdr->e_phoff);
	for (i = 0; i < ehdr->e_phnum; i++, phdp++) {
		switch (phdp->p_type) {
		case PT_LOAD:
			if (phdp->p_vaddr < minva)
				minva = phdp->p_vaddr;
			if (phdp->p_vaddr + phdp->p_memsz > maxva)
				maxva = phdp->p_vaddr + phdp->p_memsz;
			break;
		case PT_DYNAMIC:
			dynp = (Elf_Dyn *)phdp->p_vaddr;
			break;
		case PT_TLS:
			ptls = phdp;
			break;
		default:
			break;
		}
	}
	minva = TRUNC_PG(minva);
	maxva = ROUND_PG(maxva);

	/*
	 * We map the entire area to see that we can get the VM
	 * space required. Map it unaccessible to start with.
	 *
	 * We must map the file we'll map later otherwise the VM
	 * system won't be able to align the mapping properly
	 * on VAC architectures.
	 */
	libaddr = (Elf_Addr)_dl_mmap(0, maxva - minva, PROT_NONE,
	    MAP_PRIVATE|MAP_FILE, libfile, 0);
	if (_dl_mmap_error(libaddr)) {
		_dl_printf("%s: rtld mmap failed mapping %s.\n",
		    _dl_progname, libname);
		_dl_close(libfile);
		_dl_errno = DL_CANT_MMAP;
		return(0);
	}

	loff = libaddr - minva;
	phdp = (Elf_Phdr *)(hbuf + ehdr->e_phoff);

	for (i = 0; i < ehdr->e_phnum; i++, phdp++) {
		switch (phdp->p_type) {
		case PT_LOAD: {
			char *start = (char *)(TRUNC_PG(phdp->p_vaddr)) + loff;
			Elf_Addr off = (phdp->p_vaddr & align);
			Elf_Addr size = off + phdp->p_filesz;
			void *res;

			if (size != 0) {
				res = _dl_mmap(start, ROUND_PG(size),
				    PFLAGS(phdp->p_flags),
				    MAP_FIXED|MAP_PRIVATE, libfile,
				    TRUNC_PG(phdp->p_offset));
			} else
				res = NULL;	/* silence gcc */
			next_load = _dl_malloc(sizeof(struct load_list));
			next_load->next = load_list;
			load_list = next_load;
			next_load->start = start;
			next_load->size = size;
			next_load->prot = PFLAGS(phdp->p_flags);
			if (size != 0 && _dl_mmap_error(res)) {
				_dl_printf("%s: rtld mmap failed mapping %s.\n",
				    _dl_progname, libname);
				_dl_close(libfile);
				_dl_errno = DL_CANT_MMAP;
				_dl_munmap((void *)libaddr, maxva - minva);
				_dl_load_list_free(load_list);
				return(0);
			}
			if (phdp->p_flags & PF_W) {
				/* Zero out everything past the EOF */
				if ((size & align) != 0)
					_dl_memset(start + size, 0,
					    _dl_pagesz - (size & align));
				if (ROUND_PG(size) ==
				    ROUND_PG(off + phdp->p_memsz))
					continue;
				start = start + ROUND_PG(size);
				size = ROUND_PG(off + phdp->p_memsz) -
				    ROUND_PG(size);
				res = _dl_mmap(start, size,
				    PFLAGS(phdp->p_flags),
				    MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0);
				if (_dl_mmap_error(res)) {
					_dl_printf("%s: rtld mmap failed mapping %s.\n",
					    _dl_progname, libname);
					_dl_close(libfile);
					_dl_errno = DL_CANT_MMAP;
					_dl_munmap((void *)libaddr, maxva - minva);
					_dl_load_list_free(load_list);
					return(0);
				}
			}
			break;
		}

		case PT_OPENBSD_RANDOMIZE:
			_dl_randombuf((char *)(phdp->p_vaddr + loff),
			    phdp->p_memsz);
			break;

		default:
			break;
		}
	}

	prebind_data = prebind_load_fd(libfile, libname);

	_dl_close(libfile);

	dynp = (Elf_Dyn *)((unsigned long)dynp + loff);
	object = _dl_finalize_object(libname, dynp,
	    (Elf_Phdr *)((char *)libaddr + ehdr->e_phoff), ehdr->e_phnum,type,
	    libaddr, loff);
	if (object) {
		object->prebind_data = prebind_data;
		object->load_size = maxva - minva;	/*XXX*/
		object->load_list = load_list;
		/* set inode, dev from stat info */
		object->dev = sb.st_dev;
		object->inode = sb.st_ino;
		object->obj_flags |= flags;
		_dl_set_sod(object->load_name, &object->sod);
		if (ptls && ptls->p_memsz) {
			if (ptls->p_filesz > ptls->p_memsz) {
				_dl_printf("%s: invalid tls data in %s.\n",
				    _dl_progname, libname);
				_dl_exit(9);
			}
			if (ptls->p_vaddr != 0 && ptls->p_filesz != 0) {
				object->tls_static_data =
				    (void *)(ptls->p_vaddr + libaddr);
			}
			_dl_tls_dtv_generation++;
			object->tls_index = _dl_tls_max_index++;
			object->tls_fsize = ptls->p_filesz;
			object->tls_msize = ptls->p_memsz;
			object->tls_align = ptls->p_align;
			DL_DEB(("tls %x %x %x %x %u\n",
			    object->tls_static_data, object->tls_fsize,
			    object->tls_msize, object->tls_align,
			    object->tls_index));
		}
	} else {
		_dl_munmap((void *)libaddr, maxva - minva);
		_dl_load_list_free(load_list);
	}
	return(object);
}
コード例 #11
0
ファイル: resolve.c プロジェクト: ajinkya93/OpenBSD
/*
 * Initialize a new dynamic object.
 */
elf_object_t *
_dl_finalize_object(const char *objname, Elf_Dyn *dynp, Elf_Phdr *phdrp,
    int phdrc, const int objtype, const long lbase, const long obase)
{
	elf_object_t *object;
#if 0
	_dl_printf("objname [%s], dynp %p, objtype %x lbase %lx, obase %lx\n",
	    objname, dynp, objtype, lbase, obase);
#endif
	object = _dl_calloc(1, sizeof(elf_object_t));
	if (object == NULL)
		_dl_exit(7);
	object->prev = object->next = NULL;

	object->load_dyn = dynp;
	while (dynp->d_tag != DT_NULL) {
		if (dynp->d_tag < DT_NUM)
			object->Dyn.info[dynp->d_tag] = dynp->d_un.d_val;
		else if (dynp->d_tag >= DT_LOPROC &&
		    dynp->d_tag < DT_LOPROC + DT_PROCNUM)
			object->Dyn.info[dynp->d_tag + DT_NUM - DT_LOPROC] =
			    dynp->d_un.d_val;
		if (dynp->d_tag == DT_TEXTREL)
			object->dyn.textrel = 1;
		if (dynp->d_tag == DT_SYMBOLIC)
			object->dyn.symbolic = 1;
		if (dynp->d_tag == DT_BIND_NOW)
			object->obj_flags |= DF_1_NOW;
		if (dynp->d_tag == DT_FLAGS_1)
			object->obj_flags |= dynp->d_un.d_val;
		if (dynp->d_tag == DT_RELACOUNT)
			object->relacount = dynp->d_un.d_val;
		if (dynp->d_tag == DT_RELCOUNT)
			object->relcount = dynp->d_un.d_val;
		dynp++;
	}
	DL_DEB((" flags %s = 0x%x\n", objname, object->obj_flags ));
	object->obj_type = objtype;

	if (_dl_loading_object == NULL) {
		/*
		 * no loading object, object is the loading object,
		 * as it is either executable, or dlopened()
		 */
		_dl_loading_object = object;
	}

	if ((object->obj_flags & DF_1_NOOPEN) != 0 &&
	    _dl_loading_object->obj_type == OBJTYPE_DLO &&
	    _dl_traceld == NULL) {
		_dl_free(object);
		_dl_errno = DL_CANT_LOAD_OBJ;
		return(NULL);
	}

	/*
	 *  Now relocate all pointer to dynamic info, but only
	 *  the ones which have pointer values.
	 */
	if (object->Dyn.info[DT_PLTGOT])
		object->Dyn.info[DT_PLTGOT] += obase;
	if (object->Dyn.info[DT_HASH])
		object->Dyn.info[DT_HASH] += obase;
	if (object->Dyn.info[DT_STRTAB])
		object->Dyn.info[DT_STRTAB] += obase;
	if (object->Dyn.info[DT_SYMTAB])
		object->Dyn.info[DT_SYMTAB] += obase;
	if (object->Dyn.info[DT_RELA])
		object->Dyn.info[DT_RELA] += obase;
	if (object->Dyn.info[DT_SONAME])
		object->Dyn.info[DT_SONAME] += object->Dyn.info[DT_STRTAB];
	if (object->Dyn.info[DT_RPATH])
		object->Dyn.info[DT_RPATH] += object->Dyn.info[DT_STRTAB];
	if (object->Dyn.info[DT_REL])
		object->Dyn.info[DT_REL] += obase;
	if (object->Dyn.info[DT_INIT])
		object->Dyn.info[DT_INIT] += obase;
	if (object->Dyn.info[DT_FINI])
		object->Dyn.info[DT_FINI] += obase;
	if (object->Dyn.info[DT_JMPREL])
		object->Dyn.info[DT_JMPREL] += obase;

	if (object->Dyn.info[DT_HASH] != 0) {
		Elf_Word *hashtab = (Elf_Word *)object->Dyn.info[DT_HASH];

		object->nbuckets = hashtab[0];
		object->nchains = hashtab[1];
		object->buckets = hashtab + 2;
		object->chains = object->buckets + object->nbuckets;
	}

	object->phdrp = phdrp;
	object->phdrc = phdrc;
	object->load_base = lbase;
	object->obj_base = obase;
	object->load_name = _dl_strdup(objname);
	if (object->load_name == NULL)
		_dl_exit(7);
	object->load_object = _dl_loading_object;
	if (object->load_object == object)
		DL_DEB(("head %s\n", object->load_name));
	DL_DEB(("obj %s has %s as head\n", object->load_name,
	    _dl_loading_object->load_name ));
	object->refcount = 0;
	TAILQ_INIT(&object->child_list);
	object->opencount = 0;	/* # dlopen() & exe */
	object->grprefcount = 0;
	/* default dev, inode for dlopen-able objects. */
	object->dev = 0;
	object->inode = 0;
	object->grpsym_gen = 0;
	TAILQ_INIT(&object->grpsym_list);
	TAILQ_INIT(&object->grpref_list);

	if (object->dyn.rpath) {
		object->rpath = _dl_split_path(object->dyn.rpath);
		if ((object->obj_flags & DF_1_ORIGIN) && _dl_trust)
			_dl_origin_subst(object);
	}

	_dl_trace_object_setup(object);

	return (object);
}
コード例 #12
0
ファイル: resolve.c プロジェクト: ajinkya93/OpenBSD
/*
 * Perform $ORIGIN substitutions on path
 */
static void
_dl_origin_subst_path(elf_object_t *object, const char *origin_path,
    char **path)
{
	char tmp_path[PATH_MAX];
	char *new_path, *tp;
	const char *pp, *name, *value;
	static struct utsname uts;
	size_t value_len;
	int skip_brace;

	if (uts.sysname[0] == '\0') {
		if (_dl_uname(&uts) != 0)
			return;
	}

	tp = tmp_path;
	pp = *path;

	while (*pp != '\0' && (tp - tmp_path) < sizeof(tmp_path)) {

		/* copy over chars up to but not including $ */
		while (*pp != '\0' && *pp != '$' &&
		    (tp - tmp_path) < sizeof(tmp_path))
			*tp++ = *pp++;

		/* substitution sequence detected */
		if (*pp == '$' && (tp - tmp_path) < sizeof(tmp_path)) {
			pp++;

			if ((skip_brace = (*pp == '{')))
				pp++;

			/* skip over name */
			name = pp;
			while (_dl_isalnum((unsigned char)*pp) || *pp == '_')
				pp++;

			switch (_dl_subst_name(name, pp - name)) {
			case SUBST_ORIGIN:
				value = origin_path;
				break;
			case SUBST_OSNAME:
				value = uts.sysname;
				break;
			case SUBST_OSREL:
				value = uts.release;
				break;
			case SUBST_PLATFORM:
				value = uts.machine;
				break;
			default:
				value = "";
			}

			value_len = _dl_strlen(value);
			if (value_len >= sizeof(tmp_path) - (tp - tmp_path))
				return;

			_dl_bcopy(value, tp, value_len);
			tp += value_len;

			if (skip_brace && *pp == '}')
				pp++;
		}
	}

	/* no substitution made if result exceeds sizeof(tmp_path) */
	if (tp - tmp_path >= sizeof(tmp_path))
		return;

	/* NULL terminate tmp_path */
	*tp = '\0';

	if (_dl_strcmp(tmp_path, *path) == 0)
		return;

	new_path = _dl_strdup(tmp_path);
	if (new_path == NULL)
		return;

	DL_DEB(("orig_path %s\n", *path));
	DL_DEB(("new_path  %s\n", new_path));

	_dl_free(*path);
	*path = new_path;
}