Пример #1
0
int
_elf_slide(Elf * elf)
{
	NOTE(ASSUMING_PROTECTED(*elf))
	Elf		*par = elf->ed_parent;
	size_t		sz, szof;
	register char	*dst;
	register char	*src = elf->ed_ident;

	if (par == 0 || par->ed_kind != ELF_K_AR)
		return (0);

	/*
	 * This code relies on other code to ensure
	 * the ar_hdr is big enough to move into.
	 */
	if (elf->ed_ident[EI_CLASS] == ELFCLASS64)
		szof = sizeof (Elf64);
	else
		szof = sizeof (Elf32);
	if ((sz = (size_t)(src - (char *)elf->ed_image) % szof) == 0)
		return (0);
	dst = src - sz;
	elf->ed_ident -= sz;
	elf->ed_memoff -= sz;
	elf->ed_armem->m_slide = sz;
	if (_elf_vm(par, elf->ed_memoff, sz + elf->ed_fsz) != OK_YES)
		return (-1);

	/*
	 * If the archive has been mmaped in, and we're going to slide it,
	 * and it wasn't open for write in the first place, and we've never
	 * done the mprotect() operation before, then do it now.
	 */
	if ((elf->ed_vm == 0) && ((elf->ed_myflags & EDF_WRITE) == 0) &&
	    ((elf->ed_myflags & EDF_MPROTECT) == 0)) {
		if (mprotect((char *)elf->ed_image, elf->ed_imagesz,
		    PROT_READ|PROT_WRITE) == -1) {
			_elf_seterr(EIO_VM, errno);
			return (-1);
		}
		elf->ed_myflags |= EDF_MPROTECT;
	}

	if (memmove((void *)dst, (const void *)src, elf->ed_fsz) != (void *)dst)
		return (-1);
	else
		return (0);
}
Пример #2
0
static size_t
wrt(Elf * elf, Xword outsz, unsigned fill, int update_cmd)
{
	NOTE(ASSUMING_PROTECTED(*elf))
	Elf_Data	dst, src;
	unsigned	flag;
	Xword		hi, sz;
	char		*image;
	Elf_Scn		*s;
	Ehdr		*eh = elf->ed_ehdr;
	unsigned	ver = eh->e_version;
	unsigned	encode;
	int		byte;

	/*
	 * If this is an ELF_C_WRIMAGE write, then we encode into the
	 * byte order of the system we are running on rather than that of
	 * of the object. For ld.so.1, this is the same order, but
	 * for 'ld', it might not be in the case where we are cross
	 * linking an object for a different target. In this later case,
	 * the linker-host byte order is necessary so that the linker can
	 * manipulate the resulting  image. It is expected that the linker
	 * will call elf_swap_wrimage() if necessary to convert the image
	 * to the target byte order.
	 */
	encode = (update_cmd == ELF_C_WRIMAGE) ? _elf_sys_encoding() :
	    eh->e_ident[EI_DATA];

	/*
	 * Two issues can cause trouble for the output file.
	 * First, begin() with ELF_C_RDWR opens a file for both
	 * read and write.  On the write update(), the library
	 * has to read everything it needs before truncating
	 * the file.  Second, using mmap for both read and write
	 * is too tricky.  Consequently, the library disables mmap
	 * on the read side.  Using mmap for the output saves swap
	 * space, because that mapping is SHARED, not PRIVATE.
	 *
	 * If the file is write-only, there can be nothing of
	 * interest to bother with.
	 *
	 * The following reads the entire file, which might be
	 * more than necessary.  Better safe than sorry.
	 */

	if ((elf->ed_myflags & EDF_READ) &&
	    (_elf_vm(elf, (size_t)0, elf->ed_fsz) != OK_YES))
		return (0);

	flag = elf->ed_myflags & EDF_WRALLOC;
	if ((image = _elf_outmap(elf->ed_fd, outsz, &flag)) == 0)
		return (0);

	if (flag == 0)
		elf->ed_myflags |= EDF_IMALLOC;

	/*
	 * If an error occurs below, a "dirty" bit may be cleared
	 * improperly.  To save a second pass through the file,
	 * this code sets the dirty bit on the elf descriptor
	 * when an error happens, assuming that will "cover" any
	 * accidents.
	 */

	/*
	 * Hi is needed only when 'fill' is non-zero.
	 * Fill is non-zero only when the library
	 * calculates file/section/data buffer offsets.
	 * The lib guarantees they increase monotonically.
	 * That guarantees proper filling below.
	 */


	/*
	 * Ehdr first
	 */

	src.d_buf = (Elf_Void *)eh;
	src.d_type = ELF_T_EHDR;
	src.d_size = sizeof (Ehdr);
	src.d_version = EV_CURRENT;
	dst.d_buf = (Elf_Void *)image;
	dst.d_size = eh->e_ehsize;
	dst.d_version = ver;
	if (elf_xlatetof(&dst, &src, encode) == 0)
		return (0);
	elf->ed_ehflags &= ~ELF_F_DIRTY;
	hi = eh->e_ehsize;

	/*
	 * Phdr table if one exists
	 */

	if (eh->e_phnum != 0) {
		unsigned	work;
		/*
		 * Unlike other library data, phdr table is
		 * in the user version.  Change src buffer
		 * version here, fix it after translation.
		 */

		src.d_buf = (Elf_Void *)elf->ed_phdr;
		src.d_type = ELF_T_PHDR;
		src.d_size = elf->ed_phdrsz;
		ELFACCESSDATA(work, _elf_work)
		src.d_version = work;
		dst.d_buf = (Elf_Void *)(image + eh->e_phoff);
		dst.d_size = eh->e_phnum * eh->e_phentsize;
		hi = (Xword)(eh->e_phoff + dst.d_size);
		if (elf_xlatetof(&dst, &src, encode) == 0) {
			elf->ed_uflags |= ELF_F_DIRTY;
			return (0);
		}
		elf->ed_phflags &= ~ELF_F_DIRTY;
		src.d_version = EV_CURRENT;
	}

	/*
	 * Loop through sections
	 */

	ELFACCESSDATA(byte, _elf_byte);
	for (s = elf->ed_hdscn; s != 0; s = s->s_next) {
		register Dnode	*d, *prevd;
		Xword		off = 0;
		Shdr		*sh = s->s_shdr;
		char		*start = image + sh->sh_offset;
		char		*here;

		/*
		 * Just "clean" DIRTY flag for "empty" sections.  Even if
		 * NOBITS needs padding, the next thing in the
		 * file will provide it.  (And if this NOBITS is
		 * the last thing in the file, no padding needed.)
		 */
		if ((sh->sh_type == SHT_NOBITS) ||
		    (sh->sh_type == SHT_NULL)) {
			d = s->s_hdnode, prevd = 0;
			for (; d != 0; prevd = d, d = d->db_next)
				d->db_uflags &= ~ELF_F_DIRTY;
			continue;
		}
		/*
		 * Clear out the memory between the end of the last
		 * section and the begining of this section.
		 */
		if (fill && (sh->sh_offset > hi)) {
			sz = sh->sh_offset - hi;
			(void) memset(start - sz, byte, sz);
		}


		for (d = s->s_hdnode, prevd = 0;
		    d != 0; prevd = d, d = d->db_next) {
			d->db_uflags &= ~ELF_F_DIRTY;
			here = start + d->db_data.d_off;

			/*
			 * Clear out the memory between the end of the
			 * last update and the start of this data buffer.
			 */
			if (fill && (d->db_data.d_off > off)) {
				sz = (Xword)(d->db_data.d_off - off);
				(void) memset(here - sz, byte, sz);
			}

			if ((d->db_myflags & DBF_READY) == 0) {
				SCNLOCK(s);
				if (_elf_locked_getdata(s, &prevd->db_data) !=
				    &d->db_data) {
					elf->ed_uflags |= ELF_F_DIRTY;
					SCNUNLOCK(s);
					return (0);
				}
				SCNUNLOCK(s);
			}
			dst.d_buf = (Elf_Void *)here;
			dst.d_size = d->db_osz;

			/*
			 * Copy the translated bits out to the destination
			 * image.
			 */
			if (elf_xlatetof(&dst, &d->db_data, encode) == 0) {
				elf->ed_uflags |= ELF_F_DIRTY;
				return (0);
			}

			off = (Xword)(d->db_data.d_off + dst.d_size);
		}
		hi = sh->sh_offset + sh->sh_size;
	}

	/*
	 * Shdr table last
	 */

	if (fill && (eh->e_shoff > hi)) {
		sz = eh->e_shoff - hi;
		(void) memset(image + hi, byte, sz);
	}

	src.d_type = ELF_T_SHDR;
	src.d_size = sizeof (Shdr);
	dst.d_buf = (Elf_Void *)(image + eh->e_shoff);
	dst.d_size = eh->e_shentsize;
	for (s = elf->ed_hdscn; s != 0; s = s->s_next) {
		assert((uintptr_t)dst.d_buf < ((uintptr_t)image + outsz));
		s->s_shflags &= ~ELF_F_DIRTY;
		s->s_uflags &= ~ELF_F_DIRTY;
		src.d_buf = s->s_shdr;

		if (elf_xlatetof(&dst, &src, encode) == 0) {
			elf->ed_uflags |= ELF_F_DIRTY;
			return (0);
		}

		dst.d_buf = (char *)dst.d_buf + eh->e_shentsize;
	}
	/*
	 * ELF_C_WRIMAGE signifyes that we build the memory image, but
	 * that we do not actually write it to disk.  This is used
	 * by ld(1) to build up a full image of an elf file and then
	 * to process the file before it's actually written out to
	 * disk.  This saves ld(1) the overhead of having to write
	 * the image out to disk twice.
	 */
	if (update_cmd == ELF_C_WRIMAGE) {
		elf->ed_uflags &= ~ELF_F_DIRTY;
		elf->ed_wrimage = image;
		elf->ed_wrimagesz = outsz;
		return (outsz);
	}

	if (_elf_outsync(elf->ed_fd, image, outsz,
	    ((elf->ed_myflags & EDF_IMALLOC) ? 0 : 1)) != 0) {
		elf->ed_uflags &= ~ELF_F_DIRTY;
		elf->ed_myflags &= ~EDF_IMALLOC;
		return (outsz);
	}

	elf->ed_uflags |= ELF_F_DIRTY;
	return (0);
}
Пример #3
0
static size_t
_elf_upd_usr(Elf * elf)
{
	NOTE(ASSUMING_PROTECTED(*elf))
	Lword		hi;
	Elf_Scn *	s;
	register Lword	sz;
	Ehdr *		eh = elf->ed_ehdr;
	unsigned	ver = eh->e_version;
	register char	*p = (char *)eh->e_ident;


	/*
	 * Ehdr and Phdr table go first
	 */
	p[EI_MAG0] = ELFMAG0;
	p[EI_MAG1] = ELFMAG1;
	p[EI_MAG2] = ELFMAG2;
	p[EI_MAG3] = ELFMAG3;
	p[EI_CLASS] = ELFCLASS;
	/* LINTED */
	p[EI_VERSION] = (Byte)ver;
	hi = elf_fsize(ELF_T_EHDR, 1, ver);
	/* LINTED */
	eh->e_ehsize = (Half)hi;

	/*
	 * If phnum is zero, phoff "should" be zero too,
	 * but the application is responsible for it.
	 * Allow a non-zero value here and update the
	 * hi water mark accordingly.
	 */

	if (eh->e_phnum != 0)
		/* LINTED */
		eh->e_phentsize = (Half)elf_fsize(ELF_T_PHDR, 1, ver);
	else
		eh->e_phentsize = 0;
	if ((sz = eh->e_phoff + eh->e_phentsize * eh->e_phnum) > hi)
		hi = sz;

	/*
	 * Loop through sections, skipping index zero.
	 * Compute section size before changing hi.
	 * Allow null buffers for NOBITS.
	 */

	if ((s = elf->ed_hdscn) == 0)
		eh->e_shnum = 0;
	else {
		eh->e_shnum = 1;
		*(Shdr*)s->s_shdr = _elf_snode_init.sb_shdr;
		s = s->s_next;
	}
	for (; s != 0; s = s->s_next) {
		register Dnode	*d;
		register Lword	fsz, j;
		Shdr *sh = s->s_shdr;

		if ((s->s_myflags & SF_READY) == 0)
			(void) _elfxx_cookscn(s);

		++eh->e_shnum;
		sz = 0;
		for (d = s->s_hdnode; d != 0; d = d->db_next) {
			if ((fsz = elf_fsize(d->db_data.d_type, 1,
			    ver)) == 0)
				return (0);
			j = _elf_msize(d->db_data.d_type, ver);
			fsz *= (d->db_data.d_size / j);
			d->db_osz = (size_t)fsz;

			if ((sh->sh_type != SHT_NOBITS) &&
			    ((j = (d->db_data.d_off + d->db_osz)) > sz))
				sz = j;
		}
		if (sh->sh_size < sz) {
			_elf_seterr(EFMT_SCNSZ, 0);
			return (0);
		}
		if ((sh->sh_type != SHT_NOBITS) &&
		    (hi < sh->sh_offset + sh->sh_size))
			hi = sh->sh_offset + sh->sh_size;
	}

	/*
	 * Shdr table last.  Comment above for phnum/phoff applies here.
	 */
	if (eh->e_shnum != 0)
		/* LINTED */
		eh->e_shentsize = (Half)elf_fsize(ELF_T_SHDR, 1, ver);
	else
		eh->e_shentsize = 0;

	if ((sz = eh->e_shoff + eh->e_shentsize * eh->e_shnum) > hi)
		hi = sz;

#ifdef TEST_SIZE
	if (test_size(hi) == 0)
		return (0);
#endif

	return ((size_t)hi);
}
Пример #4
0
static size_t
_elf_upd_lib(Elf * elf)
{
	NOTE(ASSUMING_PROTECTED(*elf))
	Lword		hi;
	Lword		hibit;
	Elf_Scn *	s;
	register Lword	sz;
	Ehdr *		eh = elf->ed_ehdr;
	unsigned	ver = eh->e_version;
	register char	*p = (char *)eh->e_ident;
	size_t		scncnt;

	/*
	 * Ehdr and Phdr table go first
	 */
	p[EI_MAG0] = ELFMAG0;
	p[EI_MAG1] = ELFMAG1;
	p[EI_MAG2] = ELFMAG2;
	p[EI_MAG3] = ELFMAG3;
	p[EI_CLASS] = ELFCLASS;
	/* LINTED */
	p[EI_VERSION] = (Byte)ver;
	hi = elf_fsize(ELF_T_EHDR, 1, ver);
	/* LINTED */
	eh->e_ehsize = (Half)hi;
	if (eh->e_phnum != 0) {
		/* LINTED */
		eh->e_phentsize = (Half)elf_fsize(ELF_T_PHDR, 1, ver);
		/* LINTED */
		eh->e_phoff = (Off)hi;
		hi += eh->e_phentsize * eh->e_phnum;
	} else {
		eh->e_phoff = 0;
		eh->e_phentsize = 0;
	}

	/*
	 * Obtain the first section header.  Typically, this section has NULL
	 * contents, however in the case of Extended ELF Sections this section
	 * is used to hold an alternative e_shnum, e_shstrndx and e_phnum.
	 * On initial allocation (see _elf_snode) the elements of this section
	 * would have been zeroed.  The e_shnum is initialized later, after the
	 * section header count has been determined.  The e_shstrndx and
	 * e_phnum may have already been initialized by the caller (for example,
	 * gelf_update_shdr() in mcs(1)).
	 */
	if ((s = elf->ed_hdscn) == 0) {
		eh->e_shnum = 0;
		scncnt = 0;
	} else {
		s = s->s_next;
		scncnt = 1;
	}

	/*
	 * Loop through sections.  Compute section size before changing hi.
	 * Allow null buffers for NOBITS.
	 */
	hibit = 0;
	for (; s != 0; s = s->s_next) {
		register Dnode	*d;
		register Lword	fsz, j;
		Shdr *sh = s->s_shdr;

		scncnt++;
		if (sh->sh_type == SHT_NULL) {
			*sh = _elf_snode_init.sb_shdr;
			continue;
		}

		if ((s->s_myflags & SF_READY) == 0)
			(void) _elfxx_cookscn(s);

		sh->sh_addralign = 1;
		if ((sz = (Lword)_elf_entsz(elf, sh->sh_type, ver)) != 0)
			/* LINTED */
			sh->sh_entsize = (Half)sz;
		sz = 0;
		for (d = s->s_hdnode; d != 0; d = d->db_next) {
			if ((fsz = elf_fsize(d->db_data.d_type,
			    1, ver)) == 0)
				return (0);

			j = _elf_msize(d->db_data.d_type, ver);
			fsz *= (d->db_data.d_size / j);
			d->db_osz = (size_t)fsz;
			if ((j = d->db_data.d_align) > 1) {
				if (j > sh->sh_addralign)
					sh->sh_addralign = (Xword)j;

				if (sz % j != 0)
					sz += j - sz % j;
			}
			d->db_data.d_off = (off_t)sz;
			d->db_xoff = sz;
			sz += fsz;
		}

		sh->sh_size = (Xword) sz;
		/*
		 * We want to take into account the offsets for NOBITS
		 * sections and let the "sh_offsets" point to where
		 * the section would 'conceptually' fit within
		 * the file (as required by the ABI).
		 *
		 * But - we must also make sure that the NOBITS does
		 * not take up any actual space in the file.  We preserve
		 * the actual offset into the file in the 'hibit' variable.
		 * When we come to the first non-NOBITS section after a
		 * encountering a NOBITS section the hi counter is restored
		 * to its proper place in the file.
		 */
		if (sh->sh_type == SHT_NOBITS) {
			if (hibit == 0)
				hibit = hi;
		} else {
			if (hibit) {
				hi = hibit;
				hibit = 0;
			}
		}
		j = sh->sh_addralign;
		if ((fsz = hi % j) != 0)
			hi += j - fsz;

		/* LINTED */
		sh->sh_offset = (Off)hi;
		hi += sz;
	}

	/*
	 * if last section was a 'NOBITS' section then we need to
	 * restore the 'hi' counter to point to the end of the last
	 * non 'NOBITS' section.
	 */
	if (hibit) {
		hi = hibit;
		hibit = 0;
	}

	/*
	 * Shdr table last
	 */
	if (scncnt != 0) {
		if (hi % FSZ_LONG != 0)
			hi += FSZ_LONG - hi % FSZ_LONG;
		/* LINTED */
		eh->e_shoff = (Off)hi;
		/*
		 * If we are using 'extended sections' then the
		 * e_shnum is stored in the sh_size field of the
		 * first section header.
		 *
		 * NOTE: we set e_shnum to '0' because it's specified
		 * this way in the gABI, and in the hopes that
		 * this will cause less problems to unaware
		 * tools then if we'd set it to SHN_XINDEX (0xffff).
		 */
		if (scncnt < SHN_LORESERVE)
			eh->e_shnum = scncnt;
		else {
			Shdr	*sh;
			sh = (Shdr *)elf->ed_hdscn->s_shdr;
			sh->sh_size = scncnt;
			eh->e_shnum = 0;
		}
		/* LINTED */
		eh->e_shentsize = (Half)elf_fsize(ELF_T_SHDR, 1, ver);
		hi += eh->e_shentsize * scncnt;
	} else {
		eh->e_shoff = 0;
		eh->e_shentsize = 0;
	}

#ifdef TEST_SIZE
	if (test_size(hi) == 0)
		return (0);
#endif

	return ((size_t)hi);
}
Пример #5
0
/*
 * ibmf_i_issue_pkt():
 *	Post an IB packet on the specified QP's send queue
 */
