1 /* ldcref.c -- output a cross reference table
2 Copyright (C) 1996-2024 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor <ian@cygnus.com>
5 This file is part of the GNU Binutils.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
23 /* This file holds routines that manage the cross reference table.
24 The table is used to generate cross reference reports. It is also
25 used to implement the NOCROSSREFS command in the linker script. */
31 #include "libiberty.h"
41 /* We keep an instance of this structure for each reference to a
42 symbol from a given object. */
46 /* The next reference. */
47 struct cref_ref
*next
;
50 /* True if the symbol is defined. */
52 /* True if the symbol is common. */
53 unsigned int common
: 1;
54 /* True if the symbol is undefined. */
55 unsigned int undef
: 1;
58 /* We keep a hash table of symbols. Each entry looks like this. */
60 struct cref_hash_entry
62 struct bfd_hash_entry root
;
63 /* The demangled name. */
64 const char *demangled
;
65 /* References to and definitions of this symbol. */
66 struct cref_ref
*refs
;
69 /* This is what the hash table looks like. */
71 struct cref_hash_table
73 struct bfd_hash_table root
;
76 /* Forward declarations. */
78 static void output_one_cref (FILE *, struct cref_hash_entry
*);
79 static void check_local_sym_xref (lang_input_statement_type
*);
80 static bool check_nocrossref (struct cref_hash_entry
*, void *);
81 static void check_refs (const char *, bool, asection
*, bfd
*,
82 struct lang_nocrossrefs
*);
83 static void check_reloc_refs (bfd
*, asection
*, void *);
85 /* Look up an entry in the cref hash table. */
87 #define cref_hash_lookup(table, string, create, copy) \
88 ((struct cref_hash_entry *) \
89 bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
91 /* Traverse the cref hash table. */
93 #define cref_hash_traverse(table, func, info) \
96 (bool (*) (struct bfd_hash_entry *, void *)) (func), (info)))
98 /* The cref hash table. */
100 static struct cref_hash_table cref_table
;
102 /* Whether the cref hash table has been initialized. */
104 static bool cref_initialized
;
106 /* The number of symbols seen so far. */
108 static size_t cref_symcount
;
110 /* Used to take a snapshot of the cref hash table when starting to
111 add syms from an as-needed library. */
112 static struct bfd_hash_entry
**old_table
;
113 static unsigned int old_size
;
114 static unsigned int old_count
;
115 static void *old_tab
;
116 static void *alloc_mark
;
117 static size_t tabsize
, entsize
, refsize
;
118 static size_t old_symcount
;
120 /* Create an entry in a cref hash table. */
122 static struct bfd_hash_entry
*
123 cref_hash_newfunc (struct bfd_hash_entry
*entry
,
124 struct bfd_hash_table
*table
,
127 struct cref_hash_entry
*ret
= (struct cref_hash_entry
*) entry
;
129 /* Allocate the structure if it has not already been allocated by a
132 ret
= ((struct cref_hash_entry
*)
133 bfd_hash_allocate (table
, sizeof (struct cref_hash_entry
)));
137 /* Call the allocation method of the superclass. */
138 ret
= ((struct cref_hash_entry
*)
139 bfd_hash_newfunc ((struct bfd_hash_entry
*) ret
, table
, string
));
142 /* Set local fields. */
143 ret
->demangled
= NULL
;
146 /* Keep a count of the number of entries created in the hash
154 /* Add a symbol to the cref hash table. This is called for every
155 global symbol that is seen during the link. */
158 add_cref (const char *name
,
161 bfd_vma value ATTRIBUTE_UNUSED
)
163 struct cref_hash_entry
*h
;
166 if (!cref_initialized
)
168 if (!bfd_hash_table_init (&cref_table
.root
, cref_hash_newfunc
,
169 sizeof (struct cref_hash_entry
)))
170 einfo (_("%X%P: bfd_hash_table_init of cref table failed: %E\n"));
171 cref_initialized
= true;
174 h
= cref_hash_lookup (&cref_table
, name
, true, false);
176 einfo (_("%X%P: cref_hash_lookup failed: %E\n"));
178 for (r
= h
->refs
; r
!= NULL
; r
= r
->next
)
184 r
= (struct cref_ref
*) bfd_hash_allocate (&cref_table
.root
, sizeof *r
);
186 einfo (_("%X%P: cref alloc failed: %E\n"));
195 if (bfd_is_und_section (section
))
197 else if (bfd_is_com_section (section
))
203 /* Called before loading an as-needed library to take a snapshot of
204 the cref hash table, and after we have loaded or found that the
205 library was not needed. */
208 handle_asneeded_cref (bfd
*abfd ATTRIBUTE_UNUSED
,
209 enum notice_asneeded_action act
)
213 if (!cref_initialized
)
216 if (act
== notice_as_needed
)
218 char *old_ent
, *old_ref
;
220 for (i
= 0; i
< cref_table
.root
.size
; i
++)
222 struct bfd_hash_entry
*p
;
223 struct cref_hash_entry
*c
;
226 for (p
= cref_table
.root
.table
[i
]; p
!= NULL
; p
= p
->next
)
228 entsize
+= cref_table
.root
.entsize
;
229 c
= (struct cref_hash_entry
*) p
;
230 for (r
= c
->refs
; r
!= NULL
; r
= r
->next
)
231 refsize
+= sizeof (struct cref_ref
);
235 tabsize
= cref_table
.root
.size
* sizeof (struct bfd_hash_entry
*);
236 old_tab
= xmalloc (tabsize
+ entsize
+ refsize
);
238 alloc_mark
= bfd_hash_allocate (&cref_table
.root
, 1);
239 if (alloc_mark
== NULL
)
242 memcpy (old_tab
, cref_table
.root
.table
, tabsize
);
243 old_ent
= (char *) old_tab
+ tabsize
;
244 old_ref
= (char *) old_ent
+ entsize
;
245 old_table
= cref_table
.root
.table
;
246 old_size
= cref_table
.root
.size
;
247 old_count
= cref_table
.root
.count
;
248 old_symcount
= cref_symcount
;
250 for (i
= 0; i
< cref_table
.root
.size
; i
++)
252 struct bfd_hash_entry
*p
;
253 struct cref_hash_entry
*c
;
256 for (p
= cref_table
.root
.table
[i
]; p
!= NULL
; p
= p
->next
)
258 memcpy (old_ent
, p
, cref_table
.root
.entsize
);
259 old_ent
= (char *) old_ent
+ cref_table
.root
.entsize
;
260 c
= (struct cref_hash_entry
*) p
;
261 for (r
= c
->refs
; r
!= NULL
; r
= r
->next
)
263 memcpy (old_ref
, r
, sizeof (struct cref_ref
));
264 old_ref
= (char *) old_ref
+ sizeof (struct cref_ref
);
271 if (act
== notice_not_needed
)
273 char *old_ent
, *old_ref
;
277 /* The only way old_tab can be NULL is if the cref hash table
278 had not been initialised when notice_as_needed. */
279 bfd_hash_table_free (&cref_table
.root
);
280 cref_initialized
= false;
284 old_ent
= (char *) old_tab
+ tabsize
;
285 old_ref
= (char *) old_ent
+ entsize
;
286 cref_table
.root
.table
= old_table
;
287 cref_table
.root
.size
= old_size
;
288 cref_table
.root
.count
= old_count
;
289 memcpy (cref_table
.root
.table
, old_tab
, tabsize
);
290 cref_symcount
= old_symcount
;
292 for (i
= 0; i
< cref_table
.root
.size
; i
++)
294 struct bfd_hash_entry
*p
;
295 struct cref_hash_entry
*c
;
298 for (p
= cref_table
.root
.table
[i
]; p
!= NULL
; p
= p
->next
)
300 memcpy (p
, old_ent
, cref_table
.root
.entsize
);
301 old_ent
= (char *) old_ent
+ cref_table
.root
.entsize
;
302 c
= (struct cref_hash_entry
*) p
;
303 for (r
= c
->refs
; r
!= NULL
; r
= r
->next
)
305 memcpy (r
, old_ref
, sizeof (struct cref_ref
));
306 old_ref
= (char *) old_ref
+ sizeof (struct cref_ref
);
311 objalloc_free_block ((struct objalloc
*) cref_table
.root
.memory
,
314 else if (act
!= notice_needed
)
322 /* Copy the addresses of the hash table entries into an array. This
323 is called via cref_hash_traverse. We also fill in the demangled
327 cref_fill_array (struct cref_hash_entry
*h
, void *data
)
329 struct cref_hash_entry
***pph
= (struct cref_hash_entry
***) data
;
331 ASSERT (h
->demangled
== NULL
);
332 h
->demangled
= bfd_demangle (link_info
.output_bfd
, h
->root
.string
,
333 DMGL_ANSI
| DMGL_PARAMS
);
334 if (h
->demangled
== NULL
)
335 h
->demangled
= h
->root
.string
;
344 /* Sort an array of cref hash table entries by name. */
347 cref_sort_array (const void *a1
, const void *a2
)
349 const struct cref_hash_entry
*const *p1
350 = (const struct cref_hash_entry
*const *) a1
;
351 const struct cref_hash_entry
*const *p2
352 = (const struct cref_hash_entry
*const *) a2
;
355 return strcmp ((*p1
)->demangled
, (*p2
)->demangled
);
357 return strcmp ((*p1
)->root
.string
, (*p2
)->root
.string
);
360 /* Write out the cref table. */
365 output_cref (FILE *fp
)
368 struct cref_hash_entry
**csyms
, **csym_fill
, **csym
, **csym_end
;
371 fprintf (fp
, _("\nCross Reference Table\n\n"));
373 fprintf (fp
, "%s", msg
);
375 while (len
< FILECOL
)
380 fprintf (fp
, _("File\n"));
382 if (!cref_initialized
)
384 fprintf (fp
, _("No symbols\n"));
388 csyms
= (struct cref_hash_entry
**) xmalloc (cref_symcount
* sizeof (*csyms
));
391 cref_hash_traverse (&cref_table
, cref_fill_array
, &csym_fill
);
392 ASSERT ((size_t) (csym_fill
- csyms
) == cref_symcount
);
394 qsort (csyms
, cref_symcount
, sizeof (*csyms
), cref_sort_array
);
396 csym_end
= csyms
+ cref_symcount
;
397 for (csym
= csyms
; csym
< csym_end
; csym
++)
398 output_one_cref (fp
, *csym
);
401 /* Output one entry in the cross reference table. */
404 output_one_cref (FILE *fp
, struct cref_hash_entry
*h
)
407 struct bfd_link_hash_entry
*hl
;
410 hl
= bfd_link_hash_lookup (link_info
.hash
, h
->root
.string
, false,
413 einfo (_("%P: symbol `%pT' missing from main hash table\n"),
417 /* If this symbol is defined in a dynamic object but never
418 referenced by a normal object, then don't print it. */
419 if (hl
->type
== bfd_link_hash_defined
)
421 if (hl
->u
.def
.section
->output_section
== NULL
)
423 if (hl
->u
.def
.section
->owner
!= NULL
424 && (hl
->u
.def
.section
->owner
->flags
& DYNAMIC
) != 0)
426 for (r
= h
->refs
; r
!= NULL
; r
= r
->next
)
427 if ((r
->abfd
->flags
& DYNAMIC
) == 0)
437 fprintf (fp
, "%s ", h
->demangled
);
438 len
= strlen (h
->demangled
) + 1;
442 fprintf (fp
, "%s ", h
->root
.string
);
443 len
= strlen (h
->root
.string
) + 1;
446 for (r
= h
->refs
; r
!= NULL
; r
= r
->next
)
450 while (len
< FILECOL
)
455 lfinfo (fp
, "%pB\n", r
->abfd
);
460 for (r
= h
->refs
; r
!= NULL
; r
= r
->next
)
464 while (len
< FILECOL
)
469 lfinfo (fp
, "%pB\n", r
->abfd
);
474 for (r
= h
->refs
; r
!= NULL
; r
= r
->next
)
476 if (!r
->def
&& !r
->common
)
478 while (len
< FILECOL
)
483 lfinfo (fp
, "%pB\n", r
->abfd
);
491 /* Check for prohibited cross references. */
494 check_nocrossrefs (void)
496 if (!cref_initialized
)
499 cref_hash_traverse (&cref_table
, check_nocrossref
, NULL
);
501 lang_for_each_file (check_local_sym_xref
);
504 /* Check for prohibited cross references to local and section symbols. */
507 check_local_sym_xref (lang_input_statement_type
*statement
)
512 abfd
= statement
->the_bfd
;
516 if (!bfd_generic_link_read_symbols (abfd
))
517 einfo (_("%F%P: %pB: could not read symbols: %E\n"), abfd
);
519 for (syms
= bfd_get_outsymbols (abfd
); *syms
; ++syms
)
521 asymbol
*sym
= *syms
;
522 if (sym
->flags
& (BSF_GLOBAL
| BSF_WARNING
| BSF_INDIRECT
| BSF_FILE
))
524 if ((sym
->flags
& (BSF_LOCAL
| BSF_SECTION_SYM
)) != 0
525 && sym
->section
->output_section
!= NULL
)
527 const char *outsecname
, *symname
;
528 struct lang_nocrossrefs
*ncrs
;
529 struct lang_nocrossref
*ncr
;
531 outsecname
= sym
->section
->output_section
->name
;
533 if ((sym
->flags
& BSF_SECTION_SYM
) == 0)
535 for (ncrs
= nocrossref_list
; ncrs
!= NULL
; ncrs
= ncrs
->next
)
536 for (ncr
= ncrs
->list
; ncr
!= NULL
; ncr
= ncr
->next
)
538 if (strcmp (ncr
->name
, outsecname
) == 0)
539 check_refs (symname
, false, sym
->section
, abfd
, ncrs
);
540 /* The NOCROSSREFS_TO command only checks symbols defined in
541 the first section in the list. */
549 /* Check one symbol to see if it is a prohibited cross reference. */
552 check_nocrossref (struct cref_hash_entry
*h
, void *ignore ATTRIBUTE_UNUSED
)
554 struct bfd_link_hash_entry
*hl
;
556 const char *defsecname
;
557 struct lang_nocrossrefs
*ncrs
;
558 struct lang_nocrossref
*ncr
;
559 struct cref_ref
*ref
;
561 hl
= bfd_link_hash_lookup (link_info
.hash
, h
->root
.string
, false,
565 einfo (_("%P: symbol `%pT' missing from main hash table\n"),
570 if (hl
->type
!= bfd_link_hash_defined
571 && hl
->type
!= bfd_link_hash_defweak
)
574 defsec
= hl
->u
.def
.section
->output_section
;
577 defsecname
= bfd_section_name (defsec
);
579 for (ncrs
= nocrossref_list
; ncrs
!= NULL
; ncrs
= ncrs
->next
)
580 for (ncr
= ncrs
->list
; ncr
!= NULL
; ncr
= ncr
->next
)
582 if (strcmp (ncr
->name
, defsecname
) == 0)
583 for (ref
= h
->refs
; ref
!= NULL
; ref
= ref
->next
)
584 check_refs (hl
->root
.string
, true, hl
->u
.def
.section
,
586 /* The NOCROSSREFS_TO command only checks symbols defined in the first
587 section in the list. */
595 /* The struct is used to pass information from check_refs to
596 check_reloc_refs through bfd_map_over_sections. */
598 struct check_refs_info
600 const char *sym_name
;
602 struct lang_nocrossrefs
*ncrs
;
607 /* This function is called for each symbol defined in a section which
608 prohibits cross references. We need to look through all references
609 to this symbol, and ensure that the references are not from
610 prohibited sections. */
613 check_refs (const char *name
,
617 struct lang_nocrossrefs
*ncrs
)
619 struct check_refs_info info
;
621 /* We need to look through the relocations for this BFD, to see
622 if any of the relocations which refer to this symbol are from
623 a prohibited section. Note that we need to do this even for
624 the BFD in which the symbol is defined, since even a single
625 BFD might contain a prohibited cross reference. */
627 if (!bfd_generic_link_read_symbols (abfd
))
628 einfo (_("%F%P: %pB: could not read symbols: %E\n"), abfd
);
630 info
.sym_name
= name
;
631 info
.global
= global
;
634 info
.asymbols
= bfd_get_outsymbols (abfd
);
635 bfd_map_over_sections (abfd
, check_reloc_refs
, &info
);
638 /* This is called via bfd_map_over_sections. INFO->SYM_NAME is a symbol
639 defined in INFO->DEFSECNAME. If this section maps into any of the
640 sections listed in INFO->NCRS, other than INFO->DEFSECNAME, then we
641 look through the relocations. If any of the relocations are to
642 INFO->SYM_NAME, then we report a prohibited cross reference error. */
645 check_reloc_refs (bfd
*abfd
, asection
*sec
, void *iarg
)
647 struct check_refs_info
*info
= (struct check_refs_info
*) iarg
;
649 const char *outsecname
;
651 const char *outdefsecname
;
652 struct lang_nocrossref
*ncr
;
660 outsec
= sec
->output_section
;
661 outsecname
= bfd_section_name (outsec
);
663 outdefsec
= info
->defsec
->output_section
;
664 outdefsecname
= bfd_section_name (outdefsec
);
666 /* The section where the symbol is defined is permitted. */
667 if (strcmp (outsecname
, outdefsecname
) == 0)
670 for (ncr
= info
->ncrs
->list
; ncr
!= NULL
; ncr
= ncr
->next
)
671 if (strcmp (outsecname
, ncr
->name
) == 0)
677 /* This section is one for which cross references are prohibited.
678 Look through the relocations, and see if any of them are to
679 INFO->SYM_NAME. If INFO->SYMNAME is NULL, check for relocations
680 against the section symbol. If INFO->GLOBAL is TRUE, the
681 definition is global, check for relocations against the global
682 symbols. Otherwise check for relocations against the local and
685 symname
= info
->sym_name
;
686 global
= info
->global
;
688 relsize
= bfd_get_reloc_upper_bound (abfd
, sec
);
690 einfo (_("%F%P: %pB: could not read relocs: %E\n"), abfd
);
694 relpp
= (arelent
**) xmalloc (relsize
);
695 relcount
= bfd_canonicalize_reloc (abfd
, sec
, relpp
, info
->asymbols
);
697 einfo (_("%F%P: %pB: could not read relocs: %E\n"), abfd
);
701 for (; p
< pend
&& *p
!= NULL
; p
++)
705 if (q
->sym_ptr_ptr
!= NULL
706 && *q
->sym_ptr_ptr
!= NULL
708 && (bfd_is_und_section (bfd_asymbol_section (*q
->sym_ptr_ptr
))
709 || bfd_is_com_section (bfd_asymbol_section (*q
->sym_ptr_ptr
))
710 || ((*q
->sym_ptr_ptr
)->flags
& (BSF_GLOBAL
713 && ((*q
->sym_ptr_ptr
)->flags
& (BSF_LOCAL
714 | BSF_SECTION_SYM
)) != 0
715 && bfd_asymbol_section (*q
->sym_ptr_ptr
) == info
->defsec
))
717 ? strcmp (bfd_asymbol_name (*q
->sym_ptr_ptr
), symname
) == 0
718 : ((*q
->sym_ptr_ptr
)->flags
& BSF_SECTION_SYM
) != 0))
720 /* We found a reloc for the symbol. The symbol is defined
721 in OUTSECNAME. This reloc is from a section which is
722 mapped into a section from which references to OUTSECNAME
723 are prohibited. We must report an error. */
724 einfo (_("%X%P: %H: prohibited cross reference from %s to `%pT' in %s\n"),
725 abfd
, sec
, q
->address
, outsecname
,
726 bfd_asymbol_name (*q
->sym_ptr_ptr
), outdefsecname
);