示例#1
0
/*
 * Return an initialized Str_tbl - returns NULL on failure.
 *
 * flags:
 *	FLG_STTAB_COMPRESS - build a compressed string table
 */
Str_tbl *
st_new(uint_t flags)
{
	Str_tbl	*stp;

	if ((stp = calloc(sizeof (Str_tbl), 1)) == NULL)
		return (NULL);

	/*
	 * Start with a leading '\0' - it's tradition.
	 */
	stp->st_strsize = stp->st_fullstrsize = stp->st_nextoff = 1;

	/*
	 * Do we compress this string table?
	 */
	stp->st_flags = flags;
	if ((stp->st_flags & FLG_STTAB_COMPRESS) == 0)
		return (stp);

	if ((stp->st_lentree = calloc(sizeof (avl_tree_t), 1)) == NULL)
		return (NULL);

	avl_create(stp->st_lentree, &avl_len_compare, sizeof (LenNode),
	    SGSOFFSETOF(LenNode, ln_avlnode));

	return (stp);
}
示例#2
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);
}
示例#3
0
/*
 * Insert a new string into the Str_tbl.  There are two AVL trees used.
 *
 *  .	The first LenNode AVL tree maintains a tree of nodes based on string
 *	sizes.
 *  .	Each LenNode maintains a StrNode AVL tree for each string.  Large
 *	applications have been known to contribute thousands of strings of
 *	the same size.  Should strings need to be removed (-z ignore), then
 *	the string AVL tree makes this removal efficient and scalable.
 */
int
st_insert(Str_tbl *stp, const char *str)
{
	size_t		len;
	StrNode		*snp, sn = { 0 };
	LenNode		*lnp, ln = { 0 };
	avl_index_t	where;

	/*
	 * String table can't have been cooked
	 */
	assert((stp->st_flags & FLG_STTAB_COOKED) == 0);

	/*
	 * Null strings always point to the head of the string
	 * table - no reason to keep searching.
	 */
	if ((len = strlen(str)) == 0)
		return (0);

	stp->st_fullstrsize += len + 1;
	stp->st_strcnt++;

	if ((stp->st_flags & FLG_STTAB_COMPRESS) == 0)
		return (0);

	/*
	 * From the controlling string table, determine which LenNode AVL node
	 * provides for this string length.  If the node doesn't exist, insert
	 * a new node to represent this string length.
	 */
	ln.ln_strlen = len;
	if ((lnp = avl_find(stp->st_lentree, &ln, &where)) == NULL) {
		if ((lnp = calloc(sizeof (LenNode), 1)) == NULL)
			return (-1);
		lnp->ln_strlen = len;
		avl_insert(stp->st_lentree, lnp, where);

		if ((lnp->ln_strtree = calloc(sizeof (avl_tree_t), 1)) == NULL)
			return (0);

		avl_create(lnp->ln_strtree, &avl_str_compare, sizeof (StrNode),
		    SGSOFFSETOF(StrNode, sn_avlnode));
	}

	/*
	 * From the string length AVL node determine whether a StrNode AVL node
	 * provides this string.  If the node doesn't exist, insert a new node
	 * to represent this string.
	 */
	sn.sn_str = str;
	if ((snp = avl_find(lnp->ln_strtree, &sn, &where)) == NULL) {
		if ((snp = calloc(sizeof (StrNode), 1)) == NULL)
			return (-1);
		snp->sn_str = str;
		avl_insert(lnp->ln_strtree, snp, where);
	}
	snp->sn_refcnt++;

	return (0);
}
示例#4
0
文件: entry.c 项目: pathscale/linker
/*
 * Initialize new entrance and segment descriptors and add them as lists to
 * the output file descriptor.
 */
