Exemplo n.º 1
0
/*
 * Process a shared object's DYNAMIC section, and save the important
 * information in its Obj_Entry structure.
 */
void
_rtld_digest_dynamic(const char *execname, Obj_Entry *obj)
{
	Elf_Dyn        *dynp;
	Needed_Entry  **needed_tail = &obj->needed;
	const Elf_Dyn  *dyn_rpath = NULL;
	bool		use_pltrel = false;
	bool		use_pltrela = false;
	Elf_Addr        relsz = 0, relasz = 0;
	Elf_Addr	pltrel = 0, pltrelsz = 0;
	Elf_Addr	init = 0, fini = 0;

	for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; ++dynp) {
		switch (dynp->d_tag) {

		case DT_REL:
			obj->rel = (const Elf_Rel *)
			    (obj->relocbase + dynp->d_un.d_ptr);
			break;

		case DT_RELSZ:
			relsz = dynp->d_un.d_val;
			break;

		case DT_RELENT:
			assert(dynp->d_un.d_val == sizeof(Elf_Rel));
			break;

		case DT_JMPREL:
			pltrel = dynp->d_un.d_ptr;
			break;

		case DT_PLTRELSZ:
			pltrelsz = dynp->d_un.d_val;
			break;

		case DT_RELA:
			obj->rela = (const Elf_Rela *)
			    (obj->relocbase + dynp->d_un.d_ptr);
			break;

		case DT_RELASZ:
			relasz = dynp->d_un.d_val;
			break;

		case DT_RELAENT:
			assert(dynp->d_un.d_val == sizeof(Elf_Rela));
			break;

		case DT_PLTREL:
			use_pltrel = dynp->d_un.d_val == DT_REL;
			use_pltrela = dynp->d_un.d_val == DT_RELA;
			assert(use_pltrel || use_pltrela);
			break;

		case DT_SYMTAB:
			obj->symtab = (const Elf_Sym *)
				(obj->relocbase + dynp->d_un.d_ptr);
			break;

		case DT_SYMENT:
			assert(dynp->d_un.d_val == sizeof(Elf_Sym));
			break;

		case DT_STRTAB:
			obj->strtab = (const char *)
			    (obj->relocbase + dynp->d_un.d_ptr);
			break;

		case DT_STRSZ:
			obj->strsize = dynp->d_un.d_val;
			break;

		case DT_HASH:
			{
				const Elf_Symindx *hashtab = (const Elf_Symindx *)
				    (obj->relocbase + dynp->d_un.d_ptr);

				if (hashtab[0] > UINT32_MAX)
					obj->nbuckets = UINT32_MAX;
				else
					obj->nbuckets = hashtab[0];
				obj->nchains = hashtab[1];
				obj->buckets = hashtab + 2;
				obj->chains = obj->buckets + obj->nbuckets;
				/*
				 * Should really be in _rtld_relocate_objects,
				 * but _rtld_symlook_obj might be used before.
				 */
				if (obj->nbuckets) {
					fast_divide32_prepare(obj->nbuckets,
					    &obj->nbuckets_m,
					    &obj->nbuckets_s1,
					    &obj->nbuckets_s2);
				}
			}
			break;

		case DT_NEEDED:
			{
				Needed_Entry *nep = NEW(Needed_Entry);

				nep->name = dynp->d_un.d_val;
				nep->obj = NULL;
				nep->next = NULL;

				*needed_tail = nep;
				needed_tail = &nep->next;
			}
			break;

		case DT_PLTGOT:
			obj->pltgot = (Elf_Addr *)
			    (obj->relocbase + dynp->d_un.d_ptr);
			break;

		case DT_TEXTREL:
			obj->textrel = true;
			break;

		case DT_SYMBOLIC:
			obj->symbolic = true;
			break;

		case DT_RPATH:
			/*
		         * We have to wait until later to process this, because
			 * we might not have gotten the address of the string
			 * table yet.
		         */
			dyn_rpath = dynp;
			break;

		case DT_SONAME:
			/* Not used by the dynamic linker. */
			break;

		case DT_INIT:
			init = dynp->d_un.d_ptr;
			break;

		case DT_FINI:
			fini = dynp->d_un.d_ptr;
			break;

		/*
		 * Don't process DT_DEBUG on MIPS as the dynamic section
		 * is mapped read-only. DT_MIPS_RLD_MAP is used instead.
		 * XXX: n32/n64 may use DT_DEBUG, not sure yet.
		 */
#ifndef __mips__
		case DT_DEBUG:
#ifdef RTLD_LOADER
			dynp->d_un.d_ptr = (Elf_Addr)&_rtld_debug;
#endif
			break;
#endif

#ifdef __mips__
		case DT_MIPS_LOCAL_GOTNO:
			obj->local_gotno = dynp->d_un.d_val;
			break;

		case DT_MIPS_SYMTABNO:
			obj->symtabno = dynp->d_un.d_val;
			break;

		case DT_MIPS_GOTSYM:
			obj->gotsym = dynp->d_un.d_val;
			break;

		case DT_MIPS_RLD_MAP:
#ifdef RTLD_LOADER
			*((Elf_Addr *)(dynp->d_un.d_ptr)) = (Elf_Addr)
			    &_rtld_debug;
#endif
			break;
#endif
#ifdef __powerpc__
		case DT_PPC_GOT:
			obj->gotptr = (Elf_Addr *)(obj->relocbase + dynp->d_un.d_ptr);
			break;
#endif
		case DT_FLAGS_1:
			obj->z_now =
			    ((dynp->d_un.d_val & DF_1_BIND_NOW) != 0);
			obj->z_nodelete =
			    ((dynp->d_un.d_val & DF_1_NODELETE) != 0);
			obj->z_initfirst =
			    ((dynp->d_un.d_val & DF_1_INITFIRST) != 0);
			obj->z_noopen =
			    ((dynp->d_un.d_val & DF_1_NOOPEN) != 0);
			break;
		}
	}

	obj->rellim = (const Elf_Rel *)((const uint8_t *)obj->rel + relsz);
	obj->relalim = (const Elf_Rela *)((const uint8_t *)obj->rela + relasz);
	if (use_pltrel) {
		obj->pltrel = (const Elf_Rel *)(obj->relocbase + pltrel);
		obj->pltrellim = (const Elf_Rel *)(obj->relocbase + pltrel + pltrelsz);
		obj->pltrelalim = 0;
		/* On PPC and SPARC, at least, REL(A)SZ may include JMPREL.
		   Trim rel(a)lim to save time later. */
		if (obj->rellim && obj->pltrel &&
		    obj->rellim > obj->pltrel &&
		    obj->rellim <= obj->pltrellim)
			obj->rellim = obj->pltrel;
	} else if (use_pltrela) {
		obj->pltrela = (const Elf_Rela *)(obj->relocbase + pltrel);
		obj->pltrellim = 0;
		obj->pltrelalim = (const Elf_Rela *)(obj->relocbase + pltrel + pltrelsz);
		/* On PPC and SPARC, at least, REL(A)SZ may include JMPREL.
		   Trim rel(a)lim to save time later. */
		if (obj->relalim && obj->pltrela &&
		    obj->relalim > obj->pltrela &&
		    obj->relalim <= obj->pltrelalim)
			obj->relalim = obj->pltrela;
	}

