xref: /netbsd-src/external/gpl3/binutils.old/dist/ld/ldcref.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
175fd0b74Schristos /* ldcref.c -- output a cross reference table
2*e992f068Schristos    Copyright (C) 1996-2022 Free Software Foundation, Inc.
375fd0b74Schristos    Written by Ian Lance Taylor <ian@cygnus.com>
475fd0b74Schristos 
575fd0b74Schristos    This file is part of the GNU Binutils.
675fd0b74Schristos 
775fd0b74Schristos    This program is free software; you can redistribute it and/or modify
875fd0b74Schristos    it under the terms of the GNU General Public License as published by
975fd0b74Schristos    the Free Software Foundation; either version 3 of the License, or
1075fd0b74Schristos    (at your option) any later version.
1175fd0b74Schristos 
1275fd0b74Schristos    This program is distributed in the hope that it will be useful,
1375fd0b74Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
1475fd0b74Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1575fd0b74Schristos    GNU General Public License for more details.
1675fd0b74Schristos 
1775fd0b74Schristos    You should have received a copy of the GNU General Public License
1875fd0b74Schristos    along with this program; if not, write to the Free Software
1975fd0b74Schristos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
2075fd0b74Schristos    MA 02110-1301, USA.  */
2175fd0b74Schristos 
2275fd0b74Schristos 
2375fd0b74Schristos /* This file holds routines that manage the cross reference table.
2475fd0b74Schristos    The table is used to generate cross reference reports.  It is also
2575fd0b74Schristos    used to implement the NOCROSSREFS command in the linker script.  */
2675fd0b74Schristos 
2775fd0b74Schristos #include "sysdep.h"
2875fd0b74Schristos #include "bfd.h"
2975fd0b74Schristos #include "bfdlink.h"
30012573ebSchristos #include "ctf-api.h"
3175fd0b74Schristos #include "libiberty.h"
3275fd0b74Schristos #include "demangle.h"
3375fd0b74Schristos #include "objalloc.h"
3475fd0b74Schristos 
3575fd0b74Schristos #include "ld.h"
3675fd0b74Schristos #include "ldmain.h"
3775fd0b74Schristos #include "ldmisc.h"
3875fd0b74Schristos #include "ldexp.h"
3975fd0b74Schristos #include "ldlang.h"
4075fd0b74Schristos 
4175fd0b74Schristos /* We keep an instance of this structure for each reference to a
4275fd0b74Schristos    symbol from a given object.  */
4375fd0b74Schristos 
4475fd0b74Schristos struct cref_ref
4575fd0b74Schristos {
4675fd0b74Schristos   /* The next reference.  */
4775fd0b74Schristos   struct cref_ref *next;
4875fd0b74Schristos   /* The object.  */
4975fd0b74Schristos   bfd *abfd;
5075fd0b74Schristos   /* True if the symbol is defined.  */
5175fd0b74Schristos   unsigned int def : 1;
5275fd0b74Schristos   /* True if the symbol is common.  */
5375fd0b74Schristos   unsigned int common : 1;
5475fd0b74Schristos   /* True if the symbol is undefined.  */
5575fd0b74Schristos   unsigned int undef : 1;
5675fd0b74Schristos };
5775fd0b74Schristos 
5875fd0b74Schristos /* We keep a hash table of symbols.  Each entry looks like this.  */
5975fd0b74Schristos 
6075fd0b74Schristos struct cref_hash_entry
6175fd0b74Schristos {
6275fd0b74Schristos   struct bfd_hash_entry root;
6375fd0b74Schristos   /* The demangled name.  */
6475fd0b74Schristos   const char *demangled;
6575fd0b74Schristos   /* References to and definitions of this symbol.  */
6675fd0b74Schristos   struct cref_ref *refs;
6775fd0b74Schristos };
6875fd0b74Schristos 
6975fd0b74Schristos /* This is what the hash table looks like.  */
7075fd0b74Schristos 
7175fd0b74Schristos struct cref_hash_table
7275fd0b74Schristos {
7375fd0b74Schristos   struct bfd_hash_table root;
7475fd0b74Schristos };
7575fd0b74Schristos 
7675fd0b74Schristos /* Forward declarations.  */
7775fd0b74Schristos 
7875fd0b74Schristos static void output_one_cref (FILE *, struct cref_hash_entry *);
7975fd0b74Schristos static void check_local_sym_xref (lang_input_statement_type *);
80*e992f068Schristos static bool check_nocrossref (struct cref_hash_entry *, void *);
81*e992f068Schristos static void check_refs (const char *, bool, asection *, bfd *,
8275fd0b74Schristos 			struct lang_nocrossrefs *);
8375fd0b74Schristos static void check_reloc_refs (bfd *, asection *, void *);
8475fd0b74Schristos 
8575fd0b74Schristos /* Look up an entry in the cref hash table.  */
8675fd0b74Schristos 
8775fd0b74Schristos #define cref_hash_lookup(table, string, create, copy)		\
8875fd0b74Schristos   ((struct cref_hash_entry *)					\
8975fd0b74Schristos    bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
9075fd0b74Schristos 
9175fd0b74Schristos /* Traverse the cref hash table.  */
9275fd0b74Schristos 
9375fd0b74Schristos #define cref_hash_traverse(table, func, info)				\
9475fd0b74Schristos   (bfd_hash_traverse							\
9575fd0b74Schristos    (&(table)->root,							\
96*e992f068Schristos     (bool (*) (struct bfd_hash_entry *, void *)) (func), (info)))
9775fd0b74Schristos 
9875fd0b74Schristos /* The cref hash table.  */
9975fd0b74Schristos 
10075fd0b74Schristos static struct cref_hash_table cref_table;
10175fd0b74Schristos 
10275fd0b74Schristos /* Whether the cref hash table has been initialized.  */
10375fd0b74Schristos 
104*e992f068Schristos static bool cref_initialized;
10575fd0b74Schristos 
10675fd0b74Schristos /* The number of symbols seen so far.  */
10775fd0b74Schristos 
10875fd0b74Schristos static size_t cref_symcount;
10975fd0b74Schristos 
11075fd0b74Schristos /* Used to take a snapshot of the cref hash table when starting to
11175fd0b74Schristos    add syms from an as-needed library.  */
11275fd0b74Schristos static struct bfd_hash_entry **old_table;
11375fd0b74Schristos static unsigned int old_size;
11475fd0b74Schristos static unsigned int old_count;
11575fd0b74Schristos static void *old_tab;
11675fd0b74Schristos static void *alloc_mark;
11775fd0b74Schristos static size_t tabsize, entsize, refsize;
11875fd0b74Schristos static size_t old_symcount;
11975fd0b74Schristos 
12075fd0b74Schristos /* Create an entry in a cref hash table.  */
12175fd0b74Schristos 
12275fd0b74Schristos static struct bfd_hash_entry *
cref_hash_newfunc(struct bfd_hash_entry * entry,struct bfd_hash_table * table,const char * string)12375fd0b74Schristos cref_hash_newfunc (struct bfd_hash_entry *entry,
12475fd0b74Schristos 		   struct bfd_hash_table *table,
12575fd0b74Schristos 		   const char *string)
12675fd0b74Schristos {
12775fd0b74Schristos   struct cref_hash_entry *ret = (struct cref_hash_entry *) entry;
12875fd0b74Schristos 
12975fd0b74Schristos   /* Allocate the structure if it has not already been allocated by a
13075fd0b74Schristos      subclass.  */
13175fd0b74Schristos   if (ret == NULL)
13275fd0b74Schristos     ret = ((struct cref_hash_entry *)
13375fd0b74Schristos 	   bfd_hash_allocate (table, sizeof (struct cref_hash_entry)));
13475fd0b74Schristos   if (ret == NULL)
13575fd0b74Schristos     return NULL;
13675fd0b74Schristos 
13775fd0b74Schristos   /* Call the allocation method of the superclass.  */
13875fd0b74Schristos   ret = ((struct cref_hash_entry *)
13975fd0b74Schristos 	 bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
14075fd0b74Schristos   if (ret != NULL)
14175fd0b74Schristos     {
14275fd0b74Schristos       /* Set local fields.  */
14375fd0b74Schristos       ret->demangled = NULL;
14475fd0b74Schristos       ret->refs = NULL;
14575fd0b74Schristos 
14675fd0b74Schristos       /* Keep a count of the number of entries created in the hash
14775fd0b74Schristos 	 table.  */
14875fd0b74Schristos       ++cref_symcount;
14975fd0b74Schristos     }
15075fd0b74Schristos 
15175fd0b74Schristos   return &ret->root;
15275fd0b74Schristos }
15375fd0b74Schristos 
15475fd0b74Schristos /* Add a symbol to the cref hash table.  This is called for every
15575fd0b74Schristos    global symbol that is seen during the link.  */
15675fd0b74Schristos 
15775fd0b74Schristos void
add_cref(const char * name,bfd * abfd,asection * section,bfd_vma value ATTRIBUTE_UNUSED)15875fd0b74Schristos add_cref (const char *name,
15975fd0b74Schristos 	  bfd *abfd,
16075fd0b74Schristos 	  asection *section,
16175fd0b74Schristos 	  bfd_vma value ATTRIBUTE_UNUSED)
16275fd0b74Schristos {
16375fd0b74Schristos   struct cref_hash_entry *h;
16475fd0b74Schristos   struct cref_ref *r;
16575fd0b74Schristos 
16675fd0b74Schristos   if (!cref_initialized)
16775fd0b74Schristos     {
16875fd0b74Schristos       if (!bfd_hash_table_init (&cref_table.root, cref_hash_newfunc,
16975fd0b74Schristos 				sizeof (struct cref_hash_entry)))
17075fd0b74Schristos 	einfo (_("%X%P: bfd_hash_table_init of cref table failed: %E\n"));
171*e992f068Schristos       cref_initialized = true;
17275fd0b74Schristos     }
17375fd0b74Schristos 
174*e992f068Schristos   h = cref_hash_lookup (&cref_table, name, true, false);
17575fd0b74Schristos   if (h == NULL)
17675fd0b74Schristos     einfo (_("%X%P: cref_hash_lookup failed: %E\n"));
17775fd0b74Schristos 
17875fd0b74Schristos   for (r = h->refs; r != NULL; r = r->next)
17975fd0b74Schristos     if (r->abfd == abfd)
18075fd0b74Schristos       break;
18175fd0b74Schristos 
18275fd0b74Schristos   if (r == NULL)
18375fd0b74Schristos     {
18475fd0b74Schristos       r = (struct cref_ref *) bfd_hash_allocate (&cref_table.root, sizeof *r);
18575fd0b74Schristos       if (r == NULL)
18675fd0b74Schristos 	einfo (_("%X%P: cref alloc failed: %E\n"));
18775fd0b74Schristos       r->next = h->refs;
18875fd0b74Schristos       h->refs = r;
18975fd0b74Schristos       r->abfd = abfd;
190*e992f068Schristos       r->def = false;
191*e992f068Schristos       r->common = false;
192*e992f068Schristos       r->undef = false;
19375fd0b74Schristos     }
19475fd0b74Schristos 
19575fd0b74Schristos   if (bfd_is_und_section (section))
196*e992f068Schristos     r->undef = true;
19775fd0b74Schristos   else if (bfd_is_com_section (section))
198*e992f068Schristos     r->common = true;
19975fd0b74Schristos   else
200*e992f068Schristos     r->def = true;
20175fd0b74Schristos }
20275fd0b74Schristos 
20375fd0b74Schristos /* Called before loading an as-needed library to take a snapshot of
20475fd0b74Schristos    the cref hash table, and after we have loaded or found that the
20575fd0b74Schristos    library was not needed.  */
20675fd0b74Schristos 
207*e992f068Schristos bool
handle_asneeded_cref(bfd * abfd ATTRIBUTE_UNUSED,enum notice_asneeded_action act)20875fd0b74Schristos handle_asneeded_cref (bfd *abfd ATTRIBUTE_UNUSED,
20975fd0b74Schristos 		      enum notice_asneeded_action act)
21075fd0b74Schristos {
21175fd0b74Schristos   unsigned int i;
21275fd0b74Schristos 
21375fd0b74Schristos   if (!cref_initialized)
214*e992f068Schristos     return true;
21575fd0b74Schristos 
21675fd0b74Schristos   if (act == notice_as_needed)
21775fd0b74Schristos     {
21875fd0b74Schristos       char *old_ent, *old_ref;
21975fd0b74Schristos 
22075fd0b74Schristos       for (i = 0; i < cref_table.root.size; i++)
22175fd0b74Schristos 	{
22275fd0b74Schristos 	  struct bfd_hash_entry *p;
22375fd0b74Schristos 	  struct cref_hash_entry *c;
22475fd0b74Schristos 	  struct cref_ref *r;
22575fd0b74Schristos 
22675fd0b74Schristos 	  for (p = cref_table.root.table[i]; p != NULL; p = p->next)
22775fd0b74Schristos 	    {
22875fd0b74Schristos 	      entsize += cref_table.root.entsize;
22975fd0b74Schristos 	      c = (struct cref_hash_entry *) p;
23075fd0b74Schristos 	      for (r = c->refs; r != NULL; r = r->next)
23175fd0b74Schristos 		refsize += sizeof (struct cref_ref);
23275fd0b74Schristos 	    }
23375fd0b74Schristos 	}
23475fd0b74Schristos 
23575fd0b74Schristos       tabsize = cref_table.root.size * sizeof (struct bfd_hash_entry *);
23675fd0b74Schristos       old_tab = xmalloc (tabsize + entsize + refsize);
23775fd0b74Schristos 
23875fd0b74Schristos       alloc_mark = bfd_hash_allocate (&cref_table.root, 1);
23975fd0b74Schristos       if (alloc_mark == NULL)
240*e992f068Schristos 	return false;
24175fd0b74Schristos 
24275fd0b74Schristos       memcpy (old_tab, cref_table.root.table, tabsize);
24375fd0b74Schristos       old_ent = (char *) old_tab + tabsize;
24475fd0b74Schristos       old_ref = (char *) old_ent + entsize;
24575fd0b74Schristos       old_table = cref_table.root.table;
24675fd0b74Schristos       old_size = cref_table.root.size;
24775fd0b74Schristos       old_count = cref_table.root.count;
24875fd0b74Schristos       old_symcount = cref_symcount;
24975fd0b74Schristos 
25075fd0b74Schristos       for (i = 0; i < cref_table.root.size; i++)
25175fd0b74Schristos 	{
25275fd0b74Schristos 	  struct bfd_hash_entry *p;
25375fd0b74Schristos 	  struct cref_hash_entry *c;
25475fd0b74Schristos 	  struct cref_ref *r;
25575fd0b74Schristos 
25675fd0b74Schristos 	  for (p = cref_table.root.table[i]; p != NULL; p = p->next)
25775fd0b74Schristos 	    {
25875fd0b74Schristos 	      memcpy (old_ent, p, cref_table.root.entsize);
25975fd0b74Schristos 	      old_ent = (char *) old_ent + cref_table.root.entsize;
26075fd0b74Schristos 	      c = (struct cref_hash_entry *) p;
26175fd0b74Schristos 	      for (r = c->refs; r != NULL; r = r->next)
26275fd0b74Schristos 		{
26375fd0b74Schristos 		  memcpy (old_ref, r, sizeof (struct cref_ref));
26475fd0b74Schristos 		  old_ref = (char *) old_ref + sizeof (struct cref_ref);
26575fd0b74Schristos 		}
26675fd0b74Schristos 	    }
26775fd0b74Schristos 	}
268*e992f068Schristos       return true;
26975fd0b74Schristos     }
27075fd0b74Schristos 
27175fd0b74Schristos   if (act == notice_not_needed)
27275fd0b74Schristos     {
27375fd0b74Schristos       char *old_ent, *old_ref;
27475fd0b74Schristos 
27575fd0b74Schristos       if (old_tab == NULL)
27675fd0b74Schristos 	{
27775fd0b74Schristos 	  /* The only way old_tab can be NULL is if the cref hash table
27875fd0b74Schristos 	     had not been initialised when notice_as_needed.  */
27975fd0b74Schristos 	  bfd_hash_table_free (&cref_table.root);
280*e992f068Schristos 	  cref_initialized = false;
281*e992f068Schristos 	  return true;
28275fd0b74Schristos 	}
28375fd0b74Schristos 
28475fd0b74Schristos       old_ent = (char *) old_tab + tabsize;
28575fd0b74Schristos       old_ref = (char *) old_ent + entsize;
28675fd0b74Schristos       cref_table.root.table = old_table;
28775fd0b74Schristos       cref_table.root.size = old_size;
28875fd0b74Schristos       cref_table.root.count = old_count;
28975fd0b74Schristos       memcpy (cref_table.root.table, old_tab, tabsize);
29075fd0b74Schristos       cref_symcount = old_symcount;
29175fd0b74Schristos 
29275fd0b74Schristos       for (i = 0; i < cref_table.root.size; i++)
29375fd0b74Schristos 	{
29475fd0b74Schristos 	  struct bfd_hash_entry *p;
29575fd0b74Schristos 	  struct cref_hash_entry *c;
29675fd0b74Schristos 	  struct cref_ref *r;
29775fd0b74Schristos 
29875fd0b74Schristos 	  for (p = cref_table.root.table[i]; p != NULL; p = p->next)
29975fd0b74Schristos 	    {
30075fd0b74Schristos 	      memcpy (p, old_ent, cref_table.root.entsize);
30175fd0b74Schristos 	      old_ent = (char *) old_ent + cref_table.root.entsize;
30275fd0b74Schristos 	      c = (struct cref_hash_entry *) p;
30375fd0b74Schristos 	      for (r = c->refs; r != NULL; r = r->next)
30475fd0b74Schristos 		{
30575fd0b74Schristos 		  memcpy (r, old_ref, sizeof (struct cref_ref));
30675fd0b74Schristos 		  old_ref = (char *) old_ref + sizeof (struct cref_ref);
30775fd0b74Schristos 		}
30875fd0b74Schristos 	    }
30975fd0b74Schristos 	}
31075fd0b74Schristos 
31175fd0b74Schristos       objalloc_free_block ((struct objalloc *) cref_table.root.memory,
31275fd0b74Schristos 			   alloc_mark);
31375fd0b74Schristos     }
31475fd0b74Schristos   else if (act != notice_needed)
315*e992f068Schristos     return false;
31675fd0b74Schristos 
31775fd0b74Schristos   free (old_tab);
31875fd0b74Schristos   old_tab = NULL;
319*e992f068Schristos   return true;
32075fd0b74Schristos }
32175fd0b74Schristos 
32275fd0b74Schristos /* Copy the addresses of the hash table entries into an array.  This
32375fd0b74Schristos    is called via cref_hash_traverse.  We also fill in the demangled
32475fd0b74Schristos    name.  */
32575fd0b74Schristos 
326*e992f068Schristos static bool
cref_fill_array(struct cref_hash_entry * h,void * data)32775fd0b74Schristos cref_fill_array (struct cref_hash_entry *h, void *data)
32875fd0b74Schristos {
32975fd0b74Schristos   struct cref_hash_entry ***pph = (struct cref_hash_entry ***) data;
33075fd0b74Schristos 
33175fd0b74Schristos   ASSERT (h->demangled == NULL);
33275fd0b74Schristos   h->demangled = bfd_demangle (link_info.output_bfd, h->root.string,
33375fd0b74Schristos 			       DMGL_ANSI | DMGL_PARAMS);
33475fd0b74Schristos   if (h->demangled == NULL)
33575fd0b74Schristos     h->demangled = h->root.string;
33675fd0b74Schristos 
33775fd0b74Schristos   **pph = h;
33875fd0b74Schristos 
33975fd0b74Schristos   ++*pph;
34075fd0b74Schristos 
341*e992f068Schristos   return true;
34275fd0b74Schristos }
34375fd0b74Schristos 
34475fd0b74Schristos /* Sort an array of cref hash table entries by name.  */
34575fd0b74Schristos 
34675fd0b74Schristos static int
cref_sort_array(const void * a1,const void * a2)34775fd0b74Schristos cref_sort_array (const void *a1, const void *a2)
34875fd0b74Schristos {
34975fd0b74Schristos   const struct cref_hash_entry *const *p1
35075fd0b74Schristos     = (const struct cref_hash_entry *const *) a1;
35175fd0b74Schristos   const struct cref_hash_entry *const *p2
35275fd0b74Schristos     = (const struct cref_hash_entry *const *) a2;
35375fd0b74Schristos 
35475fd0b74Schristos   if (demangling)
35575fd0b74Schristos     return strcmp ((*p1)->demangled, (*p2)->demangled);
35675fd0b74Schristos   else
35775fd0b74Schristos     return strcmp ((*p1)->root.string, (*p2)->root.string);
35875fd0b74Schristos }
35975fd0b74Schristos 
36075fd0b74Schristos /* Write out the cref table.  */
36175fd0b74Schristos 
36275fd0b74Schristos #define FILECOL (50)
36375fd0b74Schristos 
36475fd0b74Schristos void
output_cref(FILE * fp)36575fd0b74Schristos output_cref (FILE *fp)
36675fd0b74Schristos {
36775fd0b74Schristos   int len;
36875fd0b74Schristos   struct cref_hash_entry **csyms, **csym_fill, **csym, **csym_end;
36975fd0b74Schristos   const char *msg;
37075fd0b74Schristos 
37175fd0b74Schristos   fprintf (fp, _("\nCross Reference Table\n\n"));
37275fd0b74Schristos   msg = _("Symbol");
37375fd0b74Schristos   fprintf (fp, "%s", msg);
37475fd0b74Schristos   len = strlen (msg);
37575fd0b74Schristos   while (len < FILECOL)
37675fd0b74Schristos     {
37775fd0b74Schristos       putc (' ', fp);
37875fd0b74Schristos       ++len;
37975fd0b74Schristos     }
38075fd0b74Schristos   fprintf (fp, _("File\n"));
38175fd0b74Schristos 
38275fd0b74Schristos   if (!cref_initialized)
38375fd0b74Schristos     {
38475fd0b74Schristos       fprintf (fp, _("No symbols\n"));
38575fd0b74Schristos       return;
38675fd0b74Schristos     }
38775fd0b74Schristos 
38875fd0b74Schristos   csyms = (struct cref_hash_entry **) xmalloc (cref_symcount * sizeof (*csyms));
38975fd0b74Schristos 
39075fd0b74Schristos   csym_fill = csyms;
39175fd0b74Schristos   cref_hash_traverse (&cref_table, cref_fill_array, &csym_fill);
39275fd0b74Schristos   ASSERT ((size_t) (csym_fill - csyms) == cref_symcount);
39375fd0b74Schristos 
39475fd0b74Schristos   qsort (csyms, cref_symcount, sizeof (*csyms), cref_sort_array);
39575fd0b74Schristos 
39675fd0b74Schristos   csym_end = csyms + cref_symcount;
39775fd0b74Schristos   for (csym = csyms; csym < csym_end; csym++)
39875fd0b74Schristos     output_one_cref (fp, *csym);
39975fd0b74Schristos }
40075fd0b74Schristos 
40175fd0b74Schristos /* Output one entry in the cross reference table.  */
40275fd0b74Schristos 
40375fd0b74Schristos static void
output_one_cref(FILE * fp,struct cref_hash_entry * h)40475fd0b74Schristos output_one_cref (FILE *fp, struct cref_hash_entry *h)
40575fd0b74Schristos {
40675fd0b74Schristos   int len;
40775fd0b74Schristos   struct bfd_link_hash_entry *hl;
40875fd0b74Schristos   struct cref_ref *r;
40975fd0b74Schristos 
410*e992f068Schristos   hl = bfd_link_hash_lookup (link_info.hash, h->root.string, false,
411*e992f068Schristos 			     false, true);
41275fd0b74Schristos   if (hl == NULL)
413ede78133Schristos     einfo (_("%P: symbol `%pT' missing from main hash table\n"),
41475fd0b74Schristos 	   h->root.string);
41575fd0b74Schristos   else
41675fd0b74Schristos     {
41775fd0b74Schristos       /* If this symbol is defined in a dynamic object but never
41875fd0b74Schristos 	 referenced by a normal object, then don't print it.  */
41975fd0b74Schristos       if (hl->type == bfd_link_hash_defined)
42075fd0b74Schristos 	{
42175fd0b74Schristos 	  if (hl->u.def.section->output_section == NULL)
42275fd0b74Schristos 	    return;
42375fd0b74Schristos 	  if (hl->u.def.section->owner != NULL
42475fd0b74Schristos 	      && (hl->u.def.section->owner->flags & DYNAMIC) != 0)
42575fd0b74Schristos 	    {
42675fd0b74Schristos 	      for (r = h->refs; r != NULL; r = r->next)
42775fd0b74Schristos 		if ((r->abfd->flags & DYNAMIC) == 0)
42875fd0b74Schristos 		  break;
42975fd0b74Schristos 	      if (r == NULL)
43075fd0b74Schristos 		return;
43175fd0b74Schristos 	    }
43275fd0b74Schristos 	}
43375fd0b74Schristos     }
43475fd0b74Schristos 
43575fd0b74Schristos   if (demangling)
43675fd0b74Schristos     {
43775fd0b74Schristos       fprintf (fp, "%s ", h->demangled);
43875fd0b74Schristos       len = strlen (h->demangled) + 1;
43975fd0b74Schristos     }
44075fd0b74Schristos   else
44175fd0b74Schristos     {
44275fd0b74Schristos       fprintf (fp, "%s ", h->root.string);
44375fd0b74Schristos       len = strlen (h->root.string) + 1;
44475fd0b74Schristos     }
44575fd0b74Schristos 
44675fd0b74Schristos   for (r = h->refs; r != NULL; r = r->next)
44775fd0b74Schristos     {
44875fd0b74Schristos       if (r->def)
44975fd0b74Schristos 	{
45075fd0b74Schristos 	  while (len < FILECOL)
45175fd0b74Schristos 	    {
45275fd0b74Schristos 	      putc (' ', fp);
45375fd0b74Schristos 	      ++len;
45475fd0b74Schristos 	    }
455ede78133Schristos 	  lfinfo (fp, "%pB\n", r->abfd);
45675fd0b74Schristos 	  len = 0;
45775fd0b74Schristos 	}
45875fd0b74Schristos     }
45975fd0b74Schristos 
46075fd0b74Schristos   for (r = h->refs; r != NULL; r = r->next)
46175fd0b74Schristos     {
46275fd0b74Schristos       if (r->common)
46375fd0b74Schristos 	{
46475fd0b74Schristos 	  while (len < FILECOL)
46575fd0b74Schristos 	    {
46675fd0b74Schristos 	      putc (' ', fp);
46775fd0b74Schristos 	      ++len;
46875fd0b74Schristos 	    }
469ede78133Schristos 	  lfinfo (fp, "%pB\n", r->abfd);
47075fd0b74Schristos 	  len = 0;
47175fd0b74Schristos 	}
47275fd0b74Schristos     }
47375fd0b74Schristos 
47475fd0b74Schristos   for (r = h->refs; r != NULL; r = r->next)
47575fd0b74Schristos     {
47675fd0b74Schristos       if (!r->def && !r->common)
47775fd0b74Schristos 	{
47875fd0b74Schristos 	  while (len < FILECOL)
47975fd0b74Schristos 	    {
48075fd0b74Schristos 	      putc (' ', fp);
48175fd0b74Schristos 	      ++len;
48275fd0b74Schristos 	    }
483ede78133Schristos 	  lfinfo (fp, "%pB\n", r->abfd);
48475fd0b74Schristos 	  len = 0;
48575fd0b74Schristos 	}
48675fd0b74Schristos     }
48775fd0b74Schristos 
48875fd0b74Schristos   ASSERT (len == 0);
48975fd0b74Schristos }
49075fd0b74Schristos 
49175fd0b74Schristos /* Check for prohibited cross references.  */
49275fd0b74Schristos 
49375fd0b74Schristos void
check_nocrossrefs(void)49475fd0b74Schristos check_nocrossrefs (void)
49575fd0b74Schristos {
49675fd0b74Schristos   if (!cref_initialized)
49775fd0b74Schristos     return;
49875fd0b74Schristos 
49975fd0b74Schristos   cref_hash_traverse (&cref_table, check_nocrossref, NULL);
50075fd0b74Schristos 
50175fd0b74Schristos   lang_for_each_file (check_local_sym_xref);
50275fd0b74Schristos }
50375fd0b74Schristos 
50475fd0b74Schristos /* Check for prohibited cross references to local and section symbols.  */
50575fd0b74Schristos 
50675fd0b74Schristos static void
check_local_sym_xref(lang_input_statement_type * statement)50775fd0b74Schristos check_local_sym_xref (lang_input_statement_type *statement)
50875fd0b74Schristos {
50975fd0b74Schristos   bfd *abfd;
51075fd0b74Schristos   asymbol **syms;
51175fd0b74Schristos 
51275fd0b74Schristos   abfd = statement->the_bfd;
51375fd0b74Schristos   if (abfd == NULL)
51475fd0b74Schristos     return;
51575fd0b74Schristos 
51675fd0b74Schristos   if (!bfd_generic_link_read_symbols (abfd))
517ede78133Schristos     einfo (_("%F%P: %pB: could not read symbols: %E\n"), abfd);
51875fd0b74Schristos 
51975fd0b74Schristos   for (syms = bfd_get_outsymbols (abfd); *syms; ++syms)
52075fd0b74Schristos     {
52175fd0b74Schristos       asymbol *sym = *syms;
52275fd0b74Schristos       if (sym->flags & (BSF_GLOBAL | BSF_WARNING | BSF_INDIRECT | BSF_FILE))
52375fd0b74Schristos 	continue;
52475fd0b74Schristos       if ((sym->flags & (BSF_LOCAL | BSF_SECTION_SYM)) != 0
52575fd0b74Schristos 	  && sym->section->output_section != NULL)
52675fd0b74Schristos 	{
52775fd0b74Schristos 	  const char *outsecname, *symname;
52875fd0b74Schristos 	  struct lang_nocrossrefs *ncrs;
52975fd0b74Schristos 	  struct lang_nocrossref *ncr;
53075fd0b74Schristos 
53175fd0b74Schristos 	  outsecname = sym->section->output_section->name;
53275fd0b74Schristos 	  symname = NULL;
53375fd0b74Schristos 	  if ((sym->flags & BSF_SECTION_SYM) == 0)
53475fd0b74Schristos 	    symname = sym->name;
53575fd0b74Schristos 	  for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next)
53675fd0b74Schristos 	    for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next)
53775fd0b74Schristos 	      {
53875fd0b74Schristos 		if (strcmp (ncr->name, outsecname) == 0)
539*e992f068Schristos 		  check_refs (symname, false, sym->section, abfd, ncrs);
54075fd0b74Schristos 		/* The NOCROSSREFS_TO command only checks symbols defined in
54175fd0b74Schristos 		   the first section in the list.  */
54275fd0b74Schristos 		if (ncrs->onlyfirst)
54375fd0b74Schristos 		  break;
54475fd0b74Schristos 	      }
54575fd0b74Schristos 	}
54675fd0b74Schristos     }
54775fd0b74Schristos }
54875fd0b74Schristos 
54975fd0b74Schristos /* Check one symbol to see if it is a prohibited cross reference.  */
55075fd0b74Schristos 
551*e992f068Schristos static bool
check_nocrossref(struct cref_hash_entry * h,void * ignore ATTRIBUTE_UNUSED)55275fd0b74Schristos check_nocrossref (struct cref_hash_entry *h, void *ignore ATTRIBUTE_UNUSED)
55375fd0b74Schristos {
55475fd0b74Schristos   struct bfd_link_hash_entry *hl;
55575fd0b74Schristos   asection *defsec;
55675fd0b74Schristos   const char *defsecname;
55775fd0b74Schristos   struct lang_nocrossrefs *ncrs;
55875fd0b74Schristos   struct lang_nocrossref *ncr;
55975fd0b74Schristos   struct cref_ref *ref;
56075fd0b74Schristos 
561*e992f068Schristos   hl = bfd_link_hash_lookup (link_info.hash, h->root.string, false,
562*e992f068Schristos 			     false, true);
56375fd0b74Schristos   if (hl == NULL)
56475fd0b74Schristos     {
565ede78133Schristos       einfo (_("%P: symbol `%pT' missing from main hash table\n"),
56675fd0b74Schristos 	     h->root.string);
567*e992f068Schristos       return true;
56875fd0b74Schristos     }
56975fd0b74Schristos 
57075fd0b74Schristos   if (hl->type != bfd_link_hash_defined
57175fd0b74Schristos       && hl->type != bfd_link_hash_defweak)
572*e992f068Schristos     return true;
57375fd0b74Schristos 
57475fd0b74Schristos   defsec = hl->u.def.section->output_section;
57575fd0b74Schristos   if (defsec == NULL)
576*e992f068Schristos     return true;
577012573ebSchristos   defsecname = bfd_section_name (defsec);
57875fd0b74Schristos 
57975fd0b74Schristos   for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next)
58075fd0b74Schristos     for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next)
58175fd0b74Schristos       {
58275fd0b74Schristos 	if (strcmp (ncr->name, defsecname) == 0)
58375fd0b74Schristos 	  for (ref = h->refs; ref != NULL; ref = ref->next)
584*e992f068Schristos 	    check_refs (hl->root.string, true, hl->u.def.section,
58575fd0b74Schristos 			ref->abfd, ncrs);
58675fd0b74Schristos 	/* The NOCROSSREFS_TO command only checks symbols defined in the first
58775fd0b74Schristos 	   section in the list.  */
58875fd0b74Schristos 	if (ncrs->onlyfirst)
58975fd0b74Schristos 	  break;
59075fd0b74Schristos       }
59175fd0b74Schristos 
592*e992f068Schristos   return true;
59375fd0b74Schristos }
59475fd0b74Schristos 
59575fd0b74Schristos /* The struct is used to pass information from check_refs to
59675fd0b74Schristos    check_reloc_refs through bfd_map_over_sections.  */
59775fd0b74Schristos 
59875fd0b74Schristos struct check_refs_info
59975fd0b74Schristos {
60075fd0b74Schristos   const char *sym_name;
60175fd0b74Schristos   asection *defsec;
60275fd0b74Schristos   struct lang_nocrossrefs *ncrs;
60375fd0b74Schristos   asymbol **asymbols;
604*e992f068Schristos   bool global;
60575fd0b74Schristos };
60675fd0b74Schristos 
60775fd0b74Schristos /* This function is called for each symbol defined in a section which
60875fd0b74Schristos    prohibits cross references.  We need to look through all references
60975fd0b74Schristos    to this symbol, and ensure that the references are not from
61075fd0b74Schristos    prohibited sections.  */
61175fd0b74Schristos 
61275fd0b74Schristos static void
check_refs(const char * name,bool global,asection * sec,bfd * abfd,struct lang_nocrossrefs * ncrs)61375fd0b74Schristos check_refs (const char *name,
614*e992f068Schristos 	    bool global,
61575fd0b74Schristos 	    asection *sec,
61675fd0b74Schristos 	    bfd *abfd,
61775fd0b74Schristos 	    struct lang_nocrossrefs *ncrs)
61875fd0b74Schristos {
61975fd0b74Schristos   struct check_refs_info info;
62075fd0b74Schristos 
62175fd0b74Schristos   /* We need to look through the relocations for this BFD, to see
62275fd0b74Schristos      if any of the relocations which refer to this symbol are from
62375fd0b74Schristos      a prohibited section.  Note that we need to do this even for
62475fd0b74Schristos      the BFD in which the symbol is defined, since even a single
62575fd0b74Schristos      BFD might contain a prohibited cross reference.  */
62675fd0b74Schristos 
62775fd0b74Schristos   if (!bfd_generic_link_read_symbols (abfd))
628ede78133Schristos     einfo (_("%F%P: %pB: could not read symbols: %E\n"), abfd);
62975fd0b74Schristos 
63075fd0b74Schristos   info.sym_name = name;
63175fd0b74Schristos   info.global = global;
63275fd0b74Schristos   info.defsec = sec;
63375fd0b74Schristos   info.ncrs = ncrs;
63475fd0b74Schristos   info.asymbols = bfd_get_outsymbols (abfd);
63575fd0b74Schristos   bfd_map_over_sections (abfd, check_reloc_refs, &info);
63675fd0b74Schristos }
63775fd0b74Schristos 
63875fd0b74Schristos /* This is called via bfd_map_over_sections.  INFO->SYM_NAME is a symbol
63975fd0b74Schristos    defined in INFO->DEFSECNAME.  If this section maps into any of the
64075fd0b74Schristos    sections listed in INFO->NCRS, other than INFO->DEFSECNAME, then we
64175fd0b74Schristos    look through the relocations.  If any of the relocations are to
64275fd0b74Schristos    INFO->SYM_NAME, then we report a prohibited cross reference error.  */
64375fd0b74Schristos 
64475fd0b74Schristos static void
check_reloc_refs(bfd * abfd,asection * sec,void * iarg)64575fd0b74Schristos check_reloc_refs (bfd *abfd, asection *sec, void *iarg)
64675fd0b74Schristos {
64775fd0b74Schristos   struct check_refs_info *info = (struct check_refs_info *) iarg;
64875fd0b74Schristos   asection *outsec;
64975fd0b74Schristos   const char *outsecname;
65075fd0b74Schristos   asection *outdefsec;
65175fd0b74Schristos   const char *outdefsecname;
65275fd0b74Schristos   struct lang_nocrossref *ncr;
65375fd0b74Schristos   const char *symname;
654*e992f068Schristos   bool global;
65575fd0b74Schristos   long relsize;
65675fd0b74Schristos   arelent **relpp;
65775fd0b74Schristos   long relcount;
65875fd0b74Schristos   arelent **p, **pend;
65975fd0b74Schristos 
66075fd0b74Schristos   outsec = sec->output_section;
661012573ebSchristos   outsecname = bfd_section_name (outsec);
66275fd0b74Schristos 
66375fd0b74Schristos   outdefsec = info->defsec->output_section;
664012573ebSchristos   outdefsecname = bfd_section_name (outdefsec);
66575fd0b74Schristos 
66675fd0b74Schristos   /* The section where the symbol is defined is permitted.  */
66775fd0b74Schristos   if (strcmp (outsecname, outdefsecname) == 0)
66875fd0b74Schristos     return;
66975fd0b74Schristos 
67075fd0b74Schristos   for (ncr = info->ncrs->list; ncr != NULL; ncr = ncr->next)
67175fd0b74Schristos     if (strcmp (outsecname, ncr->name) == 0)
67275fd0b74Schristos       break;
67375fd0b74Schristos 
67475fd0b74Schristos   if (ncr == NULL)
67575fd0b74Schristos     return;
67675fd0b74Schristos 
67775fd0b74Schristos   /* This section is one for which cross references are prohibited.
67875fd0b74Schristos      Look through the relocations, and see if any of them are to
67975fd0b74Schristos      INFO->SYM_NAME.  If INFO->SYMNAME is NULL, check for relocations
68075fd0b74Schristos      against the section symbol.  If INFO->GLOBAL is TRUE, the
68175fd0b74Schristos      definition is global, check for relocations against the global
68275fd0b74Schristos      symbols.  Otherwise check for relocations against the local and
68375fd0b74Schristos      section symbols.  */
68475fd0b74Schristos 
68575fd0b74Schristos   symname = info->sym_name;
68675fd0b74Schristos   global = info->global;
68775fd0b74Schristos 
68875fd0b74Schristos   relsize = bfd_get_reloc_upper_bound (abfd, sec);
68975fd0b74Schristos   if (relsize < 0)
690ede78133Schristos     einfo (_("%F%P: %pB: could not read relocs: %E\n"), abfd);
69175fd0b74Schristos   if (relsize == 0)
69275fd0b74Schristos     return;
69375fd0b74Schristos 
69475fd0b74Schristos   relpp = (arelent **) xmalloc (relsize);
69575fd0b74Schristos   relcount = bfd_canonicalize_reloc (abfd, sec, relpp, info->asymbols);
69675fd0b74Schristos   if (relcount < 0)
697ede78133Schristos     einfo (_("%F%P: %pB: could not read relocs: %E\n"), abfd);
69875fd0b74Schristos 
69975fd0b74Schristos   p = relpp;
70075fd0b74Schristos   pend = p + relcount;
70175fd0b74Schristos   for (; p < pend && *p != NULL; p++)
70275fd0b74Schristos     {
70375fd0b74Schristos       arelent *q = *p;
70475fd0b74Schristos 
70575fd0b74Schristos       if (q->sym_ptr_ptr != NULL
70675fd0b74Schristos 	  && *q->sym_ptr_ptr != NULL
70775fd0b74Schristos 	  && ((global
708012573ebSchristos 	       && (bfd_is_und_section (bfd_asymbol_section (*q->sym_ptr_ptr))
709012573ebSchristos 		   || bfd_is_com_section (bfd_asymbol_section (*q->sym_ptr_ptr))
71075fd0b74Schristos 		   || ((*q->sym_ptr_ptr)->flags & (BSF_GLOBAL
71175fd0b74Schristos 						   | BSF_WEAK)) != 0))
71275fd0b74Schristos 	      || (!global
71375fd0b74Schristos 		  && ((*q->sym_ptr_ptr)->flags & (BSF_LOCAL
71475fd0b74Schristos 						  | BSF_SECTION_SYM)) != 0
715012573ebSchristos 		  && bfd_asymbol_section (*q->sym_ptr_ptr) == info->defsec))
71675fd0b74Schristos 	  && (symname != NULL
71775fd0b74Schristos 	      ? strcmp (bfd_asymbol_name (*q->sym_ptr_ptr), symname) == 0
71875fd0b74Schristos 	      : ((*q->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0))
71975fd0b74Schristos 	{
72075fd0b74Schristos 	  /* We found a reloc for the symbol.  The symbol is defined
72175fd0b74Schristos 	     in OUTSECNAME.  This reloc is from a section which is
72275fd0b74Schristos 	     mapped into a section from which references to OUTSECNAME
72375fd0b74Schristos 	     are prohibited.  We must report an error.  */
724ede78133Schristos 	  einfo (_("%X%P: %C: prohibited cross reference from %s to `%pT' in %s\n"),
72575fd0b74Schristos 		 abfd, sec, q->address, outsecname,
72675fd0b74Schristos 		 bfd_asymbol_name (*q->sym_ptr_ptr), outdefsecname);
72775fd0b74Schristos 	}
72875fd0b74Schristos     }
72975fd0b74Schristos 
73075fd0b74Schristos   free (relpp);
73175fd0b74Schristos }
732