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