12a6b7db3Sskrll /* ldcref.c -- output a cross reference table
2*cb63e24eSchristos Copyright (C) 1996-2024 Free Software Foundation, Inc.
32a6b7db3Sskrll Written by Ian Lance Taylor <ian@cygnus.com>
42a6b7db3Sskrll
52a6b7db3Sskrll This file is part of the GNU Binutils.
62a6b7db3Sskrll
72a6b7db3Sskrll This program is free software; you can redistribute it and/or modify
82a6b7db3Sskrll it under the terms of the GNU General Public License as published by
92a6b7db3Sskrll the Free Software Foundation; either version 3 of the License, or
102a6b7db3Sskrll (at your option) any later version.
112a6b7db3Sskrll
122a6b7db3Sskrll This program is distributed in the hope that it will be useful,
132a6b7db3Sskrll but WITHOUT ANY WARRANTY; without even the implied warranty of
142a6b7db3Sskrll MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
152a6b7db3Sskrll GNU General Public License for more details.
162a6b7db3Sskrll
172a6b7db3Sskrll You should have received a copy of the GNU General Public License
182a6b7db3Sskrll along with this program; if not, write to the Free Software
192a6b7db3Sskrll Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
202a6b7db3Sskrll MA 02110-1301, USA. */
212a6b7db3Sskrll
222a6b7db3Sskrll
232a6b7db3Sskrll /* This file holds routines that manage the cross reference table.
242a6b7db3Sskrll The table is used to generate cross reference reports. It is also
252a6b7db3Sskrll used to implement the NOCROSSREFS command in the linker script. */
262a6b7db3Sskrll
272a6b7db3Sskrll #include "sysdep.h"
282a6b7db3Sskrll #include "bfd.h"
292a6b7db3Sskrll #include "bfdlink.h"
306f4ced0bSchristos #include "ctf-api.h"
312a6b7db3Sskrll #include "libiberty.h"
322a6b7db3Sskrll #include "demangle.h"
332a6b7db3Sskrll #include "objalloc.h"
342a6b7db3Sskrll
352a6b7db3Sskrll #include "ld.h"
362a6b7db3Sskrll #include "ldmain.h"
372a6b7db3Sskrll #include "ldmisc.h"
382a6b7db3Sskrll #include "ldexp.h"
392a6b7db3Sskrll #include "ldlang.h"
402a6b7db3Sskrll
412a6b7db3Sskrll /* We keep an instance of this structure for each reference to a
422a6b7db3Sskrll symbol from a given object. */
432a6b7db3Sskrll
449573673dSchristos struct cref_ref
459573673dSchristos {
462a6b7db3Sskrll /* The next reference. */
472a6b7db3Sskrll struct cref_ref *next;
482a6b7db3Sskrll /* The object. */
492a6b7db3Sskrll bfd *abfd;
502a6b7db3Sskrll /* True if the symbol is defined. */
512a6b7db3Sskrll unsigned int def : 1;
522a6b7db3Sskrll /* True if the symbol is common. */
532a6b7db3Sskrll unsigned int common : 1;
542a6b7db3Sskrll /* True if the symbol is undefined. */
552a6b7db3Sskrll unsigned int undef : 1;
562a6b7db3Sskrll };
572a6b7db3Sskrll
582a6b7db3Sskrll /* We keep a hash table of symbols. Each entry looks like this. */
592a6b7db3Sskrll
609573673dSchristos struct cref_hash_entry
619573673dSchristos {
622a6b7db3Sskrll struct bfd_hash_entry root;
632a6b7db3Sskrll /* The demangled name. */
642a6b7db3Sskrll const char *demangled;
652a6b7db3Sskrll /* References to and definitions of this symbol. */
662a6b7db3Sskrll struct cref_ref *refs;
672a6b7db3Sskrll };
682a6b7db3Sskrll
692a6b7db3Sskrll /* This is what the hash table looks like. */
702a6b7db3Sskrll
719573673dSchristos struct cref_hash_table
729573673dSchristos {
732a6b7db3Sskrll struct bfd_hash_table root;
742a6b7db3Sskrll };
752a6b7db3Sskrll
762a6b7db3Sskrll /* Forward declarations. */
772a6b7db3Sskrll
782a6b7db3Sskrll static void output_one_cref (FILE *, struct cref_hash_entry *);
792a6b7db3Sskrll static void check_local_sym_xref (lang_input_statement_type *);
804f645668Schristos static bool check_nocrossref (struct cref_hash_entry *, void *);
814f645668Schristos static void check_refs (const char *, bool, asection *, bfd *,
822a6b7db3Sskrll struct lang_nocrossrefs *);
832a6b7db3Sskrll static void check_reloc_refs (bfd *, asection *, void *);
842a6b7db3Sskrll
852a6b7db3Sskrll /* Look up an entry in the cref hash table. */
862a6b7db3Sskrll
872a6b7db3Sskrll #define cref_hash_lookup(table, string, create, copy) \
882a6b7db3Sskrll ((struct cref_hash_entry *) \
892a6b7db3Sskrll bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
902a6b7db3Sskrll
912a6b7db3Sskrll /* Traverse the cref hash table. */
922a6b7db3Sskrll
932a6b7db3Sskrll #define cref_hash_traverse(table, func, info) \
942a6b7db3Sskrll (bfd_hash_traverse \
952a6b7db3Sskrll (&(table)->root, \
964f645668Schristos (bool (*) (struct bfd_hash_entry *, void *)) (func), (info)))
972a6b7db3Sskrll
982a6b7db3Sskrll /* The cref hash table. */
992a6b7db3Sskrll
1002a6b7db3Sskrll static struct cref_hash_table cref_table;
1012a6b7db3Sskrll
1022a6b7db3Sskrll /* Whether the cref hash table has been initialized. */
1032a6b7db3Sskrll
1044f645668Schristos static bool cref_initialized;
1052a6b7db3Sskrll
1062a6b7db3Sskrll /* The number of symbols seen so far. */
1072a6b7db3Sskrll
1082a6b7db3Sskrll static size_t cref_symcount;
1092a6b7db3Sskrll
1102a6b7db3Sskrll /* Used to take a snapshot of the cref hash table when starting to
1112a6b7db3Sskrll add syms from an as-needed library. */
1122a6b7db3Sskrll static struct bfd_hash_entry **old_table;
1132a6b7db3Sskrll static unsigned int old_size;
1142a6b7db3Sskrll static unsigned int old_count;
1152a6b7db3Sskrll static void *old_tab;
1162a6b7db3Sskrll static void *alloc_mark;
1172a6b7db3Sskrll static size_t tabsize, entsize, refsize;
1182a6b7db3Sskrll static size_t old_symcount;
1192a6b7db3Sskrll
1202a6b7db3Sskrll /* Create an entry in a cref hash table. */
1212a6b7db3Sskrll
1222a6b7db3Sskrll static struct bfd_hash_entry *
cref_hash_newfunc(struct bfd_hash_entry * entry,struct bfd_hash_table * table,const char * string)1232a6b7db3Sskrll cref_hash_newfunc (struct bfd_hash_entry *entry,
1242a6b7db3Sskrll struct bfd_hash_table *table,
1252a6b7db3Sskrll const char *string)
1262a6b7db3Sskrll {
1272a6b7db3Sskrll struct cref_hash_entry *ret = (struct cref_hash_entry *) entry;
1282a6b7db3Sskrll
1292a6b7db3Sskrll /* Allocate the structure if it has not already been allocated by a
1302a6b7db3Sskrll subclass. */
1312a6b7db3Sskrll if (ret == NULL)
1322a6b7db3Sskrll ret = ((struct cref_hash_entry *)
1332a6b7db3Sskrll bfd_hash_allocate (table, sizeof (struct cref_hash_entry)));
1342a6b7db3Sskrll if (ret == NULL)
1352a6b7db3Sskrll return NULL;
1362a6b7db3Sskrll
1372a6b7db3Sskrll /* Call the allocation method of the superclass. */
1382a6b7db3Sskrll ret = ((struct cref_hash_entry *)
1392a6b7db3Sskrll bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
1402a6b7db3Sskrll if (ret != NULL)
1412a6b7db3Sskrll {
1422a6b7db3Sskrll /* Set local fields. */
1432a6b7db3Sskrll ret->demangled = NULL;
1442a6b7db3Sskrll ret->refs = NULL;
1452a6b7db3Sskrll
1462a6b7db3Sskrll /* Keep a count of the number of entries created in the hash
1472a6b7db3Sskrll table. */
1482a6b7db3Sskrll ++cref_symcount;
1492a6b7db3Sskrll }
1502a6b7db3Sskrll
1512a6b7db3Sskrll return &ret->root;
1522a6b7db3Sskrll }
1532a6b7db3Sskrll
1542a6b7db3Sskrll /* Add a symbol to the cref hash table. This is called for every
1552a6b7db3Sskrll global symbol that is seen during the link. */
1562a6b7db3Sskrll
1572a6b7db3Sskrll void
add_cref(const char * name,bfd * abfd,asection * section,bfd_vma value ATTRIBUTE_UNUSED)1582a6b7db3Sskrll add_cref (const char *name,
1592a6b7db3Sskrll bfd *abfd,
1602a6b7db3Sskrll asection *section,
1612a6b7db3Sskrll bfd_vma value ATTRIBUTE_UNUSED)
1622a6b7db3Sskrll {
1632a6b7db3Sskrll struct cref_hash_entry *h;
1642a6b7db3Sskrll struct cref_ref *r;
1652a6b7db3Sskrll
1662a6b7db3Sskrll if (!cref_initialized)
1672a6b7db3Sskrll {
1682a6b7db3Sskrll if (!bfd_hash_table_init (&cref_table.root, cref_hash_newfunc,
1692a6b7db3Sskrll sizeof (struct cref_hash_entry)))
1702a6b7db3Sskrll einfo (_("%X%P: bfd_hash_table_init of cref table failed: %E\n"));
1714f645668Schristos cref_initialized = true;
1722a6b7db3Sskrll }
1732a6b7db3Sskrll
1744f645668Schristos h = cref_hash_lookup (&cref_table, name, true, false);
1752a6b7db3Sskrll if (h == NULL)
1762a6b7db3Sskrll einfo (_("%X%P: cref_hash_lookup failed: %E\n"));
1772a6b7db3Sskrll
1782a6b7db3Sskrll for (r = h->refs; r != NULL; r = r->next)
1792a6b7db3Sskrll if (r->abfd == abfd)
1802a6b7db3Sskrll break;
1812a6b7db3Sskrll
1822a6b7db3Sskrll if (r == NULL)
1832a6b7db3Sskrll {
184be9ac0eaSchristos r = (struct cref_ref *) bfd_hash_allocate (&cref_table.root, sizeof *r);
1852a6b7db3Sskrll if (r == NULL)
1862a6b7db3Sskrll einfo (_("%X%P: cref alloc failed: %E\n"));
1872a6b7db3Sskrll r->next = h->refs;
1882a6b7db3Sskrll h->refs = r;
1892a6b7db3Sskrll r->abfd = abfd;
1904f645668Schristos r->def = false;
1914f645668Schristos r->common = false;
1924f645668Schristos r->undef = false;
1932a6b7db3Sskrll }
1942a6b7db3Sskrll
1952a6b7db3Sskrll if (bfd_is_und_section (section))
1964f645668Schristos r->undef = true;
1972a6b7db3Sskrll else if (bfd_is_com_section (section))
1984f645668Schristos r->common = true;
1992a6b7db3Sskrll else
2004f645668Schristos r->def = true;
2012a6b7db3Sskrll }
2022a6b7db3Sskrll
2032a6b7db3Sskrll /* Called before loading an as-needed library to take a snapshot of
2042a6b7db3Sskrll the cref hash table, and after we have loaded or found that the
2052a6b7db3Sskrll library was not needed. */
2062a6b7db3Sskrll
2074f645668Schristos bool
handle_asneeded_cref(bfd * abfd ATTRIBUTE_UNUSED,enum notice_asneeded_action act)2082a6b7db3Sskrll handle_asneeded_cref (bfd *abfd ATTRIBUTE_UNUSED,
2092a6b7db3Sskrll enum notice_asneeded_action act)
2102a6b7db3Sskrll {
2112a6b7db3Sskrll unsigned int i;
2122a6b7db3Sskrll
2132a6b7db3Sskrll if (!cref_initialized)
2144f645668Schristos return true;
2152a6b7db3Sskrll
2162a6b7db3Sskrll if (act == notice_as_needed)
2172a6b7db3Sskrll {
2182a6b7db3Sskrll char *old_ent, *old_ref;
2192a6b7db3Sskrll
2202a6b7db3Sskrll for (i = 0; i < cref_table.root.size; i++)
2212a6b7db3Sskrll {
2222a6b7db3Sskrll struct bfd_hash_entry *p;
2232a6b7db3Sskrll struct cref_hash_entry *c;
2242a6b7db3Sskrll struct cref_ref *r;
2252a6b7db3Sskrll
2262a6b7db3Sskrll for (p = cref_table.root.table[i]; p != NULL; p = p->next)
2272a6b7db3Sskrll {
2282a6b7db3Sskrll entsize += cref_table.root.entsize;
2292a6b7db3Sskrll c = (struct cref_hash_entry *) p;
2302a6b7db3Sskrll for (r = c->refs; r != NULL; r = r->next)
231be9ac0eaSchristos refsize += sizeof (struct cref_ref);
2322a6b7db3Sskrll }
2332a6b7db3Sskrll }
2342a6b7db3Sskrll
2352a6b7db3Sskrll tabsize = cref_table.root.size * sizeof (struct bfd_hash_entry *);
2362a6b7db3Sskrll old_tab = xmalloc (tabsize + entsize + refsize);
2372a6b7db3Sskrll
2382a6b7db3Sskrll alloc_mark = bfd_hash_allocate (&cref_table.root, 1);
2392a6b7db3Sskrll if (alloc_mark == NULL)
2404f645668Schristos return false;
2412a6b7db3Sskrll
2422a6b7db3Sskrll memcpy (old_tab, cref_table.root.table, tabsize);
2432a6b7db3Sskrll old_ent = (char *) old_tab + tabsize;
2442a6b7db3Sskrll old_ref = (char *) old_ent + entsize;
2452a6b7db3Sskrll old_table = cref_table.root.table;
2462a6b7db3Sskrll old_size = cref_table.root.size;
2472a6b7db3Sskrll old_count = cref_table.root.count;
2482a6b7db3Sskrll old_symcount = cref_symcount;
2492a6b7db3Sskrll
2502a6b7db3Sskrll for (i = 0; i < cref_table.root.size; i++)
2512a6b7db3Sskrll {
2522a6b7db3Sskrll struct bfd_hash_entry *p;
2532a6b7db3Sskrll struct cref_hash_entry *c;
2542a6b7db3Sskrll struct cref_ref *r;
2552a6b7db3Sskrll
2562a6b7db3Sskrll for (p = cref_table.root.table[i]; p != NULL; p = p->next)
2572a6b7db3Sskrll {
2582a6b7db3Sskrll memcpy (old_ent, p, cref_table.root.entsize);
2592a6b7db3Sskrll old_ent = (char *) old_ent + cref_table.root.entsize;
2602a6b7db3Sskrll c = (struct cref_hash_entry *) p;
2612a6b7db3Sskrll for (r = c->refs; r != NULL; r = r->next)
2622a6b7db3Sskrll {
263be9ac0eaSchristos memcpy (old_ref, r, sizeof (struct cref_ref));
264be9ac0eaSchristos old_ref = (char *) old_ref + sizeof (struct cref_ref);
2652a6b7db3Sskrll }
2662a6b7db3Sskrll }
2672a6b7db3Sskrll }
2684f645668Schristos return true;
2692a6b7db3Sskrll }
2702a6b7db3Sskrll
2712a6b7db3Sskrll if (act == notice_not_needed)
2722a6b7db3Sskrll {
2732a6b7db3Sskrll char *old_ent, *old_ref;
2742a6b7db3Sskrll
2752a6b7db3Sskrll if (old_tab == NULL)
2762a6b7db3Sskrll {
2772a6b7db3Sskrll /* The only way old_tab can be NULL is if the cref hash table
2782a6b7db3Sskrll had not been initialised when notice_as_needed. */
2792a6b7db3Sskrll bfd_hash_table_free (&cref_table.root);
2804f645668Schristos cref_initialized = false;
2814f645668Schristos return true;
2822a6b7db3Sskrll }
2832a6b7db3Sskrll
2842a6b7db3Sskrll old_ent = (char *) old_tab + tabsize;
2852a6b7db3Sskrll old_ref = (char *) old_ent + entsize;
2862a6b7db3Sskrll cref_table.root.table = old_table;
2872a6b7db3Sskrll cref_table.root.size = old_size;
2882a6b7db3Sskrll cref_table.root.count = old_count;
2892a6b7db3Sskrll memcpy (cref_table.root.table, old_tab, tabsize);
2902a6b7db3Sskrll cref_symcount = old_symcount;
2912a6b7db3Sskrll
2922a6b7db3Sskrll for (i = 0; i < cref_table.root.size; i++)
2932a6b7db3Sskrll {
2942a6b7db3Sskrll struct bfd_hash_entry *p;
2952a6b7db3Sskrll struct cref_hash_entry *c;
2962a6b7db3Sskrll struct cref_ref *r;
2972a6b7db3Sskrll
2982a6b7db3Sskrll for (p = cref_table.root.table[i]; p != NULL; p = p->next)
2992a6b7db3Sskrll {
3002a6b7db3Sskrll memcpy (p, old_ent, cref_table.root.entsize);
3012a6b7db3Sskrll old_ent = (char *) old_ent + cref_table.root.entsize;
3022a6b7db3Sskrll c = (struct cref_hash_entry *) p;
3032a6b7db3Sskrll for (r = c->refs; r != NULL; r = r->next)
3042a6b7db3Sskrll {
305be9ac0eaSchristos memcpy (r, old_ref, sizeof (struct cref_ref));
306be9ac0eaSchristos old_ref = (char *) old_ref + sizeof (struct cref_ref);
3072a6b7db3Sskrll }
3082a6b7db3Sskrll }
3092a6b7db3Sskrll }
3102a6b7db3Sskrll
3112a6b7db3Sskrll objalloc_free_block ((struct objalloc *) cref_table.root.memory,
3122a6b7db3Sskrll alloc_mark);
3132a6b7db3Sskrll }
3142a6b7db3Sskrll else if (act != notice_needed)
3154f645668Schristos return false;
3162a6b7db3Sskrll
3172a6b7db3Sskrll free (old_tab);
3182a6b7db3Sskrll old_tab = NULL;
3194f645668Schristos return true;
3202a6b7db3Sskrll }
3212a6b7db3Sskrll
3222a6b7db3Sskrll /* Copy the addresses of the hash table entries into an array. This
3232a6b7db3Sskrll is called via cref_hash_traverse. We also fill in the demangled
3242a6b7db3Sskrll name. */
3252a6b7db3Sskrll
3264f645668Schristos static bool
cref_fill_array(struct cref_hash_entry * h,void * data)3272a6b7db3Sskrll cref_fill_array (struct cref_hash_entry *h, void *data)
3282a6b7db3Sskrll {
329be9ac0eaSchristos struct cref_hash_entry ***pph = (struct cref_hash_entry ***) data;
3302a6b7db3Sskrll
3312a6b7db3Sskrll ASSERT (h->demangled == NULL);
3322a6b7db3Sskrll h->demangled = bfd_demangle (link_info.output_bfd, h->root.string,
3332a6b7db3Sskrll DMGL_ANSI | DMGL_PARAMS);
3342a6b7db3Sskrll if (h->demangled == NULL)
3352a6b7db3Sskrll h->demangled = h->root.string;
3362a6b7db3Sskrll
3372a6b7db3Sskrll **pph = h;
3382a6b7db3Sskrll
3392a6b7db3Sskrll ++*pph;
3402a6b7db3Sskrll
3414f645668Schristos return true;
3422a6b7db3Sskrll }
3432a6b7db3Sskrll
3442a6b7db3Sskrll /* Sort an array of cref hash table entries by name. */
3452a6b7db3Sskrll
3462a6b7db3Sskrll static int
cref_sort_array(const void * a1,const void * a2)3472a6b7db3Sskrll cref_sort_array (const void *a1, const void *a2)
3482a6b7db3Sskrll {
3498cbf5cb7Schristos const struct cref_hash_entry *const *p1
3508cbf5cb7Schristos = (const struct cref_hash_entry *const *) a1;
3518cbf5cb7Schristos const struct cref_hash_entry *const *p2
3528cbf5cb7Schristos = (const struct cref_hash_entry *const *) a2;
3532a6b7db3Sskrll
3549573673dSchristos if (demangling)
3552a6b7db3Sskrll return strcmp ((*p1)->demangled, (*p2)->demangled);
3569573673dSchristos else
3579573673dSchristos return strcmp ((*p1)->root.string, (*p2)->root.string);
3582a6b7db3Sskrll }
3592a6b7db3Sskrll
3602a6b7db3Sskrll /* Write out the cref table. */
3612a6b7db3Sskrll
3622a6b7db3Sskrll #define FILECOL (50)
3632a6b7db3Sskrll
3642a6b7db3Sskrll void
output_cref(FILE * fp)3652a6b7db3Sskrll output_cref (FILE *fp)
3662a6b7db3Sskrll {
3672a6b7db3Sskrll int len;
3682a6b7db3Sskrll struct cref_hash_entry **csyms, **csym_fill, **csym, **csym_end;
3692a6b7db3Sskrll const char *msg;
3702a6b7db3Sskrll
3712a6b7db3Sskrll fprintf (fp, _("\nCross Reference Table\n\n"));
3722a6b7db3Sskrll msg = _("Symbol");
3732a6b7db3Sskrll fprintf (fp, "%s", msg);
3742a6b7db3Sskrll len = strlen (msg);
3752a6b7db3Sskrll while (len < FILECOL)
3762a6b7db3Sskrll {
3772a6b7db3Sskrll putc (' ', fp);
3782a6b7db3Sskrll ++len;
3792a6b7db3Sskrll }
3802a6b7db3Sskrll fprintf (fp, _("File\n"));
3812a6b7db3Sskrll
3822a6b7db3Sskrll if (!cref_initialized)
3832a6b7db3Sskrll {
3842a6b7db3Sskrll fprintf (fp, _("No symbols\n"));
3852a6b7db3Sskrll return;
3862a6b7db3Sskrll }
3872a6b7db3Sskrll
388be9ac0eaSchristos csyms = (struct cref_hash_entry **) xmalloc (cref_symcount * sizeof (*csyms));
3892a6b7db3Sskrll
3902a6b7db3Sskrll csym_fill = csyms;
3912a6b7db3Sskrll cref_hash_traverse (&cref_table, cref_fill_array, &csym_fill);
3922a6b7db3Sskrll ASSERT ((size_t) (csym_fill - csyms) == cref_symcount);
3932a6b7db3Sskrll
3942a6b7db3Sskrll qsort (csyms, cref_symcount, sizeof (*csyms), cref_sort_array);
3952a6b7db3Sskrll
3962a6b7db3Sskrll csym_end = csyms + cref_symcount;
3972a6b7db3Sskrll for (csym = csyms; csym < csym_end; csym++)
3982a6b7db3Sskrll output_one_cref (fp, *csym);
3992a6b7db3Sskrll }
4002a6b7db3Sskrll
4012a6b7db3Sskrll /* Output one entry in the cross reference table. */
4022a6b7db3Sskrll
4032a6b7db3Sskrll static void
output_one_cref(FILE * fp,struct cref_hash_entry * h)4042a6b7db3Sskrll output_one_cref (FILE *fp, struct cref_hash_entry *h)
4052a6b7db3Sskrll {
4062a6b7db3Sskrll int len;
4072a6b7db3Sskrll struct bfd_link_hash_entry *hl;
4082a6b7db3Sskrll struct cref_ref *r;
4092a6b7db3Sskrll
4104f645668Schristos hl = bfd_link_hash_lookup (link_info.hash, h->root.string, false,
4114f645668Schristos false, true);
4122a6b7db3Sskrll if (hl == NULL)
413c1a20988Schristos einfo (_("%P: symbol `%pT' missing from main hash table\n"),
4142a6b7db3Sskrll h->root.string);
4152a6b7db3Sskrll else
4162a6b7db3Sskrll {
4172a6b7db3Sskrll /* If this symbol is defined in a dynamic object but never
4182a6b7db3Sskrll referenced by a normal object, then don't print it. */
4192a6b7db3Sskrll if (hl->type == bfd_link_hash_defined)
4202a6b7db3Sskrll {
4212a6b7db3Sskrll if (hl->u.def.section->output_section == NULL)
4222a6b7db3Sskrll return;
4232a6b7db3Sskrll if (hl->u.def.section->owner != NULL
4242a6b7db3Sskrll && (hl->u.def.section->owner->flags & DYNAMIC) != 0)
4252a6b7db3Sskrll {
4262a6b7db3Sskrll for (r = h->refs; r != NULL; r = r->next)
4272a6b7db3Sskrll if ((r->abfd->flags & DYNAMIC) == 0)
4282a6b7db3Sskrll break;
4292a6b7db3Sskrll if (r == NULL)
4302a6b7db3Sskrll return;
4312a6b7db3Sskrll }
4322a6b7db3Sskrll }
4332a6b7db3Sskrll }
4342a6b7db3Sskrll
4359573673dSchristos if (demangling)
4369573673dSchristos {
4372a6b7db3Sskrll fprintf (fp, "%s ", h->demangled);
4382a6b7db3Sskrll len = strlen (h->demangled) + 1;
4399573673dSchristos }
4409573673dSchristos else
4419573673dSchristos {
4429573673dSchristos fprintf (fp, "%s ", h->root.string);
4439573673dSchristos len = strlen (h->root.string) + 1;
4449573673dSchristos }
4452a6b7db3Sskrll
4462a6b7db3Sskrll for (r = h->refs; r != NULL; r = r->next)
4472a6b7db3Sskrll {
4482a6b7db3Sskrll if (r->def)
4492a6b7db3Sskrll {
4502a6b7db3Sskrll while (len < FILECOL)
4512a6b7db3Sskrll {
4522a6b7db3Sskrll putc (' ', fp);
4532a6b7db3Sskrll ++len;
4542a6b7db3Sskrll }
455c1a20988Schristos lfinfo (fp, "%pB\n", r->abfd);
4562a6b7db3Sskrll len = 0;
4572a6b7db3Sskrll }
4582a6b7db3Sskrll }
4592a6b7db3Sskrll
4602a6b7db3Sskrll for (r = h->refs; r != NULL; r = r->next)
4612a6b7db3Sskrll {
4629573673dSchristos if (r->common)
4639573673dSchristos {
4649573673dSchristos while (len < FILECOL)
4659573673dSchristos {
4669573673dSchristos putc (' ', fp);
4679573673dSchristos ++len;
4689573673dSchristos }
469c1a20988Schristos lfinfo (fp, "%pB\n", r->abfd);
4709573673dSchristos len = 0;
4719573673dSchristos }
4729573673dSchristos }
4739573673dSchristos
4749573673dSchristos for (r = h->refs; r != NULL; r = r->next)
4759573673dSchristos {
4769573673dSchristos if (!r->def && !r->common)
4772a6b7db3Sskrll {
4782a6b7db3Sskrll while (len < FILECOL)
4792a6b7db3Sskrll {
4802a6b7db3Sskrll putc (' ', fp);
4812a6b7db3Sskrll ++len;
4822a6b7db3Sskrll }
483c1a20988Schristos lfinfo (fp, "%pB\n", r->abfd);
4842a6b7db3Sskrll len = 0;
4852a6b7db3Sskrll }
4862a6b7db3Sskrll }
4872a6b7db3Sskrll
4882a6b7db3Sskrll ASSERT (len == 0);
4892a6b7db3Sskrll }
4902a6b7db3Sskrll
4912a6b7db3Sskrll /* Check for prohibited cross references. */
4922a6b7db3Sskrll
4932a6b7db3Sskrll void
check_nocrossrefs(void)4942a6b7db3Sskrll check_nocrossrefs (void)
4952a6b7db3Sskrll {
4962a6b7db3Sskrll if (!cref_initialized)
4972a6b7db3Sskrll return;
4982a6b7db3Sskrll
4992a6b7db3Sskrll cref_hash_traverse (&cref_table, check_nocrossref, NULL);
5002a6b7db3Sskrll
5012a6b7db3Sskrll lang_for_each_file (check_local_sym_xref);
5022a6b7db3Sskrll }
5032a6b7db3Sskrll
5042a6b7db3Sskrll /* Check for prohibited cross references to local and section symbols. */
5052a6b7db3Sskrll
5062a6b7db3Sskrll static void
check_local_sym_xref(lang_input_statement_type * statement)5072a6b7db3Sskrll check_local_sym_xref (lang_input_statement_type *statement)
5082a6b7db3Sskrll {
5092a6b7db3Sskrll bfd *abfd;
5102a6b7db3Sskrll asymbol **syms;
5112a6b7db3Sskrll
5122a6b7db3Sskrll abfd = statement->the_bfd;
5132a6b7db3Sskrll if (abfd == NULL)
5142a6b7db3Sskrll return;
5152a6b7db3Sskrll
5162a6b7db3Sskrll if (!bfd_generic_link_read_symbols (abfd))
517c1a20988Schristos einfo (_("%F%P: %pB: could not read symbols: %E\n"), abfd);
5182a6b7db3Sskrll
5192a6b7db3Sskrll for (syms = bfd_get_outsymbols (abfd); *syms; ++syms)
5202a6b7db3Sskrll {
5212a6b7db3Sskrll asymbol *sym = *syms;
5222a6b7db3Sskrll if (sym->flags & (BSF_GLOBAL | BSF_WARNING | BSF_INDIRECT | BSF_FILE))
5232a6b7db3Sskrll continue;
5242a6b7db3Sskrll if ((sym->flags & (BSF_LOCAL | BSF_SECTION_SYM)) != 0
5252a6b7db3Sskrll && sym->section->output_section != NULL)
5262a6b7db3Sskrll {
5272a6b7db3Sskrll const char *outsecname, *symname;
5282a6b7db3Sskrll struct lang_nocrossrefs *ncrs;
5292a6b7db3Sskrll struct lang_nocrossref *ncr;
5302a6b7db3Sskrll
5312a6b7db3Sskrll outsecname = sym->section->output_section->name;
5322a6b7db3Sskrll symname = NULL;
5332a6b7db3Sskrll if ((sym->flags & BSF_SECTION_SYM) == 0)
5342a6b7db3Sskrll symname = sym->name;
5352a6b7db3Sskrll for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next)
5362a6b7db3Sskrll for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next)
5378cbf5cb7Schristos {
5382a6b7db3Sskrll if (strcmp (ncr->name, outsecname) == 0)
5394f645668Schristos check_refs (symname, false, sym->section, abfd, ncrs);
5408cbf5cb7Schristos /* The NOCROSSREFS_TO command only checks symbols defined in
5418cbf5cb7Schristos the first section in the list. */
5428cbf5cb7Schristos if (ncrs->onlyfirst)
5438cbf5cb7Schristos break;
5448cbf5cb7Schristos }
5452a6b7db3Sskrll }
5462a6b7db3Sskrll }
5472a6b7db3Sskrll }
5482a6b7db3Sskrll
5492a6b7db3Sskrll /* Check one symbol to see if it is a prohibited cross reference. */
5502a6b7db3Sskrll
5514f645668Schristos static bool
check_nocrossref(struct cref_hash_entry * h,void * ignore ATTRIBUTE_UNUSED)5522a6b7db3Sskrll check_nocrossref (struct cref_hash_entry *h, void *ignore ATTRIBUTE_UNUSED)
5532a6b7db3Sskrll {
5542a6b7db3Sskrll struct bfd_link_hash_entry *hl;
5552a6b7db3Sskrll asection *defsec;
5562a6b7db3Sskrll const char *defsecname;
5572a6b7db3Sskrll struct lang_nocrossrefs *ncrs;
5582a6b7db3Sskrll struct lang_nocrossref *ncr;
5592a6b7db3Sskrll struct cref_ref *ref;
5602a6b7db3Sskrll
5614f645668Schristos hl = bfd_link_hash_lookup (link_info.hash, h->root.string, false,
5624f645668Schristos false, true);
5632a6b7db3Sskrll if (hl == NULL)
5642a6b7db3Sskrll {
565c1a20988Schristos einfo (_("%P: symbol `%pT' missing from main hash table\n"),
5662a6b7db3Sskrll h->root.string);
5674f645668Schristos return true;
5682a6b7db3Sskrll }
5692a6b7db3Sskrll
5702a6b7db3Sskrll if (hl->type != bfd_link_hash_defined
5712a6b7db3Sskrll && hl->type != bfd_link_hash_defweak)
5724f645668Schristos return true;
5732a6b7db3Sskrll
5742a6b7db3Sskrll defsec = hl->u.def.section->output_section;
5752a6b7db3Sskrll if (defsec == NULL)
5764f645668Schristos return true;
5776f4ced0bSchristos defsecname = bfd_section_name (defsec);
5782a6b7db3Sskrll
5792a6b7db3Sskrll for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next)
5802a6b7db3Sskrll for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next)
5818cbf5cb7Schristos {
5822a6b7db3Sskrll if (strcmp (ncr->name, defsecname) == 0)
5832a6b7db3Sskrll for (ref = h->refs; ref != NULL; ref = ref->next)
5844f645668Schristos check_refs (hl->root.string, true, hl->u.def.section,
5852a6b7db3Sskrll ref->abfd, ncrs);
5868cbf5cb7Schristos /* The NOCROSSREFS_TO command only checks symbols defined in the first
5878cbf5cb7Schristos section in the list. */
5888cbf5cb7Schristos if (ncrs->onlyfirst)
5898cbf5cb7Schristos break;
5908cbf5cb7Schristos }
5912a6b7db3Sskrll
5924f645668Schristos return true;
5932a6b7db3Sskrll }
5942a6b7db3Sskrll
5952a6b7db3Sskrll /* The struct is used to pass information from check_refs to
5962a6b7db3Sskrll check_reloc_refs through bfd_map_over_sections. */
5972a6b7db3Sskrll
5988cbf5cb7Schristos struct check_refs_info
5998cbf5cb7Schristos {
6002a6b7db3Sskrll const char *sym_name;
6012a6b7db3Sskrll asection *defsec;
6022a6b7db3Sskrll struct lang_nocrossrefs *ncrs;
6032a6b7db3Sskrll asymbol **asymbols;
6044f645668Schristos bool global;
6052a6b7db3Sskrll };
6062a6b7db3Sskrll
6072a6b7db3Sskrll /* This function is called for each symbol defined in a section which
6082a6b7db3Sskrll prohibits cross references. We need to look through all references
6092a6b7db3Sskrll to this symbol, and ensure that the references are not from
6102a6b7db3Sskrll prohibited sections. */
6112a6b7db3Sskrll
6122a6b7db3Sskrll static void
check_refs(const char * name,bool global,asection * sec,bfd * abfd,struct lang_nocrossrefs * ncrs)6132a6b7db3Sskrll check_refs (const char *name,
6144f645668Schristos bool global,
6152a6b7db3Sskrll asection *sec,
6162a6b7db3Sskrll bfd *abfd,
6172a6b7db3Sskrll struct lang_nocrossrefs *ncrs)
6182a6b7db3Sskrll {
6192a6b7db3Sskrll struct check_refs_info info;
6202a6b7db3Sskrll
6212a6b7db3Sskrll /* We need to look through the relocations for this BFD, to see
6222a6b7db3Sskrll if any of the relocations which refer to this symbol are from
6232a6b7db3Sskrll a prohibited section. Note that we need to do this even for
6242a6b7db3Sskrll the BFD in which the symbol is defined, since even a single
6252a6b7db3Sskrll BFD might contain a prohibited cross reference. */
6262a6b7db3Sskrll
6272a6b7db3Sskrll if (!bfd_generic_link_read_symbols (abfd))
628c1a20988Schristos einfo (_("%F%P: %pB: could not read symbols: %E\n"), abfd);
6292a6b7db3Sskrll
6302a6b7db3Sskrll info.sym_name = name;
6312a6b7db3Sskrll info.global = global;
6322a6b7db3Sskrll info.defsec = sec;
6332a6b7db3Sskrll info.ncrs = ncrs;
6342a6b7db3Sskrll info.asymbols = bfd_get_outsymbols (abfd);
6352a6b7db3Sskrll bfd_map_over_sections (abfd, check_reloc_refs, &info);
6362a6b7db3Sskrll }
6372a6b7db3Sskrll
6382a6b7db3Sskrll /* This is called via bfd_map_over_sections. INFO->SYM_NAME is a symbol
6392a6b7db3Sskrll defined in INFO->DEFSECNAME. If this section maps into any of the
6402a6b7db3Sskrll sections listed in INFO->NCRS, other than INFO->DEFSECNAME, then we
6412a6b7db3Sskrll look through the relocations. If any of the relocations are to
6422a6b7db3Sskrll INFO->SYM_NAME, then we report a prohibited cross reference error. */
6432a6b7db3Sskrll
6442a6b7db3Sskrll static void
check_reloc_refs(bfd * abfd,asection * sec,void * iarg)6452a6b7db3Sskrll check_reloc_refs (bfd *abfd, asection *sec, void *iarg)
6462a6b7db3Sskrll {
647be9ac0eaSchristos struct check_refs_info *info = (struct check_refs_info *) iarg;
6482a6b7db3Sskrll asection *outsec;
6492a6b7db3Sskrll const char *outsecname;
6502a6b7db3Sskrll asection *outdefsec;
6512a6b7db3Sskrll const char *outdefsecname;
6522a6b7db3Sskrll struct lang_nocrossref *ncr;
6532a6b7db3Sskrll const char *symname;
6544f645668Schristos bool global;
6552a6b7db3Sskrll long relsize;
6562a6b7db3Sskrll arelent **relpp;
6572a6b7db3Sskrll long relcount;
6582a6b7db3Sskrll arelent **p, **pend;
6592a6b7db3Sskrll
6602a6b7db3Sskrll outsec = sec->output_section;
6616f4ced0bSchristos outsecname = bfd_section_name (outsec);
6622a6b7db3Sskrll
6632a6b7db3Sskrll outdefsec = info->defsec->output_section;
6646f4ced0bSchristos outdefsecname = bfd_section_name (outdefsec);
6652a6b7db3Sskrll
6662a6b7db3Sskrll /* The section where the symbol is defined is permitted. */
6672a6b7db3Sskrll if (strcmp (outsecname, outdefsecname) == 0)
6682a6b7db3Sskrll return;
6692a6b7db3Sskrll
6702a6b7db3Sskrll for (ncr = info->ncrs->list; ncr != NULL; ncr = ncr->next)
6712a6b7db3Sskrll if (strcmp (outsecname, ncr->name) == 0)
6722a6b7db3Sskrll break;
6732a6b7db3Sskrll
6742a6b7db3Sskrll if (ncr == NULL)
6752a6b7db3Sskrll return;
6762a6b7db3Sskrll
6772a6b7db3Sskrll /* This section is one for which cross references are prohibited.
6782a6b7db3Sskrll Look through the relocations, and see if any of them are to
6792a6b7db3Sskrll INFO->SYM_NAME. If INFO->SYMNAME is NULL, check for relocations
6802a6b7db3Sskrll against the section symbol. If INFO->GLOBAL is TRUE, the
6812a6b7db3Sskrll definition is global, check for relocations against the global
6822a6b7db3Sskrll symbols. Otherwise check for relocations against the local and
6832a6b7db3Sskrll section symbols. */
6842a6b7db3Sskrll
6852a6b7db3Sskrll symname = info->sym_name;
6862a6b7db3Sskrll global = info->global;
6872a6b7db3Sskrll
6882a6b7db3Sskrll relsize = bfd_get_reloc_upper_bound (abfd, sec);
6892a6b7db3Sskrll if (relsize < 0)
690c1a20988Schristos einfo (_("%F%P: %pB: could not read relocs: %E\n"), abfd);
6912a6b7db3Sskrll if (relsize == 0)
6922a6b7db3Sskrll return;
6932a6b7db3Sskrll
694be9ac0eaSchristos relpp = (arelent **) xmalloc (relsize);
6952a6b7db3Sskrll relcount = bfd_canonicalize_reloc (abfd, sec, relpp, info->asymbols);
6962a6b7db3Sskrll if (relcount < 0)
697c1a20988Schristos einfo (_("%F%P: %pB: could not read relocs: %E\n"), abfd);
6982a6b7db3Sskrll
6992a6b7db3Sskrll p = relpp;
7002a6b7db3Sskrll pend = p + relcount;
7012a6b7db3Sskrll for (; p < pend && *p != NULL; p++)
7022a6b7db3Sskrll {
7032a6b7db3Sskrll arelent *q = *p;
7042a6b7db3Sskrll
7052a6b7db3Sskrll if (q->sym_ptr_ptr != NULL
7062a6b7db3Sskrll && *q->sym_ptr_ptr != NULL
7072a6b7db3Sskrll && ((global
7086f4ced0bSchristos && (bfd_is_und_section (bfd_asymbol_section (*q->sym_ptr_ptr))
7096f4ced0bSchristos || bfd_is_com_section (bfd_asymbol_section (*q->sym_ptr_ptr))
7102a6b7db3Sskrll || ((*q->sym_ptr_ptr)->flags & (BSF_GLOBAL
7112a6b7db3Sskrll | BSF_WEAK)) != 0))
7122a6b7db3Sskrll || (!global
7132a6b7db3Sskrll && ((*q->sym_ptr_ptr)->flags & (BSF_LOCAL
7142a6b7db3Sskrll | BSF_SECTION_SYM)) != 0
7156f4ced0bSchristos && bfd_asymbol_section (*q->sym_ptr_ptr) == info->defsec))
7162a6b7db3Sskrll && (symname != NULL
7172a6b7db3Sskrll ? strcmp (bfd_asymbol_name (*q->sym_ptr_ptr), symname) == 0
7182a6b7db3Sskrll : ((*q->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0))
7192a6b7db3Sskrll {
7202a6b7db3Sskrll /* We found a reloc for the symbol. The symbol is defined
7212a6b7db3Sskrll in OUTSECNAME. This reloc is from a section which is
7222a6b7db3Sskrll mapped into a section from which references to OUTSECNAME
7232a6b7db3Sskrll are prohibited. We must report an error. */
724*cb63e24eSchristos einfo (_("%X%P: %H: prohibited cross reference from %s to `%pT' in %s\n"),
7252a6b7db3Sskrll abfd, sec, q->address, outsecname,
7262a6b7db3Sskrll bfd_asymbol_name (*q->sym_ptr_ptr), outdefsecname);
7272a6b7db3Sskrll }
7282a6b7db3Sskrll }
7292a6b7db3Sskrll
7302a6b7db3Sskrll free (relpp);
7312a6b7db3Sskrll }
732