* ld.h (args_type): Add gc_sections.
authorRichard Henderson <rth@redhat.com>
Thu, 2 Jul 1998 02:52:31 +0000 (02:52 +0000)
committerRichard Henderson <rth@redhat.com>
Thu, 2 Jul 1998 02:52:31 +0000 (02:52 +0000)
        * 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.

ld/ChangeLog
ld/ld.h
ld/ld.texinfo
ld/ldgram.y
ld/ldlang.c
ld/ldlex.l
ld/lexsup.c
ld/scripttempl/elfppc.sc

index 886c74e..dea26e1 100644 (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.
diff --git a/ld/ld.h b/ld/ld.h
index c6ee15f..d92b148 100644 (file)
--- a/ld/ld.h
+++ b/ld/ld.h
@@ -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;
 
index 80aaabc..b23d7c9 100644 (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.
index d9a6bff..da8d214 100644 (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,51 +366,81 @@ 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); }
+                       {
+                         $$ = "?";
+                       }
        ;
 
-input_section_spec:
-               NAME
-               {
-               lang_add_wild((char *)NULL, $1);
-               }
-        |      '['
+wildcard_spec:
+               wildcard_name
                        {
-                       current_file = (char *)NULL;
+                         $$.name = $1;
+                         $$.sorted = false;
                        }
-                       file_NAME_list
-               ']'
-       |       NAME
+       |       SORT '(' wildcard_name ')'
                        {
-                       current_file = $1;
+                         $$.name = $3;
+                         $$.sorted = true;
                        }
-               '(' file_NAME_list ')'
-       |       '?'
-               /* This case is needed because the lexer returns a
-                   single question mark as '?' rather than NAME.  */
+       ;
+
+file_NAME_list:
+               wildcard_spec
                        {
-                       current_file = "?";
+                         lang_add_wild ($1.name, $1.sorted,
+                                        current_file.name,
+                                        current_file.sorted,
+                                        ldgram_had_keep);
                        }
-               '(' file_NAME_list ')'
-       |       '*'
+       |       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 = (char *)NULL;
+                         current_file = $1;
+                         /* '*' matches any file name.  */
+                         if (strcmp (current_file.name, "*") == 0)
+                           current_file.name = NULL;
                        }
                '(' file_NAME_list ')'
        ;
 
+input_section_spec:
+               input_section_spec_no_keep
+       |       KEEP '('
+                       { ldgram_had_keep = true; }
+               input_section_spec_no_keep ')'
+                       { ldgram_had_keep = false; }
+       ;
+
 statement:
                assignment end
        |       CREATE_OBJECT_SYMBOLS
@@ -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]);
index 4f692b1..feee324 100644 (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);
 }
 
index e821494..12c9f0e 100644 (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)
index 28b7e09..3a03f20 100644 (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:
index 61ef133..9bf21fc 100644 (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_ = .);}