* ld.h (check_nocrossrefs): Declare.

* ldlang.h (struct lang_nocrossref): Define.
	(struct lang_nocrossrefs): Define.
	(nocrossref_list): Declare.
	(lang_add_nocrossref): Declare.
	* ldlex.l: Recognize NOCROSSREFS keyword.
	* ldgram.y (%union): Add nocrossref field.
	(NOCROSSREFS): New terminal.
	(ifile_p1): Recognize NOCROSSREFS.
	(nocrossref_list): New nonterminal.
	* ldlang.c (nocrossref_list): Define.
	(lang_add_nocrossref): New function.
	* ldmain.c (main): If nocrossref_list is not NULL, call
	check_nocrossrefs.
	(warning_callback): Free symbols if there is no place to store
	them.
	(notice): Call add_cref if nocrossref_list is not NULL.
	* ldcref.c: Include "ldexp.h" and "ldlang.h".
	(check_nocrossrefs): New function.
	(check_nocrossref): New static function.
	(struct check_refs_info): Define.
	(check_refs, check_reloc_refs): New static functions.
	* Makefile.in: Rebuild dependencies.
	* ld.texinfo (Option Commands): Document NOCROSSREFS.
This commit is contained in:
Ian Lance Taylor
1996-08-01 17:35:49 +00:00
parent 8efb80797c
commit 582dd77f65
9 changed files with 359 additions and 10 deletions

View File

