* ld.h (args_type): Add gc_sections.

* ldgram.y (ldgram_had_keep, KEEP): New.
        (input_section_spec_no_keep): Rename from old input_section_spec.
        (input_section_spec): New.  Recognize KEEP.
        * ldlang.c (wild_section): Handle keep sections.
        (lang_gc_wild_section, lang_gc_wild_file, lang_gc_wild): New.
        (lang_gc_sections_1, lang_gc_sections): New.
        (lang_process): Invoke lang_gc_sections.
        (lang_add_wild): Add keep argument.  Update all callers.
        * ldlang.h (lang_wild_statement_struct): Add keep_sections.
        * ldlex.l (KEEP): Match it.
        * ldmain.c (main): Error on -r and --gc-sections.
        * lexsup.c: Add --gc-sections.

        * scripttempl/elf.sc: Merge .text.* etc sections appropriately.
        Mark startup sections with KEEP.
        * scripttempl/elfppc.sc: Likewise.

        * ld.texinfo: Update for --gc-sections and KEEP.
This commit is contained in:
Richard Henderson 1998-07-02 02:52:31 +00:00
parent 5ea0771f4c
commit 71b012a810
8 changed files with 620 additions and 99 deletions

View File

@ -1,3 +1,30 @@
Wed Jul 1 19:40:34 1998 Richard Henderson <rth@cygnus.com>
* ld.h (args_type): Add gc_sections.
* ldgram.y (ldgram_had_keep, KEEP): New.
(input_section_spec_no_keep): Rename from old input_section_spec.
(input_section_spec): New. Recognize KEEP.
* ldlang.c (wild_section): Handle keep sections.
(lang_gc_wild_section, lang_gc_wild_file, lang_gc_wild): New.
(lang_gc_sections_1, lang_gc_sections): New.
(lang_process): Invoke lang_gc_sections.
(lang_add_wild): Add keep argument. Update all callers.
* ldlang.h (lang_wild_statement_struct): Add keep_sections.
* ldlex.l (KEEP): Match it.
* ldmain.c (main): Error on -r and --gc-sections.
* lexsup.c: Add --gc-sections.
* scripttempl/elf.sc: Merge .text.* etc sections appropriately.
Mark startup sections with KEEP.
* scripttempl/elfppc.sc: Likewise.
* ld.texinfo: Update for --gc-sections and KEEP.
Wed Jul 1 15:21:20 1998 Ian Lance Taylor <ian@cygnus.com>
From Peter Jordan <pjordan@chla.usc.edu>:
* scripttempl/i386go32.sc: Correct constructor handling for -u.
Tue Jun 23 15:17:27 1998 Ian Lance Taylor <ian@cygnus.com>
* Makefile.am (install-data-local): Make ldscripts subdirectory.

View File

@ -138,6 +138,9 @@ typedef struct
/* Name of shared object for whose symbol table this shared object
is an auxiliary filter. From the --auxiliary option. */
char **auxiliary_filters;
/* Remove unreferenced sections? */
boolean gc_sections;
} args_type;
extern args_type command_line;
@ -153,6 +156,12 @@ typedef struct
/* If true, doing a dynamic link. */
boolean dynamic_link;
/* If true, -shared is supported. */
/* ??? A better way to do this is perhaps to define this in the
ld_emulation_xfer_struct since this is really a target dependent
parameter. */
boolean has_shared;
/* If true, build constructors. */
boolean build_constructors;

View File

@ -414,6 +414,13 @@ Set the maximum size of objects to be optimized using the GP register to
MIPS ECOFF which supports putting large and small objects into different
sections. This is ignored for other object file formats.
@kindex --gc-sections
@cindex garbage collection
@item --gc-sections
Enable garbage collection of unused input sections. It is ignored on
targets that do not support this option. This option is not compatible
with @samp{-r}, nor should it be used with dynamic linking.
@cindex runtime library name
@kindex -h@var{name}
@kindex -soname=@var{name}
@ -877,8 +884,11 @@ in the program, such as relaxing address modes and synthesizing new
instructions in the output object file.
On some platforms these link time global optimizations may make symbolic
debugging of the resulting executable impossible. This is known to be
debugging of the resulting executable impossible.
@ifset GENERIC
This is known to be
the case for the Matsushita MN10200 and MN10300 family of processors.
@end ifset
@ifset GENERIC
On platforms where this is not supported, @samp{--relax} is accepted,
@ -1963,6 +1973,7 @@ map the input files into your memory layout.
* Input Section Basics:: Input section basics
* Input Section Wildcards:: Input section wildcard patterns
* Input Section Common:: Input section for common symbols
* Input Section Keep:: Input section and garbage collection
* Input Section Example:: Input section example
@end menu
@ -2131,6 +2142,16 @@ You will sometimes see @samp{[COMMON]} in old linker scripts. This
notation is now considered obsolete. It is equivalent to
@samp{*(COMMON)}.
@node Input Section Keep
@subsubsection Input section and garbage collection
@cindex KEEP
@cindex garbage collection
When link-time garbage collection is in use (@samp{--gc-sections}),
it is often useful to mark sections that should not be eliminated.
This is accomplished by surrounding an input section's wildcard entry
with @code{KEEP()}, as in @code{KEEP(*(.init))} or
@code{KEEP(SORT(*)(.ctors))}.
@node Input Section Example
@subsubsection Input section example
The following example is a complete linker script. It tells the linker
@ -2319,6 +2340,7 @@ If you use anything other than an input section description as an output
section command, such as a symbol assignment, then the output section
will always be created, even if there are no matching input sections.
@cindex /DISCARD/
The special output section name @samp{/DISCARD/} may be used to discard
input sections. Any input sections which are assigned to an output
section named @samp{/DISCARD/} are not included in the output file.

