xref: /openbsd-src/gnu/usr.bin/binutils/ld/ldcref.c (revision 007c2a4539b8b8aaa95c5e73e77620090abe113b)
1191aa565Sniklas /* ldcref.c -- output a cross reference table
2*007c2a45Smiod    Copyright 1996, 1997, 1998, 2000, 2002, 2003
3*007c2a45Smiod    Free Software Foundation, Inc.
4191aa565Sniklas    Written by Ian Lance Taylor <ian@cygnus.com>
5191aa565Sniklas 
6191aa565Sniklas This file is part of GLD, the Gnu Linker.
7191aa565Sniklas 
8191aa565Sniklas This program is free software; you can redistribute it and/or modify
9191aa565Sniklas it under the terms of the GNU General Public License as published by
10191aa565Sniklas the Free Software Foundation; either version 2 of the License, or
11191aa565Sniklas (at your option) any later version.
12191aa565Sniklas 
13191aa565Sniklas This program is distributed in the hope that it will be useful,
14191aa565Sniklas but WITHOUT ANY WARRANTY; without even the implied warranty of
15191aa565Sniklas MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16191aa565Sniklas GNU General Public License for more details.
17191aa565Sniklas 
18191aa565Sniklas You should have received a copy of the GNU General Public License
19191aa565Sniklas along with this program; if not, write to the Free Software
20191aa565Sniklas Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
21191aa565Sniklas 
224361b62eSniklas /* This file holds routines that manage the cross reference table.
234361b62eSniklas    The table is used to generate cross reference reports.  It is also
244361b62eSniklas    used to implement the NOCROSSREFS command in the linker script.  */
25191aa565Sniklas 
26191aa565Sniklas #include "bfd.h"
27191aa565Sniklas #include "sysdep.h"
28191aa565Sniklas #include "bfdlink.h"
29191aa565Sniklas #include "libiberty.h"
30191aa565Sniklas 
31191aa565Sniklas #include "ld.h"
32191aa565Sniklas #include "ldmain.h"
33191aa565Sniklas #include "ldmisc.h"
344361b62eSniklas #include "ldexp.h"
354361b62eSniklas #include "ldlang.h"
36191aa565Sniklas 
37191aa565Sniklas /* We keep an instance of this structure for each reference to a
38191aa565Sniklas    symbol from a given object.  */
39191aa565Sniklas 
40b55d4692Sfgsch struct cref_ref {
41191aa565Sniklas   /* The next reference.  */
42191aa565Sniklas   struct cref_ref *next;
43191aa565Sniklas   /* The object.  */
44191aa565Sniklas   bfd *abfd;
45191aa565Sniklas   /* True if the symbol is defined.  */
46191aa565Sniklas   unsigned int def : 1;
47191aa565Sniklas   /* True if the symbol is common.  */
48191aa565Sniklas   unsigned int common : 1;
49191aa565Sniklas   /* True if the symbol is undefined.  */
50191aa565Sniklas   unsigned int undef : 1;
51191aa565Sniklas };
52191aa565Sniklas 
53191aa565Sniklas /* We keep a hash table of symbols.  Each entry looks like this.  */
54191aa565Sniklas 
55b55d4692Sfgsch struct cref_hash_entry {
56191aa565Sniklas   struct bfd_hash_entry root;
57191aa565Sniklas   /* The demangled name.  */
58191aa565Sniklas   char *demangled;
59191aa565Sniklas   /* References to and definitions of this symbol.  */
60191aa565Sniklas   struct cref_ref *refs;
61191aa565Sniklas };
62191aa565Sniklas 
63191aa565Sniklas /* This is what the hash table looks like.  */
64191aa565Sniklas 
65b55d4692Sfgsch struct cref_hash_table {
66191aa565Sniklas   struct bfd_hash_table root;
67191aa565Sniklas };
68191aa565Sniklas 
69*007c2a45Smiod /* Forward declarations.  */
70191aa565Sniklas 
71*007c2a45Smiod static void output_one_cref (FILE *, struct cref_hash_entry *);
72*007c2a45Smiod static void check_section_sym_xref (lang_input_statement_type *);
73*007c2a45Smiod static bfd_boolean check_nocrossref (struct cref_hash_entry *, void *);
74*007c2a45Smiod static void check_refs (const char *, asection *, bfd *,
75*007c2a45Smiod 			struct lang_nocrossrefs *);
76*007c2a45Smiod static void check_reloc_refs (bfd *, asection *, void *);
77191aa565Sniklas 
78191aa565Sniklas /* Look up an entry in the cref hash table.  */
79191aa565Sniklas 
80191aa565Sniklas #define cref_hash_lookup(table, string, create, copy)		\
81191aa565Sniklas   ((struct cref_hash_entry *)					\
82191aa565Sniklas    bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
83191aa565Sniklas 
84191aa565Sniklas /* Traverse the cref hash table.  */
85191aa565Sniklas 
86191aa565Sniklas #define cref_hash_traverse(table, func, info)				\
87191aa565Sniklas   (bfd_hash_traverse							\
88191aa565Sniklas    (&(table)->root,							\
89*007c2a45Smiod     (bfd_boolean (*) (struct bfd_hash_entry *, void *)) (func),		\
90191aa565Sniklas     (info)))
91191aa565Sniklas 
92191aa565Sniklas /* The cref hash table.  */
93191aa565Sniklas 
94191aa565Sniklas static struct cref_hash_table cref_table;
95191aa565Sniklas 
96191aa565Sniklas /* Whether the cref hash table has been initialized.  */
97191aa565Sniklas 
98c074d1c9Sdrahn static bfd_boolean cref_initialized;
99191aa565Sniklas 
100191aa565Sniklas /* The number of symbols seen so far.  */
101191aa565Sniklas 
102191aa565Sniklas static size_t cref_symcount;
103191aa565Sniklas 
104191aa565Sniklas /* Create an entry in a cref hash table.  */
105191aa565Sniklas 
106191aa565Sniklas static struct bfd_hash_entry *
cref_hash_newfunc(struct bfd_hash_entry * entry,struct bfd_hash_table * table,const char * string)107*007c2a45Smiod cref_hash_newfunc (struct bfd_hash_entry *entry,
108*007c2a45Smiod 		   struct bfd_hash_table *table,
109*007c2a45Smiod 		   const char *string)
110191aa565Sniklas {
111191aa565Sniklas   struct cref_hash_entry *ret = (struct cref_hash_entry *) entry;
112191aa565Sniklas 
113191aa565Sniklas   /* Allocate the structure if it has not already been allocated by a
114191aa565Sniklas      subclass.  */
115191aa565Sniklas   if (ret == NULL)
116191aa565Sniklas     ret = ((struct cref_hash_entry *)
117191aa565Sniklas 	   bfd_hash_allocate (table, sizeof (struct cref_hash_entry)));
118191aa565Sniklas   if (ret == NULL)
119*007c2a45Smiod     return NULL;
120191aa565Sniklas 
121191aa565Sniklas   /* Call the allocation method of the superclass.  */
122191aa565Sniklas   ret = ((struct cref_hash_entry *)
123191aa565Sniklas 	 bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
124191aa565Sniklas   if (ret != NULL)
125191aa565Sniklas     {
126191aa565Sniklas       /* Set local fields.  */
127191aa565Sniklas       ret->demangled = NULL;
128191aa565Sniklas       ret->refs = NULL;
129191aa565Sniklas 
130191aa565Sniklas       /* Keep a count of the number of entries created in the hash
131191aa565Sniklas 	 table.  */
132191aa565Sniklas       ++cref_symcount;
133191aa565Sniklas     }
134191aa565Sniklas 
135*007c2a45Smiod   return &ret->root;
136191aa565Sniklas }
137191aa565Sniklas 
138191aa565Sniklas /* Add a symbol to the cref hash table.  This is called for every
139191aa565Sniklas    symbol that is seen during the link.  */
140191aa565Sniklas 
141191aa565Sniklas void
add_cref(const char * name,bfd * abfd,asection * section,bfd_vma value ATTRIBUTE_UNUSED)142*007c2a45Smiod add_cref (const char *name,
143*007c2a45Smiod 	  bfd *abfd,
144*007c2a45Smiod 	  asection *section,
145*007c2a45Smiod 	  bfd_vma value ATTRIBUTE_UNUSED)
146191aa565Sniklas {
147191aa565Sniklas   struct cref_hash_entry *h;
148191aa565Sniklas   struct cref_ref *r;
149191aa565Sniklas 
150191aa565Sniklas   if (! cref_initialized)
151191aa565Sniklas     {
152191aa565Sniklas       if (! bfd_hash_table_init (&cref_table.root, cref_hash_newfunc))
153b305b0f1Sespie 	einfo (_("%X%P: bfd_hash_table_init of cref table failed: %E\n"));
154c074d1c9Sdrahn       cref_initialized = TRUE;
155191aa565Sniklas     }
156191aa565Sniklas 
157c074d1c9Sdrahn   h = cref_hash_lookup (&cref_table, name, TRUE, FALSE);
158191aa565Sniklas   if (h == NULL)
159b305b0f1Sespie     einfo (_("%X%P: cref_hash_lookup failed: %E\n"));
160191aa565Sniklas 
161191aa565Sniklas   for (r = h->refs; r != NULL; r = r->next)
162191aa565Sniklas     if (r->abfd == abfd)
163191aa565Sniklas       break;
164191aa565Sniklas 
165191aa565Sniklas   if (r == NULL)
166191aa565Sniklas     {
167*007c2a45Smiod       r = xmalloc (sizeof *r);
168191aa565Sniklas       r->next = h->refs;
169191aa565Sniklas       h->refs = r;
170191aa565Sniklas       r->abfd = abfd;
171c074d1c9Sdrahn       r->def = FALSE;
172c074d1c9Sdrahn       r->common = FALSE;
173c074d1c9Sdrahn       r->undef = FALSE;
174191aa565Sniklas     }
175191aa565Sniklas 
176191aa565Sniklas   if (bfd_is_und_section (section))
177c074d1c9Sdrahn     r->undef = TRUE;
178191aa565Sniklas   else if (bfd_is_com_section (section))
179c074d1c9Sdrahn     r->common = TRUE;
180191aa565Sniklas   else
181c074d1c9Sdrahn     r->def = TRUE;
182191aa565Sniklas }
183191aa565Sniklas 
184191aa565Sniklas /* Copy the addresses of the hash table entries into an array.  This
185191aa565Sniklas    is called via cref_hash_traverse.  We also fill in the demangled
186191aa565Sniklas    name.  */
187191aa565Sniklas 
188c074d1c9Sdrahn static bfd_boolean
cref_fill_array(struct cref_hash_entry * h,void * data)189*007c2a45Smiod cref_fill_array (struct cref_hash_entry *h, void *data)
190191aa565Sniklas {
191*007c2a45Smiod   struct cref_hash_entry ***pph = data;
192191aa565Sniklas 
193191aa565Sniklas   ASSERT (h->demangled == NULL);
194191aa565Sniklas   h->demangled = demangle (h->root.string);
195191aa565Sniklas 
196191aa565Sniklas   **pph = h;
197191aa565Sniklas 
198191aa565Sniklas   ++*pph;
199191aa565Sniklas 
200c074d1c9Sdrahn   return TRUE;
201191aa565Sniklas }
202191aa565Sniklas 
203191aa565Sniklas /* Sort an array of cref hash table entries by name.  */
204191aa565Sniklas 
205191aa565Sniklas static int
cref_sort_array(const void * a1,const void * a2)206*007c2a45Smiod cref_sort_array (const void *a1, const void *a2)
207191aa565Sniklas {
208*007c2a45Smiod   const struct cref_hash_entry * const *p1 = a1;
209*007c2a45Smiod   const struct cref_hash_entry * const *p2 = a2;
210191aa565Sniklas 
211191aa565Sniklas   return strcmp ((*p1)->demangled, (*p2)->demangled);
212191aa565Sniklas }
213191aa565Sniklas 
214191aa565Sniklas /* Write out the cref table.  */
215191aa565Sniklas 
216191aa565Sniklas #define FILECOL (50)
217191aa565Sniklas 
218191aa565Sniklas void
output_cref(FILE * fp)219*007c2a45Smiod output_cref (FILE *fp)
220191aa565Sniklas {
221191aa565Sniklas   int len;
222191aa565Sniklas   struct cref_hash_entry **csyms, **csym_fill, **csym, **csym_end;
223b305b0f1Sespie   const char *msg;
224191aa565Sniklas 
225b305b0f1Sespie   fprintf (fp, _("\nCross Reference Table\n\n"));
226b305b0f1Sespie   msg = _("Symbol");
227b305b0f1Sespie   fprintf (fp, "%s", msg);
228b305b0f1Sespie   len = strlen (msg);
229191aa565Sniklas   while (len < FILECOL)
230191aa565Sniklas     {
231191aa565Sniklas       putc (' ', fp);
232191aa565Sniklas       ++len;
233191aa565Sniklas     }
234b305b0f1Sespie   fprintf (fp, _("File\n"));
235191aa565Sniklas 
236191aa565Sniklas   if (! cref_initialized)
237191aa565Sniklas     {
238b305b0f1Sespie       fprintf (fp, _("No symbols\n"));
239191aa565Sniklas       return;
240191aa565Sniklas     }
241191aa565Sniklas 
242*007c2a45Smiod   csyms = xmalloc (cref_symcount * sizeof (*csyms));
243191aa565Sniklas 
244191aa565Sniklas   csym_fill = csyms;
245191aa565Sniklas   cref_hash_traverse (&cref_table, cref_fill_array, &csym_fill);
246b305b0f1Sespie   ASSERT ((size_t) (csym_fill - csyms) == cref_symcount);
247191aa565Sniklas 
248191aa565Sniklas   qsort (csyms, cref_symcount, sizeof (*csyms), cref_sort_array);
249191aa565Sniklas 
250191aa565Sniklas   csym_end = csyms + cref_symcount;
251191aa565Sniklas   for (csym = csyms; csym < csym_end; csym++)
252191aa565Sniklas     output_one_cref (fp, *csym);
253191aa565Sniklas }
254191aa565Sniklas 
255191aa565Sniklas /* Output one entry in the cross reference table.  */
256191aa565Sniklas 
257191aa565Sniklas static void
output_one_cref(FILE * fp,struct cref_hash_entry * h)258*007c2a45Smiod output_one_cref (FILE *fp, struct cref_hash_entry *h)
259191aa565Sniklas {
260191aa565Sniklas   int len;
261191aa565Sniklas   struct bfd_link_hash_entry *hl;
262191aa565Sniklas   struct cref_ref *r;
263191aa565Sniklas 
264c074d1c9Sdrahn   hl = bfd_link_hash_lookup (link_info.hash, h->root.string, FALSE,
265c074d1c9Sdrahn 			     FALSE, TRUE);
266191aa565Sniklas   if (hl == NULL)
267191aa565Sniklas     einfo ("%P: symbol `%T' missing from main hash table\n",
268191aa565Sniklas 	   h->root.string);
269191aa565Sniklas   else
270191aa565Sniklas     {
271191aa565Sniklas       /* If this symbol is defined in a dynamic object but never
272191aa565Sniklas 	 referenced by a normal object, then don't print it.  */
273191aa565Sniklas       if (hl->type == bfd_link_hash_defined)
274191aa565Sniklas 	{
275191aa565Sniklas 	  if (hl->u.def.section->output_section == NULL)
276191aa565Sniklas 	    return;
2774361b62eSniklas 	  if (hl->u.def.section->owner != NULL
2784361b62eSniklas 	      && (hl->u.def.section->owner->flags & DYNAMIC) != 0)
279191aa565Sniklas 	    {
280191aa565Sniklas 	      for (r = h->refs; r != NULL; r = r->next)
281191aa565Sniklas 		if ((r->abfd->flags & DYNAMIC) == 0)
282191aa565Sniklas 		  break;
283191aa565Sniklas 	      if (r == NULL)
284191aa565Sniklas 		return;
285191aa565Sniklas 	    }
286191aa565Sniklas 	}
287191aa565Sniklas     }
288191aa565Sniklas 
289191aa565Sniklas   fprintf (fp, "%s ", h->demangled);
290191aa565Sniklas   len = strlen (h->demangled) + 1;
291191aa565Sniklas 
292191aa565Sniklas   for (r = h->refs; r != NULL; r = r->next)
293191aa565Sniklas     {
294191aa565Sniklas       if (r->def)
295191aa565Sniklas 	{
296191aa565Sniklas 	  while (len < FILECOL)
297191aa565Sniklas 	    {
298191aa565Sniklas 	      putc (' ', fp);
299191aa565Sniklas 	      ++len;
300191aa565Sniklas 	    }
301b305b0f1Sespie 	  lfinfo (fp, "%B\n", r->abfd);
302191aa565Sniklas 	  len = 0;
303191aa565Sniklas 	}
304191aa565Sniklas     }
305191aa565Sniklas 
306191aa565Sniklas   for (r = h->refs; r != NULL; r = r->next)
307191aa565Sniklas     {
308191aa565Sniklas       if (! r->def)
309191aa565Sniklas 	{
310191aa565Sniklas 	  while (len < FILECOL)
311191aa565Sniklas 	    {
312191aa565Sniklas 	      putc (' ', fp);
313191aa565Sniklas 	      ++len;
314191aa565Sniklas 	    }
315b305b0f1Sespie 	  lfinfo (fp, "%B\n", r->abfd);
316191aa565Sniklas 	  len = 0;
317191aa565Sniklas 	}
318191aa565Sniklas     }
319191aa565Sniklas 
320191aa565Sniklas   ASSERT (len == 0);
321191aa565Sniklas }
3224361b62eSniklas 
3234361b62eSniklas /* Check for prohibited cross references.  */
3244361b62eSniklas 
3254361b62eSniklas void
check_nocrossrefs(void)326*007c2a45Smiod check_nocrossrefs (void)
3274361b62eSniklas {
3284361b62eSniklas   if (! cref_initialized)
3294361b62eSniklas     return;
3304361b62eSniklas 
331*007c2a45Smiod   cref_hash_traverse (&cref_table, check_nocrossref, NULL);
332c074d1c9Sdrahn 
333c074d1c9Sdrahn   lang_for_each_file (check_section_sym_xref);
334c074d1c9Sdrahn }
335c074d1c9Sdrahn 
336c074d1c9Sdrahn /* Checks for prohibited cross references to section symbols.  */
337c074d1c9Sdrahn 
338c074d1c9Sdrahn static void
check_section_sym_xref(lang_input_statement_type * statement)339*007c2a45Smiod check_section_sym_xref (lang_input_statement_type *statement)
340c074d1c9Sdrahn {
341c074d1c9Sdrahn   bfd *abfd;
342c074d1c9Sdrahn   asection *sec;
343c074d1c9Sdrahn 
344c074d1c9Sdrahn   abfd = statement->the_bfd;
345c074d1c9Sdrahn   if (abfd == NULL)
346c074d1c9Sdrahn     return;
347c074d1c9Sdrahn 
348c074d1c9Sdrahn   for (sec = abfd->sections; sec != NULL; sec = sec->next)
349c074d1c9Sdrahn     {
350c074d1c9Sdrahn       asection *outsec;
351c074d1c9Sdrahn 
352c074d1c9Sdrahn       outsec = sec->output_section;
353c074d1c9Sdrahn       if (outsec != NULL)
354c074d1c9Sdrahn 	{
355c074d1c9Sdrahn 	  const char *outsecname;
356c074d1c9Sdrahn 	  struct lang_nocrossrefs *ncrs;
357c074d1c9Sdrahn 	  struct lang_nocrossref *ncr;
358c074d1c9Sdrahn 
359c074d1c9Sdrahn 	  outsecname = outsec->name;
360c074d1c9Sdrahn 	  for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next)
361c074d1c9Sdrahn 	    for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next)
362c074d1c9Sdrahn 	      if (strcmp (ncr->name, outsecname) == 0)
363c074d1c9Sdrahn 		check_refs (NULL, sec, abfd, ncrs);
364c074d1c9Sdrahn 	}
365c074d1c9Sdrahn     }
3664361b62eSniklas }
3674361b62eSniklas 
3684361b62eSniklas /* Check one symbol to see if it is a prohibited cross reference.  */
3694361b62eSniklas 
370c074d1c9Sdrahn static bfd_boolean
check_nocrossref(struct cref_hash_entry * h,void * ignore ATTRIBUTE_UNUSED)371*007c2a45Smiod check_nocrossref (struct cref_hash_entry *h, void *ignore ATTRIBUTE_UNUSED)
3724361b62eSniklas {
3734361b62eSniklas   struct bfd_link_hash_entry *hl;
3744361b62eSniklas   asection *defsec;
3754361b62eSniklas   const char *defsecname;
3764361b62eSniklas   struct lang_nocrossrefs *ncrs;
3774361b62eSniklas   struct lang_nocrossref *ncr;
378c074d1c9Sdrahn   struct cref_ref *ref;
3794361b62eSniklas 
380c074d1c9Sdrahn   hl = bfd_link_hash_lookup (link_info.hash, h->root.string, FALSE,
381c074d1c9Sdrahn 			     FALSE, TRUE);
3824361b62eSniklas   if (hl == NULL)
3834361b62eSniklas     {
384b305b0f1Sespie       einfo (_("%P: symbol `%T' missing from main hash table\n"),
3854361b62eSniklas 	     h->root.string);
386c074d1c9Sdrahn       return TRUE;
3874361b62eSniklas     }
3884361b62eSniklas 
3894361b62eSniklas   if (hl->type != bfd_link_hash_defined
3904361b62eSniklas       && hl->type != bfd_link_hash_defweak)
391c074d1c9Sdrahn     return TRUE;
3924361b62eSniklas 
3934361b62eSniklas   defsec = hl->u.def.section->output_section;
3944361b62eSniklas   if (defsec == NULL)
395c074d1c9Sdrahn     return TRUE;
3964361b62eSniklas   defsecname = bfd_get_section_name (defsec->owner, defsec);
3974361b62eSniklas 
3984361b62eSniklas   for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next)
3994361b62eSniklas     for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next)
4004361b62eSniklas       if (strcmp (ncr->name, defsecname) == 0)
401c074d1c9Sdrahn 	for (ref = h->refs; ref != NULL; ref = ref->next)
402c074d1c9Sdrahn 	  check_refs (hl->root.string, hl->u.def.section, ref->abfd, ncrs);
4034361b62eSniklas 
404c074d1c9Sdrahn   return TRUE;
4054361b62eSniklas }
4064361b62eSniklas 
4074361b62eSniklas /* The struct is used to pass information from check_refs to
4084361b62eSniklas    check_reloc_refs through bfd_map_over_sections.  */
4094361b62eSniklas 
410b55d4692Sfgsch struct check_refs_info {
411c074d1c9Sdrahn   const char *sym_name;
4124361b62eSniklas   asection *defsec;
4134361b62eSniklas   struct lang_nocrossrefs *ncrs;
4144361b62eSniklas   asymbol **asymbols;
4154361b62eSniklas };
4164361b62eSniklas 
4174361b62eSniklas /* This function is called for each symbol defined in a section which
4184361b62eSniklas    prohibits cross references.  We need to look through all references
4194361b62eSniklas    to this symbol, and ensure that the references are not from
4204361b62eSniklas    prohibited sections.  */
4214361b62eSniklas 
4224361b62eSniklas static void
check_refs(const char * name,asection * sec,bfd * abfd,struct lang_nocrossrefs * ncrs)423*007c2a45Smiod check_refs (const char *name,
424*007c2a45Smiod 	    asection *sec,
425*007c2a45Smiod 	    bfd *abfd,
426*007c2a45Smiod 	    struct lang_nocrossrefs *ncrs)
4274361b62eSniklas {
4284361b62eSniklas   lang_input_statement_type *li;
4294361b62eSniklas   asymbol **asymbols;
4304361b62eSniklas   struct check_refs_info info;
4314361b62eSniklas 
4324361b62eSniklas   /* We need to look through the relocations for this BFD, to see
4334361b62eSniklas      if any of the relocations which refer to this symbol are from
4344361b62eSniklas      a prohibited section.  Note that we need to do this even for
4354361b62eSniklas      the BFD in which the symbol is defined, since even a single
436c074d1c9Sdrahn      BFD might contain a prohibited cross reference.  */
4374361b62eSniklas 
438*007c2a45Smiod   li = abfd->usrdata;
4394361b62eSniklas   if (li != NULL && li->asymbols != NULL)
4404361b62eSniklas     asymbols = li->asymbols;
4414361b62eSniklas   else
4424361b62eSniklas     {
4434361b62eSniklas       long symsize;
4444361b62eSniklas       long symbol_count;
4454361b62eSniklas 
446c074d1c9Sdrahn       symsize = bfd_get_symtab_upper_bound (abfd);
4474361b62eSniklas       if (symsize < 0)
448c074d1c9Sdrahn 	einfo (_("%B%F: could not read symbols; %E\n"), abfd);
449*007c2a45Smiod       asymbols = xmalloc (symsize);
450c074d1c9Sdrahn       symbol_count = bfd_canonicalize_symtab (abfd, asymbols);
4514361b62eSniklas       if (symbol_count < 0)
452c074d1c9Sdrahn 	einfo (_("%B%F: could not read symbols: %E\n"), abfd);
4534361b62eSniklas       if (li != NULL)
4544361b62eSniklas 	{
4554361b62eSniklas 	  li->asymbols = asymbols;
4564361b62eSniklas 	  li->symbol_count = symbol_count;
4574361b62eSniklas 	}
4584361b62eSniklas     }
4594361b62eSniklas 
460c074d1c9Sdrahn   info.sym_name = name;
461c074d1c9Sdrahn   info.defsec = sec;
4624361b62eSniklas   info.ncrs = ncrs;
4634361b62eSniklas   info.asymbols = asymbols;
464*007c2a45Smiod   bfd_map_over_sections (abfd, check_reloc_refs, &info);
4654361b62eSniklas 
4664361b62eSniklas   if (li == NULL)
4674361b62eSniklas     free (asymbols);
4684361b62eSniklas }
4694361b62eSniklas 
470c074d1c9Sdrahn /* This is called via bfd_map_over_sections.  INFO->SYM_NAME is a symbol
4714361b62eSniklas    defined in INFO->DEFSECNAME.  If this section maps into any of the
4724361b62eSniklas    sections listed in INFO->NCRS, other than INFO->DEFSECNAME, then we
4734361b62eSniklas    look through the relocations.  If any of the relocations are to
474c074d1c9Sdrahn    INFO->SYM_NAME, then we report a prohibited cross reference error.  */
4754361b62eSniklas 
4764361b62eSniklas static void
check_reloc_refs(bfd * abfd,asection * sec,void * iarg)477*007c2a45Smiod check_reloc_refs (bfd *abfd, asection *sec, void *iarg)
4784361b62eSniklas {
479*007c2a45Smiod   struct check_refs_info *info = iarg;
4804361b62eSniklas   asection *outsec;
4814361b62eSniklas   const char *outsecname;
4824361b62eSniklas   asection *outdefsec;
4834361b62eSniklas   const char *outdefsecname;
4844361b62eSniklas   struct lang_nocrossref *ncr;
4854361b62eSniklas   const char *symname;
4864361b62eSniklas   long relsize;
4874361b62eSniklas   arelent **relpp;
4884361b62eSniklas   long relcount;
4894361b62eSniklas   arelent **p, **pend;
4904361b62eSniklas 
4914361b62eSniklas   outsec = sec->output_section;
4924361b62eSniklas   outsecname = bfd_get_section_name (outsec->owner, outsec);
4934361b62eSniklas 
4944361b62eSniklas   outdefsec = info->defsec->output_section;
4954361b62eSniklas   outdefsecname = bfd_get_section_name (outdefsec->owner, outdefsec);
4964361b62eSniklas 
4974361b62eSniklas   /* The section where the symbol is defined is permitted.  */
4984361b62eSniklas   if (strcmp (outsecname, outdefsecname) == 0)
4994361b62eSniklas     return;
5004361b62eSniklas 
5014361b62eSniklas   for (ncr = info->ncrs->list; ncr != NULL; ncr = ncr->next)
5024361b62eSniklas     if (strcmp (outsecname, ncr->name) == 0)
5034361b62eSniklas       break;
5044361b62eSniklas 
5054361b62eSniklas   if (ncr == NULL)
5064361b62eSniklas     return;
5074361b62eSniklas 
5084361b62eSniklas   /* This section is one for which cross references are prohibited.
5094361b62eSniklas      Look through the relocations, and see if any of them are to
510c074d1c9Sdrahn      INFO->SYM_NAME.  If INFO->SYMNAME is NULL, check for relocations
511c074d1c9Sdrahn      against the section symbol.  */
5124361b62eSniklas 
513c074d1c9Sdrahn   symname = info->sym_name;
5144361b62eSniklas 
5154361b62eSniklas   relsize = bfd_get_reloc_upper_bound (abfd, sec);
5164361b62eSniklas   if (relsize < 0)
517b305b0f1Sespie     einfo (_("%B%F: could not read relocs: %E\n"), abfd);
5184361b62eSniklas   if (relsize == 0)
5194361b62eSniklas     return;
5204361b62eSniklas 
521*007c2a45Smiod   relpp = xmalloc (relsize);
5224361b62eSniklas   relcount = bfd_canonicalize_reloc (abfd, sec, relpp, info->asymbols);
5234361b62eSniklas   if (relcount < 0)
524b305b0f1Sespie     einfo (_("%B%F: could not read relocs: %E\n"), abfd);
5254361b62eSniklas 
5264361b62eSniklas   p = relpp;
5274361b62eSniklas   pend = p + relcount;
5284361b62eSniklas   for (; p < pend && *p != NULL; p++)
5294361b62eSniklas     {
5304361b62eSniklas       arelent *q = *p;
5314361b62eSniklas 
5324361b62eSniklas       if (q->sym_ptr_ptr != NULL
5334361b62eSniklas 	  && *q->sym_ptr_ptr != NULL
534c074d1c9Sdrahn 	  && (symname != NULL
535c074d1c9Sdrahn 	      ? strcmp (bfd_asymbol_name (*q->sym_ptr_ptr), symname) == 0
536c074d1c9Sdrahn 	      : (((*q->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0
5374361b62eSniklas 		 && bfd_get_section (*q->sym_ptr_ptr) == info->defsec)))
5384361b62eSniklas 	{
5394361b62eSniklas 	  /* We found a reloc for the symbol.  The symbol is defined
5404361b62eSniklas 	     in OUTSECNAME.  This reloc is from a section which is
5414361b62eSniklas 	     mapped into a section from which references to OUTSECNAME
5424361b62eSniklas 	     are prohibited.  We must report an error.  */
543b305b0f1Sespie 	  einfo (_("%X%C: prohibited cross reference from %s to `%T' in %s\n"),
5444361b62eSniklas 		 abfd, sec, q->address, outsecname,
5454361b62eSniklas 		 bfd_asymbol_name (*q->sym_ptr_ptr), outdefsecname);
5464361b62eSniklas 	}
5474361b62eSniklas     }
5484361b62eSniklas 
5494361b62eSniklas   free (relpp);
5504361b62eSniklas }
551