Back to index

cell-binutils  2.17cvs20070401
ldcref.c
Go to the documentation of this file.
00001 /* ldcref.c -- output a cross reference table
00002    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006,
00003    2007 Free Software Foundation, Inc.
00004    Written by Ian Lance Taylor <ian@cygnus.com>
00005 
00006 This file is part of GLD, the Gnu Linker.
00007 
00008 This program is free software; you can redistribute it and/or modify
00009 it under the terms of the GNU General Public License as published by
00010 the Free Software Foundation; either version 2 of the License, or
00011 (at your option) any later version.
00012 
00013 This program is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 GNU General Public License for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with this program; if not, write to the Free Software
00020 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00021 
00022 /* This file holds routines that manage the cross reference table.
00023    The table is used to generate cross reference reports.  It is also
00024    used to implement the NOCROSSREFS command in the linker script.  */
00025 
00026 #include "bfd.h"
00027 #include "sysdep.h"
00028 #include "bfdlink.h"
00029 #include "libiberty.h"
00030 #include "objalloc.h"
00031 
00032 #include "ld.h"
00033 #include "ldmain.h"
00034 #include "ldmisc.h"
00035 #include "ldexp.h"
00036 #include "ldlang.h"
00037 
00038 /* We keep an instance of this structure for each reference to a
00039    symbol from a given object.  */
00040 
00041 struct cref_ref {
00042   /* The next reference.  */
00043   struct cref_ref *next;
00044   /* The object.  */
00045   bfd *abfd;
00046   /* True if the symbol is defined.  */
00047   unsigned int def : 1;
00048   /* True if the symbol is common.  */
00049   unsigned int common : 1;
00050   /* True if the symbol is undefined.  */
00051   unsigned int undef : 1;
00052 };
00053 
00054 /* We keep a hash table of symbols.  Each entry looks like this.  */
00055 
00056 struct cref_hash_entry {
00057   struct bfd_hash_entry root;
00058   /* The demangled name.  */
00059   char *demangled;
00060   /* References to and definitions of this symbol.  */
00061   struct cref_ref *refs;
00062 };
00063 
00064 /* This is what the hash table looks like.  */
00065 
00066 struct cref_hash_table {
00067   struct bfd_hash_table root;
00068 };
00069 
00070 /* Forward declarations.  */
00071 
00072 static void output_one_cref (FILE *, struct cref_hash_entry *);
00073 static void check_local_sym_xref (lang_input_statement_type *);
00074 static bfd_boolean check_nocrossref (struct cref_hash_entry *, void *);
00075 static void check_refs (const char *, bfd_boolean, asection *, bfd *,
00076                      struct lang_nocrossrefs *);
00077 static void check_reloc_refs (bfd *, asection *, void *);
00078 
00079 /* Look up an entry in the cref hash table.  */
00080 
00081 #define cref_hash_lookup(table, string, create, copy)          \
00082   ((struct cref_hash_entry *)                                  \
00083    bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
00084 
00085 /* Traverse the cref hash table.  */
00086 
00087 #define cref_hash_traverse(table, func, info)                         \
00088   (bfd_hash_traverse                                           \
00089    (&(table)->root,                                            \
00090     (bfd_boolean (*) (struct bfd_hash_entry *, void *)) (func),              \
00091     (info)))
00092 
00093 /* The cref hash table.  */
00094 
00095 static struct cref_hash_table cref_table;
00096 
00097 /* Whether the cref hash table has been initialized.  */
00098 
00099 static bfd_boolean cref_initialized;
00100 
00101 /* The number of symbols seen so far.  */
00102 
00103 static size_t cref_symcount;
00104 
00105 /* Used to take a snapshot of the cref hash table when starting to
00106    add syms from an as-needed library.  */
00107 static struct bfd_hash_entry **old_table;
00108 static unsigned int old_size;
00109 static unsigned int old_count;
00110 static void *old_tab;
00111 static void *alloc_mark;
00112 static size_t tabsize, entsize, refsize;
00113 static size_t old_symcount;
00114 
00115 /* Create an entry in a cref hash table.  */
00116 
00117 static struct bfd_hash_entry *
00118 cref_hash_newfunc (struct bfd_hash_entry *entry,
00119                  struct bfd_hash_table *table,
00120                  const char *string)
00121 {
00122   struct cref_hash_entry *ret = (struct cref_hash_entry *) entry;
00123 
00124   /* Allocate the structure if it has not already been allocated by a
00125      subclass.  */
00126   if (ret == NULL)
00127     ret = ((struct cref_hash_entry *)
00128           bfd_hash_allocate (table, sizeof (struct cref_hash_entry)));
00129   if (ret == NULL)
00130     return NULL;
00131 
00132   /* Call the allocation method of the superclass.  */
00133   ret = ((struct cref_hash_entry *)
00134         bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
00135   if (ret != NULL)
00136     {
00137       /* Set local fields.  */
00138       ret->demangled = NULL;
00139       ret->refs = NULL;
00140 
00141       /* Keep a count of the number of entries created in the hash
00142         table.  */
00143       ++cref_symcount;
00144     }
00145 
00146   return &ret->root;
00147 }
00148 
00149 /* Add a symbol to the cref hash table.  This is called for every
00150    global symbol that is seen during the link.  */
00151 
00152 void
00153 add_cref (const char *name,
00154          bfd *abfd,
00155          asection *section,
00156          bfd_vma value ATTRIBUTE_UNUSED)
00157 {
00158   struct cref_hash_entry *h;
00159   struct cref_ref *r;
00160 
00161   if (! cref_initialized)
00162     {
00163       if (!bfd_hash_table_init (&cref_table.root, cref_hash_newfunc,
00164                             sizeof (struct cref_hash_entry)))
00165        einfo (_("%X%P: bfd_hash_table_init of cref table failed: %E\n"));
00166       cref_initialized = TRUE;
00167     }
00168 
00169   h = cref_hash_lookup (&cref_table, name, TRUE, FALSE);
00170   if (h == NULL)
00171     einfo (_("%X%P: cref_hash_lookup failed: %E\n"));
00172 
00173   for (r = h->refs; r != NULL; r = r->next)
00174     if (r->abfd == abfd)
00175       break;
00176 
00177   if (r == NULL)
00178     {
00179       r = bfd_hash_allocate (&cref_table.root, sizeof *r);
00180       if (r == NULL)
00181        einfo (_("%X%P: cref alloc failed: %E\n"));
00182       r->next = h->refs;
00183       h->refs = r;
00184       r->abfd = abfd;
00185       r->def = FALSE;
00186       r->common = FALSE;
00187       r->undef = FALSE;
00188     }
00189 
00190   if (bfd_is_und_section (section))
00191     r->undef = TRUE;
00192   else if (bfd_is_com_section (section))
00193     r->common = TRUE;
00194   else
00195     r->def = TRUE;
00196 }
00197 
00198 /* Called before loading an as-needed library to take a snapshot of
00199    the cref hash table, and after we have loaded or found that the
00200    library was not needed.  */
00201 
00202 bfd_boolean
00203 handle_asneeded_cref (bfd *abfd ATTRIBUTE_UNUSED,
00204                     enum notice_asneeded_action act)
00205 {
00206   unsigned int i;
00207 
00208   if (!cref_initialized)
00209     return TRUE;
00210 
00211   if (act == notice_as_needed)
00212     {
00213       char *old_ent, *old_ref;
00214 
00215       for (i = 0; i < cref_table.root.size; i++)
00216        {
00217          struct bfd_hash_entry *p;
00218          struct cref_hash_entry *c;
00219          struct cref_ref *r;
00220 
00221          for (p = cref_table.root.table[i]; p != NULL; p = p->next)
00222            {
00223              entsize += cref_table.root.entsize;
00224              c = (struct cref_hash_entry *) p;
00225              for (r = c->refs; r != NULL; r = r->next)
00226               refsize += sizeof (struct cref_hash_entry);
00227            }
00228        }
00229 
00230       tabsize = cref_table.root.size * sizeof (struct bfd_hash_entry *);
00231       old_tab = xmalloc (tabsize + entsize + refsize);
00232 
00233       alloc_mark = bfd_hash_allocate (&cref_table.root, 1);
00234       if (alloc_mark == NULL)
00235        return FALSE;
00236 
00237       memcpy (old_tab, cref_table.root.table, tabsize);
00238       old_ent = (char *) old_tab + tabsize;
00239       old_ref = (char *) old_ent + entsize;
00240       old_table = cref_table.root.table;
00241       old_size = cref_table.root.size;
00242       old_count = cref_table.root.count;
00243       old_symcount = cref_symcount;
00244 
00245       for (i = 0; i < cref_table.root.size; i++)
00246        {
00247          struct bfd_hash_entry *p;
00248          struct cref_hash_entry *c;
00249          struct cref_ref *r;
00250 
00251          for (p = cref_table.root.table[i]; p != NULL; p = p->next)
00252            {
00253              memcpy (old_ent, p, cref_table.root.entsize);
00254              old_ent = (char *) old_ent + cref_table.root.entsize;
00255              c = (struct cref_hash_entry *) p;
00256              for (r = c->refs; r != NULL; r = r->next)
00257               {
00258                 memcpy (old_ref, r, sizeof (struct cref_hash_entry));
00259                 old_ref = (char *) old_ref + sizeof (struct cref_hash_entry);
00260               }
00261            }
00262        }
00263       return TRUE;
00264     }
00265 
00266   if (act == notice_not_needed)
00267     {
00268       char *old_ent, *old_ref;
00269 
00270       if (old_tab == NULL)
00271        {
00272          /* The only way old_tab can be NULL is if the cref hash table
00273             had not been initialised when notice_as_needed.  */
00274          bfd_hash_table_free (&cref_table.root);
00275          cref_initialized = FALSE;
00276          return TRUE;
00277        }
00278 
00279       old_ent = (char *) old_tab + tabsize;
00280       old_ref = (char *) old_ent + entsize;
00281       cref_table.root.table = old_table;
00282       cref_table.root.size = old_size;
00283       cref_table.root.count = old_count;
00284       memcpy (cref_table.root.table, old_tab, tabsize);
00285       cref_symcount = old_symcount;
00286 
00287       for (i = 0; i < cref_table.root.size; i++)
00288        {
00289          struct bfd_hash_entry *p;
00290          struct cref_hash_entry *c;
00291          struct cref_ref *r;
00292 
00293          for (p = cref_table.root.table[i]; p != NULL; p = p->next)
00294            {
00295              memcpy (p, old_ent, cref_table.root.entsize);
00296              old_ent = (char *) old_ent + cref_table.root.entsize;
00297              c = (struct cref_hash_entry *) p;
00298              for (r = c->refs; r != NULL; r = r->next)
00299               {
00300                 memcpy (r, old_ref, sizeof (struct cref_hash_entry));
00301                 old_ref = (char *) old_ref + sizeof (struct cref_hash_entry);
00302               }
00303            }
00304        }
00305 
00306       objalloc_free_block ((struct objalloc *) cref_table.root.memory,
00307                         alloc_mark);
00308     }
00309   else if (act != notice_needed)
00310     return FALSE;
00311 
00312   free (old_tab);
00313   old_tab = NULL;
00314   return TRUE;
00315 }
00316 
00317 /* Copy the addresses of the hash table entries into an array.  This
00318    is called via cref_hash_traverse.  We also fill in the demangled
00319    name.  */
00320 
00321 static bfd_boolean
00322 cref_fill_array (struct cref_hash_entry *h, void *data)
00323 {
00324   struct cref_hash_entry ***pph = data;
00325 
00326   ASSERT (h->demangled == NULL);
00327   h->demangled = demangle (h->root.string);
00328 
00329   **pph = h;
00330 
00331   ++*pph;
00332 
00333   return TRUE;
00334 }
00335 
00336 /* Sort an array of cref hash table entries by name.  */
00337 
00338 static int
00339 cref_sort_array (const void *a1, const void *a2)
00340 {
00341   const struct cref_hash_entry * const *p1 = a1;
00342   const struct cref_hash_entry * const *p2 = a2;
00343 
00344   return strcmp ((*p1)->demangled, (*p2)->demangled);
00345 }
00346 
00347 /* Write out the cref table.  */
00348 
00349 #define FILECOL (50)
00350 
00351 void
00352 output_cref (FILE *fp)
00353 {
00354   int len;
00355   struct cref_hash_entry **csyms, **csym_fill, **csym, **csym_end;
00356   const char *msg;
00357 
00358   fprintf (fp, _("\nCross Reference Table\n\n"));
00359   msg = _("Symbol");
00360   fprintf (fp, "%s", msg);
00361   len = strlen (msg);
00362   while (len < FILECOL)
00363     {
00364       putc (' ', fp);
00365       ++len;
00366     }
00367   fprintf (fp, _("File\n"));
00368 
00369   if (! cref_initialized)
00370     {
00371       fprintf (fp, _("No symbols\n"));
00372       return;
00373     }
00374 
00375   csyms = xmalloc (cref_symcount * sizeof (*csyms));
00376 
00377   csym_fill = csyms;
00378   cref_hash_traverse (&cref_table, cref_fill_array, &csym_fill);
00379   ASSERT ((size_t) (csym_fill - csyms) == cref_symcount);
00380 
00381   qsort (csyms, cref_symcount, sizeof (*csyms), cref_sort_array);
00382 
00383   csym_end = csyms + cref_symcount;
00384   for (csym = csyms; csym < csym_end; csym++)
00385     output_one_cref (fp, *csym);
00386 }
00387 
00388 /* Output one entry in the cross reference table.  */
00389 
00390 static void
00391 output_one_cref (FILE *fp, struct cref_hash_entry *h)
00392 {
00393   int len;
00394   struct bfd_link_hash_entry *hl;
00395   struct cref_ref *r;
00396 
00397   hl = bfd_link_hash_lookup (link_info.hash, h->root.string, FALSE,
00398                           FALSE, TRUE);
00399   if (hl == NULL)
00400     einfo ("%P: symbol `%T' missing from main hash table\n",
00401           h->root.string);
00402   else
00403     {
00404       /* If this symbol is defined in a dynamic object but never
00405         referenced by a normal object, then don't print it.  */
00406       if (hl->type == bfd_link_hash_defined)
00407        {
00408          if (hl->u.def.section->output_section == NULL)
00409            return;
00410          if (hl->u.def.section->owner != NULL
00411              && (hl->u.def.section->owner->flags & DYNAMIC) != 0)
00412            {
00413              for (r = h->refs; r != NULL; r = r->next)
00414               if ((r->abfd->flags & DYNAMIC) == 0)
00415                 break;
00416              if (r == NULL)
00417               return;
00418            }
00419        }
00420     }
00421 
00422   fprintf (fp, "%s ", h->demangled);
00423   len = strlen (h->demangled) + 1;
00424 
00425   for (r = h->refs; r != NULL; r = r->next)
00426     {
00427       if (r->def)
00428        {
00429          while (len < FILECOL)
00430            {
00431              putc (' ', fp);
00432              ++len;
00433            }
00434          lfinfo (fp, "%B\n", r->abfd);
00435          len = 0;
00436        }
00437     }
00438 
00439   for (r = h->refs; r != NULL; r = r->next)
00440     {
00441       if (! r->def)
00442        {
00443          while (len < FILECOL)
00444            {
00445              putc (' ', fp);
00446              ++len;
00447            }
00448          lfinfo (fp, "%B\n", r->abfd);
00449          len = 0;
00450        }
00451     }
00452 
00453   ASSERT (len == 0);
00454 }
00455 
00456 /* Check for prohibited cross references.  */
00457 
00458 void
00459 check_nocrossrefs (void)
00460 {
00461   if (! cref_initialized)
00462     return;
00463 
00464   cref_hash_traverse (&cref_table, check_nocrossref, NULL);
00465 
00466   lang_for_each_file (check_local_sym_xref);
00467 }
00468 
00469 /* Check for prohibited cross references to local and section symbols.  */
00470 
00471 static void
00472 check_local_sym_xref (lang_input_statement_type *statement)
00473 {
00474   bfd *abfd;
00475   lang_input_statement_type *li;
00476   asymbol **asymbols, **syms;
00477 
00478   abfd = statement->the_bfd;
00479   if (abfd == NULL)
00480     return;
00481 
00482   li = abfd->usrdata;
00483   if (li != NULL && li->asymbols != NULL)
00484     asymbols = li->asymbols;
00485   else
00486     {
00487       long symsize;
00488       long symbol_count;
00489 
00490       symsize = bfd_get_symtab_upper_bound (abfd);
00491       if (symsize < 0)
00492        einfo (_("%B%F: could not read symbols; %E\n"), abfd);
00493       asymbols = xmalloc (symsize);
00494       symbol_count = bfd_canonicalize_symtab (abfd, asymbols);
00495       if (symbol_count < 0)
00496        einfo (_("%B%F: could not read symbols: %E\n"), abfd);
00497       if (li != NULL)
00498        {
00499          li->asymbols = asymbols;
00500          li->symbol_count = symbol_count;
00501        }
00502     }
00503 
00504   for (syms = asymbols; *syms; ++syms)
00505     {
00506       asymbol *sym = *syms;
00507       if (sym->flags & (BSF_GLOBAL | BSF_WARNING | BSF_INDIRECT | BSF_FILE))
00508        continue;
00509       if ((sym->flags & (BSF_LOCAL | BSF_SECTION_SYM)) != 0
00510          && sym->section->output_section != NULL)
00511        {
00512          const char *outsecname, *symname;
00513          struct lang_nocrossrefs *ncrs;
00514          struct lang_nocrossref *ncr;
00515 
00516          outsecname = sym->section->output_section->name;
00517          symname = NULL;
00518          if ((sym->flags & BSF_SECTION_SYM) == 0)
00519            symname = sym->name;
00520          for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next)
00521            for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next)
00522              if (strcmp (ncr->name, outsecname) == 0)
00523               check_refs (symname, FALSE, sym->section, abfd, ncrs);
00524        }
00525     }
00526 
00527   if (li == NULL)
00528     free (asymbols);
00529 }
00530 
00531 /* Check one symbol to see if it is a prohibited cross reference.  */
00532 
00533 static bfd_boolean
00534 check_nocrossref (struct cref_hash_entry *h, void *ignore ATTRIBUTE_UNUSED)
00535 {
00536   struct bfd_link_hash_entry *hl;
00537   asection *defsec;
00538   const char *defsecname;
00539   struct lang_nocrossrefs *ncrs;
00540   struct lang_nocrossref *ncr;
00541   struct cref_ref *ref;
00542 
00543   hl = bfd_link_hash_lookup (link_info.hash, h->root.string, FALSE,
00544                           FALSE, TRUE);
00545   if (hl == NULL)
00546     {
00547       einfo (_("%P: symbol `%T' missing from main hash table\n"),
00548             h->root.string);
00549       return TRUE;
00550     }
00551 
00552   if (hl->type != bfd_link_hash_defined
00553       && hl->type != bfd_link_hash_defweak)
00554     return TRUE;
00555 
00556   defsec = hl->u.def.section->output_section;
00557   if (defsec == NULL)
00558     return TRUE;
00559   defsecname = bfd_get_section_name (defsec->owner, defsec);
00560 
00561   for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next)
00562     for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next)
00563       if (strcmp (ncr->name, defsecname) == 0)
00564        for (ref = h->refs; ref != NULL; ref = ref->next)
00565          check_refs (hl->root.string, TRUE, hl->u.def.section,
00566                     ref->abfd, ncrs);
00567 
00568   return TRUE;
00569 }
00570 
00571 /* The struct is used to pass information from check_refs to
00572    check_reloc_refs through bfd_map_over_sections.  */
00573 
00574 struct check_refs_info {
00575   const char *sym_name;
00576   asection *defsec;
00577   struct lang_nocrossrefs *ncrs;
00578   asymbol **asymbols;
00579   bfd_boolean global;
00580 };
00581 
00582 /* This function is called for each symbol defined in a section which
00583    prohibits cross references.  We need to look through all references
00584    to this symbol, and ensure that the references are not from
00585    prohibited sections.  */
00586 
00587 static void
00588 check_refs (const char *name,
00589            bfd_boolean global,
00590            asection *sec,
00591            bfd *abfd,
00592            struct lang_nocrossrefs *ncrs)
00593 {
00594   lang_input_statement_type *li;
00595   asymbol **asymbols;
00596   struct check_refs_info info;
00597 
00598   /* We need to look through the relocations for this BFD, to see
00599      if any of the relocations which refer to this symbol are from
00600      a prohibited section.  Note that we need to do this even for
00601      the BFD in which the symbol is defined, since even a single
00602      BFD might contain a prohibited cross reference.  */
00603 
00604   li = abfd->usrdata;
00605   if (li != NULL && li->asymbols != NULL)
00606     asymbols = li->asymbols;
00607   else
00608     {
00609       long symsize;
00610       long symbol_count;
00611 
00612       symsize = bfd_get_symtab_upper_bound (abfd);
00613       if (symsize < 0)
00614        einfo (_("%B%F: could not read symbols; %E\n"), abfd);
00615       asymbols = xmalloc (symsize);
00616       symbol_count = bfd_canonicalize_symtab (abfd, asymbols);
00617       if (symbol_count < 0)
00618        einfo (_("%B%F: could not read symbols: %E\n"), abfd);
00619       if (li != NULL)
00620        {
00621          li->asymbols = asymbols;
00622          li->symbol_count = symbol_count;
00623        }
00624     }
00625 
00626   info.sym_name = name;
00627   info.global = global;
00628   info.defsec = sec;
00629   info.ncrs = ncrs;
00630   info.asymbols = asymbols;
00631   bfd_map_over_sections (abfd, check_reloc_refs, &info);
00632 
00633   if (li == NULL)
00634     free (asymbols);
00635 }
00636 
00637 /* This is called via bfd_map_over_sections.  INFO->SYM_NAME is a symbol
00638    defined in INFO->DEFSECNAME.  If this section maps into any of the
00639    sections listed in INFO->NCRS, other than INFO->DEFSECNAME, then we
00640    look through the relocations.  If any of the relocations are to
00641    INFO->SYM_NAME, then we report a prohibited cross reference error.  */
00642 
00643 static void
00644 check_reloc_refs (bfd *abfd, asection *sec, void *iarg)
00645 {
00646   struct check_refs_info *info = iarg;
00647   asection *outsec;
00648   const char *outsecname;
00649   asection *outdefsec;
00650   const char *outdefsecname;
00651   struct lang_nocrossref *ncr;
00652   const char *symname;
00653   bfd_boolean global;
00654   long relsize;
00655   arelent **relpp;
00656   long relcount;
00657   arelent **p, **pend;
00658 
00659   outsec = sec->output_section;
00660   outsecname = bfd_get_section_name (outsec->owner, outsec);
00661 
00662   outdefsec = info->defsec->output_section;
00663   outdefsecname = bfd_get_section_name (outdefsec->owner, outdefsec);
00664 
00665   /* The section where the symbol is defined is permitted.  */
00666   if (strcmp (outsecname, outdefsecname) == 0)
00667     return;
00668 
00669   for (ncr = info->ncrs->list; ncr != NULL; ncr = ncr->next)
00670     if (strcmp (outsecname, ncr->name) == 0)
00671       break;
00672 
00673   if (ncr == NULL)
00674     return;
00675 
00676   /* This section is one for which cross references are prohibited.
00677      Look through the relocations, and see if any of them are to
00678      INFO->SYM_NAME.  If INFO->SYMNAME is NULL, check for relocations
00679      against the section symbol.  If INFO->GLOBAL is TRUE, the
00680      definition is global, check for relocations against the global
00681      symbols.  Otherwise check for relocations against the local and
00682      section symbols.  */
00683 
00684   symname = info->sym_name;
00685   global = info->global;
00686 
00687   relsize = bfd_get_reloc_upper_bound (abfd, sec);
00688   if (relsize < 0)
00689     einfo (_("%B%F: could not read relocs: %E\n"), abfd);
00690   if (relsize == 0)
00691     return;
00692 
00693   relpp = xmalloc (relsize);
00694   relcount = bfd_canonicalize_reloc (abfd, sec, relpp, info->asymbols);
00695   if (relcount < 0)
00696     einfo (_("%B%F: could not read relocs: %E\n"), abfd);
00697 
00698   p = relpp;
00699   pend = p + relcount;
00700   for (; p < pend && *p != NULL; p++)
00701     {
00702       arelent *q = *p;
00703 
00704       if (q->sym_ptr_ptr != NULL
00705          && *q->sym_ptr_ptr != NULL
00706          && ((global
00707               && (bfd_is_und_section (bfd_get_section (*q->sym_ptr_ptr))
00708                  || bfd_is_com_section (bfd_get_section (*q->sym_ptr_ptr))
00709                  || ((*q->sym_ptr_ptr)->flags & (BSF_GLOBAL
00710                                              | BSF_WEAK)) != 0))
00711              || (!global
00712                 && ((*q->sym_ptr_ptr)->flags & (BSF_LOCAL
00713                                             | BSF_SECTION_SYM)) != 0
00714                 && bfd_get_section (*q->sym_ptr_ptr) == info->defsec))
00715          && (symname != NULL
00716              ? strcmp (bfd_asymbol_name (*q->sym_ptr_ptr), symname) == 0
00717              : ((*q->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0))
00718        {
00719          /* We found a reloc for the symbol.  The symbol is defined
00720             in OUTSECNAME.  This reloc is from a section which is
00721             mapped into a section from which references to OUTSECNAME
00722             are prohibited.  We must report an error.  */
00723          einfo (_("%X%C: prohibited cross reference from %s to `%T' in %s\n"),
00724                abfd, sec, q->address, outsecname,
00725                bfd_asymbol_name (*q->sym_ptr_ptr), outdefsecname);
00726        }
00727     }
00728 
00729   free (relpp);
00730 }