uintptr_t
ld_ent_setup(Ofl_desc *ofl, Elf64_Xword segalign)
{
	Ent_desc	*enp;
	predef_seg_t	*psegs;
	Sg_desc		*sgp;
	size_t		idx;

	/*
	 * Initialize the elf library.
	 */
	if (elf_version(EV_CURRENT) == EV_NONE) {
		ld_eprintf(ofl, ERR_FATAL, MSG_ELF_LIBELF, EV_CURRENT);
		return (S_ERROR);
	}

	/*
	 * Initialize internal Global Symbol Table AVL tree
	 */
	avl_create(&ofl->ofl_symavl, &ld_sym_avl_comp, sizeof (Sym_avlnode),
	    SGSOFFSETOF(Sym_avlnode, sav_node));

	/* Initialize segment AVL tree */
	avl_create(&ofl->ofl_segs_avl, ofl_segs_avl_cmp,
	    sizeof (Sg_desc), SGSOFFSETOF(Sg_desc, sg_avlnode));

	/* Initialize entrance criteria AVL tree */
	avl_create(&ofl->ofl_ents_avl, ofl_ents_avl_cmp, sizeof (Ent_desc),
	    SGSOFFSETOF(Ent_desc, ec_avlnode));


	/*
	 * Allocate and initialize writable copies of both the entrance and
	 * segment descriptors.
	 *
	 * Note that on non-amd64 targets, this allocates a few more
	 * elements than are needed. For now, we are willing to overallocate
	 * a small amount to simplify the code.
	 */
	if ((psegs = libld_malloc(sizeof (sg_desc))) == NULL)
		return (S_ERROR);
	(void) memcpy(psegs, &sg_desc, sizeof (sg_desc));
	sgp = (Sg_desc *) psegs;

	/*
	 * The data segment and stack permissions can differ:
	 *
	 *	- Architectural/ABI per-platform differences
	 *	- Whether the object is built statically or dynamically
	 *
	 * Those segments so affected have their program header flags
	 * set here at runtime, rather than in the sg_desc templates above.
	 */
	psegs->psg_data.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
	psegs->psg_bss.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
	psegs->psg_dynamic.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
	psegs->psg_sunwdtrace.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
#if	defined(_ELF64)
	psegs->psg_ldata.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
	psegs->psg_sunwdtrace.sg_phdr.p_flags |= PF_X;
#endif
	psegs->psg_sunwstack.sg_phdr.p_flags = ld_targ.t_m.m_stack_perm;
	if ((ofl->ofl_flags & FLG_OF_DYNAMIC) == 0)
		psegs->psg_data.sg_phdr.p_flags |= PF_X;

	/*
	 * Traverse the new entrance descriptor list converting the segment
	 * pointer entries to the absolute address within the new segment
	 * descriptor list.  Add each entrance descriptor to the output file
	 * list.
	 */
	if ((enp = libld_malloc(sizeof (ent_desc))) == NULL)
		return (S_ERROR);
	(void) memcpy(enp, ent_desc, sizeof (ent_desc));
	for (idx = 0; idx < (sizeof (ent_desc) / sizeof (ent_desc[0])); idx++,
	    enp++) {

#if	defined(_ELF64)
		/* Don't use the amd64 entry conditions for non-amd64 targets */
		if ((enp->ec_attrmask & SHF_X86_64_LARGE) &&
		    (ld_targ.t_m.m_mach != EM_X86_64))
			continue;
#endif
		if (aplist_append(&ofl->ofl_ents, enp,
		    AL_CNT_OFL_ENTRANCE) == NULL)
			return (S_ERROR);

		/*
		 * The segment pointer is currently pointing at a template
		 * segment descriptor in sg_desc. Compute its array index,
		 * and then use that index to compute the address of the
		 * corresponding descriptor in the writable copy.
		 */
		enp->ec_segment =
		    &sgp[(enp->ec_segment - (Sg_desc *) &sg_desc)];
	}

	/*
	 * Add each segment descriptor to the segment descriptor list. The
	 * ones with non-NULL sg_name are also entered into the AVL tree.
	 * For each loadable segment initialize a default alignment. Note
	 * that ld(1) and ld.so.1 initialize this differently.
	 */
	for (idx = 0; idx < predef_seg_nelts; idx++, sgp++) {
		Elf64_Phdr	*phdr = &(sgp->sg_phdr);

		/* Ignore amd64 segment templates for non-amd64 targets */
		switch (sgp->sg_id) {
		case SGID_LRODATA:
		case SGID_LDATA:
			if ((ld_targ.t_m.m_mach != EM_X86_64))
				continue;
		}

		if (phdr->p_type == PT_LOAD)
			phdr->p_align = segalign;

		if ((aplist_append(&ofl->ofl_segs, sgp,
		    AL_CNT_SEGMENTS)) == NULL)
			return (S_ERROR);

#ifdef NDEBUG			/* assert() is enabled */
		/*
		 * Enforce the segment name rule: Any segment that can
		 * be referenced by an entrance descriptor must have
		 * a name. Any segment that cannot, must have a NULL
		 * name pointer.
		 */
		switch (phdr->p_type) {
		case PT_LOAD:
		case PT_NOTE:
		case PT_NULL:
			assert(sgp->sg_name != NULL);
			break;
		default:
			assert(sgp->sg_name == NULL);
			break;
		}
#endif

		/*
		 * Add named segment descriptors to the AVL tree to
		 * provide O(logN) lookups.
		 */
		if (sgp->sg_name != NULL)
			avl_add(&ofl->ofl_segs_avl, sgp);
	}

	return (1);
}
示例#5
0
/*
 * Change the current scope for the given version.
 *
 * entry:
 *	mf - Mapfile descriptor
 *	scope_name - Name for new scope
 *	mv - Information related to version being defined
 *
 * exit:
 *	On success, mv is updated to change the current scope.
 *	On failure, mv->errcnt is incremented, and mv is otherwise unaltered.
 */
