Beispiel #1
0
/*
 * Create a pseudo input file descriptor to represent the specified Mapfile.
 * An input descriptor is required any time a symbol is generated.
 *
 * entry:
 *	mf - Mapfile descriptor.
 *
 * exit:
 *	If an input descriptor was already created for this mapfile
 *	by a previous call, it is returned. Otherwise, a new descriptor
 *	is created, entered into the mapfile descriptor, and returned.
 *
 *	Success is indicated by a non-NULL return value, failure by NULL.
 */
Ifl_desc *
ld_map_ifl(Mapfile *mf)
{
	Ifl_desc	*ifl;

	/*
	 * If we've already created a pseudo input descriptor for this
	 * mapfile, reuse it.
	 */
	if (mf->mf_ifl != NULL)
		return (mf->mf_ifl);

	if ((ifl = libld_calloc(sizeof (Ifl_desc), 1)) == NULL)
		return (NULL);
	ifl->ifl_name = mf->mf_name;
	ifl->ifl_flags = (FLG_IF_MAPFILE | FLG_IF_NEEDED | FLG_IF_FILEREF);
	if ((ifl->ifl_ehdr = libld_calloc(sizeof (Elf64_Ehdr), 1)) == NULL)
		return (NULL);
	ifl->ifl_ehdr->e_type = ET_REL;

	if (aplist_append(&mf->mf_ofl->ofl_objs, ifl, AL_CNT_OFL_OBJS) == NULL)
		return (NULL);

	mf->mf_ifl = ifl;
	return (mf->mf_ifl);
}
Beispiel #2
0
static int
setup_sortbuf(Os_desc *osp)
{
	Sort_desc	*st = osp->os_sort;
	Word		num_after = 0, num_before = 0, num_order = 0;
	Listnode	*lnp1;
	Is_desc		*isp;

	if ((st == NULL) ||
	    ((st->st_ordercnt + st->st_beforecnt + st->st_aftercnt) == 0))
		return (0);

	/*
	 * Get memory
	 */
	if (st->st_beforecnt != 0) {
		if ((st->st_before =
		    libld_calloc(st->st_beforecnt, sizeof (Is_desc *))) == 0)
			return (0);
	}
	if (st->st_ordercnt != 0) {
		if ((st->st_order =
		    libld_calloc(st->st_ordercnt, sizeof (Is_desc *))) == 0)
			return (0);
	}
	if (st->st_aftercnt != 0) {
		if ((st->st_after =
		    libld_calloc(st->st_aftercnt, sizeof (Is_desc *))) == 0)
			return (0);
	}

	/*
	 * Set info.
	 */
	for (LIST_TRAVERSE(&(osp->os_isdescs), lnp1, isp)) {
		Word	keylink = 0;

		if ((isp->is_flags & FLG_IS_ORDERED) == 0)
			continue;

		if (isp->is_shdr->sh_flags & SHF_ORDERED)
			keylink = isp->is_shdr->sh_info;
		else if (isp->is_shdr->sh_flags & SHF_LINK_ORDER)
			keylink = isp->is_shdr->sh_link;

		if (keylink == SHN_BEFORE)
			st->st_before[num_before++] = isp;
		else if (keylink == SHN_AFTER)
			st->st_after[num_after++] = isp;
		else
			st->st_order[num_order++] = isp;
	}
	return (1);
}
Beispiel #3
0
/*
 * Determine whether a (COMDAT) group has already been encountered.  If so,
 * indicate that the group descriptor has an overriding group (gd_oisc).  This
 * indication triggers the ld_place_section() to discard this group, while the
 * gd_oisc information provides for complete diagnostics of the override.
 * Otherwise, this is the first occurrence of this group, therefore the group
 * descriptor is saved for future comparisons.
 */
static uintptr_t
gpavl_loaded(Ofl_desc *ofl, Group_desc *gdp)
{
	Isd_node	isd, *isdp;
	avl_tree_t	*avlt;
	avl_index_t	where;

	/*
	 * Create a groups avl tree if required.
	 */
	if ((avlt = ofl->ofl_groups) == NULL) {
		if ((avlt = libld_calloc(sizeof (avl_tree_t), 1)) == NULL)
			return (S_ERROR);
		avl_create(avlt, isdavl_compare, sizeof (Isd_node),
		    SGSOFFSETOF(Isd_node, isd_avl));
		ofl->ofl_groups = avlt;
	}

	/*
	 * An SHT_GROUP section is identified by the name of its signature
	 * symbol rather than section name. Although the section names are
	 * often unique, this is not required, and some compilers set it to
	 * a generic name like ".group".
	 */
	isd.isd_name = gdp->gd_name;
	isd.isd_hash = sgs_str_hash(isd.isd_name);

	if ((isdp = avl_find(avlt, &isd, &where)) != NULL) {
		gdp->gd_oisc = isdp->isd_isp;
		return (1);
	}

	/*
	 * This is a new group - so keep it.
	 */
	if ((isdp = libld_calloc(sizeof (Isd_node), 1)) == NULL)
		return (S_ERROR);

	isdp->isd_name = isd.isd_name;
	isdp->isd_hash = isd.isd_hash;
	isdp->isd_isp = gdp->gd_isc;

	avl_insert(avlt, isdp, where);
	return (0);
}
Beispiel #4
0
static Ver_index *
vers_index(Ofl_desc *ofl, Ifl_desc *ifl, int avail)
{
	size_t		idx1;
	Ver_desc	*vdp;
	Ver_index	*vip;
	Sdf_desc	*sdf = ifl->ifl_sdfdesc;
	Elf64_Word		count = ifl->ifl_vercnt;
	Sdv_desc	*sdv;

	/*
	 * Allocate an index array large enough to hold all of the files
	 * version descriptors.
	 */
	if ((vip = libld_calloc(sizeof (Ver_index), (count + 1))) == NULL)
		return ((Ver_index *)S_ERROR);

	for (APLIST_TRAVERSE(ifl->ifl_verdesc, idx1, vdp)) {
		int	ndx = vdp->vd_ndx;

		vip[ndx].vi_name = vdp->vd_name;
		vip[ndx].vi_desc = vdp;

		/*
		 * Any relocatable object versions, and the `base' version are
		 * always available.
		 */
		if (avail || (vdp->vd_flags & VER_FLG_BASE))
			vip[ndx].vi_flags |= FLG_VER_AVAIL;

		/*
		 * If this is a weak version mark it as such.  Weak versions
		 * are always dragged into any version dependencies created,
		 * and if a weak version is referenced it will be promoted to
		 * a non-weak version dependency.
		 */
		if (vdp->vd_flags & VER_FLG_WEAK)
			vip[ndx].vi_flags |= VER_FLG_WEAK;
		/*
		 * If this version is mentioned in a mapfile using ADDVERS
		 * syntax then check to see if it corresponds to an actual
		 * version in the file.
		 */
		if (sdf && (sdf->sdf_flags & FLG_SDF_ADDVER)) {
			size_t	idx2;

			for (ALIST_TRAVERSE(sdf->sdf_verneed, idx2, sdv)) {
				if (strcmp(vip[ndx].vi_name, sdv->sdv_name))
					continue;

				vip[ndx].vi_flags |= FLG_VER_REFER;
				sdv->sdv_flags |= FLG_SDV_MATCHED;
				break;
			}
		}
	}
Beispiel #5
0
/*
 * Create an archive descriptor.  By maintaining a list of archives any
 * duplicate occurrences of the same archive specified by the user enable us to
 * pick off where the last processing finished.
 */
Ar_desc *
ld_ar_setup(const char *name, Elf *elf, Ofl_desc *ofl)
{
	Ar_desc *	adp;
	size_t		number;
	Elf_Arsym *	start;

	/*
	 * Unless, -z allextract is specified, get the archive symbol table
	 * if one exists, and ignore the file with a warning message otherwise.
	 */
	if (ofl->ofl_flags1 & FLG_OF1_ALLEXRT) {
		start = NULL;
	} else  if ((start = elf_getarsym(elf, &number)) == NULL) {
		if (elf_errno())
			ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_GETARSYM),
			    name);
		else
			ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_ELF_ARSYM),
			    name);
		return (0);
	}

	/*
	 * As this is a new archive reference establish a new descriptor.
	 */
	if ((adp = libld_malloc(sizeof (Ar_desc))) == NULL)
		return ((Ar_desc *)S_ERROR);
	adp->ad_name = name;
	adp->ad_elf = elf;
	adp->ad_start = start;
	if (start) {
		adp->ad_aux = libld_calloc(sizeof (Ar_aux), number);
		if (adp->ad_aux == NULL)
			return ((Ar_desc *)S_ERROR);
	} else {
		adp->ad_aux = NULL;
	}

	/*
	 * Retain any command line options that are applicable to archive
	 * extraction in case we have to rescan this archive later.
	 */
	adp->ad_flags = ofl->ofl_flags1 & MSK_OF1_ARCHIVE;

	ofl->ofl_arscnt++;

	/*
	 * Add this new descriptor to the list of archives.
	 */
	if (aplist_append(&ofl->ofl_ars, adp, AL_CNT_OFL_LIBS) == NULL)
		return ((Ar_desc *)S_ERROR);
	else
		return (adp);
}
Beispiel #6
0
/*
 * Allocate a zeroed segment descriptor.
 *
 * exit:
 *	Returns pointer to the descriptor on success, NULL on failure.
 *	The contents of the returned descriptor have been zeroed.
 *	The returned descriptor is not added to the segment list
 *	(ofl_segs). That is done using ld_map_seg_insert().
 */
