예제 #1
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);
}
예제 #2
0
/*
 * Construct the member's full pathname, using the format "%s(%s)".
 *
 * entry:
 *	name - Name of archive
 *	arname - Name of archive member
 * exit:
 *	Returns pointer to constructed pathname on success, NULL on error.
 */
static const char *
ar_member_path(const char *name, const char *arname)
{
	size_t		len;
	char		*path;

	len = strlen(name) + strlen(arname) + 3;
	if ((path = libld_malloc(len)) == NULL)
		return (NULL);
	(void) snprintf(path, len, MSG_ORIG(MSG_FMT_ARMEM), name, arname);
	return (path);
}
예제 #3
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);
}