void
ld_map_sym_scope(Mapfile *mf, const char *scope_name, ld_map_ver_t *mv)
{
	typedef struct {
		const char	*name;		/* scope keyword string */
		ld_map_scope_t	type;		/* Resulting type */
		ofl_flag_t	ofl_flags;	/* 0, or ofl flags to add */
	} scope_t;

	/*
	 * Valid symbol scope keywords
	 *
	 * All symbols added by a mapfile are actually global entries, and
	 * are assigned the scope that is presently in effect.
	 *
	 * If a protected/symbolic scope is detected, remember this. If
	 * a protected/symbolic scope is the only scope defined in this
	 * (or any other mapfiles), then the mode -Bsymbolic is established.
	 */
	static scope_t scope_list[] = {
		{ (MSG_MAPKW_DEFAULT), FLG_SCOPE_DFLT, FLG_OF_MAPGLOB },
		{ (MSG_MAPKW_ELIMINATE), FLG_SCOPE_ELIM, 0 },
		{ (MSG_MAPKW_EXPORTED), FLG_SCOPE_EXPT, 0 },
		{ (MSG_MAPKW_HIDDEN), FLG_SCOPE_HIDD, 0 },
		{ (MSG_MAPKW_GLOBAL), FLG_SCOPE_DFLT, FLG_OF_MAPGLOB },
		{ (MSG_MAPKW_LOCAL), FLG_SCOPE_HIDD, 0 },
		{ (MSG_MAPKW_PROTECTED),
		    FLG_SCOPE_PROT, FLG_OF_MAPSYMB },
		{ (MSG_MAPKW_SINGLETON),
		    FLG_SCOPE_SNGL, FLG_OF_MAPGLOB },
		{ (MSG_MAPKW_SYMBOLIC),
		    FLG_SCOPE_PROT, FLG_OF_MAPSYMB },

		/* List must be null terminated */
		{ 0 }
	};

	/*
	 * Size of buffer needed to format the names in scope_list[]. Must
	 * be kept in sync with scope_list.
	 */
	static size_t scope_list_bufsize =
	    sizeof(MSG_MAPKW_DEFAULT) +
	    sizeof(MSG_MAPKW_ELIMINATE) +
	    sizeof(MSG_MAPKW_EXPORTED) +
	    sizeof(MSG_MAPKW_HIDDEN) +
	    sizeof(MSG_MAPKW_GLOBAL) +
	    sizeof(MSG_MAPKW_LOCAL) +
	    sizeof(MSG_MAPKW_PROTECTED) +
	    sizeof(MSG_MAPKW_SINGLETON) +
	    sizeof(MSG_MAPKW_SYMBOLIC);

	scope_t	*scope;

	scope = ld_map_kwfind(scope_name, scope_list,
	    SGSOFFSETOF(scope_t, name), sizeof (scope_list[0]));
	if (scope == NULL) {
		char buf[VLA_SIZE(scope_list_bufsize)];

		mf_fatal(mf, (MSG_MAP_EXP_SYMSCOPE),
		    ld_map_kwnames(scope_list, SGSOFFSETOF(scope_t, name),
		    sizeof (scope[0]), buf, scope_list_bufsize), scope_name);
		mv->mv_errcnt++;
		return;
	}

	mv->mv_scope = scope->type;
	mf->mf_ofl->ofl_flags |= scope->ofl_flags;
}