* 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

@ -1,5 +1,34 @@
Thu Aug 1 12:52:19 1996 Ian Lance Taylor <ian@cygnus.com>
* 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.
* ld.texinfo (Section Placement): Improve the wording of the
wildcard documentation. Mention that wildcards are only searched
for on the command line, not in the file system.
* emultempl/sunos.em (gld${EMULATION_NAME}_after_open): Move
definition of lib_path inside condition where it is used.

View file

@ -5,6 +5,8 @@ Changes since version 2.7:
* Linker scripts may now contain shell wildcard characters for file and section
names.
* The NOCROSSREFS command was added to the linker script language.
Changes since version 2.6:
* New option --cref to print out a cross reference table.

View file

@ -2704,6 +2704,24 @@ the environment variable @code{GNUTARGET}, if available, to select the
output file format. If that variable is also absent, @code{ld} uses
the default format configured for your machine in the BFD libraries.
@end ifclear
@cindex cross references
@kindex NOCROSSREFS ( @var{sections} )
@item NOCROSSREFS ( @var{section} @var{section} @dots{} )
This command may be used to tell @code{ld} to issue an error about any
references among certain sections.
In certain types of programs, particularly on embedded systems, when one
section is loaded into memory, another section will not be. Any direct
references between the two sections would be errors. For example, it
would be an error if code in one section called a function defined in
the other section.
The @code{NOCROSSREFS} command takes a list of section names. If
@code{ld} detects any cross references between the sections, it reports
an error and returns a non-zero exit status. The @code{NOCROSSREFS}
command uses output section names, defined in the @code{SECTIONS}
command. It does not use the names of input sections.
@end table
@ifset GENERIC

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);
}

View file

@ -75,6 +75,7 @@ static int error_index;
union etree_union *at;
union etree_union *flags;
} phdr;
struct lang_nocrossref *nocrossref;
}
%type <etree> exp opt_exp_with_type mustbe_exp opt_at phdr_type phdr_val
@ -82,8 +83,9 @@ static int error_index;
%type <name> memspec_opt casesymlist
%token <integer> INT
%token <name> NAME LNAME
%type <integer> length
%type <integer> length
%type <phdr> phdr_qualifiers
%type <nocrossref> nocrossref_list
%right <token> PLUSEQ MINUSEQ MULTEQ DIVEQ '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ
%right <token> '?' ':'
@ -112,7 +114,7 @@ static int error_index;
%token NOLOAD DSECT COPY INFO OVERLAY
%token NAME LNAME DEFINED TARGET_K SEARCH_DIR MAP ENTRY
%token <integer> SIZEOF NEXT ADDR
%token STARTUP HLL SYSLIB FLOAT NOFLOAT
%token STARTUP HLL SYSLIB FLOAT NOFLOAT NOCROSSREFS
%token ORIGIN FILL
%token LENGTH CREATE_OBJECT_SYMBOLS INPUT GROUP OUTPUT CONSTRUCTORS
%token ALIGNMOD AT PROVIDE
@ -299,6 +301,10 @@ ifile_p1:
{ lang_add_map($3); }
| INCLUDE filename
{ ldfile_open_command_file($2); } ifile_list END
| NOCROSSREFS '(' nocrossref_list ')'
{
lang_add_nocrossref ($3);
}
;
input_list:
@ -569,6 +575,30 @@ floating_point_support:
{ lang_float(false); }
;
nocrossref_list:
/* empty */
{
$$ = NULL;
}
| NAME nocrossref_list
{
struct lang_nocrossref *n;
n = (struct lang_nocrossref *) xmalloc (sizeof *n);
n->name = $1;
n->next = $2;
$$ = n;
}
| NAME ',' nocrossref_list
{
struct lang_nocrossref *n;
n = (struct lang_nocrossref *) xmalloc (sizeof *n);
n->name = $1;
n->next = $3;
$$ = n;
}
;
mustbe_exp: { ldlex_expression(); }
exp

View file

@ -142,6 +142,7 @@ boolean lang_has_input_file = false;
boolean had_output_filename = false;
boolean lang_float_flag = false;
boolean delete_output_file_on_failure = false;
struct lang_nocrossrefs *nocrossref_list;
etree_type *base; /* Relocation base - or null */
@ -3617,3 +3618,20 @@ lang_record_phdrs ()
u->output_section_statement.name, pl->name);
}
}
/* Record a list of sections which may not be cross referenced. */
void
lang_add_nocrossref (l)
struct lang_nocrossref *l;
{
struct lang_nocrossrefs *n;
n = (struct lang_nocrossrefs *) xmalloc (sizeof *n);
n->next = nocrossref_list;
n->list = l;
nocrossref_list = n;
/* Set notice_all so that we get informed about all symbols. */
link_info.notice_all = true;
}

