- Fix for possible unset uid/gid in toproto
 - Fix for default mtree style
 - Update libelf
 - Importing libexecinfo
 - Resynchronize GCC, mpc, gmp, mpfr
 - build.sh: Replace params with show-params.
     This has been done as the make target has been renamed in the same
     way, while a new target named params has been added. This new
     target generates a file containing all the parameters, instead of
     printing it on the console.
 - Update test48 with new etc/services (Fix by Ben Gras <ben@minix3.org)
     get getservbyport() out of the inner loop
Change-Id: Ie6ad5226fa2621ff9f0dee8782ea48f9443d2091
		
	
			
		
			
				
	
	
		
			234 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			234 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*	$NetBSD: reloc.c,v 1.106 2012/01/06 10:38:56 skrll Exp $	 */
 | 
						|
 | 
						|
/*
 | 
						|
 * Copyright 1996 John D. Polstra.
 | 
						|
 * Copyright 1996 Matt Thomas <matt@3am-software.com>
 | 
						|
 * All rights reserved.
 | 
						|
 *
 | 
						|
 * Redistribution and use in source and binary forms, with or without
 | 
						|
 * modification, are permitted provided that the following conditions
 | 
						|
 * are met:
 | 
						|
 * 1. Redistributions of source code must retain the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer.
 | 
						|
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer in the
 | 
						|
 *    documentation and/or other materials provided with the distribution.
 | 
						|
 * 3. All advertising materials mentioning features or use of this software
 | 
						|
 *    must display the following acknowledgement:
 | 
						|
 *      This product includes software developed by John Polstra.
 | 
						|
 * 4. The name of the author may not be used to endorse or promote products
 | 
						|
 *    derived from this software without specific prior written permission.
 | 
						|
 *
 | 
						|
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 | 
						|
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
						|
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | 
						|
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
						|
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
						|
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
						|
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
						|
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
						|
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
						|
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * Dynamic linker for ELF.
 | 
						|
 *
 | 
						|
 * John Polstra <jdp@polstra.com>.
 | 
						|
 */
 | 
						|
 | 
						|
#include <sys/cdefs.h>
 | 
						|
#ifndef lint
 | 
						|
__RCSID("$NetBSD: reloc.c,v 1.106 2012/01/06 10:38:56 skrll Exp $");
 | 
						|
#endif /* not lint */
 | 
						|
 | 
						|
#include <err.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <fcntl.h>
 | 
						|
#include <stdarg.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <sys/types.h>
 | 
						|
#include <sys/mman.h>
 | 
						|
#include <sys/bitops.h>
 | 
						|
#include <dirent.h>
 | 
						|
 | 
						|
#include "debug.h"
 | 
						|
#include "rtld.h"
 | 
						|
 | 
						|
#ifndef RTLD_INHIBIT_COPY_RELOCS
 | 
						|
static int _rtld_do_copy_relocation(const Obj_Entry *, const Elf_Rela *);
 | 
						|
 | 
						|
static int
 | 
						|
_rtld_do_copy_relocation(const Obj_Entry *dstobj, const Elf_Rela *rela)
 | 
						|
{
 | 
						|
	void           *dstaddr = (void *)(dstobj->relocbase + rela->r_offset);
 | 
						|
	const Elf_Sym  *dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
 | 
						|
	const char     *name = dstobj->strtab + dstsym->st_name;
 | 
						|
	unsigned long   hash = _rtld_elf_hash(name);
 | 
						|
	size_t          size = dstsym->st_size;
 | 
						|
	const void     *srcaddr;
 | 
						|
	const Elf_Sym  *srcsym = NULL;
 | 
						|
	Obj_Entry      *srcobj;
 | 
						|
 | 
						|
	for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) {
 | 
						|
		srcsym = _rtld_symlook_obj(name, hash, srcobj, 0,
 | 
						|
		    _rtld_fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)));
 | 
						|
		if (srcsym != NULL)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	if (srcobj == NULL) {
 | 
						|
		_rtld_error("Undefined symbol \"%s\" referenced from COPY"
 | 
						|
		    " relocation in %s", name, dstobj->path);
 | 
						|
		return (-1);
 | 
						|
	}
 | 
						|
	srcaddr = (const void *)(srcobj->relocbase + srcsym->st_value);
 | 
						|
	(void)memcpy(dstaddr, srcaddr, size);
 | 
						|
	rdbg(("COPY %s %s %s --> src=%p dst=%p size %ld",
 | 
						|
	    dstobj->path, srcobj->path, name, srcaddr,
 | 
						|
	    (void *)dstaddr, (long)size));
 | 
						|
	return (0);
 | 
						|
}
 | 
						|
#endif /* RTLD_INHIBIT_COPY_RELOCS */
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Process the special R_xxx_COPY relocations in the main program.  These
 | 
						|
 * copy data from a shared object into a region in the main program's BSS
 | 
						|
 * segment.
 | 
						|
 *
 | 
						|
 * Returns 0 on success, -1 on failure.
 | 
						|
 */
 | 
						|
int
 | 
						|