View File

@ -1,5 +1,6 @@
/* A YACC grammer to parse a superset of the AT&T linker scripting languaue.
Copyright (C) 1991, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 1998
Free Software Foundation, Inc.
Written by Steve Chamberlain of Cygnus Support (steve@cygnus.com).
This file is part of GNU ld.
@ -47,15 +48,14 @@ static enum section_type sectype;
lang_memory_region_type *region;
char *current_file;
struct wildcard_spec current_file;
boolean ldgram_want_filename = true;
boolean had_script = false;
boolean force_make_executable = false;
boolean ldgram_in_script = false;
boolean ldgram_had_equals = false;
boolean ldgram_had_keep = false;
#define ERROR_NAME_MAX 20
static char *error_names[ERROR_NAME_MAX];
@ -66,6 +66,8 @@ static int error_index;
%union {
bfd_vma integer;
char *name;
const char *cname;
struct wildcard_spec wildcard;
int token;
union etree_union *etree;
struct phdr_info
@ -76,16 +78,25 @@ static int error_index;
union etree_union *flags;
} phdr;
struct lang_nocrossref *nocrossref;
struct lang_output_section_phdr_list *section_phdr;
struct bfd_elf_version_deps *deflist;
struct bfd_elf_version_expr *versyms;
struct bfd_elf_version_tree *versnode;
}
%type <etree> exp opt_exp_with_type mustbe_exp opt_at phdr_type phdr_val
%type <etree> opt_exp_without_type
%type <integer> fill_opt
%type <name> memspec_opt casesymlist
%type <cname> wildcard_name
%type <wildcard> wildcard_spec
%token <integer> INT
%token <name> NAME LNAME
%type <integer> length
%type <phdr> phdr_qualifiers
%type <nocrossref> nocrossref_list
%type <section_phdr> phdr_opt
%type <integer> opt_nocrossrefs
%right <token> PLUSEQ MINUSEQ MULTEQ DIVEQ '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ
%right <token> '?' ':'
@ -104,8 +115,8 @@ static int error_index;
%right UNARY
%token END
%left <token> '('
%token <token> ALIGN_K BLOCK BIND QUAD LONG SHORT BYTE
%token SECTIONS PHDRS
%token <token> ALIGN_K BLOCK BIND QUAD SQUAD LONG SHORT BYTE
%token SECTIONS PHDRS SORT
%token '{' '}'
%token SIZEOF_HEADERS OUTPUT_FORMAT FORCE_COMMON_ALLOCATION OUTPUT_ARCH
%token SIZEOF_HEADERS
@ -113,7 +124,8 @@ static int error_index;
%token MEMORY DEFSYMEND
%token NOLOAD DSECT COPY INFO OVERLAY
%token NAME LNAME DEFINED TARGET_K SEARCH_DIR MAP ENTRY
%token <integer> SIZEOF NEXT ADDR LOADADDR
%token <integer> NEXT
%token SIZEOF ADDR LOADADDR MAX MIN
%token STARTUP HLL SYSLIB FLOAT NOFLOAT NOCROSSREFS
%token ORIGIN FILL
%token LENGTH CREATE_OBJECT_SYMBOLS INPUT GROUP OUTPUT CONSTRUCTORS
@ -123,12 +135,19 @@ static int error_index;
%token CHIP LIST SECT ABSOLUTE LOAD NEWLINE ENDWORD ORDER NAMEWORD
%token FORMAT PUBLIC DEFSYMEND BASE ALIAS TRUNCATE REL
%token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM CASE EXTERN START
%token <name> VERS_TAG VERS_IDENTIFIER
%token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT
%token KEEP
%type <versyms> vers_defns
%type <versnode> vers_tag
%type <deflist> verdep
%%
file:
INPUT_SCRIPT script_file
| INPUT_MRI_SCRIPT mri_script_file
| INPUT_VERSION_SCRIPT version_script_file
| INPUT_DEFSYM defsym_expr
;
@ -148,7 +167,7 @@ defsym_expr:
mri_script_file:
{
ldlex_mri_script ();
PUSH_ERROR ("MRI style script");
PUSH_ERROR (_("MRI style script"));
}
mri_script_lines
{
@ -167,7 +186,7 @@ mri_script_command:
CHIP exp
| CHIP exp ',' exp
| NAME {
einfo("%P%F: unrecognised keyword in MRI style script '%s'\n",$1);
einfo(_("%P%F: unrecognised keyword in MRI style script '%s'\n"),$1);
}
| LIST {
config.map_filename = "-";
@ -276,6 +295,7 @@ ifile_p1:
| low_level_library
| floating_point_support
| statement_anywhere
| version
| ';'
| TARGET_K '(' NAME ')'
{ lang_add_target($3); }
@ -346,49 +366,79 @@ statement_anywhere:
/* The '*' and '?' cases are there because the lexer returns them as
separate tokens rather than as NAME. */
file_NAME_list:
wildcard_name:
NAME
{ lang_add_wild ($1, current_file); }
{
$$ = $1;
}
| '*'
{ lang_add_wild ("*", current_file); }
{
$$ = "*";
}
| '?'
{ lang_add_wild ("?", current_file); }
| file_NAME_list opt_comma NAME
{ lang_add_wild ($3, current_file); }
| file_NAME_list opt_comma '*'
{ lang_add_wild ("*", current_file); }
| file_NAME_list opt_comma '?'
{ lang_add_wild ("?", current_file); }
{
$$ = "?";
}
;
wildcard_spec:
wildcard_name
{
$$.name = $1;
$$.sorted = false;
}
| SORT '(' wildcard_name ')'
{
$$.name = $3;
$$.sorted = true;
}
;
file_NAME_list:
wildcard_spec
{
lang_add_wild ($1.name, $1.sorted,
current_file.name,
current_file.sorted,
ldgram_had_keep);
}
| file_NAME_list opt_comma wildcard_spec
{
lang_add_wild ($3.name, $3.sorted,
current_file.name,
current_file.sorted,
ldgram_had_keep);
}
;
input_section_spec_no_keep:
NAME
{
lang_add_wild (NULL, false, $1, false,
ldgram_had_keep);
}
| '['
{
current_file.name = NULL;
current_file.sorted = false;
}
file_NAME_list ']'
| wildcard_spec
{
current_file = $1;
/* '*' matches any file name. */
if (strcmp (current_file.name, "*") == 0)
current_file.name = NULL;
}
'(' file_NAME_list ')'
;
input_section_spec:
NAME
{
lang_add_wild((char *)NULL, $1);
}
| '['
{
current_file = (char *)NULL;
}
file_NAME_list
']'
| NAME
{
current_file = $1;
}
'(' file_NAME_list ')'
| '?'
/* This case is needed because the lexer returns a
single question mark as '?' rather than NAME. */
{
current_file = "?";
}
'(' file_NAME_list ')'
| '*'
{
current_file = (char *)NULL;
}
'(' file_NAME_list ')'
input_section_spec_no_keep
| KEEP '('
{ ldgram_had_keep = true; }
input_section_spec_no_keep ')'
{ ldgram_had_keep = false; }
;
statement:
@ -432,6 +482,8 @@ statement_list_opt:
length:
QUAD
{ $$ = $1; }
| SQUAD
{ $$ = $1; }
| LONG
{ $$ = $1; }
| SHORT
@ -523,7 +575,9 @@ memory_spec: NAME
region->origin =
exp_get_vma($3, 0L,"origin", lang_first_phase_enum);
}
; length_spec:
;
length_spec:
LENGTH '=' mustbe_exp
{ region->length = exp_get_vma($3,
~((bfd_vma)0),
@ -535,7 +589,7 @@ memory_spec: NAME
attributes_opt:
'(' NAME ')'
{
lang_set_flags(&region->flags, $2);
lang_set_flags(region, $2);
}
|
@ -678,6 +732,10 @@ exp :
{ $$ = exp_unop(ALIGN_K,$3); }
| NAME
{ $$ = exp_nameop(NAME,$1); }
| MAX '(' exp ',' exp ')'
{ $$ = exp_binop (MAX, $3, $5 ); }
| MIN '(' exp ',' exp ')'
{ $$ = exp_binop (MIN, $3, $5 ); }
;
@ -699,10 +757,27 @@ section: NAME { ldlex_expression(); }
'}' { ldlex_popstate (); ldlex_expression (); }
memspec_opt phdr_opt fill_opt
{
ldlex_popstate();
lang_leave_output_section_statement($13, $11);
ldlex_popstate ();
lang_leave_output_section_statement ($13, $11, $12);
}
opt_comma
| OVERLAY
{ ldlex_expression (); }
opt_exp_without_type opt_nocrossrefs opt_at
{ ldlex_popstate (); ldlex_script (); }
'{'
{
lang_enter_overlay ($3, $5, (int) $4);
}
overlay_section
'}'
{ ldlex_popstate (); ldlex_expression (); }
memspec_opt phdr_opt fill_opt
{
ldlex_popstate ();
lang_leave_overlay ($14, $12, $13);
}
opt_comma
| /* The GROUP case is just enough to support the gcc
svr3.ifile script. It is not intended to be full
support. I'm not even sure what GROUP is supposed
@ -727,6 +802,7 @@ type:
atype:
'(' type ')'
| /* EMPTY */ { sectype = normal_section; }
| '(' ')' { sectype = normal_section; }
;
opt_exp_with_type:
@ -741,6 +817,18 @@ opt_exp_with_type:
{ $$ = $3; }
;
opt_exp_without_type:
exp ':' { $$ = $1; }
| ':' { $$ = (etree_type *) NULL; }
;
opt_nocrossrefs:
/* empty */
{ $$ = 0; }
| NOCROSSREFS
{ $$ = 1; }
;
memspec_opt:
'>' NAME
{ $$ = $2; }
@ -749,12 +837,40 @@ memspec_opt:
phdr_opt:
/* empty */
{
$$ = NULL;
}
| phdr_opt ':' NAME
{
lang_section_in_phdr ($3);
struct lang_output_section_phdr_list *n;
n = ((struct lang_output_section_phdr_list *)
xmalloc (sizeof *n));
n->name = $3;
n->used = false;
n->next = $1;
$$ = n;
}
;
overlay_section:
/* empty */
| overlay_section
NAME
{
ldlex_script ();
lang_enter_overlay_section ($2);
}
'{' statement_list_opt '}'
{ ldlex_popstate (); ldlex_expression (); }
phdr_opt fill_opt
{
ldlex_popstate ();
lang_leave_overlay_section ($9, $8);
}
opt_comma
;
phdrs:
PHDRS '{' phdr_list '}'
;
@ -819,7 +935,7 @@ phdr_qualifiers:
else if (strcmp ($1, "FLAGS") == 0 && $2 != NULL)
$$.flags = $2;
else
einfo ("%X%P:%S: PHDRS syntax error at `%s'\n", $1);
einfo (_("%X%P:%S: PHDRS syntax error at `%s'\n"), $1);
}
| AT '(' exp ')' phdr_qualifiers
{
@ -839,13 +955,100 @@ phdr_val:
}
;
/* This syntax is used within an external version script file. */
version_script_file:
{
ldlex_version_file ();
PUSH_ERROR (_("VERSION script"));
}
vers_nodes
{
ldlex_popstate ();
POP_ERROR ();
}
;
/* This is used within a normal linker script file. */
version:
{
ldlex_version_script ();
}
VERSIONK '{' vers_nodes '}'
{
ldlex_popstate ();
}
;
vers_nodes:
vers_node
| vers_nodes vers_node
;
vers_node:
VERS_TAG '{' vers_tag '}' ';'
{
lang_register_vers_node ($1, $3, NULL);
}
| VERS_TAG '{' vers_tag '}' verdep ';'
{
lang_register_vers_node ($1, $3, $5);
}
;
verdep:
VERS_TAG
{
$$ = lang_add_vers_depend (NULL, $1);
}
| verdep VERS_TAG
{
$$ = lang_add_vers_depend ($1, $2);
}
;
vers_tag:
/* empty */
{
$$ = lang_new_vers_node (NULL, NULL);
}
| vers_defns ';'
{
$$ = lang_new_vers_node ($1, NULL);
}
| GLOBAL ':' vers_defns ';'
{
$$ = lang_new_vers_node ($3, NULL);
}
| LOCAL ':' vers_defns ';'
{
$$ = lang_new_vers_node (NULL, $3);
}
| GLOBAL ':' vers_defns ';' LOCAL ':' vers_defns ';'
{
$$ = lang_new_vers_node ($3, $7);
}
;
vers_defns:
VERS_IDENTIFIER
{
$$ = lang_new_vers_regex (NULL, $1);
}
| vers_defns ';' VERS_IDENTIFIER
{
$$ = lang_new_vers_regex ($1, $3);
}
;
%%
void
yyerror(arg)
const char *arg;
{
if (ldfile_assumed_script)
einfo ("%P:%s: file format not recognized; treating as linker script\n",
einfo (_("%P:%s: file format not recognized; treating as linker script\n"),
ldfile_input_filename);
if (error_index > 0 && error_index < ERROR_NAME_MAX)
einfo ("%P%F:%S: %s in %s\n", arg, error_names[error_index-1]);

View File

@ -141,6 +141,17 @@ static int topower PARAMS ((int));
static void lang_set_startof PARAMS ((void));
static void reset_memory_regions PARAMS ((void));
static void lang_record_phdrs PARAMS ((void));
static void lang_gc_wild_section
PARAMS ((lang_wild_statement_type *, const char *,
lang_input_statement_type *));
static void lang_gc_wild_file
PARAMS ((lang_wild_statement_type *, const char *,
lang_input_statement_type *));
static void lang_gc_wild
PARAMS ((lang_wild_statement_type *, const char *, const char *));
static void lang_gc_sections_1 PARAMS ((lang_statement_union_type *));
static void lang_gc_sections PARAMS ((void));
/* EXPORTS */
lang_output_section_statement_type *abs_output_section;
@ -1056,6 +1067,11 @@ wild_section (ptr, section, file, output)
{
lang_statement_union_type *before;
/* If the wild pattern was marked KEEP, the member sections
should be as well. */
if (ptr->keep_sections)
s->flags |= SEC_KEEP;
before = wild_sort (ptr, file, s);
/* Here BEFORE points to the lang_input_section which
@ -2792,7 +2808,7 @@ lang_finish ()
else
{
bfd_vma val;
char *send;
CONST char *send;
/* We couldn't find the entry symbol. Try parsing it as a
number. */
@ -3333,6 +3349,192 @@ reset_memory_regions ()
}
}
/* ??? At some point this traversal for GC should share code with the
traversal for manipulating the output file. */
/* Expand a wild statement for a particular FILE, marking its sections KEEP
as needed. SECTION may be NULL, in which case it is a wild card. */
static void
lang_gc_wild_section (ptr, section, file)
lang_wild_statement_type *ptr;
const char *section;
lang_input_statement_type *file;
{
if (file->just_syms_flag == false)
{
register asection *s;
boolean wildcard;
if (section == NULL)
wildcard = false;
else
wildcard = wildcardp (section);
for (s = file->the_bfd->sections; s != NULL; s = s->next)
{
boolean match;
if (section == NULL)
match = true;
else
{
const char *name;
name = bfd_get_section_name (file->the_bfd, s);
if (wildcard)
match = fnmatch (section, name, 0) == 0 ? true : false;
else
match = strcmp (section, name) == 0 ? true : false;
}
if (match)
{
/* If the wild pattern was marked KEEP, the member sections
should be as well. */
if (ptr->keep_sections)
s->flags |= SEC_KEEP;
}
}
}
}
/* Handle a wild statement for a single file F. */
static void
lang_gc_wild_file (s, section, f)
lang_wild_statement_type *s;
const char *section;
lang_input_statement_type *f;
{
if (f->the_bfd == NULL
|| ! bfd_check_format (f->the_bfd, bfd_archive))
lang_gc_wild_section (s, section, f);
else
{
bfd *member;
/* This is an archive file. We must map each member of the
archive separately. */
member = bfd_openr_next_archived_file (f->the_bfd, (bfd *) NULL);
while (member != NULL)
{
/* When lookup_name is called, it will call the add_symbols
entry point for the archive. For each element of the
archive which is included, BFD will call ldlang_add_file,
which will set the usrdata field of the member to the
lang_input_statement. */
if (member->usrdata != NULL)
{
lang_gc_wild_section (s, section,
(lang_input_statement_type *) member->usrdata);
}
member = bfd_openr_next_archived_file (f->the_bfd, member);
}
}
}
/* Handle a wild statement, marking it against GC. SECTION or FILE or both
may be NULL, indicating that it is a wildcard. */
static void
lang_gc_wild (s, section, file)
lang_wild_statement_type *s;
const char *section;
const char *file;
{
lang_input_statement_type *f;
if (file == (char *) NULL)
{
/* Perform the iteration over all files in the list */
for (f = (lang_input_statement_type *) file_chain.head;
f != (lang_input_statement_type *) NULL;
f = (lang_input_statement_type *) f->next)
{
lang_gc_wild_file (s, section, f);
}
}
else if (wildcardp (file))
{
for (f = (lang_input_statement_type *) file_chain.head;
f != (lang_input_statement_type *) NULL;
f = (lang_input_statement_type *) f->next)
{
if (fnmatch (file, f->filename, FNM_FILE_NAME) == 0)
lang_gc_wild_file (s, section, f);
}
}
else
{
/* Perform the iteration over a single file */
f = lookup_name (file);
lang_gc_wild_file (s, section, f);
}
}
/* Iterate over sections marking them against GC. */
static void
lang_gc_sections_1 (s)
lang_statement_union_type * s;
{
for (; s != (lang_statement_union_type *) NULL; s = s->next)
{
switch (s->header.type)
{
case lang_wild_statement_enum:
lang_gc_wild (&s->wild_statement,
s->wild_statement.section_name,
s->wild_statement.filename);
break;
case lang_constructors_statement_enum:
lang_gc_sections_1 (constructor_list.head);
break;
case lang_output_section_statement_enum:
lang_gc_sections_1 (s->output_section_statement.children.head);
break;
case lang_group_statement_enum:
lang_gc_sections_1 (s->group_statement.children.head);
break;
}
}
}
static void
lang_gc_sections ()
{
struct bfd_link_hash_entry *h;
ldlang_undef_chain_list_type *ulist, fake_list_start;
/* Keep all sections so marked in the link script. */
lang_gc_sections_1 (statement_list.head);
/* Keep all sections containing symbols undefined on the command-line.
Handle the entry symbol at the same time. */
fake_list_start.next = ldlang_undef_chain_list_head;
fake_list_start.name = entry_symbol;
for (ulist = &fake_list_start; ulist; ulist = ulist->next)
{
h = bfd_link_hash_lookup (link_info.hash, ulist->name,
false, false, false);
if (h != (struct bfd_link_hash_entry *) NULL
&& (h->type == bfd_link_hash_defined
|| h->type == bfd_link_hash_defweak)
&& ! bfd_is_abs_section (h->u.def.section))
{
h->u.def.section->flags |= SEC_KEEP;
}
}
bfd_gc_sections (output_bfd, &link_info);
}
void
lang_process ()
{
@ -3363,6 +3565,10 @@ lang_process ()
files. */
ldctor_build_sets ();
/* Remove unreferenced sections if asked to. */
if (command_line.gc_sections)
lang_gc_sections ();
/* Size up the common data */
lang_common ();
@ -3443,11 +3649,13 @@ lang_process ()
/* EXPORTED TO YACC */
void
lang_add_wild (section_name, sections_sorted, filename, filenames_sorted)
lang_add_wild (section_name, sections_sorted, filename, filenames_sorted,
keep_sections)
const char *const section_name;
boolean sections_sorted;
const char *const filename;
boolean filenames_sorted;
boolean keep_sections;
{
lang_wild_statement_type *new = new_stat (lang_wild_statement,
stat_ptr);
@ -3464,6 +3672,7 @@ lang_add_wild (section_name, sections_sorted, filename, filenames_sorted)
new->sections_sorted = sections_sorted;
new->filename = filename;
new->filenames_sorted = filenames_sorted;
new->keep_sections = keep_sections;
lang_list_init (&new->children);
}

View File

@ -1,6 +1,7 @@
%{
/* Copyright (C) 1991, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
/* Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 1998
Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
@ -15,8 +16,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
along with GLD; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
/*
This was written by steve chamberlain
@ -48,9 +50,6 @@ This was written by steve chamberlain
yylex and yyparse (indirectly) both check this. */
input_type parser_input;
/* Radix to use for bfd_scan_vma -- 0 (default to base 10) or 16. */
int hex_mode;
/* Line number in the current input file.
(FIXME Actually, it doesn't appear to get reset for each file?) */
unsigned int lineno = 1;
@ -115,7 +114,7 @@ WHITE [ \t\n\r]+
NOCFILENAMECHAR [_a-zA-Z0-9\/\.\-\_\+\$\:\[\]\\\~]
V_TAG [.$_a-zA-Z][._a-zA-Z0-9]*
V_IDENTIFIER [*?$_a-zA-Z][*?_a-zA-Z0-9]*
V_IDENTIFIER [*?.$_a-zA-Z][*?_a-zA-Z0-9]*
%s SCRIPT
%s EXPRESSION
@ -179,17 +178,18 @@ V_IDENTIFIER [*?$_a-zA-Z][*?_a-zA-Z0-9]*
ibase);
return INT;
}
<SCRIPT,DEFSYMEXP,MRI,BOTH,EXPRESSION>"$"?"0x"?([0-9A-Fa-f])+(M|K|m|k)? {
yylval.integer = bfd_scan_vma (yytext, 0,
hex_mode);
if (yytext[yyleng-1]=='M'
|| yytext[yyleng-1] == 'm') {
yylval.integer *= 1024*1024;
}
if (yytext[yyleng-1]=='K'
|| yytext[yyleng-1]=='k') {
yylval.integer *= 1024;
}
<SCRIPT,DEFSYMEXP,MRI,BOTH,EXPRESSION>((("$"|"0x")([0-9A-Fa-f])+)|(([0-9])+))(M|K|m|k)? {
char *s = yytext;
if (*s == '$')
++s;
yylval.integer = bfd_scan_vma (s, 0, 0);
if (yytext[yyleng-1] == 'M'
|| yytext[yyleng-1] == 'm')
yylval.integer *= 1024 * 1024;
if (yytext[yyleng-1] == 'K'
|| yytext[yyleng-1]=='k')
yylval.integer *= 1024;
return INT;
}
<BOTH,SCRIPT,EXPRESSION,MRI>"]" { RTOKEN(']');}
@ -232,7 +232,7 @@ V_IDENTIFIER [*?$_a-zA-Z][*?_a-zA-Z0-9]*
<BOTH,SCRIPT,EXPRESSION,MRI>";" { RTOKEN(';');}
<BOTH,SCRIPT>"MEMORY" { RTOKEN(MEMORY);}
<BOTH,SCRIPT>"ORIGIN" { RTOKEN(ORIGIN);}
<BOTH,SCRIPT>"VERSION" { RTOKEN(VERSION);}
<BOTH,SCRIPT>"VERSION" { RTOKEN(VERSIONK);}
<EXPRESSION,BOTH,SCRIPT>"BLOCK" { RTOKEN(BLOCK);}
<EXPRESSION,BOTH,SCRIPT>"BIND" { RTOKEN(BIND);}
<BOTH,SCRIPT>"LENGTH" { RTOKEN(LENGTH);}
@ -272,6 +272,7 @@ V_IDENTIFIER [*?$_a-zA-Z][*?_a-zA-Z0-9]*
<BOTH,SCRIPT>"NOFLOAT" { RTOKEN(NOFLOAT);}
<EXPRESSION,BOTH,SCRIPT>"NOCROSSREFS" { RTOKEN(NOCROSSREFS);}
<BOTH,SCRIPT>"OVERLAY" { RTOKEN(OVERLAY); }
<BOTH,SCRIPT>"SORT" { RTOKEN(SORT); }
<EXPRESSION,BOTH,SCRIPT>"NOLOAD" { RTOKEN(NOLOAD);}
<EXPRESSION,BOTH,SCRIPT>"DSECT" { RTOKEN(DSECT);}
<EXPRESSION,BOTH,SCRIPT>"COPY" { RTOKEN(COPY);}
@ -285,9 +286,9 @@ V_IDENTIFIER [*?$_a-zA-Z][*?_a-zA-Z0-9]*
<BOTH,SCRIPT>"PHDRS" { RTOKEN (PHDRS); }
<EXPRESSION,BOTH,SCRIPT>"AT" { RTOKEN(AT);}
<EXPRESSION,BOTH,SCRIPT>"PROVIDE" { RTOKEN(PROVIDE); }
<MRI>"#".*\n?\r? { ++ lineno; }
<EXPRESSION,BOTH,SCRIPT>"KEEP" { RTOKEN(KEEP); }
<MRI>"#".*\n? { ++ lineno; }
<MRI>"\n" { ++ lineno; RTOKEN(NEWLINE); }
<MRI>"\r" { ++ lineno; RTOKEN(NEWLINE); }
<MRI>"*".* { /* Mri comment line */ }
<MRI>";".* { /* Mri comment line */ }
<MRI>"END" { RTOKEN(ENDWORD); }
@ -342,7 +343,22 @@ V_IDENTIFIER [*?$_a-zA-Z][*?_a-zA-Z0-9]*
yylval.name = buystring (yytext + 2);
return LNAME;
}
<SCRIPT>{WILDCHAR}* { yylval.name = buystring(yytext); return NAME; }
<SCRIPT>{WILDCHAR}* {
/* Annoyingly, this pattern can match comments, and we have
longest match issues to consider. So if the first two
characters are a comment opening, put the input back and
try again. */
if (yytext[0] == '/' && yytext[1] == '*')
{
yyless(2);
comment ();
}
else
{
yylval.name = buystring(yytext);
return NAME;
}
}
<EXPRESSION,BOTH,SCRIPT>"\""[^\"]*"\"" {
/* No matter the state, quotes
@ -352,8 +368,7 @@ V_IDENTIFIER [*?$_a-zA-Z][*?_a-zA-Z0-9]*
return NAME;
}
<BOTH,SCRIPT,EXPRESSION>"\n" { lineno++;}
<BOTH,SCRIPT,EXPRESSION>"\r" { lineno++;}
<MRI,BOTH,SCRIPT,EXPRESSION>[ \t]
<MRI,BOTH,SCRIPT,EXPRESSION>[ \t\r]+ { }
<VERS_NODE,VERS_SCRIPT>[:,;] { return *yytext; }
@ -372,11 +387,11 @@ V_IDENTIFIER [*?$_a-zA-Z][*?_a-zA-Z0-9]*
<VERS_SCRIPT>"{" { BEGIN(VERS_NODE); return *yytext; }
<VERS_SCRIPT,VERS_NODE>"}" { BEGIN(VERS_SCRIPT); return *yytext; }
<VERS_START,VERS_NODE,VERS_SCRIPT>[\n\r] { lineno++; }
<VERS_START,VERS_NODE,VERS_SCRIPT>[\n] { lineno++; }
<VERS_START,VERS_NODE,VERS_SCRIPT>#.* { /* Eat up comments */ }
<VERS_START,VERS_NODE,VERS_SCRIPT>[ \t]+ { /* Eat up whitespace */ }
<VERS_START,VERS_NODE,VERS_SCRIPT>[ \t\r]+ { /* Eat up whitespace */ }
<<EOF>> {
include_stack_ptr--;
@ -580,7 +595,7 @@ comment ()
c = input();
while (c != '*' && c != EOF)
{
if (c == '\n' || c == '\r')
if (c == '\n')
lineno++;
c = input();
}
@ -594,7 +609,7 @@ comment ()
break; /* found the end */
}
if (c == '\n' || c == '\r')
if (c == '\n')
lineno++;
if (c == EOF)

View File

@ -111,6 +111,8 @@ int parsing_defsym = 0;
#define OPTION_WHOLE_ARCHIVE (OPTION_SPLIT_BY_FILE + 1)
#define OPTION_WRAP (OPTION_WHOLE_ARCHIVE + 1)
#define OPTION_FORCE_EXE_SUFFIX (OPTION_WRAP + 1)
#define OPTION_GC_SECTIONS (OPTION_FORCE_EXE_SUFFIX + 1)
#define OPTION_NO_GC_SECTIONS (OPTION_GC_SECTIONS + 1)
/* The long options. This structure is used for both the option
parsing and the help text. */
@ -163,6 +165,12 @@ static const struct ld_option ld_options[] =
'F', N_("SHLIB"), N_("Filter for shared object symbol table"), TWO_DASHES },
{ {NULL, no_argument, NULL, '\0'},
'g', NULL, N_("Ignored"), ONE_DASH },
{ {"gc-sections", no_argument, NULL, OPTION_GC_SECTIONS},
'\0', NULL, N_("Remove unused sections on certain targets"),
TWO_DASHES },
{ {"no-gc-sections", no_argument, NULL, OPTION_NO_GC_SECTIONS},
'\0', NULL, N_("(Don't) Remove unused sections on certain targets"),
TWO_DASHES },
{ {"gpsize", required_argument, NULL, 'G'},
'G', N_("SIZE"), N_("Small data size (if no size, same as --shared)"),
TWO_DASHES },
@ -575,6 +583,9 @@ parse_args (argc, argv)
case 'g':
/* Ignore. */
break;
case OPTION_GC_SECTIONS:
command_line.gc_sections = true;
break;
case OPTION_HELP:
help ();
xexit (0);
@ -604,6 +615,9 @@ parse_args (argc, argv)
config.magic_demand_paged = false;
config.dynamic_link = false;
break;
case OPTION_NO_GC_SECTIONS:
command_line.gc_sections = false;
break;
case OPTION_NO_KEEP_MEMORY:
link_info.keep_memory = false;
break;
@ -701,7 +715,10 @@ parse_args (argc, argv)
link_info.strip = strip_all;
break;
case OPTION_SHARED:
link_info.shared = true;
if (config.has_shared)
link_info.shared = true;
else
einfo (_("%P%F: -shared not supported\n"));
break;
case 'h': /* Used on Solaris. */
case OPTION_SONAME:

View File

@ -56,11 +56,23 @@ SECTIONS
.gnu.version_d ${RELOCATING-0} : { *(.gnu.version_d) }
.gnu.version_r ${RELOCATING-0} : { *(.gnu.version_r) }
.rela.text ${RELOCATING-0} :
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
{
*(.rela.text)
${RELOCATING+*(.rela.text.*)}
${RELOCATING+*(.rela.gnu.linkonce.t*)}
}
.rela.data ${RELOCATING-0} :
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
{
*(.rela.data)
${RELOCATING+*(.rela.data.*)}
${RELOCATING+*(.rela.gnu.linkonce.d*)}
}
.rela.rodata ${RELOCATING-0} :
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
{
*(.rela.rodata)
${RELOCATING+*(.rela.rodata.*)}
${RELOCATING+*(.rela.gnu.linkonce.r*)}
}
.rela.got ${RELOCATING-0} : { *(.rela.got) }
.rela.got1 ${RELOCATING-0} : { *(.rela.got1) }
.rela.got2 ${RELOCATING-0} : { *(.rela.got2) }
@ -78,13 +90,19 @@ SECTIONS
{
${RELOCATING+${TEXT_START_SYMBOLS}}
*(.text)
${RELOCATING+*(.text.*)}
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t*)
${RELOCATING+*(.gnu.linkonce.t*)}
} =${NOP-0}
.init ${RELOCATING-0} : { *(.init) } =${NOP-0}
.fini ${RELOCATING-0} : { *(.fini) } =${NOP-0}
.rodata ${RELOCATING-0} : { *(.rodata) *(.gnu.linkonce.r*) }
.init ${RELOCATING-0} : { KEEP (*(.init)) } =${NOP-0}
.fini ${RELOCATING-0} : { KEEP (*(.fini)) } =${NOP-0}
.rodata ${RELOCATING-0} :
{
*(.rodata)
${RELOCATING+*(.rodata.*)}
${RELOCATING+*(.gnu.linkonce.r*)}
}
.rodata1 ${RELOCATING-0} : { *(.rodata1) }
${RELOCATING+_etext = .;}
${RELOCATING+PROVIDE (etext = .);}
@ -112,7 +130,8 @@ SECTIONS
{
${RELOCATING+${DATA_START_SYMBOLS}}
*(.data)
*(.gnu.linkonce.d*)
${RELOCATING+*(.data.*)}
${RELOCATING+*(.gnu.linkonce.d*)}
${CONSTRUCTING+CONSTRUCTORS}
}
.data1 ${RELOCATING-0} : { *(.data1) }
@ -139,16 +158,16 @@ SECTIONS
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
*crtbegin.o(.ctors)
*(SORT(.ctors.*))
*(.ctors) }
KEEP (*crtbegin.o(.ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors)) }
${RELOCATING+PROVIDE (__CTOR_END__ = .);}
${RELOCATING+PROVIDE (__DTOR_LIST__ = .);}
.dtors ${RELOCATING-0} : {
*crtbegin.o(.dtors)
*(SORT(.dtors.*))
*(.dtors) }
KEEP (*crtbegin.o(.dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors)) }
${RELOCATING+PROVIDE (__DTOR_END__ = .);}
${RELOCATING+PROVIDE (_FIXUP_START_ = .);}