Esempio n. 1
0
static inline int
_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *tp)
{
	Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
	Elf_Addr new_value;
	const Elf_Sym  *def;
	const Obj_Entry *defobj;
	unsigned long info = rela->r_info;

	assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT));

	def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL);
	if (__predict_false(def == NULL))
		return -1;
	if (__predict_false(def == &_rtld_sym_zero))
		return 0;

	new_value = (Elf_Addr)(defobj->relocbase + def->st_value +
	    rela->r_addend);
	rdbg(("bind now/fixup in %s --> old=%p new=%p",
	    defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
	if (*where != new_value)
		*where = new_value;

	if (tp)
		*tp = new_value - rela->r_addend;

	return 0;
}
Esempio n. 2
0
static int
_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rel *rel,
                          Elf_Addr *tp)
{
    Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
    Elf_Addr new_value;
    const Elf_Sym  *def;
    const Obj_Entry *defobj;
    unsigned long info = rel->r_info;

    assert(ELF_R_TYPE(info) == R_TYPE(JUMP_SLOT));

    def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL);
    if (__predict_false(def == NULL))
        return -1;
    if (__predict_false(def == &_rtld_sym_zero))
        return 0;

    if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
        if (tp == NULL)
            return 0;
        new_value = _rtld_resolve_ifunc(defobj, def);
    } else {
        new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
    }
    rdbg(("bind now/fixup in %s --> old=%p new=%p",
          defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
    if (*where != new_value)
        *where = new_value;
    if (tp)
        *tp = new_value;

    return 0;
}
Esempio n. 3
0
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)
		if ((srcsym = _rtld_symlook_obj(name, hash, srcobj, false)) != 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);
}
Esempio n. 4
0
static inline int
_rtld_relocate_plt_object(const Obj_Entry *obj, Elf_Word sym, Elf_Addr *tp)
{
	Elf_Addr *got = obj->pltgot;
	const Elf_Sym *def;
	const Obj_Entry *defobj;
	Elf_Addr new_value;

	def = _rtld_find_plt_symdef(sym, obj, &defobj, tp != NULL);
	if (__predict_false(def == NULL))
		return -1;
	if (__predict_false(def == &_rtld_sym_zero))
		return 0;

	if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
		if (tp == NULL)
			return 0;
		new_value = _rtld_resolve_ifunc(defobj, def);
	} else {
		new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
	}
	rdbg(("bind now/fixup in %s --> new=%p",
	    defobj->strtab + def->st_name, (void *)new_value));
	got[obj->local_gotno + sym - obj->gotsym] = new_value;

	if (tp)
		*tp = new_value;
	return 0;
}
Esempio n. 5
0
static void read_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) {

	if(EV_ERROR & revents) {
		rdlog(LOG_ERR,"Read callback error: %s",mystrerror(errno,errbuf,
			ERROR_BUFFER_SIZE));
	}

	struct connection_private *connection = (struct connection_private *) watcher->data;
	struct sockaddr_in6 saddr;

#ifdef CONNECTION_PRIVATE_MAGIC
	assert(connection->magic == CONNECTION_PRIVATE_MAGIC);
#endif

	char *buffer = calloc(READ_BUFFER_SIZE,sizeof(char));
	const int recv_result = receive_from_socket(watcher->fd,&saddr,buffer,READ_BUFFER_SIZE);
	if(recv_result > 0){
		process_data_received_from_socket(buffer,(size_t)recv_result,connection->client,
		            connection->callback,connection->callback_opaque);
	}else if(recv_result < 0){
		if(errno == EAGAIN){
			rdbg("Socket not ready. re-trying");
			free(buffer);
			return;
		}else{
			rdlog(LOG_ERR,"Recv error: %s",mystrerror(errno,errbuf,ERROR_BUFFER_SIZE));
			free(buffer);
			close_socket_and_stop_watcher(loop,watcher);
			return;
		}
	}else{ /* recv_result == 0 */
		free(buffer);
		close_socket_and_stop_watcher(loop,watcher);
		return;
	}

	if(NULL!=global_config.response && !connection->first_response_sent){
		int send_ret = 1;
		rdlog(LOG_DEBUG,"Sending first response...");

		if(global_config.response_len == 0){
			rdlog(LOG_ERR,"Can't send first response to %s: size of response == 0",connection->client);
			connection->first_response_sent = 1;
		} else {
			send_ret = send_to_socket(watcher->fd,global_config.response,(size_t)global_config.response_len-1);
		}

		if(send_ret <= 0){
			rdlog(LOG_ERR,"Cannot send first response to %s socket: %s",
				connection->client, mystrerror(errno,errbuf,ERROR_BUFFER_SIZE));
			close_socket_and_stop_watcher(loop,watcher);
		}
		
		rdlog(LOG_DEBUG,"first response ok");
		connection->first_response_sent = 1;
	}
}
Esempio n. 6
0
int
_rtld_relocate_plt_lazy(const Obj_Entry *obj)
{

    if (!obj->relocbase)
        return 0;

    for (const Elf_Rel *rel = obj->pltrel; rel < obj->pltrellim; rel++) {
        Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset);

        assert(ELF_R_TYPE(rel->r_info) == R_TYPE(JUMP_SLOT));

        /* Just relocate the GOT slots pointing into the PLT */
        *where += (Elf_Addr)obj->relocbase;
        rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where));
    }

    return 0;
}
Esempio n. 7
0
int
_rtld_relocate_plt_lazy(const Obj_Entry *obj)
{
	const Elf_Rela *rela;

	if (!obj->relocbase)
		return 0;

	for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) {
		Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);

		assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT));

		/* Just relocate the GOT slots pointing into the PLT */
		*where += (Elf_Addr)obj->relocbase;
		rdbg(("lazy fixup pltgot %p in %s --> %p", where, obj->path,
		    (void *)*where));
	}

	return 0;
}
Esempio n. 8
0
int
_rtld_relocate_nonplt_objects(Obj_Entry *obj)
{

    for (const Elf_Rela *rela = obj->rela; rela < obj->relalim; rela++) {
        Elf_Addr        *where;
        const Elf_Sym   *def;
        const Obj_Entry *defobj;
        unsigned long	 symnum;
        Elf_Addr	 addend;

        where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
        symnum = ELF_R_SYM(rela->r_info);
        addend = rela->r_addend;

        switch (ELF_R_TYPE(rela->r_info)) {
        case R_TYPE(NONE):
            break;

        case R_TYPE(ABS64):	/* word B + S + A */
        case R_TYPE(GLOB_DAT):	/* word B + S */
            def = _rtld_find_symdef(symnum, obj, &defobj, false);
            if (def == NULL)
                return -1;
            *where = addend + (Elf_Addr)defobj->relocbase +
                     def->st_value;
            rdbg(("ABS64/GLOB_DAT %s in %s --> %p @ %p in %s",
                  obj->strtab + obj->symtab[symnum].st_name,
                  obj->path, (void *)tmp, where, defobj->path));
            break;

        case R_TYPE(RELATIVE):	/* word B + A */
            *where = addend + (Elf_Addr)obj->relocbase;
            rdbg(("RELATIVE in %s --> %p", obj->path,
                  (void *)tmp));
            break;

        case R_TYPE(COPY):
            /*
             * These are deferred until all other relocations have
             * been done.  All we do here is make sure that the
             * COPY relocation is not in a shared library.  They
             * are allowed only in executable files.
             */
            if (obj->isdynamic) {
                _rtld_error(
                    "%s: Unexpected R_COPY relocation in shared library",
                    obj->path);
                return -1;
            }
            rdbg(("COPY (avoid in main)"));
            break;

        case R_TLS_TYPE(TLS_DTPREL):
            def = _rtld_find_symdef(symnum, obj, &defobj, false);
            if (def == NULL)
                return -1;

            *where = addend + (Elf_Addr)(def->st_value);

            rdbg(("TLS_DTPOFF32 %s in %s --> %p",
                  obj->strtab + obj->symtab[symnum].st_name,
                  obj->path, (void *)tmp));

            break;
        case R_TLS_TYPE(TLS_DTPMOD):
            def = _rtld_find_symdef(symnum, obj, &defobj, false);
            if (def == NULL)
                return -1;

            *where = (Elf_Addr)(defobj->tlsindex);

            rdbg(("TLS_DTPMOD %s in %s --> %p",
                  obj->strtab + obj->symtab[symnum].st_name,
                  obj->path, (void *)tmp));

            break;

        case R_TLS_TYPE(TLS_TPREL):
            def = _rtld_find_symdef(symnum, obj, &defobj, false);
            if (def == NULL)
                return -1;

            if (!defobj->tls_done &&
                    _rtld_tls_offset_allocate(obj))
                return -1;

            *where = (Elf_Addr)def->st_value + defobj->tlsoffset +
                     sizeof(struct tls_tcb);
            rdbg(("TLS_TPOFF32 %s in %s --> %p",
                  obj->strtab + obj->symtab[symnum].st_name,
                  obj->path, (void *)tmp));
            break;

        default:
            rdbg(("sym = %lu, type = %lu, offset = %p, "
                  "contents = %p, symbol = %s",
                  symnum, (u_long)ELF_R_TYPE(rela->r_info),
                  (void *)rela->r_offset, *where,
                  obj->strtab + obj->symtab[symnum].st_name));
            _rtld_error("%s: Unsupported relocation type %ld "
                        "in non-PLT relocations",
                        obj->path, (u_long) ELF_R_TYPE(rela->r_info));
            return -1;
        }
    }
    return 0;
}
Esempio n. 9
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)));

