133965Sjdp/* ldcref.c -- output a cross reference table 2218822Sdim Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006, 3218822Sdim 2007 Free Software Foundation, Inc. 433965Sjdp Written by Ian Lance Taylor <ian@cygnus.com> 533965Sjdp 633965SjdpThis file is part of GLD, the Gnu Linker. 733965Sjdp 833965SjdpThis program is free software; you can redistribute it and/or modify 933965Sjdpit under the terms of the GNU General Public License as published by 1033965Sjdpthe Free Software Foundation; either version 2 of the License, or 1133965Sjdp(at your option) any later version. 1233965Sjdp 1333965SjdpThis program is distributed in the hope that it will be useful, 1433965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of 1533965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1633965SjdpGNU General Public License for more details. 1733965Sjdp 1833965SjdpYou should have received a copy of the GNU General Public License 1933965Sjdpalong with this program; if not, write to the Free Software 20218822SdimFoundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 2133965Sjdp 2233965Sjdp/* This file holds routines that manage the cross reference table. 2333965Sjdp The table is used to generate cross reference reports. It is also 2433965Sjdp used to implement the NOCROSSREFS command in the linker script. */ 2533965Sjdp 26218822Sdim#include "sysdep.h" 2733965Sjdp#include "bfd.h" 2833965Sjdp#include "bfdlink.h" 2933965Sjdp#include "libiberty.h" 30218822Sdim#include "demangle.h" 31218822Sdim#include "objalloc.h" 3233965Sjdp 3333965Sjdp#include "ld.h" 3433965Sjdp#include "ldmain.h" 3533965Sjdp#include "ldmisc.h" 3633965Sjdp#include "ldexp.h" 3733965Sjdp#include "ldlang.h" 3833965Sjdp 3933965Sjdp/* We keep an instance of this structure for each reference to a 4033965Sjdp symbol from a given object. */ 4133965Sjdp 4277298Sobrienstruct cref_ref { 4333965Sjdp /* The next reference. */ 4433965Sjdp struct cref_ref *next; 4533965Sjdp /* The object. */ 4633965Sjdp bfd *abfd; 4733965Sjdp /* True if the symbol is defined. */ 4833965Sjdp unsigned int def : 1; 4933965Sjdp /* True if the symbol is common. */ 5033965Sjdp unsigned int common : 1; 5133965Sjdp /* True if the symbol is undefined. */ 5233965Sjdp unsigned int undef : 1; 5333965Sjdp}; 5433965Sjdp 5533965Sjdp/* We keep a hash table of symbols. Each entry looks like this. */ 5633965Sjdp 5777298Sobrienstruct cref_hash_entry { 5833965Sjdp struct bfd_hash_entry root; 5933965Sjdp /* The demangled name. */ 60218822Sdim const char *demangled; 6133965Sjdp /* References to and definitions of this symbol. */ 6233965Sjdp struct cref_ref *refs; 6333965Sjdp}; 6433965Sjdp 6533965Sjdp/* This is what the hash table looks like. */ 6633965Sjdp 6777298Sobrienstruct cref_hash_table { 6833965Sjdp struct bfd_hash_table root; 6933965Sjdp}; 7033965Sjdp 71130561Sobrien/* Forward declarations. */ 7233965Sjdp 73130561Sobrienstatic void output_one_cref (FILE *, struct cref_hash_entry *); 74218822Sdimstatic void check_local_sym_xref (lang_input_statement_type *); 75130561Sobrienstatic bfd_boolean check_nocrossref (struct cref_hash_entry *, void *); 76218822Sdimstatic void check_refs (const char *, bfd_boolean, asection *, bfd *, 77130561Sobrien struct lang_nocrossrefs *); 78130561Sobrienstatic void check_reloc_refs (bfd *, asection *, void *); 7933965Sjdp 8033965Sjdp/* Look up an entry in the cref hash table. */ 8133965Sjdp 8233965Sjdp#define cref_hash_lookup(table, string, create, copy) \ 8333965Sjdp ((struct cref_hash_entry *) \ 8433965Sjdp bfd_hash_lookup (&(table)->root, (string), (create), (copy))) 8533965Sjdp 8633965Sjdp/* Traverse the cref hash table. */ 8733965Sjdp 8833965Sjdp#define cref_hash_traverse(table, func, info) \ 8933965Sjdp (bfd_hash_traverse \ 9033965Sjdp (&(table)->root, \ 91130561Sobrien (bfd_boolean (*) (struct bfd_hash_entry *, void *)) (func), \ 9233965Sjdp (info))) 9333965Sjdp 9433965Sjdp/* The cref hash table. */ 9533965Sjdp 9633965Sjdpstatic struct cref_hash_table cref_table; 9733965Sjdp 9833965Sjdp/* Whether the cref hash table has been initialized. */ 9933965Sjdp 100130561Sobrienstatic bfd_boolean cref_initialized; 10133965Sjdp 10233965Sjdp/* The number of symbols seen so far. */ 10333965Sjdp 10433965Sjdpstatic size_t cref_symcount; 10533965Sjdp 106218822Sdim/* Used to take a snapshot of the cref hash table when starting to 107218822Sdim add syms from an as-needed library. */ 108218822Sdimstatic struct bfd_hash_entry **old_table; 109218822Sdimstatic unsigned int old_size; 110218822Sdimstatic unsigned int old_count; 111218822Sdimstatic void *old_tab; 112218822Sdimstatic void *alloc_mark; 113218822Sdimstatic size_t tabsize, entsize, refsize; 114218822Sdimstatic size_t old_symcount; 115218822Sdim 11633965Sjdp/* Create an entry in a cref hash table. */ 11733965Sjdp 11833965Sjdpstatic struct bfd_hash_entry * 119130561Sobriencref_hash_newfunc (struct bfd_hash_entry *entry, 120130561Sobrien struct bfd_hash_table *table, 121130561Sobrien const char *string) 12233965Sjdp{ 12333965Sjdp struct cref_hash_entry *ret = (struct cref_hash_entry *) entry; 12433965Sjdp 12533965Sjdp /* Allocate the structure if it has not already been allocated by a 12633965Sjdp subclass. */ 12733965Sjdp if (ret == NULL) 12833965Sjdp ret = ((struct cref_hash_entry *) 12933965Sjdp bfd_hash_allocate (table, sizeof (struct cref_hash_entry))); 13033965Sjdp if (ret == NULL) 131130561Sobrien return NULL; 13233965Sjdp 13333965Sjdp /* Call the allocation method of the superclass. */ 13433965Sjdp ret = ((struct cref_hash_entry *) 13533965Sjdp bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); 13633965Sjdp if (ret != NULL) 13733965Sjdp { 13833965Sjdp /* Set local fields. */ 13933965Sjdp ret->demangled = NULL; 14033965Sjdp ret->refs = NULL; 14133965Sjdp 14233965Sjdp /* Keep a count of the number of entries created in the hash 143130561Sobrien table. */ 14433965Sjdp ++cref_symcount; 14533965Sjdp } 14633965Sjdp 147130561Sobrien return &ret->root; 14833965Sjdp} 14933965Sjdp 15033965Sjdp/* Add a symbol to the cref hash table. This is called for every 151218822Sdim global symbol that is seen during the link. */ 15233965Sjdp 15333965Sjdpvoid 154130561Sobrienadd_cref (const char *name, 155130561Sobrien bfd *abfd, 156130561Sobrien asection *section, 157130561Sobrien bfd_vma value ATTRIBUTE_UNUSED) 15833965Sjdp{ 15933965Sjdp struct cref_hash_entry *h; 16033965Sjdp struct cref_ref *r; 16133965Sjdp 16233965Sjdp if (! cref_initialized) 16333965Sjdp { 164218822Sdim if (!bfd_hash_table_init (&cref_table.root, cref_hash_newfunc, 165218822Sdim sizeof (struct cref_hash_entry))) 16660484Sobrien einfo (_("%X%P: bfd_hash_table_init of cref table failed: %E\n")); 167130561Sobrien cref_initialized = TRUE; 16833965Sjdp } 16933965Sjdp 170130561Sobrien h = cref_hash_lookup (&cref_table, name, TRUE, FALSE); 17133965Sjdp if (h == NULL) 17260484Sobrien einfo (_("%X%P: cref_hash_lookup failed: %E\n")); 17333965Sjdp 17433965Sjdp for (r = h->refs; r != NULL; r = r->next) 17533965Sjdp if (r->abfd == abfd) 17633965Sjdp break; 17733965Sjdp 17833965Sjdp if (r == NULL) 17933965Sjdp { 180218822Sdim r = bfd_hash_allocate (&cref_table.root, sizeof *r); 181218822Sdim if (r == NULL) 182218822Sdim einfo (_("%X%P: cref alloc failed: %E\n")); 18333965Sjdp r->next = h->refs; 18433965Sjdp h->refs = r; 18533965Sjdp r->abfd = abfd; 186130561Sobrien r->def = FALSE; 187130561Sobrien r->common = FALSE; 188130561Sobrien r->undef = FALSE; 18933965Sjdp } 19033965Sjdp 19133965Sjdp if (bfd_is_und_section (section)) 192130561Sobrien r->undef = TRUE; 19333965Sjdp else if (bfd_is_com_section (section)) 194130561Sobrien r->common = TRUE; 19533965Sjdp else 196130561Sobrien r->def = TRUE; 19733965Sjdp} 19833965Sjdp 199218822Sdim/* Called before loading an as-needed library to take a snapshot of 200218822Sdim the cref hash table, and after we have loaded or found that the 201218822Sdim library was not needed. */ 202218822Sdim 203218822Sdimbfd_boolean 204218822Sdimhandle_asneeded_cref (bfd *abfd ATTRIBUTE_UNUSED, 205218822Sdim enum notice_asneeded_action act) 206218822Sdim{ 207218822Sdim unsigned int i; 208218822Sdim 209218822Sdim if (!cref_initialized) 210218822Sdim return TRUE; 211218822Sdim 212218822Sdim if (act == notice_as_needed) 213218822Sdim { 214218822Sdim char *old_ent, *old_ref; 215218822Sdim 216218822Sdim for (i = 0; i < cref_table.root.size; i++) 217218822Sdim { 218218822Sdim struct bfd_hash_entry *p; 219218822Sdim struct cref_hash_entry *c; 220218822Sdim struct cref_ref *r; 221218822Sdim 222218822Sdim for (p = cref_table.root.table[i]; p != NULL; p = p->next) 223218822Sdim { 224218822Sdim entsize += cref_table.root.entsize; 225218822Sdim c = (struct cref_hash_entry *) p; 226218822Sdim for (r = c->refs; r != NULL; r = r->next) 227218822Sdim refsize += sizeof (struct cref_hash_entry); 228218822Sdim } 229218822Sdim } 230218822Sdim 231218822Sdim tabsize = cref_table.root.size * sizeof (struct bfd_hash_entry *); 232218822Sdim old_tab = xmalloc (tabsize + entsize + refsize); 233218822Sdim 234218822Sdim alloc_mark = bfd_hash_allocate (&cref_table.root, 1); 235218822Sdim if (alloc_mark == NULL) 236218822Sdim return FALSE; 237218822Sdim 238218822Sdim memcpy (old_tab, cref_table.root.table, tabsize); 239218822Sdim old_ent = (char *) old_tab + tabsize; 240218822Sdim old_ref = (char *) old_ent + entsize; 241218822Sdim old_table = cref_table.root.table; 242218822Sdim old_size = cref_table.root.size; 243218822Sdim old_count = cref_table.root.count; 244218822Sdim old_symcount = cref_symcount; 245218822Sdim 246218822Sdim for (i = 0; i < cref_table.root.size; i++) 247218822Sdim { 248218822Sdim struct bfd_hash_entry *p; 249218822Sdim struct cref_hash_entry *c; 250218822Sdim struct cref_ref *r; 251218822Sdim 252218822Sdim for (p = cref_table.root.table[i]; p != NULL; p = p->next) 253218822Sdim { 254218822Sdim memcpy (old_ent, p, cref_table.root.entsize); 255218822Sdim old_ent = (char *) old_ent + cref_table.root.entsize; 256218822Sdim c = (struct cref_hash_entry *) p; 257218822Sdim for (r = c->refs; r != NULL; r = r->next) 258218822Sdim { 259218822Sdim memcpy (old_ref, r, sizeof (struct cref_hash_entry)); 260218822Sdim old_ref = (char *) old_ref + sizeof (struct cref_hash_entry); 261218822Sdim } 262218822Sdim } 263218822Sdim } 264218822Sdim return TRUE; 265218822Sdim } 266218822Sdim 267218822Sdim if (act == notice_not_needed) 268218822Sdim { 269218822Sdim char *old_ent, *old_ref; 270218822Sdim 271218822Sdim if (old_tab == NULL) 272218822Sdim { 273218822Sdim /* The only way old_tab can be NULL is if the cref hash table 274218822Sdim had not been initialised when notice_as_needed. */ 275218822Sdim bfd_hash_table_free (&cref_table.root); 276218822Sdim cref_initialized = FALSE; 277218822Sdim return TRUE; 278218822Sdim } 279218822Sdim 280218822Sdim old_ent = (char *) old_tab + tabsize; 281218822Sdim old_ref = (char *) old_ent + entsize; 282218822Sdim cref_table.root.table = old_table; 283218822Sdim cref_table.root.size = old_size; 284218822Sdim cref_table.root.count = old_count; 285218822Sdim memcpy (cref_table.root.table, old_tab, tabsize); 286218822Sdim cref_symcount = old_symcount; 287218822Sdim 288218822Sdim for (i = 0; i < cref_table.root.size; i++) 289218822Sdim { 290218822Sdim struct bfd_hash_entry *p; 291218822Sdim struct cref_hash_entry *c; 292218822Sdim struct cref_ref *r; 293218822Sdim 294218822Sdim for (p = cref_table.root.table[i]; p != NULL; p = p->next) 295218822Sdim { 296218822Sdim memcpy (p, old_ent, cref_table.root.entsize); 297218822Sdim old_ent = (char *) old_ent + cref_table.root.entsize; 298218822Sdim c = (struct cref_hash_entry *) p; 299218822Sdim for (r = c->refs; r != NULL; r = r->next) 300218822Sdim { 301218822Sdim memcpy (r, old_ref, sizeof (struct cref_hash_entry)); 302218822Sdim old_ref = (char *) old_ref + sizeof (struct cref_hash_entry); 303218822Sdim } 304218822Sdim } 305218822Sdim } 306218822Sdim 307218822Sdim objalloc_free_block ((struct objalloc *) cref_table.root.memory, 308218822Sdim alloc_mark); 309218822Sdim } 310218822Sdim else if (act != notice_needed) 311218822Sdim return FALSE; 312218822Sdim 313218822Sdim free (old_tab); 314218822Sdim old_tab = NULL; 315218822Sdim return TRUE; 316218822Sdim} 317218822Sdim 31833965Sjdp/* Copy the addresses of the hash table entries into an array. This 31933965Sjdp is called via cref_hash_traverse. We also fill in the demangled 32033965Sjdp name. */ 32133965Sjdp 322130561Sobrienstatic bfd_boolean 323130561Sobriencref_fill_array (struct cref_hash_entry *h, void *data) 32433965Sjdp{ 325130561Sobrien struct cref_hash_entry ***pph = data; 32633965Sjdp 32733965Sjdp ASSERT (h->demangled == NULL); 328218822Sdim h->demangled = bfd_demangle (output_bfd, h->root.string, 329218822Sdim DMGL_ANSI | DMGL_PARAMS); 330218822Sdim if (h->demangled == NULL) 331218822Sdim h->demangled = h->root.string; 33233965Sjdp 33333965Sjdp **pph = h; 33433965Sjdp 33533965Sjdp ++*pph; 33633965Sjdp 337130561Sobrien return TRUE; 33833965Sjdp} 33933965Sjdp 34033965Sjdp/* Sort an array of cref hash table entries by name. */ 34133965Sjdp 34233965Sjdpstatic int 343130561Sobriencref_sort_array (const void *a1, const void *a2) 34433965Sjdp{ 345130561Sobrien const struct cref_hash_entry * const *p1 = a1; 346130561Sobrien const struct cref_hash_entry * const *p2 = a2; 34733965Sjdp 34833965Sjdp return strcmp ((*p1)->demangled, (*p2)->demangled); 34933965Sjdp} 35033965Sjdp 35133965Sjdp/* Write out the cref table. */ 35233965Sjdp 35333965Sjdp#define FILECOL (50) 35433965Sjdp 35533965Sjdpvoid 356130561Sobrienoutput_cref (FILE *fp) 35733965Sjdp{ 35833965Sjdp int len; 35933965Sjdp struct cref_hash_entry **csyms, **csym_fill, **csym, **csym_end; 36060484Sobrien const char *msg; 36133965Sjdp 36260484Sobrien fprintf (fp, _("\nCross Reference Table\n\n")); 36360484Sobrien msg = _("Symbol"); 36460484Sobrien fprintf (fp, "%s", msg); 36560484Sobrien len = strlen (msg); 36633965Sjdp while (len < FILECOL) 36733965Sjdp { 36877298Sobrien putc (' ', fp); 36933965Sjdp ++len; 37033965Sjdp } 37160484Sobrien fprintf (fp, _("File\n")); 37233965Sjdp 37333965Sjdp if (! cref_initialized) 37433965Sjdp { 37560484Sobrien fprintf (fp, _("No symbols\n")); 37633965Sjdp return; 37733965Sjdp } 37833965Sjdp 379130561Sobrien csyms = xmalloc (cref_symcount * sizeof (*csyms)); 38033965Sjdp 38133965Sjdp csym_fill = csyms; 38233965Sjdp cref_hash_traverse (&cref_table, cref_fill_array, &csym_fill); 38338889Sjdp ASSERT ((size_t) (csym_fill - csyms) == cref_symcount); 38433965Sjdp 38533965Sjdp qsort (csyms, cref_symcount, sizeof (*csyms), cref_sort_array); 38633965Sjdp 38733965Sjdp csym_end = csyms + cref_symcount; 38833965Sjdp for (csym = csyms; csym < csym_end; csym++) 38933965Sjdp output_one_cref (fp, *csym); 39033965Sjdp} 39133965Sjdp 39233965Sjdp/* Output one entry in the cross reference table. */ 39333965Sjdp 39433965Sjdpstatic void 395130561Sobrienoutput_one_cref (FILE *fp, struct cref_hash_entry *h) 39633965Sjdp{ 39733965Sjdp int len; 39833965Sjdp struct bfd_link_hash_entry *hl; 39933965Sjdp struct cref_ref *r; 40033965Sjdp 401130561Sobrien hl = bfd_link_hash_lookup (link_info.hash, h->root.string, FALSE, 402130561Sobrien FALSE, TRUE); 40333965Sjdp if (hl == NULL) 40433965Sjdp einfo ("%P: symbol `%T' missing from main hash table\n", 40533965Sjdp h->root.string); 40633965Sjdp else 40733965Sjdp { 40833965Sjdp /* If this symbol is defined in a dynamic object but never 40933965Sjdp referenced by a normal object, then don't print it. */ 41033965Sjdp if (hl->type == bfd_link_hash_defined) 41133965Sjdp { 41233965Sjdp if (hl->u.def.section->output_section == NULL) 41333965Sjdp return; 41433965Sjdp if (hl->u.def.section->owner != NULL 41533965Sjdp && (hl->u.def.section->owner->flags & DYNAMIC) != 0) 41633965Sjdp { 41733965Sjdp for (r = h->refs; r != NULL; r = r->next) 41833965Sjdp if ((r->abfd->flags & DYNAMIC) == 0) 41933965Sjdp break; 42033965Sjdp if (r == NULL) 42133965Sjdp return; 42233965Sjdp } 42333965Sjdp } 42433965Sjdp } 42533965Sjdp 42633965Sjdp fprintf (fp, "%s ", h->demangled); 42733965Sjdp len = strlen (h->demangled) + 1; 42833965Sjdp 42933965Sjdp for (r = h->refs; r != NULL; r = r->next) 43033965Sjdp { 43133965Sjdp if (r->def) 43233965Sjdp { 43333965Sjdp while (len < FILECOL) 43433965Sjdp { 43533965Sjdp putc (' ', fp); 43633965Sjdp ++len; 43733965Sjdp } 43838889Sjdp lfinfo (fp, "%B\n", r->abfd); 43933965Sjdp len = 0; 44033965Sjdp } 44133965Sjdp } 44233965Sjdp 44333965Sjdp for (r = h->refs; r != NULL; r = r->next) 44433965Sjdp { 44533965Sjdp if (! r->def) 44633965Sjdp { 44733965Sjdp while (len < FILECOL) 44833965Sjdp { 44933965Sjdp putc (' ', fp); 45033965Sjdp ++len; 45133965Sjdp } 45238889Sjdp lfinfo (fp, "%B\n", r->abfd); 45333965Sjdp len = 0; 45433965Sjdp } 45533965Sjdp } 45633965Sjdp 45733965Sjdp ASSERT (len == 0); 45833965Sjdp} 45933965Sjdp 46033965Sjdp/* Check for prohibited cross references. */ 46133965Sjdp 46233965Sjdpvoid 463130561Sobriencheck_nocrossrefs (void) 46433965Sjdp{ 46533965Sjdp if (! cref_initialized) 46633965Sjdp return; 46733965Sjdp 468130561Sobrien cref_hash_traverse (&cref_table, check_nocrossref, NULL); 46989857Sobrien 470218822Sdim lang_for_each_file (check_local_sym_xref); 47133965Sjdp} 47233965Sjdp 473218822Sdim/* Check for prohibited cross references to local and section symbols. */ 47489857Sobrien 47589857Sobrienstatic void 476218822Sdimcheck_local_sym_xref (lang_input_statement_type *statement) 47789857Sobrien{ 47889857Sobrien bfd *abfd; 479218822Sdim lang_input_statement_type *li; 480218822Sdim asymbol **asymbols, **syms; 48189857Sobrien 48289857Sobrien abfd = statement->the_bfd; 48389857Sobrien if (abfd == NULL) 48489857Sobrien return; 48589857Sobrien 486218822Sdim li = abfd->usrdata; 487218822Sdim if (li != NULL && li->asymbols != NULL) 488218822Sdim asymbols = li->asymbols; 489218822Sdim else 49089857Sobrien { 491218822Sdim long symsize; 492218822Sdim long symbol_count; 49389857Sobrien 494218822Sdim symsize = bfd_get_symtab_upper_bound (abfd); 495218822Sdim if (symsize < 0) 496218822Sdim einfo (_("%B%F: could not read symbols; %E\n"), abfd); 497218822Sdim asymbols = xmalloc (symsize); 498218822Sdim symbol_count = bfd_canonicalize_symtab (abfd, asymbols); 499218822Sdim if (symbol_count < 0) 500218822Sdim einfo (_("%B%F: could not read symbols: %E\n"), abfd); 501218822Sdim if (li != NULL) 50289857Sobrien { 503218822Sdim li->asymbols = asymbols; 504218822Sdim li->symbol_count = symbol_count; 505218822Sdim } 506218822Sdim } 507218822Sdim 508218822Sdim for (syms = asymbols; *syms; ++syms) 509218822Sdim { 510218822Sdim asymbol *sym = *syms; 511218822Sdim if (sym->flags & (BSF_GLOBAL | BSF_WARNING | BSF_INDIRECT | BSF_FILE)) 512218822Sdim continue; 513218822Sdim if ((sym->flags & (BSF_LOCAL | BSF_SECTION_SYM)) != 0 514218822Sdim && sym->section->output_section != NULL) 515218822Sdim { 516218822Sdim const char *outsecname, *symname; 51789857Sobrien struct lang_nocrossrefs *ncrs; 51889857Sobrien struct lang_nocrossref *ncr; 51989857Sobrien 520218822Sdim outsecname = sym->section->output_section->name; 521218822Sdim symname = NULL; 522218822Sdim if ((sym->flags & BSF_SECTION_SYM) == 0) 523218822Sdim symname = sym->name; 52489857Sobrien for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next) 52589857Sobrien for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next) 52689857Sobrien if (strcmp (ncr->name, outsecname) == 0) 527218822Sdim check_refs (symname, FALSE, sym->section, abfd, ncrs); 52889857Sobrien } 52989857Sobrien } 530218822Sdim 531218822Sdim if (li == NULL) 532218822Sdim free (asymbols); 53389857Sobrien} 53489857Sobrien 53533965Sjdp/* Check one symbol to see if it is a prohibited cross reference. */ 53633965Sjdp 537130561Sobrienstatic bfd_boolean 538130561Sobriencheck_nocrossref (struct cref_hash_entry *h, void *ignore ATTRIBUTE_UNUSED) 53933965Sjdp{ 54033965Sjdp struct bfd_link_hash_entry *hl; 54133965Sjdp asection *defsec; 54233965Sjdp const char *defsecname; 54333965Sjdp struct lang_nocrossrefs *ncrs; 54433965Sjdp struct lang_nocrossref *ncr; 54589857Sobrien struct cref_ref *ref; 54633965Sjdp 547130561Sobrien hl = bfd_link_hash_lookup (link_info.hash, h->root.string, FALSE, 548130561Sobrien FALSE, TRUE); 54933965Sjdp if (hl == NULL) 55033965Sjdp { 55160484Sobrien einfo (_("%P: symbol `%T' missing from main hash table\n"), 55233965Sjdp h->root.string); 553130561Sobrien return TRUE; 55433965Sjdp } 55533965Sjdp 55633965Sjdp if (hl->type != bfd_link_hash_defined 55733965Sjdp && hl->type != bfd_link_hash_defweak) 558130561Sobrien return TRUE; 55933965Sjdp 56033965Sjdp defsec = hl->u.def.section->output_section; 56133965Sjdp if (defsec == NULL) 562130561Sobrien return TRUE; 56333965Sjdp defsecname = bfd_get_section_name (defsec->owner, defsec); 56433965Sjdp 56533965Sjdp for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next) 56633965Sjdp for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next) 56733965Sjdp if (strcmp (ncr->name, defsecname) == 0) 56889857Sobrien for (ref = h->refs; ref != NULL; ref = ref->next) 569218822Sdim check_refs (hl->root.string, TRUE, hl->u.def.section, 570218822Sdim ref->abfd, ncrs); 57133965Sjdp 572130561Sobrien return TRUE; 57333965Sjdp} 57433965Sjdp 57533965Sjdp/* The struct is used to pass information from check_refs to 57633965Sjdp check_reloc_refs through bfd_map_over_sections. */ 57733965Sjdp 57877298Sobrienstruct check_refs_info { 57989857Sobrien const char *sym_name; 58033965Sjdp asection *defsec; 58133965Sjdp struct lang_nocrossrefs *ncrs; 58233965Sjdp asymbol **asymbols; 583218822Sdim bfd_boolean global; 58433965Sjdp}; 58533965Sjdp 58633965Sjdp/* This function is called for each symbol defined in a section which 58733965Sjdp prohibits cross references. We need to look through all references 58833965Sjdp to this symbol, and ensure that the references are not from 58933965Sjdp prohibited sections. */ 59033965Sjdp 59133965Sjdpstatic void 592130561Sobriencheck_refs (const char *name, 593218822Sdim bfd_boolean global, 594130561Sobrien asection *sec, 595130561Sobrien bfd *abfd, 596130561Sobrien struct lang_nocrossrefs *ncrs) 59733965Sjdp{ 59889857Sobrien lang_input_statement_type *li; 59989857Sobrien asymbol **asymbols; 60089857Sobrien struct check_refs_info info; 60133965Sjdp 60289857Sobrien /* We need to look through the relocations for this BFD, to see 60389857Sobrien if any of the relocations which refer to this symbol are from 60489857Sobrien a prohibited section. Note that we need to do this even for 60589857Sobrien the BFD in which the symbol is defined, since even a single 60689857Sobrien BFD might contain a prohibited cross reference. */ 60789857Sobrien 608130561Sobrien li = abfd->usrdata; 60989857Sobrien if (li != NULL && li->asymbols != NULL) 61089857Sobrien asymbols = li->asymbols; 61189857Sobrien else 61233965Sjdp { 61389857Sobrien long symsize; 61489857Sobrien long symbol_count; 61533965Sjdp 61689857Sobrien symsize = bfd_get_symtab_upper_bound (abfd); 61789857Sobrien if (symsize < 0) 61889857Sobrien einfo (_("%B%F: could not read symbols; %E\n"), abfd); 619130561Sobrien asymbols = xmalloc (symsize); 62089857Sobrien symbol_count = bfd_canonicalize_symtab (abfd, asymbols); 62189857Sobrien if (symbol_count < 0) 62289857Sobrien einfo (_("%B%F: could not read symbols: %E\n"), abfd); 62389857Sobrien if (li != NULL) 62433965Sjdp { 62589857Sobrien li->asymbols = asymbols; 62689857Sobrien li->symbol_count = symbol_count; 62733965Sjdp } 62889857Sobrien } 62933965Sjdp 63089857Sobrien info.sym_name = name; 631218822Sdim info.global = global; 63289857Sobrien info.defsec = sec; 63389857Sobrien info.ncrs = ncrs; 63489857Sobrien info.asymbols = asymbols; 635130561Sobrien bfd_map_over_sections (abfd, check_reloc_refs, &info); 63633965Sjdp 63789857Sobrien if (li == NULL) 63889857Sobrien free (asymbols); 63933965Sjdp} 64033965Sjdp 64189857Sobrien/* This is called via bfd_map_over_sections. INFO->SYM_NAME is a symbol 64233965Sjdp defined in INFO->DEFSECNAME. If this section maps into any of the 64333965Sjdp sections listed in INFO->NCRS, other than INFO->DEFSECNAME, then we 64433965Sjdp look through the relocations. If any of the relocations are to 64589857Sobrien INFO->SYM_NAME, then we report a prohibited cross reference error. */ 64633965Sjdp 64733965Sjdpstatic void 648130561Sobriencheck_reloc_refs (bfd *abfd, asection *sec, void *iarg) 64933965Sjdp{ 650130561Sobrien struct check_refs_info *info = iarg; 65133965Sjdp asection *outsec; 65233965Sjdp const char *outsecname; 65333965Sjdp asection *outdefsec; 65433965Sjdp const char *outdefsecname; 65533965Sjdp struct lang_nocrossref *ncr; 65633965Sjdp const char *symname; 657218822Sdim bfd_boolean global; 65833965Sjdp long relsize; 65933965Sjdp arelent **relpp; 66033965Sjdp long relcount; 66133965Sjdp arelent **p, **pend; 66233965Sjdp 66333965Sjdp outsec = sec->output_section; 66433965Sjdp outsecname = bfd_get_section_name (outsec->owner, outsec); 66533965Sjdp 66633965Sjdp outdefsec = info->defsec->output_section; 66733965Sjdp outdefsecname = bfd_get_section_name (outdefsec->owner, outdefsec); 66833965Sjdp 66933965Sjdp /* The section where the symbol is defined is permitted. */ 67033965Sjdp if (strcmp (outsecname, outdefsecname) == 0) 67133965Sjdp return; 67233965Sjdp 67333965Sjdp for (ncr = info->ncrs->list; ncr != NULL; ncr = ncr->next) 67433965Sjdp if (strcmp (outsecname, ncr->name) == 0) 67533965Sjdp break; 67633965Sjdp 67733965Sjdp if (ncr == NULL) 67833965Sjdp return; 67933965Sjdp 68033965Sjdp /* This section is one for which cross references are prohibited. 68133965Sjdp Look through the relocations, and see if any of them are to 68289857Sobrien INFO->SYM_NAME. If INFO->SYMNAME is NULL, check for relocations 683218822Sdim against the section symbol. If INFO->GLOBAL is TRUE, the 684218822Sdim definition is global, check for relocations against the global 685218822Sdim symbols. Otherwise check for relocations against the local and 686218822Sdim section symbols. */ 68733965Sjdp 68889857Sobrien symname = info->sym_name; 689218822Sdim global = info->global; 69033965Sjdp 69133965Sjdp relsize = bfd_get_reloc_upper_bound (abfd, sec); 69233965Sjdp if (relsize < 0) 69360484Sobrien einfo (_("%B%F: could not read relocs: %E\n"), abfd); 69433965Sjdp if (relsize == 0) 69533965Sjdp return; 69633965Sjdp 697130561Sobrien relpp = xmalloc (relsize); 69833965Sjdp relcount = bfd_canonicalize_reloc (abfd, sec, relpp, info->asymbols); 69933965Sjdp if (relcount < 0) 70060484Sobrien einfo (_("%B%F: could not read relocs: %E\n"), abfd); 70133965Sjdp 70233965Sjdp p = relpp; 70333965Sjdp pend = p + relcount; 70433965Sjdp for (; p < pend && *p != NULL; p++) 70533965Sjdp { 70633965Sjdp arelent *q = *p; 70733965Sjdp 70833965Sjdp if (q->sym_ptr_ptr != NULL 70933965Sjdp && *q->sym_ptr_ptr != NULL 710218822Sdim && ((global 711218822Sdim && (bfd_is_und_section (bfd_get_section (*q->sym_ptr_ptr)) 712218822Sdim || bfd_is_com_section (bfd_get_section (*q->sym_ptr_ptr)) 713218822Sdim || ((*q->sym_ptr_ptr)->flags & (BSF_GLOBAL 714218822Sdim | BSF_WEAK)) != 0)) 715218822Sdim || (!global 716218822Sdim && ((*q->sym_ptr_ptr)->flags & (BSF_LOCAL 717218822Sdim | BSF_SECTION_SYM)) != 0 718218822Sdim && bfd_get_section (*q->sym_ptr_ptr) == info->defsec)) 71989857Sobrien && (symname != NULL 72089857Sobrien ? strcmp (bfd_asymbol_name (*q->sym_ptr_ptr), symname) == 0 721218822Sdim : ((*q->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0)) 72233965Sjdp { 72333965Sjdp /* We found a reloc for the symbol. The symbol is defined 724130561Sobrien in OUTSECNAME. This reloc is from a section which is 725130561Sobrien mapped into a section from which references to OUTSECNAME 726130561Sobrien are prohibited. We must report an error. */ 72760484Sobrien einfo (_("%X%C: prohibited cross reference from %s to `%T' in %s\n"), 72833965Sjdp abfd, sec, q->address, outsecname, 72933965Sjdp bfd_asymbol_name (*q->sym_ptr_ptr), outdefsecname); 73033965Sjdp } 73133965Sjdp } 73233965Sjdp 73333965Sjdp free (relpp); 73433965Sjdp} 735