@@ -18,7 +18,9 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* This file holds routines that manage the cross reference table. */
/* This file holds routines that manage the cross reference table.
The table is used to generate cross reference reports. It is also
used to implement the NOCROSSREFS command in the linker script. */
#include "bfd.h"
#include "sysdep.h"
@@ -28,6 +30,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "ld.h"
#include "ldmain.h"
#include "ldmisc.h"
#include "ldexp.h"
#include "ldlang.h"
/* We keep an instance of this structure for each reference to a
symbol from a given object. */
@@ -71,6 +75,11 @@ static struct bfd_hash_entry *cref_hash_newfunc
static boolean cref_fill_array PARAMS ((struct cref_hash_entry *, PTR));
static int cref_sort_array PARAMS ((const PTR, const PTR));
static void output_one_cref PARAMS ((FILE *, struct cref_hash_entry *));
static boolean check_nocrossref PARAMS ((struct cref_hash_entry *, PTR));
static void check_refs
PARAMS ((struct cref_hash_entry *, struct bfd_link_hash_entry *,
struct lang_nocrossrefs *));
static void check_reloc_refs PARAMS ((bfd *, asection *, PTR));
/* Look up an entry in the cref hash table. */
@@ -325,3 +334,212 @@ output_one_cref (fp, h)
ASSERT (len == 0);
}
/* Check for prohibited cross references. */
void
check_nocrossrefs ()
{
if (! cref_initialized)
return;
cref_hash_traverse (&cref_table, check_nocrossref, (PTR) NULL);
}
/* Check one symbol to see if it is a prohibited cross reference. */
/*ARGSUSED*/
static boolean
check_nocrossref (h, ignore)
struct cref_hash_entry *h;
PTR ignore;
{
struct bfd_link_hash_entry *hl;
asection *defsec;
const char *defsecname;
struct lang_nocrossrefs *ncrs;
struct lang_nocrossref *ncr;
hl = bfd_link_hash_lookup (link_info.hash, h->root.string, false,
false, true);
if (hl == NULL)
{
einfo ("%P: symbol `%T' missing from main hash table\n",
h->root.string);
return true;
}
if (hl->type != bfd_link_hash_defined
&& hl->type != bfd_link_hash_defweak)
return true;
defsec = hl->u.def.section->output_section;
defsecname = bfd_get_section_name (defsec->owner, defsec);
for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next)
for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next)
if (strcmp (ncr->name, defsecname) == 0)
check_refs (h, hl, ncrs);
return true;
}
/* The struct is used to pass information from check_refs to
check_reloc_refs through bfd_map_over_sections. */
struct check_refs_info
{
struct cref_hash_entry *h;
asection *defsec;
struct lang_nocrossrefs *ncrs;
asymbol **asymbols;
boolean same;
};
/* This function is called for each symbol defined in a section which
prohibits cross references. We need to look through all references
to this symbol, and ensure that the references are not from
prohibited sections. */
static void
check_refs (h, hl, ncrs)
struct cref_hash_entry *h;
struct bfd_link_hash_entry *hl;
struct lang_nocrossrefs *ncrs;
{
struct cref_ref *ref;
for (ref = h->refs; ref != NULL; ref = ref->next)
{
lang_input_statement_type *li;
asymbol **asymbols;
struct check_refs_info info;
/* We need to look through the relocations for this BFD, to see
if any of the relocations which refer to this symbol are from
a prohibited section. Note that we need to do this even for
the BFD in which the symbol is defined, since even a single
BFD might contain a prohibited cross reference; for this
case, we set the SAME field in INFO, which will cause
CHECK_RELOCS_REFS to check for relocations against the
section as well as against the symbol. */
li = (lang_input_statement_type *) ref->abfd->usrdata;
if (li != NULL && li->asymbols != NULL)
asymbols = li->asymbols;
else
{
long symsize;
long symbol_count;
symsize = bfd_get_symtab_upper_bound (ref->abfd);
if (symsize < 0)
einfo ("%B%F: could not read symbols; %E\n", ref->abfd);
asymbols = (asymbol **) xmalloc (symsize);
symbol_count = bfd_canonicalize_symtab (ref->abfd, asymbols);
if (symbol_count < 0)
einfo ("%B%F: could not read symbols: %E\n", ref->abfd);
if (li != NULL)
{
li->asymbols = asymbols;
li->symbol_count = symbol_count;
}
}
info.h = h;
info.defsec = hl->u.def.section;
info.ncrs = ncrs;
info.asymbols = asymbols;
if (ref->abfd == hl->u.def.section->owner)
info.same = true;
else
info.same = false;
bfd_map_over_sections (ref->abfd, check_reloc_refs, (PTR) &info);
if (li == NULL)
free (asymbols);
}
}
/* This is called via bfd_map_over_sections. INFO->H is a symbol
defined in INFO->DEFSECNAME. If this section maps into any of the
sections listed in INFO->NCRS, other than INFO->DEFSECNAME, then we
look through the relocations. If any of the relocations are to
INFO->H, then we report a prohibited cross reference error. */
static void
check_reloc_refs (abfd, sec, iarg)
bfd *abfd;
asection *sec;
PTR iarg;
{
struct check_refs_info *info = (struct check_refs_info *) iarg;
asection *outsec;
const char *outsecname;
asection *outdefsec;
const char *outdefsecname;
struct lang_nocrossref *ncr;
const char *symname;
long relsize;
arelent **relpp;
long relcount;
arelent **p, **pend;
outsec = sec->output_section;
outsecname = bfd_get_section_name (outsec->owner, outsec);
outdefsec = info->defsec->output_section;
outdefsecname = bfd_get_section_name (outdefsec->owner, outdefsec);
/* The section where the symbol is defined is permitted. */
if (strcmp (outsecname, outdefsecname) == 0)
return;
for (ncr = info->ncrs->list; ncr != NULL; ncr = ncr->next)
if (strcmp (outsecname, ncr->name) == 0)
break;
if (ncr == NULL)
return;
/* This section is one for which cross references are prohibited.
Look through the relocations, and see if any of them are to
INFO->H. */
symname = info->h->root.string;
relsize = bfd_get_reloc_upper_bound (abfd, sec);
if (relsize < 0)
einfo ("%B%F: could not read relocs: %E\n", abfd);
if (relsize == 0)
return;
relpp = (arelent **) xmalloc (relsize);
relcount = bfd_canonicalize_reloc (abfd, sec, relpp, info->asymbols);
if (relcount < 0)
einfo ("%B%F: could not read relocs: %E\n", abfd);
p = relpp;
pend = p + relcount;
for (; p < pend && *p != NULL; p++)
{
arelent *q = *p;
if (q->sym_ptr_ptr != NULL
&& *q->sym_ptr_ptr != NULL
&& (strcmp (bfd_asymbol_name (*q->sym_ptr_ptr), symname) == 0
|| (info->same
&& *q->sym_ptr_ptr == info->defsec->symbol)))
{
/* We found a reloc for the symbol. The symbol is defined
in OUTSECNAME. This reloc is from a section which is
mapped into a section from which references to OUTSECNAME
are prohibited. We must report an error. */
einfo ("%X%C: prohibited cross reference from %s to `%T' in %s\n",
abfd, sec, q->address, outsecname,
bfd_asymbol_name (*q->sym_ptr_ptr), outdefsecname);
}
}
free (relpp);
}