Beispiel #1
0
/* Return TRUE if a defined symbol might be reachable from outside the
   universe of claimed objects.  */
static inline bfd_boolean
is_visible_from_outside (struct ld_plugin_symbol *lsym,
			 struct bfd_link_hash_entry *blhe)
{
  struct bfd_sym_chain *sym;

  if (link_info.relocatable)
    return TRUE;
  if (link_info.export_dynamic || !link_info.executable)
    {
      /* Check if symbol is hidden by version script.  */
      if (bfd_hide_sym_by_version (link_info.version_info,
				   blhe->root.string))
	return FALSE;
      /* Only ELF symbols really have visibility.  */
      if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour)
	{
	  struct elf_link_hash_entry *el = (struct elf_link_hash_entry *)blhe;
	  int vis = ELF_ST_VISIBILITY (el->other);
	  return vis == STV_DEFAULT || vis == STV_PROTECTED;
	}
      /* On non-ELF targets, we can safely make inferences by considering
	 what visibility the plugin would have liked to apply when it first
	 sent us the symbol.  During ELF symbol processing, visibility only
	 ever becomes more restrictive, not less, when symbols are merged,
	 so this is a conservative estimate; it may give false positives,
	 declaring something visible from outside when it in fact would
	 not have been, but this will only lead to missed optimisation
	 opportunities during LTRANS at worst; it will not give false
	 negatives, which can lead to the disastrous conclusion that the
	 related symbol is IRONLY.  (See GCC PR46319 for an example.)  */
      return (lsym->visibility == LDPV_DEFAULT
	      || lsym->visibility == LDPV_PROTECTED);
    }

  for (sym = &entry_symbol; sym != NULL; sym = sym->next)
    if (sym->name
	&& strcmp (sym->name, blhe->root.string) == 0)
      return TRUE;

  return FALSE;
}
Beispiel #2
0
const char *
conv_sym_other(uchar_t other)
{
	static char		string[CONV_INV_STRSIZE];
	static const char	visibility[4] = {
		'D',	/* STV_DEFAULT */
		'I',	/* STV_INTERNAL */
		'H',	/* STV_HIDDEN */
		'P'	/* STV_PROTECTED */
	};
	uint_t		vis = ELF_ST_VISIBILITY(other);
	uint_t		ndx = 0;

	string[ndx++] = visibility[vis];

	/*
	 * If unkown bits are present in stother - throw out a '?'
	 */
	if (other & ~MSK_SYM_VISIBILITY)
		string[ndx++] = '?';
	string[ndx++] = '\0';

	return (string);
}
Beispiel #3
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);
}