Пример #1
0
/*
 * Extract a trace specification field, and setup the tracespec struct
 * accordingly.
 */
const char *
_dl_trace_parse_spec(const char *var, struct tracespec *spec)
{
	const char *start, *end;

	if (*var == '!') {
		spec->inverse = 1;
		var++;
	}

	start = var;
	end = _dl_strchr(start, ':');
	if (end == NULL)
		end = start + _dl_strlen(start);

	if (end != start) {
		spec->spec = _dl_malloc(1 + end - start);
		if (spec->spec == NULL)
			_dl_exit(8);

		_dl_bcopy(start, spec->spec, end - start);
		spec->spec[end - start] = '\0';
	}

	if (*end == ':')
		end++;

	return end;
}
Пример #2
0
int
_dl_md_reloc(elf_object_t *object, int rel, int relasz)
{
	long	i;
	long	numrela;
	int	fails = 0;
	Elf64_Addr loff;
	Elf64_Rela  *relas;
	struct load_list *llist;

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

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

	/*
	 * unprotect some segments if we need it.
	 * XXX - we unprotect way to much. only the text can have cow
	 * relocations.
	 */
	if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) {
		for (llist = object->load_list; llist != NULL; llist = llist->next) {
			if (!(llist->prot & PROT_WRITE)) {
				_dl_mprotect(llist->start, llist->size,
				    llist->prot|PROT_WRITE);
			}
		}
	}

	for (i = 0; i < numrela; i++, relas++) {
		Elf64_Addr *r_addr;
		Elf64_Addr ooff;
		const Elf64_Sym *sym, *this;
		const char *symn;

		r_addr = (Elf64_Addr *)(relas->r_offset + loff);

		if (ELF64_R_SYM(relas->r_info) == 0xffffffff)
			continue;


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

		this = NULL;
		switch (ELF64_R_TYPE(relas->r_info)) {
		case R_TYPE(REFQUAD):
			ooff =  _dl_find_symbol_bysym(object,
			    ELF64_R_SYM(relas->r_info), &this,
			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
			    sym, NULL);
			if (this == NULL)
				goto resolve_failed;
			*r_addr += ooff + this->st_value + relas->r_addend;
			break;
		case R_TYPE(RELATIVE):
			/*
			 * There is a lot of unaligned RELATIVE
			 * relocs generated by gcc in the exception handlers.
			 */
			if ((((Elf_Addr) r_addr) & 0x7) != 0) {
				Elf_Addr tmp;
#if 0
_dl_printf("unaligned RELATIVE: %p type: %d %s 0x%lx -> 0x%lx\n", r_addr,
    ELF_R_TYPE(relas->r_info), object->load_name, *r_addr, *r_addr+loff);
#endif
				_dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr));
				tmp += loff;
				_dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr));
			} else
				*r_addr += loff;
			break;
		case R_TYPE(JMP_SLOT):
			ooff = _dl_find_symbol(symn, &this,
			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT,
			    sym, object, NULL);
			if (this == NULL)
				goto resolve_failed;
			*r_addr = ooff + this->st_value + relas->r_addend;
			break;
		case R_TYPE(GLOB_DAT):
			ooff =  _dl_find_symbol_bysym(object,
			    ELF64_R_SYM(relas->r_info), &this,
			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
			    sym, NULL);
			if (this == NULL)
				goto resolve_failed;
			*r_addr = ooff + this->st_value + relas->r_addend;
			break;
		case R_TYPE(NONE):
			break;
		default:
			_dl_printf("%s:"
			    " %s: unsupported relocation '%s' %d at %lx\n",
			    _dl_progname, object->load_name, symn,
			    ELF64_R_TYPE(relas->r_info), r_addr );
			_dl_exit(1);
		}
		continue;