Sg_desc *
ld_map_seg_alloc(const char *name, Elf64_Word p_type, sg_flags_t sg_flags)
{
	Sg_desc	*sgp;

	if ((sgp = libld_calloc(sizeof (Sg_desc), 1)) == NULL)
		return (NULL);
	sgp->sg_phdr.p_type = p_type;
	sgp->sg_name = name;
	sgp->sg_flags = sg_flags;

	return (sgp);
}
Beispiel #7
0
/*
 * Add a new version descriptor to a version descriptor list.  Note, users of
 * this are responsible for determining if the version descriptor already
 * exists (this can reduce the need to allocate storage for descriptor names
 * until it is determined a descriptor need be created (see map_symbol())).
 */
Ver_desc *
ld_vers_desc(const char *name, Elf64_Word hash, APlist **alpp)
{
	Ver_desc	*vdp;

	if ((vdp = libld_calloc(sizeof (Ver_desc), 1)) == NULL)
		return ((Ver_desc *)S_ERROR);

	vdp->vd_name = name;
	vdp->vd_hash = hash;

	if (aplist_append(alpp, vdp, AL_CNT_VERDESCS) == NULL)
		return ((Ver_desc *)S_ERROR);

	return (vdp);
}
Beispiel #8
0
/*
 * Add an entrance criteria record for the specified segment
 *
 * entry:
 *	mf - Mapfile descriptor
 *	sgp - Segment for which a new entrance criteria record is needed
 *	name - NULL, or name by which the entrance criteria can be referenced.
 *
 * exit:
 *	On success, a pointer to the new entrace criteria record is
 *	returned, the contents of which have been zeroed. On failure,
 *	NULL is returned.
 */
Ent_desc *
ld_map_seg_ent_add(Mapfile *mf, Sg_desc *sgp, const char *name)
{
	Ent_desc	*enp;
	avl_index_t	where;
	Ofl_desc	*ofl = mf->mf_ofl;

	if ((name != NULL) &&
	    (ld_ent_lookup(mf->mf_ofl, name, &where) != NULL)) {
		mf_fatal(mf, (MSG_MAP_DUPNAMENT), name);
		return (NULL);
	}

	/* Allocate and initialize the entrace criteria descriptor */
	if ((enp = libld_calloc(1, sizeof (*enp))) == NULL)
		return (NULL);
	enp->ec_name = name;
	enp->ec_segment = sgp;	 /* Tie criteria to segment */


	/*
	 * Insert into the APlist. The mf_ec_insndx field for each mapfile
	 * starts at 0, and is incremented with each insertion. This means
	 * that the entrance criteria for each mapfile go to the head of
	 * the list, but that within a single mapfile, they are inserted in
	 * the order they are seen.
	 */
	if (aplist_insert(&ofl->ofl_ents, enp, AL_CNT_OFL_ENTRANCE,
	    mf->mf_ec_insndx) == NULL)
		return (NULL);
	mf->mf_ec_insndx++;

	/*
	 * If the entrance criteria is named insert it into the AVL tree
	 * as well. This provides O(logN) lookups by name.
	 */
	if (name != NULL)
		avl_insert(&ofl->ofl_ents_avl, enp, where);

	return (enp);
}
Beispiel #9
0
/*
 * 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);
}
Beispiel #10
0
/*
 * Read the archive symbol table.  For each symbol in the table, determine
 * whether that symbol satisfies an unresolved reference, tentative reference,
 * or a reference that expects hidden or protected visibility.  If so, the
 * corresponding object from the archive is processed.  The archive symbol
 * table is searched until we go through a complete pass without satisfying any
 * unresolved symbols
 *
 * entry:
 *	name - Name of archive
 *	fd - Open file descriptor for archive
 *	adp - Archive descriptor
 *	ofl - output descriptor
 *	found - Address of variable to set to TRUE if any objects are extracted
 *	rej - Rejection descriptor to pass to ld_process_ifl().
 *
 * exit:
 *	Returns FALSE on fatal error. On success, *found will be TRUE
 *	if any object was extracted, rej will be set if any object
 *	was rejected, and TRUE is returned.
 */