View file

@ -1,5 +1,5 @@
/* ldlang.h - linker command language support
Copyright 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
Copyright 1991, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
@ -96,6 +96,17 @@ typedef struct lang_output_statement_struct
const char *name;
} lang_output_statement_type;
/* Section types specified in a linker script. */
enum section_type
{
normal_section,
dsect_section,
copy_section,
noload_section,
info_section,
overlay_section
};
/* This structure holds a list of program headers describing segments
in which this section should be placed. */
@ -120,7 +131,7 @@ typedef struct lang_output_section_statement_struct
asection *bfd_section;
int flags; /* Or together of all input sections */
int loadable; /* set from NOLOAD flag in script */
enum section_type sectype;
struct memory_region_struct *region;
size_t block_value;
fill_type fill;
@ -243,9 +254,6 @@ typedef struct lang_input_statement_struct
/* unsigned int globals_in_this_file;*/
const char *target;
boolean real;
asection *common_section;
asection *common_output_section;
boolean complained;
} lang_input_statement_type;
typedef struct
@ -335,6 +343,25 @@ struct lang_phdr
etree_type *flags;
};
/* This structure is used to hold a list of sections which may not
cross reference each other. */
struct lang_nocrossref
{
struct lang_nocrossref *next;
const char *name;
};
/* The list of nocrossref lists. */
struct lang_nocrossrefs
{
struct lang_nocrossrefs *next;
struct lang_nocrossref *list;
};
extern struct lang_nocrossrefs *nocrossref_list;
extern lang_output_section_statement_type *abs_output_section;
extern boolean lang_has_input_file;
extern etree_type *base;
@ -353,7 +380,7 @@ extern void lang_add_output PARAMS ((const char *, int from_script));
extern void lang_enter_output_section_statement
PARAMS ((const char *output_section_statement_name,
etree_type * address_exp,
int flags,
enum section_type sectype,
bfd_vma block_value,
etree_type *align,
etree_type *subalign,
@ -431,5 +458,6 @@ extern void lang_new_phdr
PARAMS ((const char *, etree_type *, boolean, boolean, etree_type *,
etree_type *));
extern void lang_section_in_phdr PARAMS ((const char *));
extern void lang_add_nocrossref PARAMS ((struct lang_nocrossref *));
#endif

View file

@ -256,6 +256,7 @@ NOCFILENAMECHAR [_a-zA-Z0-9\/\.\-\_\+\$\:\[\]\\\~]
<BOTH,SCRIPT>"SHORT" { RTOKEN( SHORT);}
<BOTH,SCRIPT>"BYTE" { RTOKEN( BYTE);}
<BOTH,SCRIPT>"NOFLOAT" { RTOKEN(NOFLOAT);}
<BOTH,SCRIPT>"NOCROSSREFS" { RTOKEN(NOCROSSREFS);}
<EXPRESSION,BOTH,SCRIPT>"NOLOAD" { RTOKEN(NOLOAD);}
<EXPRESSION,BOTH,SCRIPT>"DSECT" { RTOKEN(DSECT);}
<EXPRESSION,BOTH,SCRIPT>"COPY" { RTOKEN(COPY);}

View file

@ -323,6 +323,8 @@ main (argc, argv)
lang_map ();
if (command_line.cref)
output_cref (config.map_file != NULL ? config.map_file : stdout);
if (nocrossref_list != NULL)
check_nocrossrefs ();
/* Even if we're producing relocateable output, some non-fatal errors should
be reported in the exit status. (What non-fatal errors, if any, do we
@ -1031,6 +1033,9 @@ warning_callback (info, warning, symbol, abfd, section, address)
if (! info.found)
einfo ("%B: %s\n", abfd, warning);
if (entry == NULL)
free (asymbols);
}
return true;
@ -1241,7 +1246,7 @@ notice (info, name, abfd, section, value)
bfd_is_und_section (section) ? "reference to" : "definition of",
name);
if (command_line.cref)
if (command_line.cref || nocrossref_list != NULL)
add_cref (name, abfd, section, value);
return true;