resolve_failed:
		if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
			fails++;
	}
	__asm __volatile("imb" : : : "memory");

	/* reprotect the unprotected segments */
	if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) {
		for (llist = object->load_list; llist != NULL; llist = llist->next) {
			if (!(llist->prot & PROT_WRITE))
				_dl_mprotect(llist->start, llist->size,
				    llist->prot);
		}
	}
	return (fails);
}
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);
}
Пример #4
0
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);
}
Пример #5
0
/*
 * char *dl_realpath(const char *path, char resolved[PATH_MAX]);
 *
 * Find the real name of path, by removing all ".", ".." and symlink
 * components.  Returns (resolved) on success, or (NULL) on failure,
 * in which case the path which caused trouble is left in (resolved).
 */
char *
_dl_realpath(const char *path, char *resolved)
{
	struct stat sb;
	const char *p, *s;
	char *q;
	size_t left_len, resolved_len;
	unsigned symlinks;
	int slen, mem_allocated, ret;
	char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];

	if (path[0] == '\0') {
		return (NULL);
	}

	if (resolved == NULL) {
		resolved = _dl_malloc(PATH_MAX);
		if (resolved == NULL)
			return (NULL);
		mem_allocated = 1;
	} else
		mem_allocated = 0;

	symlinks = 0;
	if (path[0] == '/') {
		resolved[0] = '/';
		resolved[1] = '\0';
		if (path[1] == '\0')
			return (resolved);
		resolved_len = 1;
		left_len = _dl_strlcpy(left, path + 1, sizeof(left));
	} else {
		if (_dl_getcwd(resolved, PATH_MAX) <= 0) {
			if (mem_allocated)
				_dl_free(resolved);
			else
				_dl_strlcpy(resolved, ".", PATH_MAX);
			return (NULL);
		}
		resolved_len = _dl_strlen(resolved);
		left_len = _dl_strlcpy(left, path, sizeof(left));
	}
	if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) {
		goto err;
	}

	/*
	 * Iterate over path components in `left'.
	 */
	while (left_len != 0) {
		/*
		 * Extract the next path component and adjust `left'
		 * and its length.
		 */
		p = _dl_strchr(left, '/');
		s = p ? p : left + left_len;
		if (s - left >= sizeof(next_token)) {
			goto err;
		}
		_dl_bcopy(left, next_token, s - left);
		next_token[s - left] = '\0';
		left_len -= s - left;
		if (p != NULL)
			_dl_bcopy(s + 1, left, left_len + 1);
		if (resolved[resolved_len - 1] != '/') {
			if (resolved_len + 1 >= PATH_MAX) {
				goto err;
			}
			resolved[resolved_len++] = '/';
			resolved[resolved_len] = '\0';
		}
		if (next_token[0] == '\0')
			continue;
		else if (_dl_strcmp(next_token, ".") == 0)
			continue;
		else if (_dl_strcmp(next_token, "..") == 0) {
			/*
			 * Strip the last path component except when we have
			 * single "/"
			 */
			if (resolved_len > 1) {
				resolved[resolved_len - 1] = '\0';
				q = _dl_strrchr(resolved, '/') + 1;
				*q = '\0';
				resolved_len = q - resolved;
			}
			continue;
		}

		/*
		 * Append the next path component and lstat() it. If
		 * lstat() fails we still can return successfully if
		 * there are no more path components left.
		 */
		resolved_len = _dl_strlcat(resolved, next_token, PATH_MAX);
		if (resolved_len >= PATH_MAX) {
			goto err;
		}
		if ((ret = _dl_lstat(resolved, &sb)) != 0) {
			if (ret == ENOENT && p == NULL) {
				return (resolved);
			}
			goto err;
		}
		if (S_ISLNK(sb.st_mode)) {
			if (symlinks++ > SYMLOOP_MAX) {
				goto err;
			}
			slen = _dl_readlink(resolved, symlink, sizeof(symlink) - 1);
			if (slen < 0)
				goto err;
			symlink[slen] = '\0';
			if (symlink[0] == '/') {
				resolved[1] = 0;
				resolved_len = 1;
			} else if (resolved_len > 1) {
				/* Strip the last path component. */
				resolved[resolved_len - 1] = '\0';
				q = _dl_strrchr(resolved, '/') + 1;
				*q = '\0';
				resolved_len = q - resolved;
			}

			/*
			 * If there are any path components left, then
			 * append them to symlink. The result is placed
			 * in `left'.
			 */
			if (p != NULL) {
				if (symlink[slen - 1] != '/') {
					if (slen + 1 >= sizeof(symlink)) {
						goto err;
					}
					symlink[slen] = '/';
					symlink[slen + 1] = 0;
				}
				left_len = _dl_strlcat(symlink, left, sizeof(symlink));
				if (left_len >= sizeof(left)) {
					goto err;
				}
			}
			left_len = _dl_strlcpy(left, symlink, sizeof(left));
		}
	}

	/*
	 * Remove trailing slash except when the resolved pathname
	 * is a single "/".
	 */
	if (resolved_len > 1 && resolved[resolved_len - 1] == '/')
		resolved[resolved_len - 1] = '\0';
	return (resolved);

