Home | History | Annotate | Line # | Download | only in ld
ldcref.c revision 1.8
      1  1.1  christos /* ldcref.c -- output a cross reference table
      2  1.8  christos    Copyright (C) 1996-2022 Free Software Foundation, Inc.
      3  1.1  christos    Written by Ian Lance Taylor <ian (at) cygnus.com>
      4  1.1  christos 
      5  1.1  christos    This file is part of the GNU Binutils.
      6  1.1  christos 
      7  1.1  christos    This program is free software; you can redistribute it and/or modify
      8  1.1  christos    it under the terms of the GNU General Public License as published by
      9  1.1  christos    the Free Software Foundation; either version 3 of the License, or
     10  1.1  christos    (at your option) any later version.
     11  1.1  christos 
     12  1.1  christos    This program is distributed in the hope that it will be useful,
     13  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  1.1  christos    GNU General Public License for more details.
     16  1.1  christos 
     17  1.1  christos    You should have received a copy of the GNU General Public License
     18  1.1  christos    along with this program; if not, write to the Free Software
     19  1.1  christos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     20  1.1  christos    MA 02110-1301, USA.  */
     21  1.1  christos 
     22  1.1  christos 
     23  1.1  christos /* This file holds routines that manage the cross reference table.
     24  1.1  christos    The table is used to generate cross reference reports.  It is also
     25  1.1  christos    used to implement the NOCROSSREFS command in the linker script.  */
     26  1.1  christos 
     27  1.1  christos #include "sysdep.h"
     28  1.1  christos #include "bfd.h"
     29  1.1  christos #include "bfdlink.h"
     30  1.7  christos #include "ctf-api.h"
     31  1.1  christos #include "libiberty.h"
     32  1.1  christos #include "demangle.h"
     33  1.1  christos #include "objalloc.h"
     34  1.1  christos 
     35  1.1  christos #include "ld.h"
     36  1.1  christos #include "ldmain.h"
     37  1.1  christos #include "ldmisc.h"
     38  1.1  christos #include "ldexp.h"
     39  1.1  christos #include "ldlang.h"
     40  1.1  christos 
     41  1.1  christos /* We keep an instance of this structure for each reference to a
     42  1.1  christos    symbol from a given object.  */
     43  1.1  christos 
     44  1.3  christos struct cref_ref
     45  1.3  christos {
     46  1.1  christos   /* The next reference.  */
     47  1.1  christos   struct cref_ref *next;
     48  1.1  christos   /* The object.  */
     49  1.1  christos   bfd *abfd;
     50  1.1  christos   /* True if the symbol is defined.  */
     51  1.1  christos   unsigned int def : 1;
     52  1.1  christos   /* True if the symbol is common.  */
     53  1.1  christos   unsigned int common : 1;
     54  1.1  christos   /* True if the symbol is undefined.  */
     55  1.1  christos   unsigned int undef : 1;
     56  1.1  christos };
     57  1.1  christos 
     58  1.1  christos /* We keep a hash table of symbols.  Each entry looks like this.  */
     59  1.1  christos 
     60  1.3  christos struct cref_hash_entry
     61  1.3  christos {
     62  1.1  christos   struct bfd_hash_entry root;
     63  1.1  christos   /* The demangled name.  */
     64  1.1  christos   const char *demangled;
     65  1.1  christos   /* References to and definitions of this symbol.  */
     66  1.1  christos   struct cref_ref *refs;
     67  1.1  christos };
     68  1.1  christos 
     69  1.1  christos /* This is what the hash table looks like.  */
     70  1.1  christos 
     71  1.3  christos struct cref_hash_table
     72  1.3  christos {
     73  1.1  christos   struct bfd_hash_table root;
     74  1.1  christos };
     75  1.1  christos 
     76  1.1  christos /* Forward declarations.  */
     77  1.1  christos 
     78  1.1  christos static void output_one_cref (FILE *, struct cref_hash_entry *);
     79  1.1  christos static void check_local_sym_xref (lang_input_statement_type *);
     80  1.8  christos static bool check_nocrossref (struct cref_hash_entry *, void *);
     81  1.8  christos static void check_refs (const char *, bool, asection *, bfd *,
     82  1.1  christos 			struct lang_nocrossrefs *);
     83  1.1  christos static void check_reloc_refs (bfd *, asection *, void *);
     84  1.1  christos 
     85  1.1  christos /* Look up an entry in the cref hash table.  */
     86  1.1  christos 
     87  1.1  christos #define cref_hash_lookup(table, string, create, copy)		\
     88  1.1  christos   ((struct cref_hash_entry *)					\
     89  1.1  christos    bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
     90  1.1  christos 
     91  1.1  christos /* Traverse the cref hash table.  */
     92  1.1  christos 
     93  1.1  christos #define cref_hash_traverse(table, func, info)				\
     94  1.1  christos   (bfd_hash_traverse							\
     95  1.1  christos    (&(table)->root,							\
     96  1.8  christos     (bool (*) (struct bfd_hash_entry *, void *)) (func), (info)))
     97  1.1  christos 
     98  1.1  christos /* The cref hash table.  */
     99  1.1  christos 
    100  1.1  christos static struct cref_hash_table cref_table;
    101  1.1  christos 
    102  1.1  christos /* Whether the cref hash table has been initialized.  */
    103  1.1  christos 
    104  1.8  christos static bool cref_initialized;
    105  1.1  christos 
    106  1.1  christos /* The number of symbols seen so far.  */
    107  1.1  christos 
    108  1.1  christos static size_t cref_symcount;
    109  1.1  christos 
    110  1.1  christos /* Used to take a snapshot of the cref hash table when starting to
    111  1.1  christos    add syms from an as-needed library.  */
    112  1.1  christos static struct bfd_hash_entry **old_table;
    113  1.1  christos static unsigned int old_size;
    114  1.1  christos static unsigned int old_count;
    115  1.5  christos static void *old_tab;
    116  1.5  christos static void *alloc_mark;
    117  1.1  christos static size_t tabsize, entsize, refsize;
    118  1.1  christos static size_t old_symcount;
    119  1.1  christos 
    120  1.1  christos /* Create an entry in a cref hash table.  */
    121  1.1  christos 
    122  1.1  christos static struct bfd_hash_entry *
    123  1.1  christos cref_hash_newfunc (struct bfd_hash_entry *entry,
    124  1.1  christos 		   struct bfd_hash_table *table,
    125  1.1  christos 		   const char *string)
    126  1.1  christos {
    127  1.1  christos   struct cref_hash_entry *ret = (struct cref_hash_entry *) entry;
    128  1.1  christos 
    129  1.1  christos   /* Allocate the structure if it has not already been allocated by a
    130  1.1  christos      subclass.  */
    131  1.1  christos   if (ret == NULL)
    132  1.1  christos     ret = ((struct cref_hash_entry *)
    133  1.1  christos 	   bfd_hash_allocate (table, sizeof (struct cref_hash_entry)));
    134  1.1  christos   if (ret == NULL)
    135  1.1  christos     return NULL;
    136  1.1  christos 
    137  1.1  christos   /* Call the allocation method of the superclass.  */
    138  1.1  christos   ret = ((struct cref_hash_entry *)
    139  1.1  christos 	 bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
    140  1.1  christos   if (ret != NULL)
    141  1.1  christos     {
    142  1.1  christos       /* Set local fields.  */
    143  1.1  christos       ret->demangled = NULL;
    144  1.1  christos       ret->refs = NULL;
    145  1.1  christos 
    146  1.1  christos       /* Keep a count of the number of entries created in the hash
    147  1.1  christos 	 table.  */
    148  1.1  christos       ++cref_symcount;
    149  1.1  christos     }
    150  1.1  christos 
    151  1.1  christos   return &ret->root;
    152  1.1  christos }
    153  1.1  christos 
    154  1.1  christos /* Add a symbol to the cref hash table.  This is called for every
    155  1.1  christos    global symbol that is seen during the link.  */
    156  1.1  christos 
    157  1.1  christos void
    158  1.1  christos add_cref (const char *name,
    159  1.1  christos 	  bfd *abfd,
    160  1.1  christos 	  asection *section,
    161  1.1  christos 	  bfd_vma value ATTRIBUTE_UNUSED)
    162  1.1  christos {
    163  1.1  christos   struct cref_hash_entry *h;
    164  1.1  christos   struct cref_ref *r;
    165  1.1  christos 
    166  1.5  christos   if (!cref_initialized)
    167  1.1  christos     {
    168  1.1  christos       if (!bfd_hash_table_init (&cref_table.root, cref_hash_newfunc,
    169  1.1  christos 				sizeof (struct cref_hash_entry)))
    170  1.1  christos 	einfo (_("%X%P: bfd_hash_table_init of cref table failed: %E\n"));
    171  1.8  christos       cref_initialized = true;
    172  1.1  christos     }
    173  1.1  christos 
    174  1.8  christos   h = cref_hash_lookup (&cref_table, name, true, false);
    175  1.1  christos   if (h == NULL)
    176  1.1  christos     einfo (_("%X%P: cref_hash_lookup failed: %E\n"));
    177  1.1  christos 
    178  1.1  christos   for (r = h->refs; r != NULL; r = r->next)
    179  1.1  christos     if (r->abfd == abfd)
    180  1.1  christos       break;
    181  1.1  christos 
    182  1.1  christos   if (r == NULL)
    183  1.1  christos     {
    184  1.1  christos       r = (struct cref_ref *) bfd_hash_allocate (&cref_table.root, sizeof *r);
    185  1.1  christos       if (r == NULL)
    186  1.1  christos 	einfo (_("%X%P: cref alloc failed: %E\n"));
    187  1.1  christos       r->next = h->refs;
    188  1.1  christos       h->refs = r;
    189  1.1  christos       r->abfd = abfd;
    190  1.8  christos       r->def = false;
    191  1.8  christos       r->common = false;
    192  1.8  christos       r->undef = false;
    193  1.1  christos     }
    194  1.1  christos 
    195  1.1  christos   if (bfd_is_und_section (section))
    196  1.8  christos     r->undef = true;
    197  1.1  christos   else if (bfd_is_com_section (section))
    198  1.8  christos     r->common = true;
    199  1.1  christos   else
    200  1.8  christos     r->def = true;
    201  1.1  christos }
    202  1.1  christos 
    203  1.1  christos /* Called before loading an as-needed library to take a snapshot of
    204  1.1  christos    the cref hash table, and after we have loaded or found that the
    205  1.1  christos    library was not needed.  */
    206  1.1  christos 
    207  1.8  christos bool
    208  1.1  christos handle_asneeded_cref (bfd *abfd ATTRIBUTE_UNUSED,
    209  1.1  christos 		      enum notice_asneeded_action act)
    210  1.1  christos {
    211  1.1  christos   unsigned int i;
    212  1.1  christos 
    213  1.1  christos   if (!cref_initialized)
    214  1.8  christos     return true;
    215  1.1  christos 
    216  1.1  christos   if (act == notice_as_needed)
    217  1.1  christos     {
    218  1.1  christos       char *old_ent, *old_ref;
    219  1.1  christos 
    220  1.1  christos       for (i = 0; i < cref_table.root.size; i++)
    221  1.1  christos 	{
    222  1.1  christos 	  struct bfd_hash_entry *p;
    223  1.1  christos 	  struct cref_hash_entry *c;
    224  1.1  christos 	  struct cref_ref *r;
    225  1.1  christos 
    226  1.1  christos 	  for (p = cref_table.root.table[i]; p != NULL; p = p->next)
    227  1.1  christos 	    {
    228  1.1  christos 	      entsize += cref_table.root.entsize;
    229  1.1  christos 	      c = (struct cref_hash_entry *) p;
    230  1.1  christos 	      for (r = c->refs; r != NULL; r = r->next)
    231  1.1  christos 		refsize += sizeof (struct cref_ref);
    232  1.1  christos 	    }
    233  1.1  christos 	}
    234  1.1  christos 
    235  1.1  christos       tabsize = cref_table.root.size * sizeof (struct bfd_hash_entry *);
    236  1.1  christos       old_tab = xmalloc (tabsize + entsize + refsize);
    237  1.1  christos 
    238  1.1  christos       alloc_mark = bfd_hash_allocate (&cref_table.root, 1);
    239  1.1  christos       if (alloc_mark == NULL)
    240  1.8  christos 	return false;
    241  1.1  christos 
    242  1.1  christos       memcpy (old_tab, cref_table.root.table, tabsize);
    243  1.1  christos       old_ent = (char *) old_tab + tabsize;
    244  1.1  christos       old_ref = (char *) old_ent + entsize;
    245  1.1  christos       old_table = cref_table.root.table;
    246  1.1  christos       old_size = cref_table.root.size;
    247  1.1  christos       old_count = cref_table.root.count;
    248  1.1  christos       old_symcount = cref_symcount;
    249  1.1  christos 
    250  1.1  christos       for (i = 0; i < cref_table.root.size; i++)
    251  1.1  christos 	{
    252  1.1  christos 	  struct bfd_hash_entry *p;
    253  1.1  christos 	  struct cref_hash_entry *c;
    254  1.1  christos 	  struct cref_ref *r;
    255  1.1  christos 
    256  1.1  christos 	  for (p = cref_table.root.table[i]; p != NULL; p = p->next)
    257  1.1  christos 	    {
    258  1.1  christos 	      memcpy (old_ent, p, cref_table.root.entsize);
    259  1.1  christos 	      old_ent = (char *) old_ent + cref_table.root.entsize;
    260  1.1  christos 	      c = (struct cref_hash_entry *) p;
    261  1.1  christos 	      for (r = c->refs; r != NULL; r = r->next)
    262  1.1  christos 		{
    263  1.1  christos 		  memcpy (old_ref, r, sizeof (struct cref_ref));
    264  1.1  christos 		  old_ref = (char *) old_ref + sizeof (struct cref_ref);
    265  1.1  christos 		}
    266  1.1  christos 	    }
    267  1.1  christos 	}
    268  1.8  christos       return true;
    269  1.1  christos     }
    270  1.1  christos 
    271  1.1  christos   if (act == notice_not_needed)
    272  1.1  christos     {
    273  1.1  christos       char *old_ent, *old_ref;
    274  1.1  christos 
    275  1.1  christos       if (old_tab == NULL)
    276  1.1  christos 	{
    277  1.1  christos 	  /* The only way old_tab can be NULL is if the cref hash table
    278  1.1  christos 	     had not been initialised when notice_as_needed.  */
    279  1.1  christos 	  bfd_hash_table_free (&cref_table.root);
    280  1.8  christos 	  cref_initialized = false;
    281  1.8  christos 	  return true;
    282  1.1  christos 	}
    283  1.1  christos 
    284  1.1  christos       old_ent = (char *) old_tab + tabsize;
    285  1.1  christos       old_ref = (char *) old_ent + entsize;
    286  1.1  christos       cref_table.root.table = old_table;
    287  1.1  christos       cref_table.root.size = old_size;
    288  1.1  christos       cref_table.root.count = old_count;
    289  1.1  christos       memcpy (cref_table.root.table, old_tab, tabsize);
    290  1.1  christos       cref_symcount = old_symcount;
    291  1.1  christos 
    292  1.1  christos       for (i = 0; i < cref_table.root.size; i++)
    293  1.1  christos 	{
    294  1.1  christos 	  struct bfd_hash_entry *p;
    295  1.1  christos 	  struct cref_hash_entry *c;
    296  1.1  christos 	  struct cref_ref *r;
    297  1.1  christos 
    298  1.1  christos 	  for (p = cref_table.root.table[i]; p != NULL; p = p->next)
    299  1.1  christos 	    {
    300  1.1  christos 	      memcpy (p, old_ent, cref_table.root.entsize);
    301  1.1  christos 	      old_ent = (char *) old_ent + cref_table.root.entsize;
    302  1.1  christos 	      c = (struct cref_hash_entry *) p;
    303  1.1  christos 	      for (r = c->refs; r != NULL; r = r->next)
    304  1.1  christos 		{
    305  1.1  christos 		  memcpy (r, old_ref, sizeof (struct cref_ref));
    306  1.1  christos 		  old_ref = (char *) old_ref + sizeof (struct cref_ref);
    307  1.1  christos 		}
    308  1.1  christos 	    }
    309  1.1  christos 	}
    310  1.1  christos 
    311  1.1  christos       objalloc_free_block ((struct objalloc *) cref_table.root.memory,
    312  1.1  christos 			   alloc_mark);
    313  1.1  christos     }
    314  1.1  christos   else if (act != notice_needed)
    315  1.8  christos     return false;
    316  1.1  christos 
    317  1.1  christos   free (old_tab);
    318  1.1  christos   old_tab = NULL;
    319  1.8  christos   return true;
    320  1.1  christos }
    321  1.1  christos 
    322  1.1  christos /* Copy the addresses of the hash table entries into an array.  This
    323  1.1  christos    is called via cref_hash_traverse.  We also fill in the demangled
    324  1.1  christos    name.  */
    325  1.1  christos 
    326  1.8  christos static bool
    327  1.1  christos cref_fill_array (struct cref_hash_entry *h, void *data)
    328  1.1  christos {
    329  1.1  christos   struct cref_hash_entry ***pph = (struct cref_hash_entry ***) data;
    330  1.1  christos 
    331  1.1  christos   ASSERT (h->demangled == NULL);
    332  1.1  christos   h->demangled = bfd_demangle (link_info.output_bfd, h->root.string,
    333  1.1  christos 			       DMGL_ANSI | DMGL_PARAMS);
    334  1.1  christos   if (h->demangled == NULL)
    335  1.1  christos     h->demangled = h->root.string;
    336  1.1  christos 
    337  1.1  christos   **pph = h;
    338  1.1  christos 
    339  1.1  christos   ++*pph;
    340  1.1  christos 
    341  1.8  christos   return true;
    342  1.1  christos }
    343  1.1  christos 
    344  1.1  christos /* Sort an array of cref hash table entries by name.  */
    345  1.1  christos 
    346  1.1  christos static int
    347  1.1  christos cref_sort_array (const void *a1, const void *a2)
    348  1.1  christos {
    349  1.5  christos   const struct cref_hash_entry *const *p1
    350  1.5  christos     = (const struct cref_hash_entry *const *) a1;
    351  1.5  christos   const struct cref_hash_entry *const *p2
    352  1.5  christos     = (const struct cref_hash_entry *const *) a2;
    353  1.1  christos 
    354  1.3  christos   if (demangling)
    355  1.3  christos     return strcmp ((*p1)->demangled, (*p2)->demangled);
    356  1.3  christos   else
    357  1.3  christos     return strcmp ((*p1)->root.string, (*p2)->root.string);
    358  1.1  christos }
    359  1.1  christos 
    360  1.1  christos /* Write out the cref table.  */
    361  1.1  christos 
    362  1.1  christos #define FILECOL (50)
    363  1.1  christos 
    364  1.1  christos void
    365  1.1  christos output_cref (FILE *fp)
    366  1.1  christos {
    367  1.1  christos   int len;
    368  1.1  christos   struct cref_hash_entry **csyms, **csym_fill, **csym, **csym_end;
    369  1.1  christos   const char *msg;
    370  1.1  christos 
    371  1.1  christos   fprintf (fp, _("\nCross Reference Table\n\n"));
    372  1.1  christos   msg = _("Symbol");
    373  1.1  christos   fprintf (fp, "%s", msg);
    374  1.1  christos   len = strlen (msg);
    375  1.1  christos   while (len < FILECOL)
    376  1.1  christos     {
    377  1.1  christos       putc (' ', fp);
    378  1.1  christos       ++len;
    379  1.1  christos     }
    380  1.1  christos   fprintf (fp, _("File\n"));
    381  1.1  christos 
    382  1.5  christos   if (!cref_initialized)
    383  1.1  christos     {
    384  1.1  christos       fprintf (fp, _("No symbols\n"));
    385  1.1  christos       return;
    386  1.1  christos     }
    387  1.1  christos 
    388  1.1  christos   csyms = (struct cref_hash_entry **) xmalloc (cref_symcount * sizeof (*csyms));
    389  1.1  christos 
    390  1.1  christos   csym_fill = csyms;
    391  1.1  christos   cref_hash_traverse (&cref_table, cref_fill_array, &csym_fill);
    392  1.1  christos   ASSERT ((size_t) (csym_fill - csyms) == cref_symcount);
    393  1.1  christos 
    394  1.1  christos   qsort (csyms, cref_symcount, sizeof (*csyms), cref_sort_array);
    395  1.1  christos 
    396  1.1  christos   csym_end = csyms + cref_symcount;
    397  1.1  christos   for (csym = csyms; csym < csym_end; csym++)
    398  1.1  christos     output_one_cref (fp, *csym);
    399  1.1  christos }
    400  1.1  christos 
    401  1.1  christos /* Output one entry in the cross reference table.  */
    402  1.1  christos 
    403  1.1  christos static void
    404  1.1  christos output_one_cref (FILE *fp, struct cref_hash_entry *h)
    405  1.1  christos {
    406  1.1  christos   int len;
    407  1.1  christos   struct bfd_link_hash_entry *hl;
    408  1.1  christos   struct cref_ref *r;
    409  1.1  christos 
    410  1.8  christos   hl = bfd_link_hash_lookup (link_info.hash, h->root.string, false,
    411  1.8  christos 			     false, true);
    412  1.1  christos   if (hl == NULL)
    413  1.6  christos     einfo (_("%P: symbol `%pT' missing from main hash table\n"),
    414  1.1  christos 	   h->root.string);
    415  1.1  christos   else
    416  1.1  christos     {
    417  1.1  christos       /* If this symbol is defined in a dynamic object but never
    418  1.1  christos 	 referenced by a normal object, then don't print it.  */
    419  1.1  christos       if (hl->type == bfd_link_hash_defined)
    420  1.1  christos 	{
    421  1.1  christos 	  if (hl->u.def.section->output_section == NULL)
    422  1.1  christos 	    return;
    423  1.1  christos 	  if (hl->u.def.section->owner != NULL
    424  1.1  christos 	      && (hl->u.def.section->owner->flags & DYNAMIC) != 0)
    425  1.1  christos 	    {
    426  1.1  christos 	      for (r = h->refs; r != NULL; r = r->next)
    427  1.1  christos 		if ((r->abfd->flags & DYNAMIC) == 0)
    428  1.1  christos 		  break;
    429  1.1  christos 	      if (r == NULL)
    430  1.1  christos 		return;
    431  1.1  christos 	    }
    432  1.1  christos 	}
    433  1.1  christos     }
    434  1.1  christos 
    435  1.3  christos   if (demangling)
    436  1.3  christos     {
    437  1.3  christos       fprintf (fp, "%s ", h->demangled);
    438  1.3  christos       len = strlen (h->demangled) + 1;
    439  1.3  christos     }
    440  1.3  christos   else
    441  1.3  christos     {
    442  1.3  christos       fprintf (fp, "%s ", h->root.string);
    443  1.3  christos       len = strlen (h->root.string) + 1;
    444  1.3  christos     }
    445  1.1  christos 
    446  1.1  christos   for (r = h->refs; r != NULL; r = r->next)
    447  1.1  christos     {
    448  1.1  christos       if (r->def)
    449  1.1  christos 	{
    450  1.1  christos 	  while (len < FILECOL)
    451  1.1  christos 	    {
    452  1.1  christos 	      putc (' ', fp);
    453  1.1  christos 	      ++len;
    454  1.1  christos 	    }
    455  1.6  christos 	  lfinfo (fp, "%pB\n", r->abfd);
    456  1.1  christos 	  len = 0;
    457  1.1  christos 	}
    458  1.1  christos     }
    459  1.1  christos 
    460  1.1  christos   for (r = h->refs; r != NULL; r = r->next)
    461  1.1  christos     {
    462  1.3  christos       if (r->common)
    463  1.3  christos 	{
    464  1.3  christos 	  while (len < FILECOL)
    465  1.3  christos 	    {
    466  1.3  christos 	      putc (' ', fp);
    467  1.3  christos 	      ++len;
    468  1.3  christos 	    }
    469  1.6  christos 	  lfinfo (fp, "%pB\n", r->abfd);
    470  1.3  christos 	  len = 0;
    471  1.3  christos 	}
    472  1.3  christos     }
    473  1.3  christos 
    474  1.3  christos   for (r = h->refs; r != NULL; r = r->next)
    475  1.3  christos     {
    476  1.5  christos       if (!r->def && !r->common)
    477  1.1  christos 	{
    478  1.1  christos 	  while (len < FILECOL)
    479  1.1  christos 	    {
    480  1.1  christos 	      putc (' ', fp);
    481  1.1  christos 	      ++len;
    482  1.1  christos 	    }
    483  1.6  christos 	  lfinfo (fp, "%pB\n", r->abfd);
    484  1.1  christos 	  len = 0;
    485  1.1  christos 	}
    486  1.1  christos     }
    487  1.1  christos 
    488  1.1  christos   ASSERT (len == 0);
    489  1.1  christos }
    490  1.1  christos 
    491  1.1  christos /* Check for prohibited cross references.  */
    492  1.1  christos 
    493  1.1  christos void
    494  1.1  christos check_nocrossrefs (void)
    495  1.1  christos {
    496  1.5  christos   if (!cref_initialized)
    497  1.1  christos     return;
    498  1.1  christos 
    499  1.1  christos   cref_hash_traverse (&cref_table, check_nocrossref, NULL);
    500  1.1  christos 
    501  1.1  christos   lang_for_each_file (check_local_sym_xref);
    502  1.1  christos }
    503  1.1  christos 
    504  1.1  christos /* Check for prohibited cross references to local and section symbols.  */
    505  1.1  christos 
    506  1.1  christos static void
    507  1.1  christos check_local_sym_xref (lang_input_statement_type *statement)
    508  1.1  christos {
    509  1.1  christos   bfd *abfd;
    510  1.1  christos   asymbol **syms;
    511  1.1  christos 
    512  1.1  christos   abfd = statement->the_bfd;
    513  1.1  christos   if (abfd == NULL)
    514  1.1  christos     return;
    515  1.1  christos 
    516  1.1  christos   if (!bfd_generic_link_read_symbols (abfd))
    517  1.6  christos     einfo (_("%F%P: %pB: could not read symbols: %E\n"), abfd);
    518  1.1  christos 
    519  1.1  christos   for (syms = bfd_get_outsymbols (abfd); *syms; ++syms)
    520  1.1  christos     {
    521  1.1  christos       asymbol *sym = *syms;
    522  1.1  christos       if (sym->flags & (BSF_GLOBAL | BSF_WARNING | BSF_INDIRECT | BSF_FILE))
    523  1.1  christos 	continue;
    524  1.1  christos       if ((sym->flags & (BSF_LOCAL | BSF_SECTION_SYM)) != 0
    525  1.1  christos 	  && sym->section->output_section != NULL)
    526  1.1  christos 	{
    527  1.1  christos 	  const char *outsecname, *symname;
    528  1.1  christos 	  struct lang_nocrossrefs *ncrs;
    529  1.1  christos 	  struct lang_nocrossref *ncr;
    530  1.1  christos 
    531  1.1  christos 	  outsecname = sym->section->output_section->name;
    532  1.1  christos 	  symname = NULL;
    533  1.1  christos 	  if ((sym->flags & BSF_SECTION_SYM) == 0)
    534  1.1  christos 	    symname = sym->name;
    535  1.1  christos 	  for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next)
    536  1.1  christos 	    for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next)
    537  1.5  christos 	      {
    538  1.5  christos 		if (strcmp (ncr->name, outsecname) == 0)
    539  1.8  christos 		  check_refs (symname, false, sym->section, abfd, ncrs);
    540  1.5  christos 		/* The NOCROSSREFS_TO command only checks symbols defined in
    541  1.5  christos 		   the first section in the list.  */
    542  1.5  christos 		if (ncrs->onlyfirst)
    543  1.5  christos 		  break;
    544  1.5  christos 	      }
    545  1.1  christos 	}
    546  1.1  christos     }
    547  1.1  christos }
    548  1.1  christos 
    549  1.1  christos /* Check one symbol to see if it is a prohibited cross reference.  */
    550  1.1  christos 
    551  1.8  christos static bool
    552  1.1  christos check_nocrossref (struct cref_hash_entry *h, void *ignore ATTRIBUTE_UNUSED)
    553  1.1  christos {
    554  1.1  christos   struct bfd_link_hash_entry *hl;
    555  1.1  christos   asection *defsec;
    556  1.1  christos   const char *defsecname;
    557  1.1  christos   struct lang_nocrossrefs *ncrs;
    558  1.1  christos   struct lang_nocrossref *ncr;
    559  1.1  christos   struct cref_ref *ref;
    560  1.1  christos 
    561  1.8  christos   hl = bfd_link_hash_lookup (link_info.hash, h->root.string, false,
    562  1.8  christos 			     false, true);
    563  1.1  christos   if (hl == NULL)
    564  1.1  christos     {
    565  1.6  christos       einfo (_("%P: symbol `%pT' missing from main hash table\n"),
    566  1.1  christos 	     h->root.string);
    567  1.8  christos       return true;
    568  1.1  christos     }
    569  1.1  christos 
    570  1.1  christos   if (hl->type != bfd_link_hash_defined
    571  1.1  christos       && hl->type != bfd_link_hash_defweak)
    572  1.8  christos     return true;
    573  1.1  christos 
    574  1.1  christos   defsec = hl->u.def.section->output_section;
    575  1.1  christos   if (defsec == NULL)
    576  1.8  christos     return true;
    577  1.7  christos   defsecname = bfd_section_name (defsec);
    578  1.1  christos 
    579  1.1  christos   for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next)
    580  1.1  christos     for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next)
    581  1.5  christos       {
    582  1.5  christos 	if (strcmp (ncr->name, defsecname) == 0)
    583  1.5  christos 	  for (ref = h->refs; ref != NULL; ref = ref->next)
    584  1.8  christos 	    check_refs (hl->root.string, true, hl->u.def.section,
    585  1.5  christos 			ref->abfd, ncrs);
    586  1.5  christos 	/* The NOCROSSREFS_TO command only checks symbols defined in the first
    587  1.5  christos 	   section in the list.  */
    588  1.5  christos 	if (ncrs->onlyfirst)
    589  1.5  christos 	  break;
    590  1.5  christos       }
    591  1.1  christos 
    592  1.8  christos   return true;
    593  1.1  christos }
    594  1.1  christos 
    595  1.1  christos /* The struct is used to pass information from check_refs to
    596  1.1  christos    check_reloc_refs through bfd_map_over_sections.  */
    597  1.1  christos 
    598  1.5  christos struct check_refs_info
    599  1.5  christos {
    600  1.1  christos   const char *sym_name;
    601  1.1  christos   asection *defsec;
    602  1.1  christos   struct lang_nocrossrefs *ncrs;
    603  1.1  christos   asymbol **asymbols;
    604  1.8  christos   bool global;
    605  1.1  christos };
    606  1.1  christos 
    607  1.1  christos /* This function is called for each symbol defined in a section which
    608  1.1  christos    prohibits cross references.  We need to look through all references
    609  1.1  christos    to this symbol, and ensure that the references are not from
    610  1.1  christos    prohibited sections.  */
    611  1.1  christos 
    612  1.1  christos static void
    613  1.1  christos check_refs (const char *name,
    614  1.8  christos 	    bool global,
    615  1.1  christos 	    asection *sec,
    616  1.1  christos 	    bfd *abfd,
    617  1.1  christos 	    struct lang_nocrossrefs *ncrs)
    618  1.1  christos {
    619  1.1  christos   struct check_refs_info info;
    620  1.1  christos 
    621  1.1  christos   /* We need to look through the relocations for this BFD, to see
    622  1.1  christos      if any of the relocations which refer to this symbol are from
    623  1.1  christos      a prohibited section.  Note that we need to do this even for
    624  1.1  christos      the BFD in which the symbol is defined, since even a single
    625  1.1  christos      BFD might contain a prohibited cross reference.  */
    626  1.1  christos 
    627  1.1  christos   if (!bfd_generic_link_read_symbols (abfd))
    628  1.6  christos     einfo (_("%F%P: %pB: could not read symbols: %E\n"), abfd);
    629  1.1  christos 
    630  1.1  christos   info.sym_name = name;
    631  1.1  christos   info.global = global;
    632  1.1  christos   info.defsec = sec;
    633  1.1  christos   info.ncrs = ncrs;
    634  1.1  christos   info.asymbols = bfd_get_outsymbols (abfd);
    635  1.1  christos   bfd_map_over_sections (abfd, check_reloc_refs, &info);
    636  1.1  christos }
    637  1.1  christos 
    638  1.1  christos /* This is called via bfd_map_over_sections.  INFO->SYM_NAME is a symbol
    639  1.1  christos    defined in INFO->DEFSECNAME.  If this section maps into any of the
    640  1.1  christos    sections listed in INFO->NCRS, other than INFO->DEFSECNAME, then we
    641  1.1  christos    look through the relocations.  If any of the relocations are to
    642  1.1  christos    INFO->SYM_NAME, then we report a prohibited cross reference error.  */
    643  1.1  christos 
    644  1.1  christos static void
    645  1.1  christos check_reloc_refs (bfd *abfd, asection *sec, void *iarg)
    646  1.1  christos {
    647  1.1  christos   struct check_refs_info *info = (struct check_refs_info *) iarg;
    648  1.1  christos   asection *outsec;
    649  1.1  christos   const char *outsecname;
    650  1.1  christos   asection *outdefsec;
    651  1.1  christos   const char *outdefsecname;
    652  1.1  christos   struct lang_nocrossref *ncr;
    653  1.1  christos   const char *symname;
    654  1.8  christos   bool global;
    655  1.1  christos   long relsize;
    656  1.1  christos   arelent **relpp;
    657  1.1  christos   long relcount;
    658  1.1  christos   arelent **p, **pend;
    659  1.1  christos 
    660  1.1  christos   outsec = sec->output_section;
    661  1.7  christos   outsecname = bfd_section_name (outsec);
    662  1.1  christos 
    663  1.1  christos   outdefsec = info->defsec->output_section;
    664  1.7  christos   outdefsecname = bfd_section_name (outdefsec);
    665  1.1  christos 
    666  1.1  christos   /* The section where the symbol is defined is permitted.  */
    667  1.1  christos   if (strcmp (outsecname, outdefsecname) == 0)
    668  1.1  christos     return;
    669  1.1  christos 
    670  1.1  christos   for (ncr = info->ncrs->list; ncr != NULL; ncr = ncr->next)
    671  1.1  christos     if (strcmp (outsecname, ncr->name) == 0)
    672  1.1  christos       break;
    673  1.1  christos 
    674  1.1  christos   if (ncr == NULL)
    675  1.1  christos     return;
    676  1.1  christos 
    677  1.1  christos   /* This section is one for which cross references are prohibited.
    678  1.1  christos      Look through the relocations, and see if any of them are to
    679  1.1  christos      INFO->SYM_NAME.  If INFO->SYMNAME is NULL, check for relocations
    680  1.1  christos      against the section symbol.  If INFO->GLOBAL is TRUE, the
    681  1.1  christos      definition is global, check for relocations against the global
    682  1.1  christos      symbols.  Otherwise check for relocations against the local and
    683  1.1  christos      section symbols.  */
    684  1.1  christos 
    685  1.1  christos   symname = info->sym_name;
    686  1.1  christos   global = info->global;
    687  1.1  christos 
    688  1.1  christos   relsize = bfd_get_reloc_upper_bound (abfd, sec);
    689  1.1  christos   if (relsize < 0)
    690  1.6  christos     einfo (_("%F%P: %pB: could not read relocs: %E\n"), abfd);
    691  1.1  christos   if (relsize == 0)
    692  1.1  christos     return;
    693  1.1  christos 
    694  1.1  christos   relpp = (arelent **) xmalloc (relsize);
    695  1.1  christos   relcount = bfd_canonicalize_reloc (abfd, sec, relpp, info->asymbols);
    696  1.1  christos   if (relcount < 0)
    697  1.6  christos     einfo (_("%F%P: %pB: could not read relocs: %E\n"), abfd);
    698  1.1  christos 
    699  1.1  christos   p = relpp;
    700  1.1  christos   pend = p + relcount;
    701  1.1  christos   for (; p < pend && *p != NULL; p++)
    702  1.1  christos     {
    703  1.1  christos       arelent *q = *p;
    704  1.1  christos 
    705  1.1  christos       if (q->sym_ptr_ptr != NULL
    706  1.1  christos 	  && *q->sym_ptr_ptr != NULL
    707  1.1  christos 	  && ((global
    708  1.7  christos 	       && (bfd_is_und_section (bfd_asymbol_section (*q->sym_ptr_ptr))
    709  1.7  christos 		   || bfd_is_com_section (bfd_asymbol_section (*q->sym_ptr_ptr))
    710  1.1  christos 		   || ((*q->sym_ptr_ptr)->flags & (BSF_GLOBAL
    711  1.1  christos 						   | BSF_WEAK)) != 0))
    712  1.1  christos 	      || (!global
    713  1.1  christos 		  && ((*q->sym_ptr_ptr)->flags & (BSF_LOCAL
    714  1.1  christos 						  | BSF_SECTION_SYM)) != 0
    715  1.7  christos 		  && bfd_asymbol_section (*q->sym_ptr_ptr) == info->defsec))
    716  1.1  christos 	  && (symname != NULL
    717  1.1  christos 	      ? strcmp (bfd_asymbol_name (*q->sym_ptr_ptr), symname) == 0
    718  1.1  christos 	      : ((*q->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0))
    719  1.1  christos 	{
    720  1.1  christos 	  /* We found a reloc for the symbol.  The symbol is defined
    721  1.1  christos 	     in OUTSECNAME.  This reloc is from a section which is
    722  1.1  christos 	     mapped into a section from which references to OUTSECNAME
    723  1.1  christos 	     are prohibited.  We must report an error.  */
    724  1.6  christos 	  einfo (_("%X%P: %C: prohibited cross reference from %s to `%pT' in %s\n"),
    725  1.1  christos 		 abfd, sec, q->address, outsecname,
    726  1.1  christos 		 bfd_asymbol_name (*q->sym_ptr_ptr), outdefsecname);
    727  1.1  christos 	}
    728  1.1  christos     }
    729  1.1  christos 
    730  1.1  christos   free (relpp);
    731  1.1  christos }
    732