Пример #1
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);
}
Пример #2
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);
	}
Пример #3
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);
}
Пример #4
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);
}