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); }
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); }
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); }
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); }
/* * 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); }