static Boolean
ar_extract_bysym(const char *name, int fd, Ar_desc *adp,
    Ofl_desc *ofl, Boolean *found, Rej_desc *rej)
{
	Elf_Arsym *	arsym;
	Elf *		arelf;
	Ar_aux *	aup;
	Sym_desc *	sdp;
	const char	*arname, *arpath;
	Boolean		again = FALSE;
	uintptr_t	err;

	/*
	 * An archive without a symbol table should not reach this function,
	 * because it can only get past ld_ar_setup() in the case where
	 * the archive is first seen under the influence of '-z allextract'.
	 * That will cause the entire archive to be extracted, and any
	 * subsequent reference to the archive will be ignored by
	 * ld_process_archive().
	 */
	if (adp->ad_start == NULL) {
		assert(adp->ad_start != NULL);
		return (TRUE);
	}

	/*
	 * Loop through archive symbol table until we make a complete pass
	 * without satisfying an unresolved reference.  For each archive
	 * symbol, see if there is a symbol with the same name in ld's
	 * symbol table.  If so, and if that symbol is still unresolved or
	 * tentative, process the corresponding archive member.
	 */
	do {
		DBG_CALL(Dbg_file_ar(ofl->ofl_lml, name, again));
		DBG_CALL(Dbg_syms_ar_title(ofl->ofl_lml, name, again));
		again = FALSE;

		for (arsym = adp->ad_start, aup = adp->ad_aux; arsym->as_name;
		    ++arsym, ++aup) {
			Ar_mem		*amp;
			Sym		*sym;
			Boolean		visible = TRUE;
			Boolean		vers;
			Ifl_desc	*ifl;

			/*
			 * If the auxiliary members value indicates that this
			 * member has been processed then this symbol will have
			 * been added to the output file image already or the
			 * object was rejected in which case we don't want to
			 * process it again.
			 */
			if (aup->au_mem == FLG_ARMEM_PROC)
				continue;

			/*
			 * If the auxiliary symbol element is non-zero lookup
			 * the symbol from the internal symbol table.
			 */
			if ((sdp = aup->au_syms) == NULL) {
				if ((sdp = ld_sym_find(arsym->as_name,
				    /* LINTED */
				    (Word)arsym->as_hash, NULL, ofl)) == NULL) {
					DBG_CALL(Dbg_syms_ar_skip(ofl->ofl_lml,
					    name, arsym));
					continue;
				}
				aup->au_syms = sdp;
			}

			/*
			 * With '-z allextract', all members will be extracted.
			 *
			 * This archive member is a candidate for extraction if
			 * the internal symbol originates from an explicit file,
			 * and represents an undefined or tentative symbol.
			 *
			 * By default, weak references do not cause archive
			 * extraction, however the -zweakextract flag overrides
			 * this default.
			 *
			 * If this symbol has already been bound to a versioned
			 * shared object, but the shared objects version is not
			 * available, then a definition of this symbol from
			 * within the archive is a better candidate.  Similarly,
			 * if this symbol has been bound to a shared object, but
			 * the original reference expected hidden or protected
			 * visibility, then a definition of this symbol from
			 * within the archive is a better candidate.
			 */
			vers = TRUE;
			ifl = sdp->sd_file;

			sym = sdp->sd_sym;

			if (sdp->sd_ref == REF_DYN_NEED) {
				uchar_t	vis;

				if (ifl->ifl_vercnt) {
					Word		vndx;
					Ver_index	*vip;

					vndx = sdp->sd_aux->sa_dverndx;
					vip = &ifl->ifl_verndx[vndx];
					if (!(vip->vi_flags & FLG_VER_AVAIL))
						vers = FALSE;
				}

				vis = ELF_ST_VISIBILITY(sym->st_other);
				visible = sym_vis[vis];
			}

			if (((ifl->ifl_flags & FLG_IF_NEEDED) == 0) ||
			    (visible && vers && (sym->st_shndx != SHN_UNDEF) &&
			    (sym->st_shndx != SHN_COMMON)) ||
			    ((ELF_ST_BIND(sym->st_info) == STB_WEAK) &&
			    (!(ofl->ofl_flags1 & FLG_OF1_WEAKEXT)))) {
				DBG_CALL(Dbg_syms_ar_skip(ofl->ofl_lml,
				    name, arsym));
				continue;
			}

			/*
			 * Determine if we have already extracted this member,
			 * and if so reuse the Ar_mem information.
			 */
			if ((amp = aup->au_mem) != 0) {
				arelf = amp->am_elf;
				arname = amp->am_name;
				arpath = amp->am_path;
			} else {
				/*
				 * Set up a new elf descriptor for this member.
				 */
				if (elf_rand(adp->ad_elf, arsym->as_off) !=
				    arsym->as_off) {
					ld_eprintf(ofl, ERR_ELF,
					    MSG_INTL(MSG_ELF_ARMEM), name,
					    EC_WORD(arsym->as_off),
					    demangle(arsym->as_name));
					return (FALSE);
				}

				if ((arelf = elf_begin(fd, ELF_C_READ,
				    adp->ad_elf)) == NULL) {
					ld_eprintf(ofl, ERR_ELF,
					    MSG_INTL(MSG_ELF_BEGIN), name);
					return (FALSE);
				}

				/* Get member filename */
				if ((arname = ar_member_name(name, arelf,
				    ofl)) == NULL)
					return (FALSE);

				/* Construct the member's full pathname */
				if ((arpath = ar_member_path(name, arname)) ==
				    NULL)
					return (S_ERROR);

				/*
				 * Determine whether the support libraries wish
				 * to process this open. See comments in
				 * ld_process_open().
				 */
				ld_sup_open(ofl, &arpath, &arname, &fd,
				    (FLG_IF_EXTRACT | FLG_IF_NEEDED),
				    &arelf, adp->ad_elf, arsym->as_off,
				    elf_kind(arelf));
				if (arelf == NULL) {
					/* Ignore this archive member */
					aup->au_mem = FLG_ARMEM_PROC;
					continue;
				}
			}

			/*
			 * The symbol for which this archive member is being
			 * processed may provide a better alternative to the
			 * symbol that is presently known.  Two cases are
			 * covered:
			 *
			 *  i.	The present symbol represents tentative data.
			 *	The archive member may provide a data
			 *	definition symbol.
			 *  ii.	The present symbol represents a reference that
			 *	has seen a definition within a shared object
			 *	dependency, but the reference expects to be
			 *	reduced to hidden or protected visibility.
			 */
			if ((sym->st_shndx == SHN_COMMON) ||
			    (visible == FALSE)) {
				/*
				 * If we don't already have a member structure
				 * allocate one.
				 */
				if (!amp) {
					if ((amp = libld_calloc(sizeof (Ar_mem),
					    1)) == NULL)
						return (FALSE);
					amp->am_elf = arelf;
					amp->am_name = arname;
					amp->am_path = arpath;
				}
				DBG_CALL(Dbg_syms_ar_checking(ofl->ofl_lml,
				    name, arname, arsym));
				if ((err = process_member(amp, arsym->as_name,
				    sdp, ofl)) == S_ERROR)
					return (FALSE);

				/*
				 * If it turns out that we don't need this
				 * member simply initialize all other auxiliary
				 * entries that match this offset with this
				 * members address.  In this way we can resuse
				 * this information if we recurse back to this
				 * symbol.
				 */
				if (err == 0) {
					if (aup->au_mem == NULL)
						ld_ar_member(adp, arsym,
						    aup, amp);
					continue;
				}
			}

			/*
			 * Process the archive member.  Retain any error for
			 * return to the caller.
			 */
			DBG_CALL(Dbg_syms_ar_resolve(ofl->ofl_lml,
			    name, arname, arsym));
			switch (ar_input(fd, adp, ofl, arelf, arpath,
			    rej)) {
			case S_ERROR:
				return (FALSE);
			case 0:
				/*
				 * Mark the member as extracted so that we
				 * don't try and process it again on a rescan.
				 */
				ld_ar_member(adp, arsym, aup, FLG_ARMEM_PROC);
				continue;
			}

			/*
			 * Note that this archive has contributed something
			 * during this specific operation, and also signal
			 * the need to rescan the archive.
			 */
			*found = again = TRUE;

			ld_ar_member(adp, arsym, aup, FLG_ARMEM_PROC);
		}
	} while (again);

	return (TRUE);
}
Beispiel #11
0
/*
 * Validate a SHT_SUNW_move section.  These are only processed from input
 * relocatable objects.  The move section entries are validated and any data
 * structures required for later processing are created.
 */