#if defined(RTLD_LOADER) && defined(__HAVE_FUNCTION_DESCRIPTORS)
	if (init != 0)
		obj->init = (void (*)(void))
		    _rtld_function_descriptor_alloc(obj, NULL, init);
	if (fini != 0)
		obj->fini = (void (*)(void))
		    _rtld_function_descriptor_alloc(obj, NULL, fini);
#else
	if (init != 0)
		obj->init = (void (*)(void))
		    (obj->relocbase + init);
	if (fini != 0)
		obj->fini = (void (*)(void))
		    (obj->relocbase + fini);
#endif

	if (dyn_rpath != NULL) {
		_rtld_add_paths(execname, &obj->rpaths, obj->strtab +
		    dyn_rpath->d_un.d_val);
	}
}
/*
 * Process a shared object's DYNAMIC section, and save the important
 * information in its Obj_Entry structure.
 */
void
_rtld_digest_dynamic(const char *execname, Obj_Entry *obj)
{
	Elf_Dyn        *dynp;
	Needed_Entry  **needed_tail = &obj->needed;
	const Elf_Dyn  *dyn_soname = NULL;
	const Elf_Dyn  *dyn_rpath = NULL;
	bool		use_pltrel = false;
	bool		use_pltrela = false;
	Elf_Addr        relsz = 0, relasz = 0;
	Elf_Addr	pltrel = 0, pltrelsz = 0;
#ifdef RTLD_LOADER
	Elf_Addr	init = 0, fini = 0;
#endif

	dbg(("headers: digesting PT_DYNAMIC at %p", obj->dynamic));
	for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; ++dynp) {
		dbg(("  d_tag %ld at %p", (long)dynp->d_tag, dynp));
		switch (dynp->d_tag) {

		case DT_REL:
			obj->rel = (const Elf_Rel *)
			    (obj->relocbase + dynp->d_un.d_ptr);
			break;

		case DT_RELSZ:
			relsz = dynp->d_un.d_val;
			break;

		case DT_RELENT:
			assert(dynp->d_un.d_val == sizeof(Elf_Rel));
			break;

		case DT_JMPREL:
			pltrel = dynp->d_un.d_ptr;
			break;

		case DT_PLTRELSZ:
			pltrelsz = dynp->d_un.d_val;
			break;

		case DT_RELA:
			obj->rela = (const Elf_Rela *)
			    (obj->relocbase + dynp->d_un.d_ptr);
			break;

		case DT_RELASZ:
			relasz = dynp->d_un.d_val;
			break;

		case DT_RELAENT:
			assert(dynp->d_un.d_val == sizeof(Elf_Rela));
			break;

		case DT_PLTREL:
			use_pltrel = dynp->d_un.d_val == DT_REL;
			use_pltrela = dynp->d_un.d_val == DT_RELA;
			assert(use_pltrel || use_pltrela);
			break;

		case DT_SYMTAB:
			obj->symtab = (const Elf_Sym *)
				(obj->relocbase + dynp->d_un.d_ptr);
			break;

		case DT_SYMENT:
			assert(dynp->d_un.d_val == sizeof(Elf_Sym));
			break;

		case DT_STRTAB:
			obj->strtab = (const char *)
			    (obj->relocbase + dynp->d_un.d_ptr);
			break;

		case DT_STRSZ:
			obj->strsize = dynp->d_un.d_val;
			break;

		case DT_VERNEED:
			obj->verneed = (const Elf_Verneed *)
			    (obj->relocbase + dynp->d_un.d_ptr);
			break;

		case DT_VERNEEDNUM:
			obj->verneednum = dynp->d_un.d_val;
			break;

		case DT_VERDEF:
			obj->verdef = (const Elf_Verdef *)
			    (obj->relocbase + dynp->d_un.d_ptr);
			break;

		case DT_VERDEFNUM:
			obj->verdefnum = dynp->d_un.d_val;
			break;

		case DT_VERSYM:
			obj->versyms = (const Elf_Versym *)
			    (obj->relocbase + dynp->d_un.d_ptr);
			break;

		case DT_HASH:
			{
				const Elf_Symindx *hashtab = (const Elf_Symindx *)
				    (obj->relocbase + dynp->d_un.d_ptr);

				if (hashtab[0] > UINT32_MAX)
					obj->nbuckets = UINT32_MAX;
				else
					obj->nbuckets = hashtab[0];
				obj->nchains = hashtab[1];
				obj->buckets = hashtab + 2;
				obj->chains = obj->buckets + obj->nbuckets;
				/*
				 * Should really be in _rtld_relocate_objects,
				 * but _rtld_symlook_obj might be used before.
				 */
				if (obj->nbuckets) {
					fast_divide32_prepare(obj->nbuckets,
					    &obj->nbuckets_m,
					    &obj->nbuckets_s1,
					    &obj->nbuckets_s2);
				}
			}
			break;

		case DT_NEEDED:
			{
				Needed_Entry *nep = NEW(Needed_Entry);

				nep->name = dynp->d_un.d_val;
				nep->obj = NULL;
				nep->next = NULL;

				*needed_tail = nep;
				needed_tail = &nep->next;
			}
			break;

		case DT_PLTGOT:
			obj->pltgot = (Elf_Addr *)
			    (obj->relocbase + dynp->d_un.d_ptr);
			break;

		case DT_TEXTREL:
			obj->textrel = true;
			break;

		case DT_SYMBOLIC:
			obj->symbolic = true;
			break;

		case DT_RPATH:
			/*
		         * We have to wait until later to process this, because
			 * we might not have gotten the address of the string
			 * table yet.
		         */
			dyn_rpath = dynp;
			break;

		case DT_SONAME:
			dyn_soname = dynp;
			break;

		case DT_INIT:
#ifdef RTLD_LOADER
			init = dynp->d_un.d_ptr;
#endif
			break;

#ifdef HAVE_INITFINI_ARRAY
		case DT_INIT_ARRAY:
			obj->init_array =
			    (Elf_Addr *)(obj->relocbase + dynp->d_un.d_ptr);
			dbg(("headers: DT_INIT_ARRAY at %p",
			    obj->init_array));
			break;

		case DT_INIT_ARRAYSZ:
			obj->init_arraysz = dynp->d_un.d_val / sizeof(fptr_t);
			dbg(("headers: DT_INIT_ARRAYZ %zu",
			    obj->init_arraysz));
			break;
#endif

		case DT_FINI:
#ifdef RTLD_LOADER
			fini = dynp->d_un.d_ptr;
#endif
			break;

#ifdef HAVE_INITFINI_ARRAY
		case DT_FINI_ARRAY:
			obj->fini_array =
			    (Elf_Addr *)(obj->relocbase + dynp->d_un.d_ptr);
			dbg(("headers: DT_FINI_ARRAY at %p",
			    obj->fini_array));
			break;

		case DT_FINI_ARRAYSZ:
			obj->fini_arraysz = dynp->d_un.d_val / sizeof(fptr_t);
			dbg(("headers: DT_FINI_ARRAYZ %zu",
			    obj->fini_arraysz));
			break;
#endif

		/*
		 * Don't process DT_DEBUG on MIPS as the dynamic section
		 * is mapped read-only. DT_MIPS_RLD_MAP is used instead.
		 * XXX: n32/n64 may use DT_DEBUG, not sure yet.
		 */
#ifndef __mips__
		case DT_DEBUG:
#ifdef RTLD_LOADER
			dynp->d_un.d_ptr = (Elf_Addr)&_rtld_debug;
#endif
			break;
#endif

#ifdef __mips__
		case DT_MIPS_LOCAL_GOTNO:
			obj->local_gotno = dynp->d_un.d_val;
			break;

		case DT_MIPS_SYMTABNO:
			obj->symtabno = dynp->d_un.d_val;
			break;

		case DT_MIPS_GOTSYM:
			obj->gotsym = dynp->d_un.d_val;
			break;

		case DT_MIPS_RLD_MAP:
#ifdef RTLD_LOADER
			*((Elf_Addr *)(dynp->d_un.d_ptr)) = (Elf_Addr)
			    &_rtld_debug;
#endif
			break;
#endif
#ifdef __powerpc__
#ifdef _LP64
		case DT_PPC64_GLINK:
			obj->glink = (Elf_Addr)(uintptr_t)obj->relocbase + dynp->d_un.d_ptr;
			break;
#else
		case DT_PPC_GOT:
			obj->gotptr = (Elf_Addr *)(obj->relocbase + dynp->d_un.d_ptr);
			break;
#endif
#endif
		case DT_FLAGS_1:
			obj->z_now =
			    ((dynp->d_un.d_val & DF_1_BIND_NOW) != 0);
			obj->z_nodelete =
			    ((dynp->d_un.d_val & DF_1_NODELETE) != 0);
			obj->z_initfirst =
			    ((dynp->d_un.d_val & DF_1_INITFIRST) != 0);
			obj->z_noopen =
			    ((dynp->d_un.d_val & DF_1_NOOPEN) != 0);
			break;
		}
	}

	obj->rellim = (const Elf_Rel *)((const uint8_t *)obj->rel + relsz);
	obj->relalim = (const Elf_Rela *)((const uint8_t *)obj->rela + relasz);
	if (use_pltrel) {
		obj->pltrel = (const Elf_Rel *)(obj->relocbase + pltrel);
		obj->pltrellim = (const Elf_Rel *)(obj->relocbase + pltrel + pltrelsz);
		obj->pltrelalim = 0;
		/* On PPC and SPARC, at least, REL(A)SZ may include JMPREL.
		   Trim rel(a)lim to save time later. */
		if (obj->rellim && obj->pltrel &&
		    obj->rellim > obj->pltrel &&
		    obj->rellim <= obj->pltrellim)
			obj->rellim = obj->pltrel;
	} else if (use_pltrela) {
		obj->pltrela = (const Elf_Rela *)(obj->relocbase + pltrel);
		obj->pltrellim = 0;
		obj->pltrelalim = (const Elf_Rela *)(obj->relocbase + pltrel + pltrelsz);
		/* On PPC and SPARC, at least, REL(A)SZ may include JMPREL.
		   Trim rel(a)lim to save time later. */
		if (obj->relalim && obj->pltrela &&
		    obj->relalim > obj->pltrela &&
		    obj->relalim <= obj->pltrelalim)
			obj->relalim = obj->pltrela;
	}

