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