175fd0b74Schristos /* ldcref.c -- output a cross reference table
2*e992f068Schristos Copyright (C) 1996-2022 Free Software Foundation, Inc.
375fd0b74Schristos Written by Ian Lance Taylor <ian@cygnus.com>
475fd0b74Schristos
575fd0b74Schristos This file is part of the GNU Binutils.
675fd0b74Schristos
775fd0b74Schristos This program is free software; you can redistribute it and/or modify
875fd0b74Schristos it under the terms of the GNU General Public License as published by
975fd0b74Schristos the Free Software Foundation; either version 3 of the License, or
1075fd0b74Schristos (at your option) any later version.
1175fd0b74Schristos
1275fd0b74Schristos This program is distributed in the hope that it will be useful,
1375fd0b74Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
1475fd0b74Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1575fd0b74Schristos GNU General Public License for more details.
1675fd0b74Schristos
1775fd0b74Schristos You should have received a copy of the GNU General Public License
1875fd0b74Schristos along with this program; if not, write to the Free Software
1975fd0b74Schristos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
2075fd0b74Schristos MA 02110-1301, USA. */
2175fd0b74Schristos
2275fd0b74Schristos
2375fd0b74Schristos /* This file holds routines that manage the cross reference table.
2475fd0b74Schristos The table is used to generate cross reference reports. It is also
2575fd0b74Schristos used to implement the NOCROSSREFS command in the linker script. */
2675fd0b74Schristos
2775fd0b74Schristos #include "sysdep.h"
2875fd0b74Schristos #include "bfd.h"
2975fd0b74Schristos #include "bfdlink.h"
30012573ebSchristos #include "ctf-api.h"
3175fd0b74Schristos #include "libiberty.h"
3275fd0b74Schristos #include "demangle.h"
3375fd0b74Schristos #include "objalloc.h"
3475fd0b74Schristos
3575fd0b74Schristos #include "ld.h"
3675fd0b74Schristos #include "ldmain.h"
3775fd0b74Schristos #include "ldmisc.h"
3875fd0b74Schristos #include "ldexp.h"
3975fd0b74Schristos #include "ldlang.h"
4075fd0b74Schristos
4175fd0b74Schristos /* We keep an instance of this structure for each reference to a
4275fd0b74Schristos symbol from a given object. */
4375fd0b74Schristos
4475fd0b74Schristos struct cref_ref
4575fd0b74Schristos {
4675fd0b74Schristos /* The next reference. */
4775fd0b74Schristos struct cref_ref *next;
4875fd0b74Schristos /* The object. */
4975fd0b74Schristos bfd *abfd;
5075fd0b74Schristos /* True if the symbol is defined. */
5175fd0b74Schristos unsigned int def : 1;
5275fd0b74Schristos /* True if the symbol is common. */
5375fd0b74Schristos unsigned int common : 1;
5475fd0b74Schristos /* True if the symbol is undefined. */
5575fd0b74Schristos unsigned int undef : 1;
5675fd0b74Schristos };
5775fd0b74Schristos
5875fd0b74Schristos /* We keep a hash table of symbols. Each entry looks like this. */
5975fd0b74Schristos
6075fd0b74Schristos struct cref_hash_entry
6175fd0b74Schristos {
6275fd0b74Schristos struct bfd_hash_entry root;
6375fd0b74Schristos /* The demangled name. */
6475fd0b74Schristos const char *demangled;
6575fd0b74Schristos /* References to and definitions of this symbol. */
6675fd0b74Schristos struct cref_ref *refs;
6775fd0b74Schristos };
6875fd0b74Schristos
6975fd0b74Schristos /* This is what the hash table looks like. */
7075fd0b74Schristos
7175fd0b74Schristos struct cref_hash_table
7275fd0b74Schristos {
7375fd0b74Schristos struct bfd_hash_table root;
7475fd0b74Schristos };
7575fd0b74Schristos
7675fd0b74Schristos /* Forward declarations. */
7775fd0b74Schristos
7875fd0b74Schristos static void output_one_cref (FILE *, struct cref_hash_entry *);
7975fd0b74Schristos static void check_local_sym_xref (lang_input_statement_type *);
80*e992f068Schristos static bool check_nocrossref (struct cref_hash_entry *, void *);
81*e992f068Schristos static void check_refs (const char *, bool, asection *, bfd *,
8275fd0b74Schristos struct lang_nocrossrefs *);
8375fd0b74Schristos static void check_reloc_refs (bfd *, asection *, void *);
8475fd0b74Schristos
8575fd0b74Schristos /* Look up an entry in the cref hash table. */
8675fd0b74Schristos
8775fd0b74Schristos #define cref_hash_lookup(table, string, create, copy) \
8875fd0b74Schristos ((struct cref_hash_entry *) \
8975fd0b74Schristos bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
9075fd0b74Schristos
9175fd0b74Schristos /* Traverse the cref hash table. */
9275fd0b74Schristos
9375fd0b74Schristos #define cref_hash_traverse(table, func, info) \
9475fd0b74Schristos (bfd_hash_traverse \
9575fd0b74Schristos (&(table)->root, \
96*e992f068Schristos (bool (*) (struct bfd_hash_entry *, void *)) (func), (info)))
9775fd0b74Schristos
9875fd0b74Schristos /* The cref hash table. */
9975fd0b74Schristos
10075fd0b74Schristos static struct cref_hash_table cref_table;
10175fd0b74Schristos
10275fd0b74Schristos /* Whether the cref hash table has been initialized. */
10375fd0b74Schristos
104*e992f068Schristos static bool cref_initialized;
10575fd0b74Schristos
10675fd0b74Schristos /* The number of symbols seen so far. */
10775fd0b74Schristos
10875fd0b74Schristos static size_t cref_symcount;
10975fd0b74Schristos
11075fd0b74Schristos /* Used to take a snapshot of the cref hash table when starting to
11175fd0b74Schristos add syms from an as-needed library. */
11275fd0b74Schristos static struct bfd_hash_entry **old_table;
11375fd0b74Schristos static unsigned int old_size;
11475fd0b74Schristos static unsigned int old_count;
11575fd0b74Schristos static void *old_tab;
11675fd0b74Schristos static void *alloc_mark;
11775fd0b74Schristos static size_t tabsize, entsize, refsize;
11875fd0b74Schristos static size_t old_symcount;
11975fd0b74Schristos
12075fd0b74Schristos /* Create an entry in a cref hash table. */
12175fd0b74Schristos
12275fd0b74Schristos static struct bfd_hash_entry *
cref_hash_newfunc(struct bfd_hash_entry * entry,struct bfd_hash_table * table,const char * string)12375fd0b74Schristos cref_hash_newfunc (struct bfd_hash_entry *entry,
12475fd0b74Schristos struct bfd_hash_table *table,
12575fd0b74Schristos const char *string)
12675fd0b74Schristos {
12775fd0b74Schristos struct cref_hash_entry *ret = (struct cref_hash_entry *) entry;
12875fd0b74Schristos
12975fd0b74Schristos /* Allocate the structure if it has not already been allocated by a
13075fd0b74Schristos subclass. */
13175fd0b74Schristos if (ret == NULL)
13275fd0b74Schristos ret = ((struct cref_hash_entry *)
13375fd0b74Schristos bfd_hash_allocate (table, sizeof (struct cref_hash_entry)));
13475fd0b74Schristos if (ret == NULL)
13575fd0b74Schristos return NULL;
13675fd0b74Schristos
13775fd0b74Schristos /* Call the allocation method of the superclass. */
13875fd0b74Schristos ret = ((struct cref_hash_entry *)
13975fd0b74Schristos bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
14075fd0b74Schristos if (ret != NULL)
14175fd0b74Schristos {
14275fd0b74Schristos /* Set local fields. */
14375fd0b74Schristos ret->demangled = NULL;
14475fd0b74Schristos ret->refs = NULL;
14575fd0b74Schristos
14675fd0b74Schristos /* Keep a count of the number of entries created in the hash
14775fd0b74Schristos table. */
14875fd0b74Schristos ++cref_symcount;
14975fd0b74Schristos }
15075fd0b74Schristos
15175fd0b74Schristos return &ret->root;
15275fd0b74Schristos }
15375fd0b74Schristos
15475fd0b74Schristos /* Add a symbol to the cref hash table. This is called for every
15575fd0b74Schristos global symbol that is seen during the link. */
15675fd0b74Schristos
15775fd0b74Schristos void
add_cref(const char * name,bfd * abfd,asection * section,bfd_vma value ATTRIBUTE_UNUSED)15875fd0b74Schristos add_cref (const char *name,
15975fd0b74Schristos bfd *abfd,
16075fd0b74Schristos asection *section,
16175fd0b74Schristos bfd_vma value ATTRIBUTE_UNUSED)
16275fd0b74Schristos {
16375fd0b74Schristos struct cref_hash_entry *h;
16475fd0b74Schristos struct cref_ref *r;
16575fd0b74Schristos
16675fd0b74Schristos if (!cref_initialized)
16775fd0b74Schristos {
16875fd0b74Schristos if (!bfd_hash_table_init (&cref_table.root, cref_hash_newfunc,
16975fd0b74Schristos sizeof (struct cref_hash_entry)))
17075fd0b74Schristos einfo (_("%X%P: bfd_hash_table_init of cref table failed: %E\n"));
171*e992f068Schristos cref_initialized = true;
17275fd0b74Schristos }
17375fd0b74Schristos
174*e992f068Schristos h = cref_hash_lookup (&cref_table, name, true, false);
17575fd0b74Schristos if (h == NULL)
17675fd0b74Schristos einfo (_("%X%P: cref_hash_lookup failed: %E\n"));
17775fd0b74Schristos
17875fd0b74Schristos for (r = h->refs; r != NULL; r = r->next)
17975fd0b74Schristos if (r->abfd == abfd)
18075fd0b74Schristos break;
18175fd0b74Schristos
18275fd0b74Schristos if (r == NULL)
18375fd0b74Schristos {
18475fd0b74Schristos r = (struct cref_ref *) bfd_hash_allocate (&cref_table.root, sizeof *r);
18575fd0b74Schristos if (r == NULL)
18675fd0b74Schristos einfo (_("%X%P: cref alloc failed: %E\n"));
18775fd0b74Schristos r->next = h->refs;
18875fd0b74Schristos h->refs = r;
18975fd0b74Schristos r->abfd = abfd;
190*e992f068Schristos r->def = false;
191*e992f068Schristos r->common = false;
192*e992f068Schristos r->undef = false;
19375fd0b74Schristos }
19475fd0b74Schristos
19575fd0b74Schristos if (bfd_is_und_section (section))
196*e992f068Schristos r->undef = true;
19775fd0b74Schristos else if (bfd_is_com_section (section))
198*e992f068Schristos r->common = true;
19975fd0b74Schristos else
200*e992f068Schristos r->def = true;
20175fd0b74Schristos }
20275fd0b74Schristos
20375fd0b74Schristos /* Called before loading an as-needed library to take a snapshot of
20475fd0b74Schristos the cref hash table, and after we have loaded or found that the
20575fd0b74Schristos library was not needed. */
20675fd0b74Schristos
207*e992f068Schristos bool
handle_asneeded_cref(bfd * abfd ATTRIBUTE_UNUSED,enum notice_asneeded_action act)20875fd0b74Schristos handle_asneeded_cref (bfd *abfd ATTRIBUTE_UNUSED,
20975fd0b74Schristos enum notice_asneeded_action act)
21075fd0b74Schristos {
21175fd0b74Schristos unsigned int i;
21275fd0b74Schristos
21375fd0b74Schristos if (!cref_initialized)
214*e992f068Schristos return true;
21575fd0b74Schristos
21675fd0b74Schristos if (act == notice_as_needed)
21775fd0b74Schristos {
21875fd0b74Schristos char *old_ent, *old_ref;
21975fd0b74Schristos
22075fd0b74Schristos for (i = 0; i < cref_table.root.size; i++)
22175fd0b74Schristos {
22275fd0b74Schristos struct bfd_hash_entry *p;
22375fd0b74Schristos struct cref_hash_entry *c;
22475fd0b74Schristos struct cref_ref *r;
22575fd0b74Schristos
22675fd0b74Schristos for (p = cref_table.root.table[i]; p != NULL; p = p->next)
22775fd0b74Schristos {
22875fd0b74Schristos entsize += cref_table.root.entsize;
22975fd0b74Schristos c = (struct cref_hash_entry *) p;
23075fd0b74Schristos for (r = c->refs; r != NULL; r = r->next)
23175fd0b74Schristos refsize += sizeof (struct cref_ref);
23275fd0b74Schristos }
23375fd0b74Schristos }
23475fd0b74Schristos
23575fd0b74Schristos tabsize = cref_table.root.size * sizeof (struct bfd_hash_entry *);
23675fd0b74Schristos old_tab = xmalloc (tabsize + entsize + refsize);
23775fd0b74Schristos
23875fd0b74Schristos alloc_mark = bfd_hash_allocate (&cref_table.root, 1);
23975fd0b74Schristos if (alloc_mark == NULL)
240*e992f068Schristos return false;
24175fd0b74Schristos
24275fd0b74Schristos memcpy (old_tab, cref_table.root.table, tabsize);
24375fd0b74Schristos old_ent = (char *) old_tab + tabsize;
24475fd0b74Schristos old_ref = (char *) old_ent + entsize;
24575fd0b74Schristos old_table = cref_table.root.table;
24675fd0b74Schristos old_size = cref_table.root.size;
24775fd0b74Schristos old_count = cref_table.root.count;
24875fd0b74Schristos old_symcount = cref_symcount;
24975fd0b74Schristos
25075fd0b74Schristos for (i = 0; i < cref_table.root.size; i++)
25175fd0b74Schristos {
25275fd0b74Schristos struct bfd_hash_entry *p;
25375fd0b74Schristos struct cref_hash_entry *c;
25475fd0b74Schristos struct cref_ref *r;
25575fd0b74Schristos
25675fd0b74Schristos for (p = cref_table.root.table[i]; p != NULL; p = p->next)
25775fd0b74Schristos {
25875fd0b74Schristos memcpy (old_ent, p, cref_table.root.entsize);
25975fd0b74Schristos old_ent = (char *) old_ent + cref_table.root.entsize;
26075fd0b74Schristos c = (struct cref_hash_entry *) p;
26175fd0b74Schristos for (r = c->refs; r != NULL; r = r->next)
26275fd0b74Schristos {
26375fd0b74Schristos memcpy (old_ref, r, sizeof (struct cref_ref));
26475fd0b74Schristos old_ref = (char *) old_ref + sizeof (struct cref_ref);
26575fd0b74Schristos }
26675fd0b74Schristos }
26775fd0b74Schristos }
268*e992f068Schristos return true;
26975fd0b74Schristos }
27075fd0b74Schristos
27175fd0b74Schristos if (act == notice_not_needed)
27275fd0b74Schristos {
27375fd0b74Schristos char *old_ent, *old_ref;
27475fd0b74Schristos
27575fd0b74Schristos if (old_tab == NULL)
27675fd0b74Schristos {
27775fd0b74Schristos /* The only way old_tab can be NULL is if the cref hash table
27875fd0b74Schristos had not been initialised when notice_as_needed. */
27975fd0b74Schristos bfd_hash_table_free (&cref_table.root);
280*e992f068Schristos cref_initialized = false;
281*e992f068Schristos return true;
28275fd0b74Schristos }
28375fd0b74Schristos
28475fd0b74Schristos old_ent = (char *) old_tab + tabsize;
28575fd0b74Schristos old_ref = (char *) old_ent + entsize;
28675fd0b74Schristos cref_table.root.table = old_table;
28775fd0b74Schristos cref_table.root.size = old_size;
28875fd0b74Schristos cref_table.root.count = old_count;
28975fd0b74Schristos memcpy (cref_table.root.table, old_tab, tabsize);
29075fd0b74Schristos cref_symcount = old_symcount;
29175fd0b74Schristos
29275fd0b74Schristos for (i = 0; i < cref_table.root.size; i++)
29375fd0b74Schristos {
29475fd0b74Schristos struct bfd_hash_entry *p;
29575fd0b74Schristos struct cref_hash_entry *c;
29675fd0b74Schristos struct cref_ref *r;
29775fd0b74Schristos
29875fd0b74Schristos for (p = cref_table.root.table[i]; p != NULL; p = p->next)
29975fd0b74Schristos {
30075fd0b74Schristos memcpy (p, old_ent, cref_table.root.entsize);
30175fd0b74Schristos old_ent = (char *) old_ent + cref_table.root.entsize;
30275fd0b74Schristos c = (struct cref_hash_entry *) p;
30375fd0b74Schristos for (r = c->refs; r != NULL; r = r->next)
30475fd0b74Schristos {
30575fd0b74Schristos memcpy (r, old_ref, sizeof (struct cref_ref));
30675fd0b74Schristos old_ref = (char *) old_ref + sizeof (struct cref_ref);
30775fd0b74Schristos }
30875fd0b74Schristos }
30975fd0b74Schristos }
31075fd0b74Schristos
31175fd0b74Schristos objalloc_free_block ((struct objalloc *) cref_table.root.memory,
31275fd0b74Schristos alloc_mark);
31375fd0b74Schristos }
31475fd0b74Schristos else if (act != notice_needed)
315*e992f068Schristos return false;
31675fd0b74Schristos
31775fd0b74Schristos free (old_tab);
31875fd0b74Schristos old_tab = NULL;
319*e992f068Schristos return true;
32075fd0b74Schristos }
32175fd0b74Schristos
32275fd0b74Schristos /* Copy the addresses of the hash table entries into an array. This
32375fd0b74Schristos is called via cref_hash_traverse. We also fill in the demangled
32475fd0b74Schristos name. */
32575fd0b74Schristos
326*e992f068Schristos static bool
cref_fill_array(struct cref_hash_entry * h,void * data)32775fd0b74Schristos cref_fill_array (struct cref_hash_entry *h, void *data)
32875fd0b74Schristos {
32975fd0b74Schristos struct cref_hash_entry ***pph = (struct cref_hash_entry ***) data;
33075fd0b74Schristos
33175fd0b74Schristos ASSERT (h->demangled == NULL);
33275fd0b74Schristos h->demangled = bfd_demangle (link_info.output_bfd, h->root.string,
33375fd0b74Schristos DMGL_ANSI | DMGL_PARAMS);
33475fd0b74Schristos if (h->demangled == NULL)
33575fd0b74Schristos h->demangled = h->root.string;
33675fd0b74Schristos
33775fd0b74Schristos **pph = h;
33875fd0b74Schristos
33975fd0b74Schristos ++*pph;
34075fd0b74Schristos
341*e992f068Schristos return true;
34275fd0b74Schristos }
34375fd0b74Schristos
34475fd0b74Schristos /* Sort an array of cref hash table entries by name. */
34575fd0b74Schristos
34675fd0b74Schristos static int
cref_sort_array(const void * a1,const void * a2)34775fd0b74Schristos cref_sort_array (const void *a1, const void *a2)
34875fd0b74Schristos {
34975fd0b74Schristos const struct cref_hash_entry *const *p1
35075fd0b74Schristos = (const struct cref_hash_entry *const *) a1;
35175fd0b74Schristos const struct cref_hash_entry *const *p2
35275fd0b74Schristos = (const struct cref_hash_entry *const *) a2;
35375fd0b74Schristos
35475fd0b74Schristos if (demangling)
35575fd0b74Schristos return strcmp ((*p1)->demangled, (*p2)->demangled);
35675fd0b74Schristos else
35775fd0b74Schristos return strcmp ((*p1)->root.string, (*p2)->root.string);
35875fd0b74Schristos }
35975fd0b74Schristos
36075fd0b74Schristos /* Write out the cref table. */
36175fd0b74Schristos
36275fd0b74Schristos #define FILECOL (50)
36375fd0b74Schristos
36475fd0b74Schristos void
output_cref(FILE * fp)36575fd0b74Schristos output_cref (FILE *fp)
36675fd0b74Schristos {
36775fd0b74Schristos int len;
36875fd0b74Schristos struct cref_hash_entry **csyms, **csym_fill, **csym, **csym_end;
36975fd0b74Schristos const char *msg;
37075fd0b74Schristos
37175fd0b74Schristos fprintf (fp, _("\nCross Reference Table\n\n"));
37275fd0b74Schristos msg = _("Symbol");
37375fd0b74Schristos fprintf (fp, "%s", msg);
37475fd0b74Schristos len = strlen (msg);
37575fd0b74Schristos while (len < FILECOL)
37675fd0b74Schristos {
37775fd0b74Schristos putc (' ', fp);
37875fd0b74Schristos ++len;
37975fd0b74Schristos }
38075fd0b74Schristos fprintf (fp, _("File\n"));
38175fd0b74Schristos
38275fd0b74Schristos if (!cref_initialized)
38375fd0b74Schristos {
38475fd0b74Schristos fprintf (fp, _("No symbols\n"));
38575fd0b74Schristos return;
38675fd0b74Schristos }
38775fd0b74Schristos
38875fd0b74Schristos csyms = (struct cref_hash_entry **) xmalloc (cref_symcount * sizeof (*csyms));
38975fd0b74Schristos
39075fd0b74Schristos csym_fill = csyms;
39175fd0b74Schristos cref_hash_traverse (&cref_table, cref_fill_array, &csym_fill);
39275fd0b74Schristos ASSERT ((size_t) (csym_fill - csyms) == cref_symcount);
39375fd0b74Schristos
39475fd0b74Schristos qsort (csyms, cref_symcount, sizeof (*csyms), cref_sort_array);
39575fd0b74Schristos
39675fd0b74Schristos csym_end = csyms + cref_symcount;
39775fd0b74Schristos for (csym = csyms; csym < csym_end; csym++)
39875fd0b74Schristos output_one_cref (fp, *csym);
39975fd0b74Schristos }
40075fd0b74Schristos
40175fd0b74Schristos /* Output one entry in the cross reference table. */
40275fd0b74Schristos
40375fd0b74Schristos static void
output_one_cref(FILE * fp,struct cref_hash_entry * h)40475fd0b74Schristos output_one_cref (FILE *fp, struct cref_hash_entry *h)
40575fd0b74Schristos {
40675fd0b74Schristos int len;
40775fd0b74Schristos struct bfd_link_hash_entry *hl;
40875fd0b74Schristos struct cref_ref *r;
40975fd0b74Schristos
410*e992f068Schristos hl = bfd_link_hash_lookup (link_info.hash, h->root.string, false,
411*e992f068Schristos false, true);
41275fd0b74Schristos if (hl == NULL)
413ede78133Schristos einfo (_("%P: symbol `%pT' missing from main hash table\n"),
41475fd0b74Schristos h->root.string);
41575fd0b74Schristos else
41675fd0b74Schristos {
41775fd0b74Schristos /* If this symbol is defined in a dynamic object but never
41875fd0b74Schristos referenced by a normal object, then don't print it. */
41975fd0b74Schristos if (hl->type == bfd_link_hash_defined)
42075fd0b74Schristos {
42175fd0b74Schristos if (hl->u.def.section->output_section == NULL)
42275fd0b74Schristos return;
42375fd0b74Schristos if (hl->u.def.section->owner != NULL
42475fd0b74Schristos && (hl->u.def.section->owner->flags & DYNAMIC) != 0)
42575fd0b74Schristos {
42675fd0b74Schristos for (r = h->refs; r != NULL; r = r->next)
42775fd0b74Schristos if ((r->abfd->flags & DYNAMIC) == 0)
42875fd0b74Schristos break;
42975fd0b74Schristos if (r == NULL)
43075fd0b74Schristos return;
43175fd0b74Schristos }
43275fd0b74Schristos }
43375fd0b74Schristos }
43475fd0b74Schristos
43575fd0b74Schristos if (demangling)
43675fd0b74Schristos {
43775fd0b74Schristos fprintf (fp, "%s ", h->demangled);
43875fd0b74Schristos len = strlen (h->demangled) + 1;
43975fd0b74Schristos }
44075fd0b74Schristos else
44175fd0b74Schristos {
44275fd0b74Schristos fprintf (fp, "%s ", h->root.string);
44375fd0b74Schristos len = strlen (h->root.string) + 1;
44475fd0b74Schristos }
44575fd0b74Schristos
44675fd0b74Schristos for (r = h->refs; r != NULL; r = r->next)
44775fd0b74Schristos {
44875fd0b74Schristos if (r->def)
44975fd0b74Schristos {
45075fd0b74Schristos while (len < FILECOL)
45175fd0b74Schristos {
45275fd0b74Schristos putc (' ', fp);
45375fd0b74Schristos ++len;
45475fd0b74Schristos }
455ede78133Schristos lfinfo (fp, "%pB\n", r->abfd);
45675fd0b74Schristos len = 0;
45775fd0b74Schristos }
45875fd0b74Schristos }
45975fd0b74Schristos
46075fd0b74Schristos for (r = h->refs; r != NULL; r = r->next)
46175fd0b74Schristos {
46275fd0b74Schristos if (r->common)
46375fd0b74Schristos {
46475fd0b74Schristos while (len < FILECOL)
46575fd0b74Schristos {
46675fd0b74Schristos putc (' ', fp);
46775fd0b74Schristos ++len;
46875fd0b74Schristos }
469ede78133Schristos lfinfo (fp, "%pB\n", r->abfd);
47075fd0b74Schristos len = 0;
47175fd0b74Schristos }
47275fd0b74Schristos }
47375fd0b74Schristos
47475fd0b74Schristos for (r = h->refs; r != NULL; r = r->next)
47575fd0b74Schristos {
47675fd0b74Schristos if (!r->def && !r->common)
47775fd0b74Schristos {
47875fd0b74Schristos while (len < FILECOL)
47975fd0b74Schristos {
48075fd0b74Schristos putc (' ', fp);
48175fd0b74Schristos ++len;
48275fd0b74Schristos }
483ede78133Schristos lfinfo (fp, "%pB\n", r->abfd);
48475fd0b74Schristos len = 0;
48575fd0b74Schristos }
48675fd0b74Schristos }
48775fd0b74Schristos
48875fd0b74Schristos ASSERT (len == 0);
48975fd0b74Schristos }
49075fd0b74Schristos
49175fd0b74Schristos /* Check for prohibited cross references. */
49275fd0b74Schristos
49375fd0b74Schristos void
check_nocrossrefs(void)49475fd0b74Schristos check_nocrossrefs (void)
49575fd0b74Schristos {
49675fd0b74Schristos if (!cref_initialized)
49775fd0b74Schristos return;
49875fd0b74Schristos
49975fd0b74Schristos cref_hash_traverse (&cref_table, check_nocrossref, NULL);
50075fd0b74Schristos
50175fd0b74Schristos lang_for_each_file (check_local_sym_xref);
50275fd0b74Schristos }
50375fd0b74Schristos
50475fd0b74Schristos /* Check for prohibited cross references to local and section symbols. */
50575fd0b74Schristos
50675fd0b74Schristos static void
check_local_sym_xref(lang_input_statement_type * statement)50775fd0b74Schristos check_local_sym_xref (lang_input_statement_type *statement)
50875fd0b74Schristos {
50975fd0b74Schristos bfd *abfd;
51075fd0b74Schristos asymbol **syms;
51175fd0b74Schristos
51275fd0b74Schristos abfd = statement->the_bfd;
51375fd0b74Schristos if (abfd == NULL)
51475fd0b74Schristos return;
51575fd0b74Schristos
51675fd0b74Schristos if (!bfd_generic_link_read_symbols (abfd))
517ede78133Schristos einfo (_("%F%P: %pB: could not read symbols: %E\n"), abfd);
51875fd0b74Schristos
51975fd0b74Schristos for (syms = bfd_get_outsymbols (abfd); *syms; ++syms)
52075fd0b74Schristos {
52175fd0b74Schristos asymbol *sym = *syms;
52275fd0b74Schristos if (sym->flags & (BSF_GLOBAL | BSF_WARNING | BSF_INDIRECT | BSF_FILE))
52375fd0b74Schristos continue;
52475fd0b74Schristos if ((sym->flags & (BSF_LOCAL | BSF_SECTION_SYM)) != 0
52575fd0b74Schristos && sym->section->output_section != NULL)
52675fd0b74Schristos {
52775fd0b74Schristos const char *outsecname, *symname;
52875fd0b74Schristos struct lang_nocrossrefs *ncrs;
52975fd0b74Schristos struct lang_nocrossref *ncr;
53075fd0b74Schristos
53175fd0b74Schristos outsecname = sym->section->output_section->name;
53275fd0b74Schristos symname = NULL;
53375fd0b74Schristos if ((sym->flags & BSF_SECTION_SYM) == 0)
53475fd0b74Schristos symname = sym->name;
53575fd0b74Schristos for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next)
53675fd0b74Schristos for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next)
53775fd0b74Schristos {
53875fd0b74Schristos if (strcmp (ncr->name, outsecname) == 0)
539*e992f068Schristos check_refs (symname, false, sym->section, abfd, ncrs);
54075fd0b74Schristos /* The NOCROSSREFS_TO command only checks symbols defined in
54175fd0b74Schristos the first section in the list. */
54275fd0b74Schristos if (ncrs->onlyfirst)
54375fd0b74Schristos break;
54475fd0b74Schristos }
54575fd0b74Schristos }
54675fd0b74Schristos }
54775fd0b74Schristos }
54875fd0b74Schristos
54975fd0b74Schristos /* Check one symbol to see if it is a prohibited cross reference. */
55075fd0b74Schristos
551*e992f068Schristos static bool
check_nocrossref(struct cref_hash_entry * h,void * ignore ATTRIBUTE_UNUSED)55275fd0b74Schristos check_nocrossref (struct cref_hash_entry *h, void *ignore ATTRIBUTE_UNUSED)
55375fd0b74Schristos {
55475fd0b74Schristos struct bfd_link_hash_entry *hl;
55575fd0b74Schristos asection *defsec;
55675fd0b74Schristos const char *defsecname;
55775fd0b74Schristos struct lang_nocrossrefs *ncrs;
55875fd0b74Schristos struct lang_nocrossref *ncr;
55975fd0b74Schristos struct cref_ref *ref;
56075fd0b74Schristos
561*e992f068Schristos hl = bfd_link_hash_lookup (link_info.hash, h->root.string, false,
562*e992f068Schristos false, true);
56375fd0b74Schristos if (hl == NULL)
56475fd0b74Schristos {
565ede78133Schristos einfo (_("%P: symbol `%pT' missing from main hash table\n"),
56675fd0b74Schristos h->root.string);
567*e992f068Schristos return true;
56875fd0b74Schristos }
56975fd0b74Schristos
57075fd0b74Schristos if (hl->type != bfd_link_hash_defined
57175fd0b74Schristos && hl->type != bfd_link_hash_defweak)
572*e992f068Schristos return true;
57375fd0b74Schristos
57475fd0b74Schristos defsec = hl->u.def.section->output_section;
57575fd0b74Schristos if (defsec == NULL)
576*e992f068Schristos return true;
577012573ebSchristos defsecname = bfd_section_name (defsec);
57875fd0b74Schristos
57975fd0b74Schristos for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next)
58075fd0b74Schristos for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next)
58175fd0b74Schristos {
58275fd0b74Schristos if (strcmp (ncr->name, defsecname) == 0)
58375fd0b74Schristos for (ref = h->refs; ref != NULL; ref = ref->next)
584*e992f068Schristos check_refs (hl->root.string, true, hl->u.def.section,
58575fd0b74Schristos ref->abfd, ncrs);
58675fd0b74Schristos /* The NOCROSSREFS_TO command only checks symbols defined in the first
58775fd0b74Schristos section in the list. */
58875fd0b74Schristos if (ncrs->onlyfirst)
58975fd0b74Schristos break;
59075fd0b74Schristos }
59175fd0b74Schristos
592*e992f068Schristos return true;
59375fd0b74Schristos }
59475fd0b74Schristos
59575fd0b74Schristos /* The struct is used to pass information from check_refs to
59675fd0b74Schristos check_reloc_refs through bfd_map_over_sections. */
59775fd0b74Schristos
59875fd0b74Schristos struct check_refs_info
59975fd0b74Schristos {
60075fd0b74Schristos const char *sym_name;
60175fd0b74Schristos asection *defsec;
60275fd0b74Schristos struct lang_nocrossrefs *ncrs;
60375fd0b74Schristos asymbol **asymbols;
604*e992f068Schristos bool global;
60575fd0b74Schristos };
60675fd0b74Schristos
60775fd0b74Schristos /* This function is called for each symbol defined in a section which
60875fd0b74Schristos prohibits cross references. We need to look through all references
60975fd0b74Schristos to this symbol, and ensure that the references are not from
61075fd0b74Schristos prohibited sections. */
61175fd0b74Schristos
61275fd0b74Schristos static void
check_refs(const char * name,bool global,asection * sec,bfd * abfd,struct lang_nocrossrefs * ncrs)61375fd0b74Schristos check_refs (const char *name,
614*e992f068Schristos bool global,
61575fd0b74Schristos asection *sec,
61675fd0b74Schristos bfd *abfd,
61775fd0b74Schristos struct lang_nocrossrefs *ncrs)
61875fd0b74Schristos {
61975fd0b74Schristos struct check_refs_info info;
62075fd0b74Schristos
62175fd0b74Schristos /* We need to look through the relocations for this BFD, to see
62275fd0b74Schristos if any of the relocations which refer to this symbol are from
62375fd0b74Schristos a prohibited section. Note that we need to do this even for
62475fd0b74Schristos the BFD in which the symbol is defined, since even a single
62575fd0b74Schristos BFD might contain a prohibited cross reference. */
62675fd0b74Schristos
62775fd0b74Schristos if (!bfd_generic_link_read_symbols (abfd))
628ede78133Schristos einfo (_("%F%P: %pB: could not read symbols: %E\n"), abfd);
62975fd0b74Schristos
63075fd0b74Schristos info.sym_name = name;
63175fd0b74Schristos info.global = global;
63275fd0b74Schristos info.defsec = sec;
63375fd0b74Schristos info.ncrs = ncrs;
63475fd0b74Schristos info.asymbols = bfd_get_outsymbols (abfd);
63575fd0b74Schristos bfd_map_over_sections (abfd, check_reloc_refs, &info);
63675fd0b74Schristos }
63775fd0b74Schristos
63875fd0b74Schristos /* This is called via bfd_map_over_sections. INFO->SYM_NAME is a symbol
63975fd0b74Schristos defined in INFO->DEFSECNAME. If this section maps into any of the
64075fd0b74Schristos sections listed in INFO->NCRS, other than INFO->DEFSECNAME, then we
64175fd0b74Schristos look through the relocations. If any of the relocations are to
64275fd0b74Schristos INFO->SYM_NAME, then we report a prohibited cross reference error. */
64375fd0b74Schristos
64475fd0b74Schristos static void
check_reloc_refs(bfd * abfd,asection * sec,void * iarg)64575fd0b74Schristos check_reloc_refs (bfd *abfd, asection *sec, void *iarg)
64675fd0b74Schristos {
64775fd0b74Schristos struct check_refs_info *info = (struct check_refs_info *) iarg;
64875fd0b74Schristos asection *outsec;
64975fd0b74Schristos const char *outsecname;
65075fd0b74Schristos asection *outdefsec;
65175fd0b74Schristos const char *outdefsecname;
65275fd0b74Schristos struct lang_nocrossref *ncr;
65375fd0b74Schristos const char *symname;
654*e992f068Schristos bool global;
65575fd0b74Schristos long relsize;
65675fd0b74Schristos arelent **relpp;
65775fd0b74Schristos long relcount;
65875fd0b74Schristos arelent **p, **pend;
65975fd0b74Schristos
66075fd0b74Schristos outsec = sec->output_section;
661012573ebSchristos outsecname = bfd_section_name (outsec);
66275fd0b74Schristos
66375fd0b74Schristos outdefsec = info->defsec->output_section;
664012573ebSchristos outdefsecname = bfd_section_name (outdefsec);
66575fd0b74Schristos
66675fd0b74Schristos /* The section where the symbol is defined is permitted. */
66775fd0b74Schristos if (strcmp (outsecname, outdefsecname) == 0)
66875fd0b74Schristos return;
66975fd0b74Schristos
67075fd0b74Schristos for (ncr = info->ncrs->list; ncr != NULL; ncr = ncr->next)
67175fd0b74Schristos if (strcmp (outsecname, ncr->name) == 0)
67275fd0b74Schristos break;
67375fd0b74Schristos
67475fd0b74Schristos if (ncr == NULL)
67575fd0b74Schristos return;
67675fd0b74Schristos
67775fd0b74Schristos /* This section is one for which cross references are prohibited.
67875fd0b74Schristos Look through the relocations, and see if any of them are to
67975fd0b74Schristos INFO->SYM_NAME. If INFO->SYMNAME is NULL, check for relocations
68075fd0b74Schristos against the section symbol. If INFO->GLOBAL is TRUE, the
68175fd0b74Schristos definition is global, check for relocations against the global
68275fd0b74Schristos symbols. Otherwise check for relocations against the local and
68375fd0b74Schristos section symbols. */
68475fd0b74Schristos
68575fd0b74Schristos symname = info->sym_name;
68675fd0b74Schristos global = info->global;
68775fd0b74Schristos
68875fd0b74Schristos relsize = bfd_get_reloc_upper_bound (abfd, sec);
68975fd0b74Schristos if (relsize < 0)
690ede78133Schristos einfo (_("%F%P: %pB: could not read relocs: %E\n"), abfd);
69175fd0b74Schristos if (relsize == 0)
69275fd0b74Schristos return;
69375fd0b74Schristos
69475fd0b74Schristos relpp = (arelent **) xmalloc (relsize);
69575fd0b74Schristos relcount = bfd_canonicalize_reloc (abfd, sec, relpp, info->asymbols);
69675fd0b74Schristos if (relcount < 0)
697ede78133Schristos einfo (_("%F%P: %pB: could not read relocs: %E\n"), abfd);
69875fd0b74Schristos
69975fd0b74Schristos p = relpp;
70075fd0b74Schristos pend = p + relcount;
70175fd0b74Schristos for (; p < pend && *p != NULL; p++)
70275fd0b74Schristos {
70375fd0b74Schristos arelent *q = *p;
70475fd0b74Schristos
70575fd0b74Schristos if (q->sym_ptr_ptr != NULL
70675fd0b74Schristos && *q->sym_ptr_ptr != NULL
70775fd0b74Schristos && ((global
708012573ebSchristos && (bfd_is_und_section (bfd_asymbol_section (*q->sym_ptr_ptr))
709012573ebSchristos || bfd_is_com_section (bfd_asymbol_section (*q->sym_ptr_ptr))
71075fd0b74Schristos || ((*q->sym_ptr_ptr)->flags & (BSF_GLOBAL
71175fd0b74Schristos | BSF_WEAK)) != 0))
71275fd0b74Schristos || (!global
71375fd0b74Schristos && ((*q->sym_ptr_ptr)->flags & (BSF_LOCAL
71475fd0b74Schristos | BSF_SECTION_SYM)) != 0
715012573ebSchristos && bfd_asymbol_section (*q->sym_ptr_ptr) == info->defsec))
71675fd0b74Schristos && (symname != NULL
71775fd0b74Schristos ? strcmp (bfd_asymbol_name (*q->sym_ptr_ptr), symname) == 0
71875fd0b74Schristos : ((*q->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0))
71975fd0b74Schristos {
72075fd0b74Schristos /* We found a reloc for the symbol. The symbol is defined
72175fd0b74Schristos in OUTSECNAME. This reloc is from a section which is
72275fd0b74Schristos mapped into a section from which references to OUTSECNAME
72375fd0b74Schristos are prohibited. We must report an error. */
724ede78133Schristos einfo (_("%X%P: %C: prohibited cross reference from %s to `%pT' in %s\n"),
72575fd0b74Schristos abfd, sec, q->address, outsecname,
72675fd0b74Schristos bfd_asymbol_name (*q->sym_ptr_ptr), outdefsecname);
72775fd0b74Schristos }
72875fd0b74Schristos }
72975fd0b74Schristos
73075fd0b74Schristos free (relpp);
73175fd0b74Schristos }
732