#ifndef __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

		dbg(("doing non-PLT relocations"));
		if (_rtld_relocate_nonplt_objects(obj) < 0)
			ok = 0;

#ifndef __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

		dbg(("doing lazy PLT binding"));
		if (_rtld_relocate_plt_lazy(obj) < 0)
			ok = 0;
#if defined(__hppa__)
		bind_now = 1;
#endif
		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 dynamic linker entry points. */
		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;
}
Esempio n. 10
0
int
_rtld_relocate_nonplt_objects(Obj_Entry *obj)
{
	const Elf_Rela *rela;

	for (rela = obj->rela; rela < obj->relalim; rela++) {
		Elf_Addr        *where;
		const Elf_Sym   *def;
		const Obj_Entry *defobj;
		Elf_Addr         tmp;
		unsigned long	 symnum;

		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
		symnum = ELF_R_SYM(rela->r_info);

		switch (ELF_R_TYPE(rela->r_info)) {
		case R_TYPE(NONE):
			break;

		case R_TYPE(32):	/* word32 S + A */
		case R_TYPE(GLOB_DAT):	/* word32 S + A */
			def = _rtld_find_symdef(symnum, obj, &defobj, false);
			if (def == NULL)
				return -1;

			tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
			    rela->r_addend);

			if (*where != tmp)
				*where = tmp;
			rdbg(("32/GLOB_DAT %s in %s --> %p in %s",
			    obj->strtab + obj->symtab[symnum].st_name,
			    obj->path, (void *)*where, defobj->path));
			break;

		case R_TYPE(RELATIVE):	/* word32 B + A */
			tmp = (Elf_Addr)(obj->relocbase + rela->r_addend);
			if (*where != tmp)
				*where = tmp;
			rdbg(("RELATIVE in %s --> %p", obj->path,
			    (void *)*where));
			break;

		case R_TYPE(COPY):
			/*
			 * These are deferred until all other relocations have
			 * been done.  All we do here is make sure that the
			 * COPY relocation is not in a shared library.  They
			 * are allowed only in executable files.
			 */
			if (obj->isdynamic) {
				_rtld_error(
			"%s: Unexpected R_COPY relocation in shared library",
				    obj->path);
				return -1;
			}
			rdbg(("COPY (avoid in main)"));
			break;

		default:
			rdbg(("sym = %lu, type = %lu, offset = %p, "
			    "addend = %p, contents = %p, symbol = %s",
			    symnum, (u_long)ELF_R_TYPE(rela->r_info),
			    (void *)rela->r_offset, (void *)rela->r_addend,
			    (void *)*where,
			    obj->strtab + obj->symtab[symnum].st_name));
			_rtld_error("%s: Unsupported relocation type %ld "
			    "in non-PLT relocations",
			    obj->path, (u_long) ELF_R_TYPE(rela->r_info));
			return -1;
		}
	}
	return 0;
}
Esempio n. 11
0
static void set_keepalive_opt(int fd){
	int i=1;
	const int sso_rc = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&i, sizeof(int));
	if(sso_rc == -1)
		rdbg("Can't set SO_KEEPALIVE option");
}
Esempio n. 12
0
int
_rtld_relocate_nonplt_objects(Obj_Entry *obj)
{
	const Elf_Rel *rel;

	for (rel = obj->rel; rel < obj->rellim; rel++) {
		Elf_Addr        *where;
		const Elf_Sym   *def;
		const Obj_Entry *defobj;
		Elf_Addr         tmp;
		unsigned long	 symnum;

		where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
		symnum = ELF_R_SYM(rel->r_info);

		switch (ELF_R_TYPE(rel->r_info)) {
		case R_TYPE(NONE):
			break;

#if 1 /* XXX should not occur */
		case R_TYPE(PC24): {	/* word32 S - P + A */
			Elf32_Sword addend;

			/*
			 * Extract addend and sign-extend if needed.
			 */
			addend = *where;
			if (addend & 0x00800000)
				addend |= 0xff000000;

			def = _rtld_find_symdef(symnum, obj, &defobj, false);
			if (def == NULL)
				return -1;
			tmp = (Elf_Addr)obj->relocbase + def->st_value
			    - (Elf_Addr)where + (addend << 2);
			if ((tmp & 0xfe000000) != 0xfe000000 &&
			    (tmp & 0xfe000000) != 0) {
				_rtld_error(
				"%s: R_ARM_PC24 relocation @ %p to %s failed "
				"(displacement %ld (%#lx) out of range)",
				    obj->path, where,
				    obj->strtab + obj->symtab[symnum].st_name,
				    (long) tmp, (long) tmp);
				return -1;
			}
			tmp >>= 2;
			*where = (*where & 0xff000000) | (tmp & 0x00ffffff);
			rdbg(("PC24 %s in %s --> %p @ %p in %s",
			    obj->strtab + obj->symtab[symnum].st_name,
			    obj->path, (void *)*where, where, defobj->path));
			break;
		}
#endif

		case R_TYPE(ABS32):	/* word32 B + S + A */
		case R_TYPE(GLOB_DAT):	/* word32 B + S */
			def = _rtld_find_symdef(symnum, obj, &defobj, false);
			if (def == NULL)
				return -1;
			if (__predict_true(RELOC_ALIGNED_P(where))) {
				tmp = *where + (Elf_Addr)defobj->relocbase +
				    def->st_value;
				/* Set the Thumb bit, if needed.  */
				if (ELF_ST_TYPE(def->st_info) == STT_ARM_TFUNC)
				    tmp |= 1;
				*where = tmp;
			} else {
				tmp = load_ptr(where) +
				    (Elf_Addr)defobj->relocbase +
				    def->st_value;
				/* Set the Thumb bit, if needed.  */
				if (ELF_ST_TYPE(def->st_info) == STT_ARM_TFUNC)
				    tmp |= 1;
				store_ptr(where, tmp);
			}
			rdbg(("ABS32/GLOB_DAT %s in %s --> %p @ %p in %s",
			    obj->strtab + obj->symtab[symnum].st_name,
			    obj->path, (void *)tmp, where, defobj->path));
			break;

		case R_TYPE(RELATIVE):	/* word32 B + A */
			if (__predict_true(RELOC_ALIGNED_P(where))) {
				tmp = *where + (Elf_Addr)obj->relocbase;
				*where = tmp;
			} else {
				tmp = load_ptr(where) +
				    (Elf_Addr)obj->relocbase;
				store_ptr(where, tmp);
			}
			rdbg(("RELATIVE in %s --> %p", obj->path,
			    (void *)tmp));
			break;

		case R_TYPE(COPY):
			/*
			 * These are deferred until all other relocations have
			 * been done.  All we do here is make sure that the
			 * COPY relocation is not in a shared library.  They
			 * are allowed only in executable files.
			 */
			if (obj->isdynamic) {
				_rtld_error(
			"%s: Unexpected R_COPY relocation in shared library",
				    obj->path);
				return -1;
			}
			rdbg(("COPY (avoid in main)"));
			break;

#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
		case R_TYPE(TLS_DTPOFF32):
			def = _rtld_find_symdef(symnum, obj, &defobj, false);
			if (def == NULL)
				return -1;

			tmp = (Elf_Addr)(def->st_value);
			if (__predict_true(RELOC_ALIGNED_P(where)))
				*where = tmp;
			else
				store_ptr(where, tmp);

			rdbg(("TLS_DTPOFF32 %s in %s --> %p",
			    obj->strtab + obj->symtab[symnum].st_name,
			    obj->path, (void *)tmp));

			break;
		case R_TYPE(TLS_DTPMOD32):
			def = _rtld_find_symdef(symnum, obj, &defobj, false);
			if (def == NULL)
				return -1;

			tmp = (Elf_Addr)(defobj->tlsindex);
			if (__predict_true(RELOC_ALIGNED_P(where)))
				*where = tmp;
			else
				store_ptr(where, tmp);

			rdbg(("TLS_DTPMOD32 %s in %s --> %p",
			    obj->strtab + obj->symtab[symnum].st_name,
			    obj->path, (void *)tmp));

			break;

		case R_TYPE(TLS_TPOFF32):
			def = _rtld_find_symdef(symnum, obj, &defobj, false);
			if (def == NULL)
				return -1;

			if (!defobj->tls_done &&
			    _rtld_tls_offset_allocate(obj))
				return -1;

			tmp = (Elf_Addr)def->st_value + defobj->tlsoffset +
			    sizeof(struct tls_tcb);
			if (__predict_true(RELOC_ALIGNED_P(where)))
				*where = tmp;
			else
				store_ptr(where, tmp);
			rdbg(("TLS_TPOFF32 %s in %s --> %p",
			    obj->strtab + obj->symtab[symnum].st_name,
			    obj->path, (void *)tmp));
			break;
#endif

		default:
			rdbg(("sym = %lu, type = %lu, offset = %p, "
			    "contents = %p, symbol = %s",
			    symnum, (u_long)ELF_R_TYPE(rel->r_info),
			    (void *)rel->r_offset, (void *)load_ptr(where),
			    obj->strtab + obj->symtab[symnum].st_name));
			_rtld_error("%s: Unsupported relocation type %ld "
			    "in non-PLT relocations",
			    obj->path, (u_long) ELF_R_TYPE(rel->r_info));
			return -1;
		}
	}
	return 0;
}
Esempio n. 13
0
int
_rtld_relocate_nonplt_objects(Obj_Entry *obj)
{
	const Elf_Rel *rel;
	Elf_Addr *got = obj->pltgot;
	const Elf_Sym *sym, *def;
	const Obj_Entry *defobj;
	Elf_Word i;
#ifdef SUPPORT_OLD_BROKEN_LD
	int broken;
#endif

#ifdef SUPPORT_OLD_BROKEN_LD
	broken = 0;
	sym = obj->symtab;
	for (i = 1; i < 12; i++)
		if (sym[i].st_info == ELF_ST_INFO(STB_LOCAL, STT_NOTYPE))
			broken = 1;
	dbg(("%s: broken=%d", obj->path, broken));
#endif

	i = (got[1] & 0x80000000) ? 2 : 1;
	/* Relocate the local GOT entries */
	got += i;
	for (; i < obj->local_gotno; i++)
		*got++ += (Elf_Addr)obj->relocbase;
	sym = obj->symtab + obj->gotsym;
	/* Now do the global GOT entries */
	for (i = obj->gotsym; i < obj->symtabno; i++) {
		rdbg((" doing got %d sym %p (%s, %lx)", i - obj->gotsym, sym,
		    sym->st_name + obj->strtab, (u_long) *got));

#ifdef SUPPORT_OLD_BROKEN_LD
		if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
		    broken && sym->st_shndx == SHN_UNDEF) {
			/*
			 * XXX DANGER WILL ROBINSON!
			 * You might think this is stupid, as it intentionally
			 * defeats lazy binding -- and you'd be right.
			 * Unfortunately, for lazy binding to work right, we
			 * need to a way to force the GOT slots used for
			 * function pointers to be resolved immediately.  This
			 * is supposed to be done automatically by the linker,
			 * by not outputting a PLT slot and setting st_value
			 * to 0 if there are non-PLT references, but older
			 * versions of GNU ld do not do this.
			 */
			def = _rtld_find_symdef(i, obj, &defobj, false);
			if (def == NULL)
				return -1;
			*got = def->st_value + (Elf_Addr)defobj->relocbase;
		} else
#endif
		if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
		    sym->st_value != 0 && sym->st_shndx == SHN_UNDEF) {
			/*
			 * If there are non-PLT references to the function,
			 * st_value should be 0, forcing us to resolve the
			 * address immediately.
			 *
			 * XXX DANGER WILL ROBINSON!
			 * The linker is not outputting PLT slots for calls to
			 * functions that are defined in the same shared
			 * library.  This is a bug, because it can screw up
			 * link ordering rules if the symbol is defined in
			 * more than one module.  For now, if there is a
			 * definition, we fail the test above and force a full
			 * symbol lookup.  This means that all intra-module
			 * calls are bound immediately.  - mycroft, 2003/09/24
			 */
			*got = sym->st_value + (Elf_Addr)obj->relocbase;
		} else if (sym->st_info == ELF_ST_INFO(STB_GLOBAL, STT_SECTION)) {
			/* Symbols with index SHN_ABS are not relocated. */
			if (sym->st_shndx != SHN_ABS)
				*got = sym->st_value +
				    (Elf_Addr)obj->relocbase;
		} else {
			def = _rtld_find_symdef(i, obj, &defobj, false);
			if (def == NULL)
				return -1;
			*got = def->st_value + (Elf_Addr)defobj->relocbase;
		}

		rdbg(("  --> now %lx", (u_long) *got));
		++sym;
		++got;
	}

	got = obj->pltgot;
	for (rel = obj->rel; rel < obj->rellim; rel++) {
		Elf_Word	r_symndx, r_type;
		void		*where;

		where = obj->relocbase + rel->r_offset;
		r_symndx = ELF_R_SYM(rel->r_info);
		r_type = ELF_R_TYPE(rel->r_info);

		switch (r_type & 0xff) {
		case R_TYPE(NONE):
			break;

		case R_TYPE(REL32): {
			/* 32-bit PC-relative reference */
			const size_t rlen =
			    ELF_R_NXTTYPE_64_P(r_type)
				? sizeof(Elf_Sxword)
				: sizeof(Elf_Sword);
			Elf_Sxword old = load_ptr(where, rlen);
			Elf_Sxword val = old;

			def = obj->symtab + r_symndx;

			if (r_symndx >= obj->gotsym) {
				val += got[obj->local_gotno + r_symndx - obj->gotsym];
				rdbg(("REL32/G(%p) %p --> %p (%s) in %s",
				    where, (void *)old, (void *)val,
				    obj->strtab + def->st_name,
				    obj->path));
			} else {
				/*
				 * XXX: ABI DIFFERENCE!
				 *
				 * Old NetBSD binutils would generate shared
				 * libs with section-relative relocations being
				 * already adjusted for the start address of
				 * the section.
				 *
				 * New binutils, OTOH, generate shared libs
				 * with the same relocations being based at
				 * zero, so we need to add in the start address
				 * of the section.
				 *
				 * --rkb, Oct 6, 2001
				 */

				if (def->st_info ==
				    ELF_ST_INFO(STB_LOCAL, STT_SECTION)
#ifdef SUPPORT_OLD_BROKEN_LD
				    && !broken
#endif
				    )
					val += (Elf_Addr)def->st_value;

				val += (Elf_Addr)obj->relocbase;

				rdbg(("REL32/L(%p) %p -> %p (%s) in %s",
				    where, (void *)old, (void *)val,
				    obj->strtab + def->st_name, obj->path));
			}
			store_ptr(where, val, rlen);
			break;
		}

#if ELFSIZE == 64
		case R_TYPE(TLS_DTPMOD64):
#else
		case R_TYPE(TLS_DTPMOD32): 
#endif
		{
			Elf_Addr old = load_ptr(where, ELFSIZE / 8);
			Elf_Addr val = old;

			def = _rtld_find_symdef(r_symndx, obj, &defobj, false);
			if (def == NULL)
				return -1;

			val += (Elf_Addr)defobj->tlsindex;

			store_ptr(where, val, ELFSIZE / 8);
			rdbg(("DTPMOD %s in %s --> %p in %s",
			    obj->strtab + obj->symtab[r_symndx].st_name,
			    obj->path, (void *)old, defobj->path));
			break;
		}

#if ELFSIZE == 64
		case R_TYPE(TLS_DTPREL64):
#else
		case R_TYPE(TLS_DTPREL32):
#endif
		{
			Elf_Addr old = load_ptr(where, ELFSIZE / 8);
			Elf_Addr val = old;

			def = _rtld_find_symdef(r_symndx, obj, &defobj, false);
			if (def == NULL)
				return -1;

			if (!defobj->tls_done && _rtld_tls_offset_allocate(obj))
				return -1;

			val += (Elf_Addr)def->st_value - TLS_DTV_OFFSET;
			store_ptr(where, val, ELFSIZE / 8);

			rdbg(("DTPREL %s in %s --> %p in %s",
			    obj->strtab + obj->symtab[r_symndx].st_name,
			    obj->path, (void *)old, defobj->path));
			break;
		}

#if ELFSIZE == 64
		case R_TYPE(TLS_TPREL64):
#else
		case R_TYPE(TLS_TPREL32):
#endif
		{
			Elf_Addr old = load_ptr(where, ELFSIZE / 8);
			Elf_Addr val = old;

			def = _rtld_find_symdef(r_symndx, obj, &defobj, false);
			if (def == NULL)
				return -1;

			if (!defobj->tls_done && _rtld_tls_offset_allocate(obj))
				return -1;

			val += (Elf_Addr)(def->st_value + defobj->tlsoffset
			    - TLS_TP_OFFSET);
			store_ptr(where, val, ELFSIZE / 8);

			rdbg(("TPREL %s in %s --> %p in %s",
			    obj->strtab + obj->symtab[r_symndx].st_name,
			    obj->path, where, defobj->path));
			break;
		}

		default:
			rdbg(("sym = %lu, type = %lu, offset = %p, "
			    "contents = %p, symbol = %s",
			    (u_long)r_symndx, (u_long)ELF_R_TYPE(rel->r_info),
			    (void *)rel->r_offset,
			    (void *)load_ptr(where, sizeof(Elf_Sword)),
			    obj->strtab + obj->symtab[r_symndx].st_name));
			_rtld_error("%s: Unsupported relocation type %ld "
			    "in non-PLT relocations",
			    obj->path, (u_long) ELF_R_TYPE(rel->r_info));
			return -1;
		}
	}

	return 0;
}
Esempio n. 14
0
void
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
{
	const Elf_Rel *rel = 0, *rellim;
	Elf_Addr relsz = 0;
	void *where;
	const Elf_Sym *symtab = NULL, *sym;
	Elf_Addr *got = NULL;
	Elf_Word local_gotno = 0, symtabno = 0, gotsym = 0;
	size_t i;

	for (; dynp->d_tag != DT_NULL; dynp++) {
		switch (dynp->d_tag) {
		case DT_REL:
			rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
			break;
		case DT_RELSZ:
			relsz = dynp->d_un.d_val;
			break;
		case DT_SYMTAB:
			symtab = (const Elf_Sym *)(relocbase + dynp->d_un.d_ptr);
			break;
		case DT_PLTGOT:
			got = (Elf_Addr *)(relocbase + dynp->d_un.d_ptr);
			break;
		case DT_MIPS_LOCAL_GOTNO:
			local_gotno = dynp->d_un.d_val;
			break;
		case DT_MIPS_SYMTABNO:
			symtabno = dynp->d_un.d_val;
			break;
		case DT_MIPS_GOTSYM:
			gotsym = dynp->d_un.d_val;
			break;
		}
	}

	i = (got[1] & 0x80000000) ? 2 : 1;
	/* Relocate the local GOT entries */
	got += i;
	for (; i < local_gotno; i++)
		*got++ += relocbase;
	sym = symtab + gotsym;
	/* Now do the global GOT entries */
	for (i = gotsym; i < symtabno; i++) {
		*got = sym->st_value + relocbase;
		++sym;
		++got;
	}

	rellim = (const Elf_Rel *)((uintptr_t)rel + relsz);
	for (; rel < rellim; rel++) {
		Elf_Word r_symndx, r_type;

		where = (void *)(relocbase + rel->r_offset);

		r_symndx = ELF_R_SYM(rel->r_info);
		r_type = ELF_R_TYPE(rel->r_info);

		switch (r_type & 0xff) {
		case R_TYPE(REL32): {
			const size_t rlen =
			    ELF_R_NXTTYPE_64_P(r_type)
				? sizeof(Elf_Sxword)
				: sizeof(Elf_Sword);
			Elf_Sxword old = load_ptr(where, rlen);
			Elf_Sxword val = old;
#if ELFSIZE == 64
			assert(r_type == R_TYPE(REL32)
			    || r_type == (R_TYPE(REL32)|(R_TYPE(64) << 8)));
#endif
			assert(r_symndx < gotsym);
			sym = symtab + r_symndx;
			assert(ELF_ST_BIND(sym->st_info) == STB_LOCAL);
			val += relocbase;
			store_ptr(where, val, sizeof(Elf_Sword));
			rdbg(("REL32/L(%p) %p -> %p in <self>",
			    where, (void *)old, (void *)val));
			store_ptr(where, val, rlen);
			break;
		}

		case R_TYPE(GPREL32):
		case R_TYPE(NONE):
			break;


		default:
			abort();
		}
	}
}