#ifdef RTLD_LOADER
	if (init != 0)
		obj->init = (Elf_Addr) obj->relocbase + init;
	if (fini != 0)
		obj->fini = (Elf_Addr) obj->relocbase + fini;
#endif

	if (dyn_rpath != NULL) {
		_rtld_add_paths(execname, &obj->rpaths, obj->strtab +
		    dyn_rpath->d_un.d_val);
	}
	if (dyn_soname != NULL) {
		_rtld_object_add_name(obj, obj->strtab +
		    dyn_soname->d_un.d_val);
	}
}
Exemplo n.º 3
0
Arquivo: cdbr.c Projeto: Ga-vin/MINIX3
/* ARGSUSED */
struct cdbr *
cdbr_open(const char *path, int flags)
{
	uint8_t buf[40];
	int fd;
	struct cdbr *cdbr;
	struct stat sb;

	if ((fd = open(path, O_RDONLY)) == -1)
		return NULL;

	errno = EINVAL;
	if (fstat(fd, &sb) == -1 ||
	    read(fd, buf, sizeof(buf)) != sizeof(buf) ||
	    memcmp(buf, "NBCDB\n\0\001", 8) ||
	    (cdbr = malloc(sizeof(*cdbr))) == NULL) {
		close(fd);
		return NULL;
	}

	cdbr->data_size = le32dec(buf + 24);
	cdbr->entries = le32dec(buf + 28);
	cdbr->entries_index = le32dec(buf + 32);
	cdbr->seed = le32dec(buf + 36);

	if (cdbr->data_size < 0x100)
		cdbr->offset_size = 1;
	else if (cdbr->data_size < 0x10000)
		cdbr->offset_size = 2;
	else
		cdbr->offset_size = 4;

	if (cdbr->entries_index < 0x100)
		cdbr->index_size = 1;
	else if (cdbr->entries_index < 0x10000)
		cdbr->index_size = 2;
	else
		cdbr->index_size = 4;

	cdbr->mmap_size = (size_t)sb.st_size;
#ifdef __minix
	if(!(cdbr->mmap_base = malloc(cdbr->mmap_size))) {
		free(cdbr);
		return NULL;
	}

	if ((size_t)read(fd, cdbr->mmap_base, cdbr->mmap_size) != cdbr->mmap_size)
	{
		free(cdbr->mmap_base);
		free(cdbr);
		return NULL;
	}
#else /* !__minix */
	cdbr->mmap_base = mmap(NULL, cdbr->mmap_size, PROT_READ, MAP_FILE|MAP_SHARED, fd, 0);
#endif /* __minix */
	close(fd);

	if (cdbr->mmap_base == MAP_FAILED) {
		free(cdbr);
		return NULL;
	}

	cdbr->hash_base = cdbr->mmap_base + 40;
	cdbr->offset_base = cdbr->hash_base + cdbr->entries_index * cdbr->index_size;
	if (cdbr->entries_index * cdbr->index_size % cdbr->offset_size)
		cdbr->offset_base += cdbr->offset_size -
		    cdbr->entries_index * cdbr->index_size % cdbr->offset_size;
	cdbr->data_base = cdbr->offset_base + (cdbr->entries + 1) * cdbr->offset_size;

	if (cdbr->hash_base < cdbr->mmap_base ||
	    cdbr->offset_base < cdbr->mmap_base ||
	    cdbr->data_base < cdbr->mmap_base ||
	    cdbr->data_base + cdbr->data_size < cdbr->mmap_base ||
	    cdbr->data_base + cdbr->data_size >
	    cdbr->mmap_base + cdbr->mmap_size ||
	    cdbr->entries == 0 || cdbr->entries_index == 0) {
		errno = EINVAL;
		cdbr_close(cdbr);
		return NULL;
	}

	fast_divide32_prepare(cdbr->entries, &cdbr->entries_m,
	    &cdbr->entries_s1, &cdbr->entries_s2);
	fast_divide32_prepare(cdbr->entries_index, &cdbr->entries_index_m,
	    &cdbr->entries_index_s1, &cdbr->entries_index_s2);

	return cdbr;
}
Exemplo n.º 4
0
struct cdbr *
cdbr_open_mem(void *base, size_t size, int flags,
    void (*unmap)(void *, void *, size_t), void *cookie)
{
	struct cdbr *cdbr;
	uint8_t *buf = base;
	if (size < 40 || memcmp(buf, "NBCDB\n\0\001", 8)) {
		SET_ERRNO(EINVAL);
		return NULL;
	}

	cdbr = malloc(sizeof(*cdbr));
	cdbr->unmap = unmap;
	cdbr->cookie = cookie;

	cdbr->data_size = le32dec(buf + 24);
	cdbr->entries = le32dec(buf + 28);
	cdbr->entries_index = le32dec(buf + 32);
	cdbr->seed = le32dec(buf + 36);

	if (cdbr->data_size < 0x100)
		cdbr->offset_size = 1;
	else if (cdbr->data_size < 0x10000)
		cdbr->offset_size = 2;
	else
		cdbr->offset_size = 4;

	if (cdbr->entries_index < 0x100)
		cdbr->index_size = 1;
	else if (cdbr->entries_index < 0x10000)
		cdbr->index_size = 2;
	else
		cdbr->index_size = 4;

	cdbr->mmap_base = base;
	cdbr->mmap_size = size;

	cdbr->hash_base = cdbr->mmap_base + 40;
	cdbr->offset_base = cdbr->hash_base + cdbr->entries_index * cdbr->index_size;
	if (cdbr->entries_index * cdbr->index_size % cdbr->offset_size)
		cdbr->offset_base += cdbr->offset_size -
		    cdbr->entries_index * cdbr->index_size % cdbr->offset_size;
	cdbr->data_base = cdbr->offset_base + (cdbr->entries + 1) * cdbr->offset_size;

	if (cdbr->hash_base < cdbr->mmap_base ||
	    cdbr->offset_base < cdbr->mmap_base ||
	    cdbr->data_base < cdbr->mmap_base ||
	    cdbr->data_base + cdbr->data_size < cdbr->mmap_base ||
	    cdbr->data_base + cdbr->data_size >
	    cdbr->mmap_base + cdbr->mmap_size) {
		SET_ERRNO(EINVAL);
		free(cdbr);
		return NULL;
	}

	if (cdbr->entries) {
		fast_divide32_prepare(cdbr->entries, &cdbr->entries_m,
		    &cdbr->entries_s1, &cdbr->entries_s2);
	}
	if (cdbr->entries_index) {
		fast_divide32_prepare(cdbr->entries_index,
		    &cdbr->entries_index_m,
		    &cdbr->entries_index_s1, &cdbr->entries_index_s2);
	}

	return cdbr;
}