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