FreeBSD/contrib/binutils/bfd/elflink.c
/* Figure out appropriate versions for all the symbols.  We may not
   have the version number script until we have read all of the input
   files, so until that point we don't know which symbols should be
   local.  This function is called via elf_link_hash_traverse.  */
Figure out appropriate versions for all the symbols.  We may not
have the version number script until we have read all of the input
files, so until that point we don't know which symbols should be
local.  This function is called via elf_link_hash_traverse.
Figure out appropriate versions for all the symbols . We may not have the version number script until we have read all of the input files so until that point we don ' t know which symbols should be local . This function is called via elf_link_hash_traverse .
bfd_boolean
_bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
{
  struct elf_assign_sym_version_info *sinfo;
  struct bfd_link_info *info;
  const struct elf_backend_data *bed;
  struct elf_info_failed eif;
  char *p;
  bfd_size_type amt;
  sinfo = data;
  info = sinfo->info;
  if (h->root.type == bfd_link_hash_warning)
    h = (struct elf_link_hash_entry *) h->root.u.i.link;
  eif.failed = FALSE;
  eif.info = info;
  if (! _bfd_elf_fix_symbol_flags (h, &eif))
    {
      if (eif.failed)
	sinfo->failed = TRUE;
      return FALSE;
    }
  if (!h->def_regular)
    return TRUE;
  bed = get_elf_backend_data (sinfo->output_bfd);
  p = strchr (h->root.root.string, ELF_VER_CHR);
  if (p != NULL && h->verinfo.vertree == NULL)
    {
      struct bfd_elf_version_tree *t;
      bfd_boolean hidden;
      hidden = TRUE;
      ++p;
      if (*p == ELF_VER_CHR)
	{
	  hidden = FALSE;
	  ++p;
	}
      if (*p == '\0')
	{
	  if (hidden)
	    h->hidden = 1;
	  return TRUE;
	}
      for (t = sinfo->verdefs; t != NULL; t = t->next)
	{
	  if (strcmp (t->name, p) == 0)
	    {
	      size_t len;
	      char *alc;
	      struct bfd_elf_version_expr *d;
	      len = p - h->root.root.string;
	      alc = bfd_malloc (len);
	      if (alc == NULL)
		return FALSE;
	      memcpy (alc, h->root.root.string, len - 1);
	      alc[len - 1] = '\0';
	      if (alc[len - 2] == ELF_VER_CHR)
		alc[len - 2] = '\0';
	      h->verinfo.vertree = t;
	      t->used = TRUE;
	      d = NULL;
	      if (t->globals.list != NULL)
		d = (*t->match) (&t->globals, NULL, alc);
	      if (d == NULL && t->locals.list != NULL)
		{
		  d = (*t->match) (&t->locals, NULL, alc);
		  if (d != NULL
		      && h->dynindx != -1
		      && ! info->export_dynamic)
		    (*bed->elf_backend_hide_symbol) (info, h, TRUE);
		}
	      free (alc);
	      break;
	    }
	}
      if (t == NULL && info->executable)
	{
	  struct bfd_elf_version_tree **pp;
	  int version_index;
	  if (h->dynindx == -1)
	    return TRUE;
	  amt = sizeof *t;
	  t = bfd_zalloc (sinfo->output_bfd, amt);
	  if (t == NULL)
	    {
	      sinfo->failed = TRUE;
	      return FALSE;
	    }
	  t->name = p;
	  t->name_indx = (unsigned int) -1;
	  t->used = TRUE;
	  version_index = 1;
	  if (sinfo->verdefs != NULL && sinfo->verdefs->vernum == 0)
	    version_index = 0;
	  for (pp = &sinfo->verdefs; *pp != NULL; pp = &(*pp)->next)
	    ++version_index;
	  t->vernum = version_index;
	  *pp = t;
	  h->verinfo.vertree = t;
	}
      else if (t == NULL)
	{
	  (*_bfd_error_handler)
	    (_("%B: version node not found for symbol %s"),
	     sinfo->output_bfd, h->root.root.string);
	  bfd_set_error (bfd_error_bad_value);
	  sinfo->failed = TRUE;
	  return FALSE;
	}
      if (hidden)
	h->hidden = 1;
    }
  if (h->verinfo.vertree == NULL && sinfo->verdefs != NULL)
    {
      struct bfd_elf_version_tree *t;
      struct bfd_elf_version_tree *local_ver;
      struct bfd_elf_version_expr *d;
      local_ver = NULL;
      for (t = sinfo->verdefs; t != NULL; t = t->next)
	{
	  if (t->globals.list != NULL)
	    {
	      bfd_boolean matched;
	      matched = FALSE;
	      d = NULL;
	      while ((d = (*t->match) (&t->globals, d,
				       h->root.root.string)) != NULL)
		if (d->symver)
		  matched = TRUE;
		else
		  {
		    h->verinfo.vertree = t;
		    local_ver = NULL;
		    d->script = 1;
		    break;
		  }
	      if (d != NULL)
		break;
	      else if (matched)
		(*bed->elf_backend_hide_symbol) (info, h, TRUE);
	    }
	  if (t->locals.list != NULL)
	    {
	      d = NULL;
	      while ((d = (*t->match) (&t->locals, d,
				       h->root.root.string)) != NULL)
		{
		  local_ver = t;
		  if (d->pattern[0] != '*' || d->pattern[1] != '\0')
		    break;
		}
	      if (d != NULL)
		break;
	    }
	}
      if (local_ver != NULL)
	{
	  h->verinfo.vertree = local_ver;
	  if (h->dynindx != -1
	      && ! info->export_dynamic)
	    {
	      (*bed->elf_backend_hide_symbol) (info, h, TRUE);
	    }
	}
    }
  return TRUE;
}
bfd_boolean _bfd_elf_link_assign_sym_version ( struct elf_link_hash_entry * h , void * data ) { struct elf_assign_sym_version_info * sinfo ; struct bfd_link_info * info ; const struct elf_backend_data * bed ; struct elf_info_failed eif ; char * p ; bfd_size_type amt ; sinfo = data ; info = sinfo -> info ; if ( h -> root . type == bfd_link_hash_warning ) h = ( struct elf_link_hash_entry * ) h -> root . u . i . link ; eif . failed = FALSE ; eif . info = info ; if ( ! _bfd_elf_fix_symbol_flags ( h , & eif ) ) { if ( eif . failed ) sinfo -> failed = TRUE ; return FALSE ; } if ( ! h -> def_regular ) return TRUE ; bed = get_elf_backend_data ( sinfo -> output_bfd ) ; p = strchr ( h -> root . root . string , ELF_VER_CHR ) ; if ( p != NULL && h -> verinfo . vertree == NULL ) { struct bfd_elf_version_tree * t ; bfd_boolean hidden ; hidden = TRUE ; ++ p ; if ( * p == ELF_VER_CHR ) { hidden = FALSE ; ++ p ; } if ( * p == ' \0 ' ) { if ( hidden ) h -> hidden = 1 ; return TRUE ; } for ( t = sinfo -> verdefs ; t != NULL ; t = t -> next ) { if ( strcmp ( t -> name , p ) == 0 ) { size_t len ; char * alc ; struct bfd_elf_version_expr * d ; len = p - h -> root . root . string ; alc = bfd_malloc ( len ) ; if ( alc == NULL ) return FALSE ; memcpy ( alc , h -> root . root . string , len - 1 ) ; alc [ len - 1 ] = ' \0 ' ; if ( alc [ len - 2 ] == ELF_VER_CHR ) alc [ len - 2 ] = ' \0 ' ; h -> verinfo . vertree = t ; t -> used = TRUE ; d = NULL ; if ( t -> globals . list != NULL ) d = ( * t -> match ) ( & t -> globals , NULL , alc ) ; if ( d == NULL && t -> locals . list != NULL ) { d = ( * t -> match ) ( & t -> locals , NULL , alc ) ; if ( d != NULL && h -> dynindx != -1 && ! info -> export_dynamic ) ( * bed -> elf_backend_hide_symbol ) ( info , h , TRUE ) ; } free ( alc ) ; break ; } } if ( t == NULL && info -> executable ) { struct bfd_elf_version_tree * * pp ; int version_index ; if ( h -> dynindx == -1 ) return TRUE ; amt = sizeof * t ; t = bfd_zalloc ( sinfo -> output_bfd , amt ) ; if ( t == NULL ) { sinfo -> failed = TRUE ; return FALSE ; } t -> name = p ; t -> name_indx = ( unsigned int ) -1 ; t -> used = TRUE ; version_index = 1 ; if ( sinfo -> verdefs != NULL && sinfo -> verdefs -> vernum == 0 ) version_index = 0 ; for ( pp = & sinfo -> verdefs ; * pp != NULL ; pp = & ( * pp ) -> next ) ++ version_index ; t -> vernum = version_index ; * pp = t ; h -> verinfo . vertree = t ; } else if ( t == NULL ) { ( * _bfd_error_handler ) ( _ ( " " ) , sinfo -> output_bfd , h -> root . root . string ) ; bfd_set_error ( bfd_error_bad_value ) ; sinfo -> failed = TRUE ; return FALSE ; } if ( hidden ) h -> hidden = 1 ; } if ( h -> verinfo . vertree == NULL && sinfo -> verdefs != NULL ) { struct bfd_elf_version_tree * t ; struct bfd_elf_version_tree * local_ver ; struct bfd_elf_version_expr * d ; local_ver = NULL ; for ( t = sinfo -> verdefs ; t != NULL ; t = t -> next ) { if ( t -> globals . list != NULL ) { bfd_boolean matched ; matched = FALSE ; d = NULL ; while ( ( d = ( * t -> match ) ( & t -> globals , d , h -> root . root . string ) ) != NULL ) if ( d -> symver ) matched = TRUE ; else { h -> verinfo . vertree = t ; local_ver = NULL ; d -> script = 1 ; break ; } if ( d != NULL ) break ; else if ( matched ) ( * bed -> elf_backend_hide_symbol ) ( info , h , TRUE ) ; } if ( t -> locals . list != NULL ) { d = NULL ; while ( ( d = ( * t -> match ) ( & t -> locals , d , h -> root . root . string ) ) != NULL ) { local_ver = t ; if ( d -> pattern [ 0 ] != ' ' || d -> pattern [ 1 ] != ' \0 ' ) break ; } if ( d != NULL ) break ; } } if ( local_ver != NULL ) { h -> verinfo . vertree = local_ver ; if ( h -> dynindx != -1 && ! info -> export_dynamic ) { ( * bed -> elf_backend_hide_symbol ) ( info , h , TRUE ) ; } } } return TRUE ; }
Figure out appropriate versions for all the symbols.
Figure out appropriate versions for all the symbols .
/* Fix the symbol flags.  */ /* We only need version numbers for symbols defined in regular
     objects.  */ /* There are two consecutive ELF_VER_CHR characters if this is
	 not a hidden symbol.  */ /* If there is no version string, we can just return out.  */ /* Look for the version.  If we find it, it is no longer weak.  */ /* See if there is anything to force this symbol to
		 local scope.  */ /* If we are building an application, we need to create a
	 version node for this version.  */ /* If we aren't going to export this symbol, we don't need
	     to worry about it.  */ /* Don't count anonymous version tag.  */ /* We could not find the version for a symbol when
	     generating a shared archive.  Return an error.  */ /* If we don't have a version for this symbol, see if we can find
     something.  */ /* See if can find what version this symbol is in.  If the
	 symbol is supposed to be local, then don't actually register
	 it.  */ /* There is a version without definition.  Make
		       the symbol the default definition for this
		       version.  */ /* There is no undefined version for this symbol. Hide the
		   default one.  */ /* If the match is "*", keep looking for a more
		     explicit, perhaps even global, match.
		     XXX: Shouldn't this be !d->wildcard instead?  */