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