uintptr_t
ld_process_move(Ofl_desc *ofl)
{
	size_t		idx;
	Is_desc		*isp;
	int 		errcnt = 0;

	for (APLIST_TRAVERSE(ofl->ofl_ismove, idx, isp)) {
		Ifl_desc	*ifile = isp->is_file;
		Elf64_Move		*mvp;
		Elf64_Xword		i, num;

		mvp = (Elf64_Move *)isp->is_indata->d_buf;

		if (isp->is_shdr->sh_entsize == 0) {
			ld_eprintf(ofl, ERR_FATAL,
			    MSG_FIL_INVSHENTSIZE,
			    isp->is_file->ifl_name, EC_WORD(isp->is_scnndx),
			    isp->is_name, EC_XWORD(0));
			return (S_ERROR);
		}
		num = isp->is_shdr->sh_size / isp->is_shdr->sh_entsize;

		for (i = 0; i < num; i++) {
			Elf64_Xword 		ndx = ELF_M_SYM(mvp->m_info);
			Sym_desc	*sdp;
			Elf64_Sym	*sym;

			if ((ndx >= (Elf64_Xword) isp->is_file->ifl_symscnt) ||
			    (ndx == 0)) {
				ld_eprintf(ofl, ERR_FATAL,
				    MSG_PSYM_INVMINFO1,
				    isp->is_file->ifl_name,
				    EC_WORD(isp->is_scnndx), isp->is_name, i,
				    EC_XWORD(mvp->m_info));
				return (S_ERROR);
			}
			if (mvp->m_repeat == 0) {
				ld_eprintf(ofl, ERR_FATAL,
				    MSG_PSYM_INVMREPEAT,
				    isp->is_file->ifl_name,
				    EC_WORD(isp->is_scnndx), isp->is_name, i,
				    EC_XWORD(mvp->m_repeat));
				return (S_ERROR);
			}

			sdp = isp->is_file->ifl_oldndx[ndx];

			/*
			 * Validate that this entry has a valid size.
			 */
			/* LINTED */
			switch (ELF_M_SIZE(mvp->m_info)) {
			case 1: case 2: case 4: case 8:
				break;
			default:
				ld_eprintf(ofl, ERR_FATAL,
				    MSG_PSYM_INVMINFO2,
				    isp->is_file->ifl_name,
				    EC_WORD(isp->is_scnndx), isp->is_name, i,
				    EC_XWORD(mvp->m_info));
				return (S_ERROR);
			}

			/*
			 * If this is a global symbol, adjust the visibility.
			 */
			if (sdp->sd_aux &&
			    ((sdp->sd_flags & FLG_SY_VISIBLE) == 0))
				ld_sym_adjust_vis(sdp, ofl);

			sym = sdp->sd_sym;

			if (sdp->sd_move == NULL) {
				/*
				 * If this is the first move entry associated
				 * with this symbol, save the symbol on the
				 * partial symbol list, and initialize various
				 * state regarding this symbol.
				 */
				if (aplist_append(&ofl->ofl_parsyms, sdp,
				    AL_CNT_OFL_PARSYMS) == NULL)
					return (S_ERROR);

				/*
				 * Even if -zredlocsym is in effect, the local
				 * symbol used for partial initialization is
				 * kept.
				 */
				if ((ofl->ofl_flags & FLG_OF_REDLSYM) &&
				    (ELF_ST_BIND(sym->st_info) == STB_LOCAL) &&
				    (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)) {
					ofl->ofl_locscnt++;
					if (st_insert(ofl->ofl_strtab,
					    sdp->sd_name) == -1)
						return (S_ERROR);
				}

				/*
				 * Mark the input section associated with this
				 * partially initialized symbol.
				 * This is needed when the symbol
				 * the relocation entry uses symbol information
				 * not from the symbol entry.
				 *
				 * For executable, the following is
				 * needed only for expanded symbol. However,
				 * for shared object any partially non
				 * expanded symbols are moved from
				 * .bss/COMMON to .sunwbss. So the following are
				 * needed.
				 */
				if ((sym->st_shndx != SHN_UNDEF) &&
				    (sym->st_shndx < SHN_LOPROC)) {
					Is_desc	*isc;

					isc = ifile->ifl_isdesc[ sym->st_shndx];
					isc->is_flags |= FLG_IS_RELUPD;

					if (sdp->sd_osym == NULL) {
						if ((sdp->sd_osym =
						    libld_calloc(sizeof(Elf64_Sym),
						    1)) == NULL)
							return (S_ERROR);
						*(sdp->sd_osym) =
						    *(sdp->sd_sym);
					}
				}
			}

			if (append_move_desc(ofl, sdp, mvp, isp) == S_ERROR)
				return (S_ERROR);

			if (sdp->sd_flags & FLG_SY_OVERLAP)
				errcnt++;

			/*
			 * If this symbol is marked to be expanded, go to the
			 * next move entry.
			 */
			if (sdp->sd_flags & FLG_SY_PAREXPN) {
				mvp++;
				continue;
			}

			/*
			 * Decide whether this partial symbol is to be expanded
			 * or not.
			 *
			 * The symbol will be expanded if:
			 *	a) '-z nopartial' is specified
			 *	b) move entries covered entire symbol
			 *
			 * To expand an move entry, size of the symbol to be
			 * expanded need to be known to generate a file space.
			 * (see make_movesections().)
			 *
			 * Therefore the move entry can not be expanded
			 * if the partial symbol is a section symbol.
			 * (The size of the symbol may be unknown.)
			 * This may happen, for example, when a local symbol is
			 * reduced by the -zredlocsym.
			 *
			 * The following two if statements checks the
			 * if the move entry can be expanded or not.
			 */
			if (OFL_IS_STATIC_EXEC(ofl)) {
				if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) {
					errcnt++;
					ld_eprintf(ofl, ERR_FATAL,
					    MSG_PSYM_CANNOTEXPND,
					    sdp->sd_file->ifl_name,
					    EC_WORD(isp->is_scnndx),
					    isp->is_name, i,
					    MSG_PSYM_NOSTATIC);
				} else {
					sdp->sd_flags |= FLG_SY_PAREXPN;
				}
			} else if ((ofl->ofl_flags1 & FLG_OF1_NOPARTI) != 0) {
				if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) {
					ld_eprintf(ofl, ERR_WARNING,
					    MSG_PSYM_CANNOTEXPND,
					    sdp->sd_file->ifl_name,
					    EC_WORD(isp->is_scnndx),
					    isp->is_name, i,
					    MSG_STR_EMPTY);
				} else {
					sdp->sd_flags |= FLG_SY_PAREXPN;
				}
			} else if (((Elf64_Xword)((sizeof (Elf64_Move)) *
			    alist_nitems(sdp->sd_move)) > sym->st_size) &&
			    (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)) {
				sdp->sd_flags |= FLG_SY_PAREXPN;
			}

			/*
			 * If a move entry exists that references a local
			 * symbol, and this symbol reference will eventually
			 * be assigned to the associated section, make sure the
			 * section symbol is available for relocating against
			 * at runtime.
			 */
			if ((ELF_ST_BIND(sym->st_info) == STB_LOCAL) &&
			    (((ofl->ofl_flags & FLG_OF_RELOBJ) == 0) ||
			    (ofl->ofl_flags & FLG_OF_REDLSYM))) {
				Os_desc *osp = sdp->sd_isc->is_osdesc;

				if (osp &&
				    ((osp->os_flags & FLG_OS_OUTREL) == 0)) {
					ofl->ofl_dynshdrcnt++;
					osp->os_flags |= FLG_OS_OUTREL;
				} else if ((sdp->sd_flags &
				    FLG_SY_PAREXPN) == 0)
					ofl->ofl_flags1 |= FLG_OF1_BSSOREL;
			}
			mvp++;
		}
	}

	if (errcnt != 0)
		return (S_ERROR);
	if (make_mvsections(ofl) == S_ERROR)
		return (S_ERROR);

	return (1);
}
Beispiel #12
0
/*
 * Add a size symbol to a segment
 *
 * entry:
 *	mf - Mapfile descriptor
 *	sgp - Segment descriptor
 *	eq_tol - Type of assignment: TK_EQUAL, or TK_PLUSEQ
 *	symname - Name of symbol. Must be in stable static storage
 *		that can be retained.
 *
 * exit:
 *	On success, the symbol has been added and true is returned.
 *	Otherwise an error is reported and false is returned.
 */