err:
	if (mem_allocated)
		_dl_free(resolved);
	return (NULL);
}
Пример #6
0
int
_dl_md_reloc(elf_object_t *object, int rel, int relasz)
{
	int	i;
	int	numrela;
	int	relrel;
	int	fails = 0;
	struct load_list *llist;
	Elf32_Addr loff;
	Elf32_Rela  *relas;

	loff = object->obj_base;
	numrela = object->Dyn.info[relasz] / sizeof(Elf32_Rela);
	relrel = rel == DT_RELA ? object->relacount : 0;
	relas = (Elf32_Rela *)(object->Dyn.info[rel]);

#ifdef DL_PRINTF_DEBUG
	_dl_printf("object relocation size %x, numrela %x\n",
	    object->Dyn.info[relasz], numrela);
#endif

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

	if (relrel > numrela) {
		_dl_printf("relacount > numrela: %ld > %ld\n", relrel, numrela);
		_dl_exit(20);
	}

	/*
	 * Change protection of all write protected segments in the object
	 * so we can do relocations such as PC32. After relocation,
	 * restore protection.
	 */
	if (object->dyn.textrel == 1 && (rel == DT_REL || rel == DT_RELA)) {
		for (llist = object->load_list; llist != NULL;
		    llist = llist->next) {
			if (!(llist->prot & PROT_WRITE)) {
				_dl_mprotect(llist->start, llist->size,
				    llist->prot|PROT_WRITE);
			}
		}
	}

	/* tight loop for leading RELATIVE relocs */
	for (i = 0; i < relrel; i++, relas++) {
		Elf32_Addr *r_addr;

#ifdef DEBUG
		if (ELF_R_TYPE(relas->r_info) != R_68K_RELATIVE) {
			_dl_printf("RELACOUNT wrong\n");
			_dl_exit(20);
		}
#endif
		r_addr = (Elf32_Addr *)(relas->r_offset + loff);
		*r_addr = relas->r_addend + loff;
	}
	for (; i < numrela; i++, relas++) {
		Elf32_Addr *r_addr = (Elf32_Addr *)(relas->r_offset + loff);
		Elf32_Addr ooff, addend, newval;
		const Elf32_Sym *sym, *this;
		const char *symn;
		int type;
		Elf32_Addr prev_value = 0, prev_ooff = 0;
		const Elf32_Sym *prev_sym = NULL;

		type = ELF32_R_TYPE(relas->r_info);

		if (type == R_68K_JMP_SLOT && rel != DT_JMPREL)
			continue;

		if (type == R_68K_NONE)
			continue;

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

		if (type == R_68K_COPY) {
			/*
			 * we need to find a symbol, that is not in the current
			 * object, start looking at the beginning of the list,
			 * searching all objects but _not_ the current object,
			 * first one found wins.
			 */
			const Elf32_Sym *cpysrc = NULL;
			Elf32_Addr src_loff;
			int size;

			src_loff = 0;
			src_loff = _dl_find_symbol(symn, &cpysrc,
			    SYM_SEARCH_OTHER|SYM_WARNNOTFOUND| SYM_NOTPLT,
			    sym, object, NULL);
			if (cpysrc != NULL) {
				size = sym->st_size;
				if (sym->st_size != cpysrc->st_size) {
					/* _dl_find_symbol() has warned
					   about this already */
					size = sym->st_size < cpysrc->st_size ?
					    sym->st_size : cpysrc->st_size;
				}
				_dl_bcopy((void *)(src_loff + cpysrc->st_value),
				    r_addr, size);
			} else
				fails++;

			continue;
		}

		if (ELF32_R_SYM(relas->r_info) &&
		    !(ELF32_ST_BIND(sym->st_info) == STB_LOCAL &&
		    ELF32_ST_TYPE (sym->st_info) == STT_NOTYPE) &&
		    sym != prev_sym) {
			this = NULL;
			ooff = _dl_find_symbol_bysym(object,
			    ELF32_R_SYM(relas->r_info), &this,
			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|
			    ((type == R_68K_JMP_SLOT) ? SYM_PLT:SYM_NOTPLT),
			    sym, NULL);

			if (this == NULL) {
				if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
					fails++;
				continue;
			}
			prev_sym = sym;
			prev_value = this->st_value;
			prev_ooff = ooff;
		}

		if (ELF32_ST_BIND(sym->st_info) == STB_LOCAL &&
		    (ELF32_ST_TYPE(sym->st_info) == STT_SECTION ||
		    ELF32_ST_TYPE(sym->st_info) == STT_NOTYPE))
			addend = relas->r_addend;
		else
			addend = prev_value + relas->r_addend;

		switch (type) {
		case R_68K_PC32:
			newval = prev_ooff + addend;
			newval -= (Elf_Addr)r_addr;
			*r_addr = newval;
			break;
		case R_68K_32:
		case R_68K_GLOB_DAT:
		case R_68K_JMP_SLOT:
			newval = prev_ooff + addend;
			*r_addr = newval;
			break;
		case R_68K_RELATIVE:
			newval = loff + addend;
			*r_addr = newval;
			break;
		default:
			_dl_printf("%s:"
			    " %s: unsupported relocation '%s' %d at %x\n",
			    _dl_progname, object->load_name, symn,
			    ELF32_R_TYPE(relas->r_info), r_addr);
			_dl_exit(1);
		}
	}

	/* reprotect the unprotected segments */
	if (object->dyn.textrel == 1 && (rel == DT_REL || rel == DT_RELA)) {
		for (llist = object->load_list; llist != NULL;
		    llist = llist->next) {
			if (!(llist->prot & PROT_WRITE))
				_dl_mprotect(llist->start, llist->size,
				    llist->prot);
		}
	}

	return(fails);
}
Пример #7
0
/*
 * 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;
}
Пример #8
0
int
_dl_md_reloc(elf_object_t *object, int rel, int relsz)
{
	long	i;
	long	numrel;
	long	relrel;
	int	fails = 0;
	Elf_Addr loff;
	Elf_Addr prev_value = 0;
	const Elf_Sym *prev_sym = NULL;
	Elf_RelA *rels;
	struct load_list *llist;

	loff = object->obj_base;
	numrel = object->Dyn.info[relsz] / sizeof(Elf_RelA);
	relrel = rel == DT_RELA ? object->relacount : 0;
	rels = (Elf_RelA *)(object->Dyn.info[rel]);
	if (rels == NULL)
		return(0);

	if (relrel > numrel) {
		_dl_printf("relacount > numrel: %ld > %ld\n", relrel, numrel);
		_dl_exit(20);
	}

	/*
	 * unprotect some segments if we need it.
	 */
	if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) {
		for (llist = object->load_list; llist != NULL; llist = llist->next) {
			if (!(llist->prot & PROT_WRITE))
				_dl_mprotect(llist->start, llist->size,
				    PROT_READ | PROT_WRITE);
		}
	}

	/* tight loop for leading RELATIVE relocs */
	for (i = 0; i < relrel; i++, rels++) {
		Elf_Addr *where;

#ifdef DEBUG
		if (ELF_R_TYPE(rels->r_info) != R_TYPE(RELATIVE)) {
			_dl_printf("RELACOUNT wrong\n");
			_dl_exit(20);
		}
#endif
		where = (Elf_Addr *)(rels->r_offset + loff);
		*where = rels->r_addend + loff;
	}
	for (; i < numrel; i++, rels++) {
		Elf_Addr *where, value, ooff, mask;
		Elf_Word type;
		const Elf_Sym *sym, *this;
		const char *symn;

		type = ELF_R_TYPE(rels->r_info);

		if (RELOC_ERROR(type)) {
			_dl_printf("relocation error %d idx %d\n", type, i);
			_dl_exit(20);
		}

		if (type == R_TYPE(NONE))
			continue;

		if (type == R_TYPE(JUMP_SLOT) && rel != DT_JMPREL)
			continue;

		where = (Elf_Addr *)(rels->r_offset + loff);

		if (RELOC_USE_ADDEND(type))
			value = rels->r_addend;
		else
			value = 0;

		sym = NULL;
		symn = NULL;
		if (RELOC_RESOLVE_SYMBOL(type)) {
			sym = object->dyn.symtab;
			sym += ELF_R_SYM(rels->r_info);
			symn = object->dyn.strtab + sym->st_name;

			if (sym->st_shndx != SHN_UNDEF &&
			    ELF_ST_BIND(sym->st_info) == STB_LOCAL) {
				value += loff;
			} else if (sym == prev_sym) {
				value += prev_value;
			} else {
				this = NULL;
				ooff = _dl_find_symbol_bysym(object,
				    ELF_R_SYM(rels->r_info), &this,
				    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|
				    ((type == R_TYPE(JUMP_SLOT))?
					SYM_PLT:SYM_NOTPLT),
				    sym, NULL);
				if (this == NULL) {
resolve_failed:
					if (ELF_ST_BIND(sym->st_info) !=
					    STB_WEAK)
						fails++;
					continue;
				}
				prev_sym = sym;
				prev_value = (Elf_Addr)(ooff + this->st_value);
				value += prev_value;
			}
		}

		if (type == R_TYPE(JUMP_SLOT)) {
			_dl_reloc_plt(where, value);
			continue;
		}

		if (type == R_TYPE(COPY)) {
			void *dstaddr = where;
			const void *srcaddr;
			const Elf_Sym *dstsym = sym, *srcsym = NULL;
			Elf_Addr soff;

			soff = _dl_find_symbol(symn, &srcsym,
			    SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT,
			    dstsym, object, NULL);
			if (srcsym == NULL)
				goto resolve_failed;

			srcaddr = (void *)(soff + srcsym->st_value);
			_dl_bcopy(srcaddr, dstaddr, dstsym->st_size);
			continue;
		}

		if (RELOC_PC_RELATIVE(type))
			value -= (Elf_Addr)where;
		if (RELOC_BASE_RELATIVE(type))
			value += loff;

		mask = RELOC_VALUE_BITMASK(type);
		value >>= RELOC_VALUE_RIGHTSHIFT(type);
		value &= mask;

		if (RELOC_TARGET_SIZE(type) > 32) {
			*where &= ~mask;
			*where |= value;
		} else {
			Elf32_Addr *where32 = (Elf32_Addr *)where;

			*where32 &= ~mask;
			*where32 |= value;
		}
	}

	/* reprotect the unprotected segments */
	if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) {
		for (llist = object->load_list; llist != NULL; llist = llist->next) {
			if (!(llist->prot & PROT_WRITE))
				_dl_mprotect(llist->start, llist->size,
				    llist->prot);
		}
	}

	return (fails);
}