/* * Called from process_elf(). * This routine does the input processing of the ordered sections. */ uintptr_t ld_process_ordered(Ifl_desc *ifl, Ofl_desc *ofl, Word ndx, Word limit) { Is_desc * isp2, * isp = ifl->ifl_isdesc[ndx]; Xword shflags = isp->is_shdr->sh_flags; uint_t keylink; Os_desc * osp2, * osp; Word dest_ndx; Sort_desc * st; Listnode * lnp; int error = 0; /* * I might have been checked and marked error already. */ if ((isp->is_flags & FLG_IS_ORDERED) == 0) return (0); if (shflags & SHF_ORDERED) keylink = isp->is_shdr->sh_info; else if (shflags & SHF_LINK_ORDER) keylink = isp->is_shdr->sh_link; else keylink = 0; if ((error = is_keylink_ok(ifl, keylink, limit)) != 0) { DBG_CALL(Dbg_sec_order_error(ofl->ofl_lml, ifl, ndx, error)); isp->is_flags &= ~FLG_IS_ORDERED; if (isp->is_osdesc == NULL) return ((uintptr_t)ld_place_section(ofl, isp, isp->is_key, 0)); return ((uintptr_t)isp->is_osdesc); } /* * If SHF_ORDERED is in effect, search for our destination section based * off of sh_link, otherwise follow the default rules for the * destination section. */ if (shflags & SHF_ORDERED) { if ((dest_ndx = get_shfordered_dest(ofl, ifl, ndx, limit)) == 0) { isp->is_flags &= ~FLG_IS_ORDERED; if (isp->is_osdesc == NULL) return ((uintptr_t)ld_place_section(ofl, isp, isp->is_key, 0)); return ((uintptr_t)isp->is_osdesc); } } else { /* * SHF_LINK_ORDER coalesces into default sections, set dest_ndx * to NULL to trigger this. */ dest_ndx = 0; } /* * Place the section into it's output section. */ if ((osp = isp->is_osdesc) == NULL) { if ((osp = ld_place_section(ofl, isp, isp->is_ident, dest_ndx)) == (Os_desc *)S_ERROR) return ((uintptr_t)S_ERROR); if (!osp) return (0); } /* * If the output section is not yet on the ordered * list - place it on the list. */ osp2 = NULL; for (LIST_TRAVERSE(&ofl->ofl_ordered, lnp, osp2)) { if (osp2 == osp) break; } if (osp != osp2) { if (list_appendc(&(ofl->ofl_ordered), osp) == 0) return ((uintptr_t)S_ERROR); } /* * Output section has been found - set up it's * sorting information. */ if (osp->os_sort == 0) { if ((osp->os_sort = libld_calloc(1, sizeof (Sort_desc))) == 0) return (S_ERROR); } st = osp->os_sort; if (keylink == SHN_BEFORE) { st->st_beforecnt++; } else if (keylink == SHN_AFTER) { st->st_aftercnt++; } else { st->st_ordercnt++; isp2 = ifl->ifl_isdesc[keylink]; if (isp2->is_flags & FLG_IS_DISCARD) { eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_FIL_BADORDREF), ifl->ifl_name, isp->is_name, isp->is_scnndx, isp2->is_name, isp2->is_scnndx); return (S_ERROR); } osp2 = isp2->is_osdesc; osp2->os_flags |= FLG_OS_ORDER_KEY; osp2->os_sgdesc->sg_flags |= FLG_SG_KEY; isp2->is_flags |= FLG_IS_KEY; } return ((uintptr_t)osp); }
/* * Create an unwind header (.eh_frame_hdr) output section. * The section is created and space reserved, but the data * is not copied into place. That is done by a later call * to ld_unwind_populate(), after active relocations have been * processed. * * When GNU linkonce processing is in effect, we can end up in a situation * where the FDEs related to discarded sections remain in the eh_frame * section. Ideally, we would remove these dead entries from eh_frame. * However, that optimization has not yet been implemented. In the current * implementation, the number of dead FDEs cannot be determined until * active relocations are processed, and that processing follows the * call to this function. This means that we are unable to detect dead FDEs * here, and the section created by this routine is sized for maximum case * where all FDEs are valid. */ uintptr_t ld_unwind_make_hdr(Ofl_desc *ofl) { int bswap = (ofl->ofl_flags1 & FLG_OF1_ENCDIFF) != 0; Shdr *shdr; Elf_Data *elfdata; Is_desc *isp; size_t size; Xword fde_cnt; Aliste idx1; Os_desc *osp; /* * we only build a unwind header if we have * some unwind information in the file. */ if (ofl->ofl_unwind == NULL) return (1); /* * Allocate and initialize the Elf_Data structure. */ if ((elfdata = libld_calloc(sizeof (Elf_Data), 1)) == NULL) return (S_ERROR); elfdata->d_type = ELF_T_BYTE; elfdata->d_align = ld_targ.t_m.m_word_align; elfdata->d_version = ofl->ofl_dehdr->e_version; /* * Allocate and initialize the Shdr structure. */ if ((shdr = libld_calloc(sizeof (Shdr), 1)) == NULL) return (S_ERROR); shdr->sh_type = ld_targ.t_m.m_sht_unwind; shdr->sh_flags = SHF_ALLOC; shdr->sh_addralign = ld_targ.t_m.m_word_align; shdr->sh_entsize = 0; /* * Allocate and initialize the Is_desc structure. */ if ((isp = libld_calloc(1, sizeof (Is_desc))) == NULL) return (S_ERROR); isp->is_name = MSG_ORIG(MSG_SCN_UNWINDHDR); isp->is_shdr = shdr; isp->is_indata = elfdata; if ((ofl->ofl_unwindhdr = ld_place_section(ofl, isp, NULL, ld_targ.t_id.id_unwindhdr, NULL)) == (Os_desc *)S_ERROR) return (S_ERROR); /* * Scan through all of the input Frame information, counting each FDE * that requires an index. Each fde_entry gets a corresponding entry * in the binary search table. */ fde_cnt = 0; for (APLIST_TRAVERSE(ofl->ofl_unwind, idx1, osp)) { Aliste idx2; int os_isdescs_idx; OS_ISDESCS_TRAVERSE(os_isdescs_idx, osp, idx2, isp) { uchar_t *data; uint64_t off = 0; data = isp->is_indata->d_buf; size = isp->is_indata->d_size; while (off < size) { uint_t length, id; uint64_t ndx = 0; /* * Extract length in lsb format. A zero length * indicates that this CIE is a terminator and * that processing for unwind information is * complete. */ length = extract_uint(data + off, &ndx, bswap); if (length == 0) break; /* * Extract CIE id in lsb format. */ id = extract_uint(data + off, &ndx, bswap); /* * A CIE record has a id of '0', otherwise * this is a FDE entry and the 'id' is the * CIE pointer. */ if (id == 0) { uint_t cieversion; /* * The only CIE version supported * is '1' - quick sanity check * here. */ cieversion = data[off + ndx]; ndx += 1; /* BEGIN CSTYLED */ if (cieversion != 1) { ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_UNW_BADCIEVERS), isp->is_file->ifl_name, isp->is_name, off); return (S_ERROR); } /* END CSTYLED */ } else { fde_cnt++; } off += length + 4; } } }