_rtld_do_copy_relocations(const Obj_Entry *dstobj)
 | 
						|
{
 | 
						|
#ifndef RTLD_INHIBIT_COPY_RELOCS
 | 
						|
 | 
						|
	/* COPY relocations are invalid elsewhere */
 | 
						|
	assert(!dstobj->isdynamic);
 | 
						|
 | 
						|
	if (dstobj->rel != NULL) {
 | 
						|
		const Elf_Rel  *rel;
 | 
						|
		for (rel = dstobj->rel; rel < dstobj->rellim; ++rel) {
 | 
						|
			if (ELF_R_TYPE(rel->r_info) == R_TYPE(COPY)) {
 | 
						|
				Elf_Rela        ourrela;
 | 
						|
				ourrela.r_info = rel->r_info;
 | 
						|
				ourrela.r_offset = rel->r_offset;
 | 
						|
				ourrela.r_addend = 0;
 | 
						|
				if (_rtld_do_copy_relocation(dstobj,
 | 
						|
				    &ourrela) < 0)
 | 
						|
					return (-1);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (dstobj->rela != NULL) {
 | 
						|
		const Elf_Rela *rela;
 | 
						|
		for (rela = dstobj->rela; rela < dstobj->relalim; ++rela) {
 | 
						|
			if (ELF_R_TYPE(rela->r_info) == R_TYPE(COPY)) {
 | 
						|
				if (_rtld_do_copy_relocation(dstobj, rela) < 0)
 | 
						|
					return (-1);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
#endif /* RTLD_INHIBIT_COPY_RELOCS */
 | 
						|
 | 
						|
	return (0);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Relocate newly-loaded shared objects.  The argument is a pointer to
 | 
						|
 * the Obj_Entry for the first such object.  All objects from the first
 | 
						|
 * to the end of the list of objects are relocated.  Returns 0 on success,
 | 
						|
 * or -1 on failure.
 | 
						|
 */
 | 
						|
int
 | 
						|
_rtld_relocate_objects(Obj_Entry *first, bool bind_now)
 | 
						|
{
 | 
						|
	Obj_Entry *obj;
 | 
						|
	int ok = 1;
 | 
						|
 | 
						|
	for (obj = first; obj != NULL; obj = obj->next) {
 | 
						|
		if (obj->nbuckets == 0 || obj->nchains == 0 ||
 | 
						|
		    obj->buckets == NULL || obj->symtab == NULL ||
 | 
						|
		    obj->strtab == NULL) {
 | 
						|
			_rtld_error("%s: Shared object has no run-time"
 | 
						|
			    " symbol table", obj->path);
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
		if (obj->nbuckets == UINT32_MAX) {
 | 
						|
			_rtld_error("%s: Symbol table too large", obj->path);
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
		rdbg((" relocating %s (%ld/%ld rel/rela, %ld/%ld plt rel/rela)",
 | 
						|
		    obj->path,
 | 
						|
		    (long)(obj->rellim - obj->rel),
 | 
						|
		    (long)(obj->relalim - obj->rela),
 | 
						|
		    (long)(obj->pltrellim - obj->pltrel),
 | 
						|
		    (long)(obj->pltrelalim - obj->pltrela)));
 | 
						|
 | 
						|
#if !defined(__minix)
 | 
						|
		if (obj->textrel) {
 | 
						|
			/*
 | 
						|
			 * There are relocations to the write-protected text
 | 
						|
			 * segment.
 | 
						|
			 */
 | 
						|
			if (mprotect(obj->mapbase, obj->textsize,
 | 
						|
				PROT_READ | PROT_WRITE | PROT_EXEC) == -1) {
 | 
						|
				_rtld_error("%s: Cannot write-enable text "
 | 
						|
				    "segment: %s", obj->path, xstrerror(errno));
 | 
						|
				return -1;
 | 
						|
			}
 | 
						|
		}
 | 
						|
#endif /* !defined(__minix) */
 | 
						|
		dbg(("doing non-PLT relocations"));
 | 
						|
		if (_rtld_relocate_nonplt_objects(obj) < 0)
 | 
						|
			ok = 0;
 | 
						|
 | 
						|
#if !defined(__minix)
 | 
						|
		if (obj->textrel) {	/* Re-protected the text segment. */
 | 
						|
			if (mprotect(obj->mapbase, obj->textsize,
 | 
						|
				     PROT_READ | PROT_EXEC) == -1) {
 | 
						|
				_rtld_error("%s: Cannot write-protect text "
 | 
						|
				    "segment: %s", obj->path, xstrerror(errno));
 | 
						|
				return -1;
 | 
						|
			}
 | 
						|
		}
 | 
						|
#endif /* !defined(__minix) */
 | 
						|
		dbg(("doing lazy PLT binding"));
 | 
						|
		if (_rtld_relocate_plt_lazy(obj) < 0)
 | 
						|
			ok = 0;
 | 
						|
		if (obj->z_now || bind_now) {
 | 
						|
			dbg(("doing immediate PLT binding"));
 | 
						|
			if (_rtld_relocate_plt_objects(obj) < 0)
 | 
						|
				ok = 0;
 | 
						|
		}
 | 
						|
		if (!ok)
 | 
						|
			return -1;
 | 
						|
 | 
						|
		/* Set some sanity-checking numbers in the Obj_Entry. */
 | 
						|
		obj->magic = RTLD_MAGIC;
 | 
						|
		obj->version = RTLD_VERSION;
 | 
						|
 | 
						|
		/*
 | 
						|
		 * Fill in the backwards compatibility dynamic linker entry points.
 | 
						|
		 *
 | 
						|
		 * DO NOT ADD TO THIS LIST
 | 
						|
		 */
 | 
						|
		obj->dlopen = dlopen;
 | 
						|
		obj->dlsym = dlsym;
 | 
						|
		obj->dlerror = dlerror;
 | 
						|
		obj->dlclose = dlclose;
 | 
						|
		obj->dladdr = dladdr;
 | 
						|
 | 
						|
		dbg(("fixing up PLTGOT"));
 | 
						|
		/* Set the special PLTGOT entries. */
 | 
						|
		if (obj->pltgot != NULL)
 | 
						|
			_rtld_setup_pltgot(obj);
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 |