int
ibmf_i_issue_pkt(ibmf_client_t *clientp, ibmf_msg_impl_t *msgimplp,
    ibmf_qp_handle_t ibmf_qp_handle, ibmf_send_wqe_t *send_wqep)
{
	int			ret;
	ibt_status_t		status;
	ibt_wr_ds_t		sgl[1];
	ibt_qp_hdl_t		ibt_qp_handle;

	_NOTE(ASSUMING_PROTECTED(*send_wqep))
	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*send_wqep))

	IBMF_TRACE_4(IBMF_TNF_DEBUG, DPRINT_L4,
	    ibmf_i_issue_pkt_start, IBMF_TNF_TRACE, "",
	    "ibmf_i_issue_pkt() enter, clientp = %p, msg = %p, "
	    "qp_hdl = %p,  swqep = %p\n", tnf_opaque, clientp, clientp,
	    tnf_opaque, msg, msgimplp, tnf_opaque, ibmf_qp_handle,
	    ibmf_qp_handle, tnf_opaque, send_wqep, send_wqep);

	ASSERT(MUTEX_HELD(&msgimplp->im_mutex));
	ASSERT(MUTEX_NOT_HELD(&clientp->ic_mutex));

	/*
	 * if the qp handle provided in ibmf_send_pkt()
	 * is not the default qp handle for this client,
	 * then the wqe must be sent on this qp,
	 * else use the default qp handle set up during ibmf_register()
	 */
	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
		ibt_qp_handle = clientp->ic_qp->iq_qp_handle;
	} else {
		ibt_qp_handle =
		    ((ibmf_alt_qp_t *)ibmf_qp_handle)->isq_qp_handle;
	}

	/* initialize the send WQE */
	ibmf_i_init_send_wqe(clientp, msgimplp, sgl, send_wqep,
	    msgimplp->im_ud_dest, ibt_qp_handle, ibmf_qp_handle);

	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*send_wqep))

	/*
	 * Issue the wqe to the transport.
	 * NOTE: ibt_post_send() will not block, so, it is ok
	 * to hold the msgimpl mutex across this call.
	 */
	status = ibt_post_send(send_wqep->send_qp_handle, &send_wqep->send_wr,
	    1, NULL);
	if (status != IBT_SUCCESS) {
		mutex_enter(&clientp->ic_kstat_mutex);
		IBMF_ADD32_KSTATS(clientp, send_pkt_failed, 1);
		mutex_exit(&clientp->ic_kstat_mutex);
		IBMF_TRACE_2(IBMF_TNF_NODEBUG, DPRINT_L1,
		    ibmf_i_issue_pkt_err, IBMF_TNF_TRACE, "",
		    "ibmf_i_issue_pkt(): %s, status = %d\n",
		    tnf_string, msg, "post send failure",
		    tnf_uint, ibt_status, status);
		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_issue_pkt_end,
		    IBMF_TNF_TRACE, "", "ibmf_i_issue_pkt(() exit\n");
		return (IBMF_TRANSPORT_FAILURE);
	}

	ret = IBMF_SUCCESS;

	/* bump the number of active sends */
	if (ibmf_qp_handle == IBMF_QP_HANDLE_DEFAULT) {
		mutex_enter(&clientp->ic_mutex);
		clientp->ic_sends_active++;
		mutex_exit(&clientp->ic_mutex);
		mutex_enter(&clientp->ic_kstat_mutex);
		IBMF_ADD32_KSTATS(clientp, sends_active, 1);
		mutex_exit(&clientp->ic_kstat_mutex);
	} else {
		ibmf_alt_qp_t *qpp = (ibmf_alt_qp_t *)ibmf_qp_handle;
		mutex_enter(&qpp->isq_mutex);
		qpp->isq_sends_active++;
		mutex_exit(&qpp->isq_mutex);
		mutex_enter(&clientp->ic_kstat_mutex);
		IBMF_ADD32_KSTATS(clientp, sends_active, 1);
		mutex_exit(&clientp->ic_kstat_mutex);
	}

	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4, ibmf_i_issue_pkt_end,
	    IBMF_TNF_TRACE, "", "ibmf_i_issue_pkt() exit\n");
	return (ret);
}