bool
ld_map_seg_size_symbol(Mapfile *mf, Sg_desc *sgp, Token eq_tok,
    const char *symname)
{
	Elf64_Sym	*sym;		/* New symbol pointer */
	Sym_desc	*sdp;		/* New symbol node pointer */
	Ifl_desc	*ifl;		/* Dummy input file structure */
	avl_index_t	where;
	Ofl_desc	*ofl = mf->mf_ofl;

	/*
	 * We don't allow resetting the list of size symbols, so if the
	 * operator is TK_EQUAL and the list is not empty, issue an error.
	 *
	 * If we want to lift this restriction, we would have to save the
	 * size symbols and enter them from ld_map_post_process(). Doing that
	 * well would require a significant overhead in saved error reporting
	 * state, and interactions with the same symbols created by symbol
	 * directives. As size symbols are of little practical use, and are
	 * maintained primarily for backward compatibility with SysV, we have
	 * decided not to do that, but to create the symbols as the mapfiles
	 * are processed, and to disallow later attempts to remove them.
	 */
	if ((eq_tok == TK_EQUAL) && (aplist_nitems(sgp->sg_sizesym) > 0)) {
		mf_fatal(mf, (MSG_MAP_SEGSIZE), sgp->sg_name);
		return (false);
	}

	/*
	 * Make sure we have a pseudo file descriptor to associate to the
	 * symbol.
	 */
	if ((ifl = ld_map_ifl(mf)) == NULL)
		return (false);

	/*
	 * Make sure the symbol doesn't already exist.  It is possible that the
	 * symbol has been scoped or versioned, in which case it does exist
	 * but we can freely update it here.
	 */
	if ((sdp = ld_sym_find(symname, SYM_NOHASH, &where, ofl)) == NULL) {
		Elf64_Word hval;

		if ((sym = libld_calloc(sizeof (Elf64_Sym), 1)) == NULL)
			return (false);
		sym->st_shndx = SHN_ABS;
		sym->st_size = 0;
		sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);

		//DBG_CALL(Dbg_map_size_new(ofl->ofl_lml, symname,
		//    sgp->sg_name, mf->mf_lineno));
		/* LINTED */
		hval = (Elf64_Word)elf_hash(symname);
		if ((sdp = ld_sym_enter(symname, sym, hval, ifl, ofl, 0,
		    SHN_ABS, (FLG_SY_SPECSEC | FLG_SY_GLOBREF), &where)) ==
		    (Sym_desc *)S_ERROR)
			return (false);
		sdp->sd_flags &= ~FLG_SY_CLEAN;
		//DBG_CALL(Dbg_map_symbol(ofl, sdp));
	} else {
		sym = sdp->sd_sym;

		if (sym->st_shndx == SHN_UNDEF) {
			sdp->sd_shndx = sym->st_shndx = SHN_ABS;
			sdp->sd_flags |= FLG_SY_SPECSEC;
			sym->st_size = 0;
			sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);

			sdp->sd_flags &= ~FLG_SY_MAPREF;

			//DBG_CALL(Dbg_map_size_old(ofl, sdp,
			//    sgp->sg_name, mf->mf_lineno));
		} else {
			mf_fatal(mf, (MSG_MAP_SYMDEF1),
			    demangle(sdp->sd_name), sdp->sd_file->ifl_name,
			    (MSG_MAP_DIFF_SYMMUL));
			return (false);
		}
	}

	/*
	 * Assign the symbol to the segment.
	 */
	if (aplist_append(&sgp->sg_sizesym, sdp, AL_CNT_SG_SIZESYM) == NULL)
		return (false);

	return (true);
}
Beispiel #13
0
/*
 * Enter a mapfile defined symbol into the given version
 *
 * entry:
 *	mf - Mapfile descriptor
 *	ms - Information related to symbol being added to version
 *
 * exit:
 *	On success, returns true. On failure that requires an immediate
 *	halt, returns false.
 *
 *	On failure that requires eventual halt, but for which it would
 *	be OK to continue parsing in hopes of flushing out additional
 *	problems, increments mv->mv_errcnt, and returns true.
 */
