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