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