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