bool
ld_map_sym_enter(Mapfile *mf, ld_map_ver_t *mv, ld_map_sym_t *ms)
{
	Ofl_desc	*ofl = mf->mf_ofl;
	Elf64_Word	hash;
	avl_index_t	where;
	Elf64_Sym	*sym;
	Sym_desc	*sdp;
	const char	*conflict;

	/*
	 * Add the new symbol.  It should be noted that all
	 * symbols added by the mapfile start out with global
	 * scope, thus they will fall through the normal symbol
	 * resolution process.  Elf64_Symbols defined as locals will
	 * be reduced in scope after all input file processing.
	 */
	/* LINTED */
	hash = (Elf64_Word)elf_hash(ms->ms_name);
	//DBG_CALL(Dbg_map_version(ofl->ofl_lml, mv->mv_name, ms->ms_name,
	//    mv->mv_scope));

	/*
	 * Make sure that any parent or external declarations fall back to
	 * references.
	 */
	if (ms->ms_sdflags & (FLG_SY_PARENT | FLG_SY_EXTERN)) {
		/*
		 * Turn it into a reference by setting the section index
		 * to UNDEF.
		 */
		ms->ms_shndx = SHN_UNDEF;

		/*
		 * It is wrong to specify size or value for an external symbol.
		 */
		if (ms->ms_value_set || (ms->ms_size != 0)) {
			mf_fatal0(mf, (MSG_MAP_NOEXVLSZ));
			mv->mv_errcnt++;
			return (true);
		}
	}

	if ((sdp = ld_sym_find(ms->ms_name, hash, &where, ofl)) == NULL) {
		if ((sym = libld_calloc(sizeof (Elf64_Sym), 1)) == NULL)
			return (false);

		sym->st_shndx = (Elf64_Half)ms->ms_shndx;
		sym->st_value = ms->ms_value;
		sym->st_size = ms->ms_size;
		sym->st_info = ELF_ST_INFO(STB_GLOBAL, ms->ms_type);

		if ((sdp = ld_sym_enter(ms->ms_name, sym, hash,
		    ld_map_ifl(mf), ofl, 0, ms->ms_shndx, ms->ms_sdflags,
		    &where)) == (Sym_desc *)S_ERROR)
			return (false);

		sdp->sd_flags &= ~FLG_SY_CLEAN;

		/*
		 * Identify any references.  FLG_SY_MAPREF is
		 * turned off once a relocatable object with
		 * the same symbol is found, thus the existence
		 * of FLG_SY_MAPREF at symbol validation is
		 * used to flag undefined/misspelled entries.
		 */
		if (sym->st_shndx == SHN_UNDEF)
			sdp->sd_flags |= (FLG_SY_MAPREF | FLG_SY_GLOBREF);

	} else {
		conflict = NULL;
		sym = sdp->sd_sym;

		/*
		 * If this symbol already exists, make sure this
		 * definition doesn't conflict with the former.
		 * Provided it doesn't, multiple definitions
		 * from different mapfiles can augment each
		 * other.
		 */
		if (sym->st_value) {
			if (ms->ms_value && (sym->st_value != ms->ms_value))
				conflict = (MSG_MAP_DIFF_SYMVAL);
		} else {
			sym->st_value = ms->ms_value;
		}
		if (sym->st_size) {
			if (ms->ms_size && (sym->st_size != ms->ms_size))
				conflict = (MSG_MAP_DIFF_SYMSZ);
		} else {
			sym->st_size = ms->ms_size;
		}
		if (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) {
			if ((ms->ms_type != STT_NOTYPE) &&
			    (ELF_ST_TYPE(sym->st_info) != ms->ms_type))
				conflict = (MSG_MAP_DIFF_SYMTYP);
		} else {
			sym->st_info = ELF_ST_INFO(STB_GLOBAL, ms->ms_type);
		}
		if (sym->st_shndx != SHN_UNDEF) {
			if ((ms->ms_shndx != SHN_UNDEF) &&
			    (sym->st_shndx != ms->ms_shndx))
				conflict = (MSG_MAP_DIFF_SYMNDX);
		} else {
			sym->st_shndx = sdp->sd_shndx = ms->ms_shndx;
		}

		if ((sdp->sd_flags & MSK_SY_GLOBAL) &&
		    (sdp->sd_aux->sa_overndx != VER_NDX_GLOBAL) &&
		    (mv->mv_vdp->vd_ndx != VER_NDX_GLOBAL) &&
		    (sdp->sd_aux->sa_overndx != mv->mv_vdp->vd_ndx)) {
			conflict = (MSG_MAP_DIFF_SYMVER);
		}

		if (conflict) {
			mf_fatal(mf, (MSG_MAP_SYMDEF1),
			    demangle(ms->ms_name),
			    sdp->sd_file->ifl_name, conflict);
			mv->mv_errcnt++;
			return (true);
		}

		/*
		 * If this mapfile entry supplies a definition,
		 * indicate that the symbol is now used.
		 */
		if (ms->ms_shndx != SHN_UNDEF)
			sdp->sd_flags |= FLG_SY_MAPUSED;
	}

	/*
	 * A symbol declaration that defines a size but no
	 * value is processed as a request to create an
	 * associated backing section.  The intent behind this
	 * functionality is to provide OBJT definitions within
	 * filters that are not ABS.  ABS symbols don't allow
	 * copy-relocations to be established to filter OBJT
	 * definitions.
	 */
	if ((ms->ms_shndx == SHN_ABS) && ms->ms_size && !ms->ms_value_set) {
		/* Create backing section if not there */
		if (sdp->sd_isc == NULL) {
			Is_desc	*isp;

			if (ms->ms_type == STT_OBJECT) {
				if ((isp = ld_make_data(ofl, ms->ms_size)) ==
				    (Is_desc *)S_ERROR)
					return (false);
			} else {
				if ((isp = ld_make_text(ofl, ms->ms_size)) ==
				    (Is_desc *)S_ERROR)
					return (false);
			}

			sdp->sd_isc = isp;
			isp->is_file = ld_map_ifl(mf);
		}

		/*
		 * Now that backing storage has been created,
		 * associate the symbol descriptor.  Remove the
		 * symbols special section tag so that it will
		 * be assigned the correct section index as part
		 * of update symbol processing.
		 */
		sdp->sd_flags &= ~FLG_SY_SPECSEC;
		ms->ms_sdflags &= ~FLG_SY_SPECSEC;
	}

	/*
	 * Indicate the new symbols scope.  Although the
	 * symbols st_other field will eventually be updated as
	 * part of writing out the final symbol, update the
	 * st_other field here to trigger better diagnostics
	 * during symbol validation (for example, undefined
	 * references that are defined symbolic in a mapfile).
	 */
	if (mv->mv_scope == FLG_SCOPE_HIDD) {
		/*
		 * This symbol needs to be reduced to local.
		 */
		if (ofl->ofl_flags & FLG_OF_REDLSYM) {
			sdp->sd_flags |= (FLG_SY_HIDDEN | FLG_SY_ELIM);
			sdp->sd_sym->st_other = STV_ELIMINATE;
		} else {
			sdp->sd_flags |= FLG_SY_HIDDEN;
			sdp->sd_sym->st_other = STV_HIDDEN;
		}
	} else if (mv->mv_scope == FLG_SCOPE_ELIM) {
		/*
		 * This symbol needs to be eliminated.  Note,
		 * the symbol is also tagged as local to trigger
		 * any necessary relocation processing prior
		 * to the symbol being eliminated.
		 */
		sdp->sd_flags |= (FLG_SY_HIDDEN | FLG_SY_ELIM);
		sdp->sd_sym->st_other = STV_ELIMINATE;

	} else {
		/*
		 * This symbol is explicitly defined to remain
		 * global.
		 */
		sdp->sd_flags |= ms->ms_sdflags;

		/*
		 * Qualify any global scope.
		 */
		if (mv->mv_scope == FLG_SCOPE_SNGL) {
			sdp->sd_flags |= (FLG_SY_SINGLE | FLG_SY_NDIR);
			sdp->sd_sym->st_other = STV_SINGLETON;
		} else if (mv->mv_scope == FLG_SCOPE_PROT) {
			sdp->sd_flags |= FLG_SY_PROTECT;
			sdp->sd_sym->st_other = STV_PROTECTED;
		} else if (mv->mv_scope == FLG_SCOPE_EXPT) {
			sdp->sd_flags |= FLG_SY_EXPORT;
			sdp->sd_sym->st_other = STV_EXPORTED;
		} else
			sdp->sd_flags |= FLG_SY_DEFAULT;

		/*
		 * Record the present version index for later
		 * potential versioning.
		 */
		if ((sdp->sd_aux->sa_overndx == 0) ||
		    (sdp->sd_aux->sa_overndx == VER_NDX_GLOBAL))
			sdp->sd_aux->sa_overndx = mv->mv_vdp->vd_ndx;
		mv->mv_vdp->vd_flags |= FLG_VER_REFER;
	}

	conflict = NULL;

	/*
	 * Carry out some validity checks to ensure incompatible
	 * symbol characteristics have not been defined.
	 * These checks are carried out after symbols are added
	 * or resolved, to catch single instance, and
	 * multi-instance definition inconsistencies.
	 */
	if ((sdp->sd_flags & (FLG_SY_HIDDEN | FLG_SY_ELIM)) &&
	    ((mv->mv_scope != FLG_SCOPE_HIDD) &&
	    (mv->mv_scope != FLG_SCOPE_ELIM))) {
		conflict = (MSG_MAP_DIFF_SYMLCL);

	} else if ((sdp->sd_flags &
	    (FLG_SY_SINGLE | FLG_SY_EXPORT)) &&
	    ((mv->mv_scope != FLG_SCOPE_DFLT) &&
	    (mv->mv_scope != FLG_SCOPE_EXPT) &&
	    (mv->mv_scope != FLG_SCOPE_SNGL))) {
		conflict = (MSG_MAP_DIFF_SYMGLOB);

	} else if ((sdp->sd_flags & FLG_SY_PROTECT) &&
	    ((mv->mv_scope != FLG_SCOPE_DFLT) &&
	    (mv->mv_scope != FLG_SCOPE_PROT))) {
		conflict = (MSG_MAP_DIFF_SYMPROT);

	} else if ((sdp->sd_flags & FLG_SY_NDIR) &&
	    (mv->mv_scope == FLG_SCOPE_PROT)) {
		conflict = (MSG_MAP_DIFF_PROTNDIR);

	} else if ((sdp->sd_flags & FLG_SY_DIR) &&
	    (mv->mv_scope == FLG_SCOPE_SNGL)) {
		conflict = (MSG_MAP_DIFF_SNGLDIR);
	}

	if (conflict) {
		/*
		 * Select the conflict message from either a
		 * single instance or multi-instance definition.
		 */
		if (sdp->sd_file->ifl_name == mf->mf_name) {
			mf_fatal(mf, (MSG_MAP_SYMDEF2),
			    demangle(ms->ms_name), conflict);
		} else {
			mf_fatal(mf, (MSG_MAP_SYMDEF1),
			    demangle(ms->ms_name),
			    sdp->sd_file->ifl_name, conflict);
		}
		mv->mv_errcnt++;
		return (true);
	}

	/*
	 * Indicate that this symbol has been explicitly
	 * contributed from a mapfile.
	 */
	sdp->sd_flags |= (FLG_SY_MAPFILE | FLG_SY_EXPDEF);

	/*
	 * If we've encountered a symbol definition simulate
	 * that an input file has been processed - this allows
	 * things like filters to be created purely from a
	 * mapfile.
	 */
	if (ms->ms_type != STT_NOTYPE)
		ofl->ofl_objscnt++;
	//DBG_CALL(Dbg_map_symbol(ofl, sdp));

	/*
	 * If this symbol has an associated filtee, record the
	 * filtee string and associate the string index with the
	 * symbol.  This is used later to associate the syminfo
	 * information with the necessary .dynamic entry.
	 */
	if (ms->ms_filtee) {
		Dfltr_desc *	dftp;
		Sfltr_desc	sft;
		size_t		idx, _idx, nitems;

		/*
		 * Make sure we don't duplicate any filtee
		 * strings, and create a new descriptor if
		 * necessary.
		 */
		idx = nitems = alist_nitems(ofl->ofl_dtsfltrs);
		for (ALIST_TRAVERSE(ofl->ofl_dtsfltrs, _idx, dftp)) {
			if ((ms->ms_dft_flag != dftp->dft_flag) ||
			    (strcmp(dftp->dft_str, ms->ms_filtee)))
				continue;
			idx = _idx;
			break;
		}
		if (idx == nitems) {
			Dfltr_desc	dft;

			dft.dft_str = ms->ms_filtee;
			dft.dft_flag = ms->ms_dft_flag;
			dft.dft_ndx = 0;

			/*
			 * The following append puts the new
			 * item at the offset contained in
			 * idx, because we know idx contains
			 * the index of the next available slot.
			 */
			if (alist_append(&ofl->ofl_dtsfltrs, &dft,
			    sizeof (Dfltr_desc), AL_CNT_OFL_DTSFLTRS) == NULL)
				return (false);
		}

		/*
		 * Create a new filter descriptor for this
		 * symbol.
		 */
		sft.sft_sdp = sdp;
		sft.sft_idx = idx;

		if (alist_append(&ofl->ofl_symfltrs, &sft, sizeof (Sfltr_desc),
		    AL_CNT_OFL_SYMFLTRS) == NULL)
			return (false);
	}
Beispiel #14
0
/*
 * 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;
			}
		}
	}
Beispiel #15
0
uintptr_t
ld_vers_check_defs(Ofl_desc *ofl)
{
	size_t		idx1;
	Ver_desc	*vdp;
	uintptr_t 	is_cyclic = 0;

	//DBG_CALL(Dbg_ver_def_title(ofl->ofl_lml, ofl->ofl_name));

	/*
	 * First check if there are any cyclic dependency
	 */
	for (APLIST_TRAVERSE(ofl->ofl_verdesc, idx1, vdp))
		if ((is_cyclic = vers_visit_children(ofl, vdp, 0)) == S_ERROR)
			return (S_ERROR);

	if (is_cyclic)
		ofl->ofl_flags |= FLG_OF_FATAL;

	for (APLIST_TRAVERSE(ofl->ofl_verdesc, idx1, vdp)) {
		uint8_t	cnt;
		Elf64_Sym	*sym;
		Sym_desc	*sdp;
		const char	*name = vdp->vd_name;
		unsigned char	bind;
		Ver_desc	*_vdp;
		avl_index_t	where;
		size_t		idx2;

		if (vdp->vd_ndx == 0) {
			ld_eprintf(ofl, ERR_FATAL,
			    (MSG_VER_UNDEF), name, vdp->vd_ref->vd_name,
			    vdp->vd_ref->vd_file->ifl_name);
			continue;
		}

		//DBG_CALL(Dbg_ver_desc_entry(ofl->ofl_lml, vdp));

		/*
		 * If a version definition contains no symbols this is possibly
		 * a mapfile error.
		 */
		#if 0
		if ((vdp->vd_flags &
		    (VER_FLG_BASE | VER_FLG_WEAK | FLG_VER_REFER)) == 0)
			DBG_CALL(Dbg_ver_nointerface(ofl->ofl_lml,	
		    	    vdp->vd_name));
		#endif

		/*
		 * Update the version entry count to account for this new
		 * version descriptor (the count is the size in bytes).
		 */
		ofl->ofl_verdefsz += sizeof (Elf64_Verdef);

		/*
		 * Traverse this versions dependency list to determine what
		 * additional version dependencies we must account for against
		 * this descriptor.
		 */
		cnt = 1;
		for (APLIST_TRAVERSE(vdp->vd_deps, idx2, _vdp)) {
#if	defined(__lint)
			/* get lint to think `_vdp' is used... */
			vdp = _vdp;
#endif
			cnt++;
		}
		ofl->ofl_verdefsz += (cnt * sizeof (Elf64_Verdaux));

		/*
		 * Except for the base version descriptor, generate an absolute
		 * symbol to reflect this version.
		 */
		if (vdp->vd_flags & VER_FLG_BASE)
			continue;

		if (vdp->vd_flags & VER_FLG_WEAK)
			bind = STB_WEAK;
		else
			bind = STB_GLOBAL;

		if (sdp = ld_sym_find(name, vdp->vd_hash, &where, ofl)) {
			/*
			 * If the symbol already exists and is undefined or was
			 * defined in a shared library, convert it to an
			 * absolute.
			 */
			if ((sdp->sd_sym->st_shndx == SHN_UNDEF) ||
			    (sdp->sd_ref != REF_REL_NEED)) {
				sdp->sd_shndx = sdp->sd_sym->st_shndx = SHN_ABS;
				sdp->sd_sym->st_info =
				    ELF_ST_INFO(bind, STT_OBJECT);
				sdp->sd_ref = REF_REL_NEED;
				sdp->sd_flags |= (FLG_SY_SPECSEC |
				    FLG_SY_DEFAULT | FLG_SY_EXPDEF);
				sdp->sd_aux->sa_overndx = vdp->vd_ndx;

				/*
				 * If the reference originated from a mapfile
				 * insure we mark the symbol as used.
				 */
				if (sdp->sd_flags & FLG_SY_MAPREF)
					sdp->sd_flags |= FLG_SY_MAPUSED;

			} else if ((sdp->sd_flags & FLG_SY_SPECSEC) &&
			    (sdp->sd_sym->st_shndx != SHN_ABS) &&
			    (sdp->sd_ref == REF_REL_NEED)) {
				ld_eprintf(ofl, ERR_WARNING,
				    (MSG_VER_DEFINED), name,
				    sdp->sd_file->ifl_name);
			}
		} else {
			/*
			 * If the symbol does not exist create it.
			 */
			if ((sym = libld_calloc(sizeof (Elf64_Sym), 1)) == NULL)
				return (S_ERROR);

			sym->st_shndx = SHN_ABS;
			sym->st_info = ELF_ST_INFO(bind, STT_OBJECT);
			
			//DBG_CALL(Dbg_ver_symbol(ofl->ofl_lml, name));

			if ((sdp = ld_sym_enter(name, sym, vdp->vd_hash,
			    vdp->vd_file, ofl, 0, SHN_ABS,
			    (FLG_SY_SPECSEC | FLG_SY_DEFAULT | FLG_SY_EXPDEF),
			    &where)) == (Sym_desc *)S_ERROR)
				return (S_ERROR);

			sdp->sd_ref = REF_REL_NEED;
			sdp->sd_aux->sa_overndx = vdp->vd_ndx;
		}
	}
	return (1);
}