From 71b012a810fd03d0aa05cd6d0fc874abdafdfc61 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 2 Jul 1998 02:52:31 +0000 Subject: [PATCH] * 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. --- ld/ChangeLog | 27 ++++ ld/ld.h | 9 ++ ld/ld.texinfo | 24 ++- ld/ldgram.y | 309 ++++++++++++++++++++++++++++++++------- ld/ldlang.c | 213 ++++++++++++++++++++++++++- ld/ldlex.l | 71 +++++---- ld/lexsup.c | 19 ++- ld/scripttempl/elfppc.sc | 47 ++++-- 8 files changed, 620 insertions(+), 99 deletions(-) diff --git a/ld/ChangeLog b/ld/ChangeLog index 886c74e4a1..dea26e1c31 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,30 @@ +Wed Jul 1 19:40:34 1998 Richard Henderson + + * 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 + + From Peter Jordan : + * scripttempl/i386go32.sc: Correct constructor handling for -u. + Tue Jun 23 15:17:27 1998 Ian Lance Taylor * Makefile.am (install-data-local): Make ldscripts subdirectory. diff --git a/ld/ld.h b/ld/ld.h index c6ee15fa9c..d92b148486 100644 --- 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; diff --git a/ld/ld.texinfo b/ld/ld.texinfo index 80aaabc0ba..b23d7c93b7 100644 --- a/ld/ld.texinfo +++ b/ld/ld.texinfo @@ -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. diff --git a/ld/ldgram.y b/ld/ldgram.y index d9a6bff6a6..da8d2145a1 100644 --- a/ld/ldgram.y +++ b/ld/ldgram.y @@ -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 exp opt_exp_with_type mustbe_exp opt_at phdr_type phdr_val +%type opt_exp_without_type %type fill_opt %type memspec_opt casesymlist +%type wildcard_name +%type wildcard_spec %token INT %token NAME LNAME %type length %type phdr_qualifiers %type nocrossref_list +%type phdr_opt +%type opt_nocrossrefs %right PLUSEQ MINUSEQ MULTEQ DIVEQ '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ %right '?' ':' @@ -104,8 +115,8 @@ static int error_index; %right UNARY %token END %left '(' -%token ALIGN_K BLOCK BIND QUAD LONG SHORT BYTE -%token SECTIONS PHDRS +%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 SIZEOF NEXT ADDR LOADADDR +%token 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 VERS_TAG VERS_IDENTIFIER +%token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT +%token KEEP +%type vers_defns +%type vers_tag +%type 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(®ion->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]); diff --git a/ld/ldlang.c b/ld/ldlang.c index 4f692b1433..feee32479b 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -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); } diff --git a/ld/ldlex.l b/ld/ldlex.l index e8214942f7..12c9f0e7b2 100644 --- a/ld/ldlex.l +++ b/ld/ldlex.l @@ -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; } -"$"?"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; - } +((("$"|"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; } "]" { RTOKEN(']');} @@ -232,7 +232,7 @@ V_IDENTIFIER [*?$_a-zA-Z][*?_a-zA-Z0-9]* ";" { RTOKEN(';');} "MEMORY" { RTOKEN(MEMORY);} "ORIGIN" { RTOKEN(ORIGIN);} -"VERSION" { RTOKEN(VERSION);} +"VERSION" { RTOKEN(VERSIONK);} "BLOCK" { RTOKEN(BLOCK);} "BIND" { RTOKEN(BIND);} "LENGTH" { RTOKEN(LENGTH);} @@ -272,6 +272,7 @@ V_IDENTIFIER [*?$_a-zA-Z][*?_a-zA-Z0-9]* "NOFLOAT" { RTOKEN(NOFLOAT);} "NOCROSSREFS" { RTOKEN(NOCROSSREFS);} "OVERLAY" { RTOKEN(OVERLAY); } +"SORT" { RTOKEN(SORT); } "NOLOAD" { RTOKEN(NOLOAD);} "DSECT" { RTOKEN(DSECT);} "COPY" { RTOKEN(COPY);} @@ -285,9 +286,9 @@ V_IDENTIFIER [*?$_a-zA-Z][*?_a-zA-Z0-9]* "PHDRS" { RTOKEN (PHDRS); } "AT" { RTOKEN(AT);} "PROVIDE" { RTOKEN(PROVIDE); } -"#".*\n?\r? { ++ lineno; } +"KEEP" { RTOKEN(KEEP); } +"#".*\n? { ++ lineno; } "\n" { ++ lineno; RTOKEN(NEWLINE); } -"\r" { ++ lineno; RTOKEN(NEWLINE); } "*".* { /* Mri comment line */ } ";".* { /* Mri comment line */ } "END" { RTOKEN(ENDWORD); } @@ -342,7 +343,22 @@ V_IDENTIFIER [*?$_a-zA-Z][*?_a-zA-Z0-9]* yylval.name = buystring (yytext + 2); return LNAME; } -