X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=ld%2Fldlang.c;h=abe38345fccf070701ae56193538f773534ea41d;hb=704e79f9824d86970b469df1c585a1965fe0852e;hp=1ddc63bc07f576bd475e019d1ed5a8b71621dc72;hpb=22f94ab06cc7802c14175f2f4dcfa73aa983aca2;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/ldlang.c b/ld/ldlang.c index 1ddc63bc07..abe38345fc 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -1,5 +1,6 @@ /* Linker command language support. - Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 98, 1999 + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002 Free Software Foundation, Inc. This file is part of GLD, the Gnu Linker. @@ -22,115 +23,108 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "bfd.h" #include "sysdep.h" #include "libiberty.h" +#include "safe-ctype.h" #include "obstack.h" #include "bfdlink.h" #include "ld.h" #include "ldmain.h" -#include "ldgram.h" #include "ldexp.h" #include "ldlang.h" -#include "ldemul.h" +#include "ldgram.h" #include "ldlex.h" #include "ldmisc.h" #include "ldctor.h" #include "ldfile.h" +#include "ldemul.h" #include "fnmatch.h" - -#include +#include "demangle.h" /* FORWARDS */ -static lang_statement_union_type *new_statement PARAMS ((enum statement_enum, - size_t, - lang_statement_list_type*)); - +static lang_statement_union_type *new_statement + PARAMS ((enum statement_enum, size_t, lang_statement_list_type *)); /* LOCALS */ static struct obstack stat_obstack; #define obstack_chunk_alloc xmalloc #define obstack_chunk_free free -static CONST char *startup_file; +static const char *startup_file; static lang_statement_list_type input_file_chain; static boolean placed_commons = false; static lang_output_section_statement_type *default_common_section; static boolean map_option_f; static bfd_vma print_dot; static lang_input_statement_type *first_file; -static lang_statement_list_type lang_output_section_statement; -static CONST char *current_target; -static CONST char *output_target; +static const char *current_target; +static const char *output_target; static lang_statement_list_type statement_list; static struct lang_phdr *lang_phdr_list; static void lang_for_each_statement_worker - PARAMS ((void (*func) (lang_statement_union_type *), - lang_statement_union_type *s)); + PARAMS ((void (*) (lang_statement_union_type *), + lang_statement_union_type *)); static lang_input_statement_type *new_afile - PARAMS ((const char *name, lang_input_file_enum_type file_type, - const char *target, boolean add_to_list)); -static void init_os PARAMS ((lang_output_section_statement_type *s)); + PARAMS ((const char *, lang_input_file_enum_type, const char *, boolean)); +static lang_memory_region_type *lang_memory_default PARAMS ((asection *)); +static void lang_map_flags PARAMS ((flagword)); +static void init_os PARAMS ((lang_output_section_statement_type *)); static void exp_init_os PARAMS ((etree_type *)); static void section_already_linked PARAMS ((bfd *, asection *, PTR)); +static struct bfd_hash_entry *already_linked_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static void already_linked_table_init PARAMS ((void)); +static void already_linked_table_free PARAMS ((void)); static boolean wildcardp PARAMS ((const char *)); static lang_statement_union_type *wild_sort - PARAMS ((lang_wild_statement_type *, lang_input_statement_type *, - asection *)); -static void wild_section PARAMS ((lang_wild_statement_type *ptr, - const char *section, - lang_input_statement_type *file, - lang_output_section_statement_type *output)); -static lang_input_statement_type *lookup_name PARAMS ((const char *name)); -static void load_symbols PARAMS ((lang_input_statement_type *entry, - lang_statement_list_type *)); -static void wild_file PARAMS ((lang_wild_statement_type *, const char *, - lang_input_statement_type *, - lang_output_section_statement_type *)); -static void wild PARAMS ((lang_wild_statement_type *s, - const char *section, const char *file, - const char *target, - lang_output_section_statement_type *output)); -static bfd *open_output PARAMS ((const char *name)); -static void ldlang_open_output PARAMS ((lang_statement_union_type *statement)); -static void open_input_bfds - PARAMS ((lang_statement_union_type *statement, boolean)); + PARAMS ((lang_wild_statement_type *, struct wildcard_list *, + lang_input_statement_type *, asection *)); +static void output_section_callback + PARAMS ((lang_wild_statement_type *, struct wildcard_list *, asection *, + lang_input_statement_type *, PTR)); +static lang_input_statement_type *lookup_name PARAMS ((const char *)); +static boolean load_symbols + PARAMS ((lang_input_statement_type *, lang_statement_list_type *)); +static void wild + PARAMS ((lang_wild_statement_type *, + const char *, lang_output_section_statement_type *)); +static bfd *open_output PARAMS ((const char *)); +static void ldlang_open_output PARAMS ((lang_statement_union_type *)); +static void open_input_bfds PARAMS ((lang_statement_union_type *, boolean)); static void lang_reasonable_defaults PARAMS ((void)); +static void insert_undefined PARAMS ((const char *)); static void lang_place_undefineds PARAMS ((void)); static void map_input_to_output_sections - PARAMS ((lang_statement_union_type *s, - const char *target, - lang_output_section_statement_type *output_section_statement)); + PARAMS ((lang_statement_union_type *, const char *, + lang_output_section_statement_type *)); static void print_output_section_statement - PARAMS ((lang_output_section_statement_type *output_section_statement)); + PARAMS ((lang_output_section_statement_type *)); static void print_assignment - PARAMS ((lang_assignment_statement_type *assignment, - lang_output_section_statement_type *output_section)); -static void print_input_statement PARAMS ((lang_input_statement_type *statm)); + PARAMS ((lang_assignment_statement_type *, + lang_output_section_statement_type *)); +static void print_input_statement PARAMS ((lang_input_statement_type *)); static boolean print_one_symbol PARAMS ((struct bfd_link_hash_entry *, PTR)); -static void print_input_section PARAMS ((lang_input_section_type *in)); -static void print_fill_statement PARAMS ((lang_fill_statement_type *fill)); -static void print_data_statement PARAMS ((lang_data_statement_type *data)); +static void print_input_section PARAMS ((lang_input_section_type *)); +static void print_fill_statement PARAMS ((lang_fill_statement_type *)); +static void print_data_statement PARAMS ((lang_data_statement_type *)); static void print_address_statement PARAMS ((lang_address_statement_type *)); -static void print_reloc_statement PARAMS ((lang_reloc_statement_type *reloc)); -static void print_padding_statement PARAMS ((lang_padding_statement_type *s)); +static void print_reloc_statement PARAMS ((lang_reloc_statement_type *)); +static void print_padding_statement PARAMS ((lang_padding_statement_type *)); static void print_wild_statement - PARAMS ((lang_wild_statement_type *w, - lang_output_section_statement_type *os)); + PARAMS ((lang_wild_statement_type *, lang_output_section_statement_type *)); static void print_group PARAMS ((lang_group_statement_type *, lang_output_section_statement_type *)); -static void print_statement PARAMS ((lang_statement_union_type *s, - lang_output_section_statement_type *os)); -static void print_statement_list PARAMS ((lang_statement_union_type *s, - lang_output_section_statement_type *os)); +static void print_statement + PARAMS ((lang_statement_union_type *, lang_output_section_statement_type *)); +static void print_statement_list + PARAMS ((lang_statement_union_type *, lang_output_section_statement_type *)); static void print_statements PARAMS ((void)); -static bfd_vma insert_pad PARAMS ((lang_statement_union_type **this_ptr, - fill_type fill, unsigned int power, - asection *output_section_statement, - bfd_vma dot)); +static void insert_pad + PARAMS ((lang_statement_union_type **, fill_type *, + unsigned int, asection *, bfd_vma)); static bfd_vma size_input_section - PARAMS ((lang_statement_union_type **this_ptr, - lang_output_section_statement_type *output_section_statement, - fill_type fill, bfd_vma dot, boolean relax)); + PARAMS ((lang_statement_union_type **, lang_output_section_statement_type *, + fill_type *, bfd_vma)); static void lang_finish PARAMS ((void)); static void ignore_bfd_errors PARAMS ((const char *, ...)); static void lang_check PARAMS ((void)); @@ -139,48 +133,85 @@ static boolean lang_one_common PARAMS ((struct bfd_link_hash_entry *, PTR)); static void lang_place_orphans PARAMS ((void)); static int topower PARAMS ((int)); static void lang_set_startof PARAMS ((void)); -static void reset_memory_regions PARAMS ((void)); +static void gc_section_callback + PARAMS ((lang_wild_statement_type *, struct wildcard_list *, asection *, + lang_input_statement_type *, PTR)); +static void lang_get_regions PARAMS ((struct memory_region_struct **, + struct memory_region_struct **, + const char *, const char *, int)); 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_wild PARAMS ((lang_wild_statement_type *)); static void lang_gc_sections_1 PARAMS ((lang_statement_union_type *)); static void lang_gc_sections PARAMS ((void)); +static int lang_vers_match_lang_c + PARAMS ((struct bfd_elf_version_expr *, const char *)); +static int lang_vers_match_lang_cplusplus + PARAMS ((struct bfd_elf_version_expr *, const char *)); +static int lang_vers_match_lang_java + PARAMS ((struct bfd_elf_version_expr *, const char *)); static void lang_do_version_exports_section PARAMS ((void)); static void lang_check_section_addresses PARAMS ((void)); - +static void os_region_check + PARAMS ((lang_output_section_statement_type *, + struct memory_region_struct *, etree_type *, bfd_vma)); +static bfd_vma lang_size_sections_1 + PARAMS ((lang_statement_union_type *, lang_output_section_statement_type *, + lang_statement_union_type **, fill_type *, bfd_vma, boolean *)); + +typedef void (*callback_t) PARAMS ((lang_wild_statement_type *, + struct wildcard_list *, + asection *, + lang_input_statement_type *, + PTR)); +static void walk_wild + PARAMS ((lang_wild_statement_type *, callback_t, PTR)); +static void walk_wild_section + PARAMS ((lang_wild_statement_type *, lang_input_statement_type *, + callback_t, PTR)); +static void walk_wild_file + PARAMS ((lang_wild_statement_type *, lang_input_statement_type *, + callback_t, PTR)); + +static int get_target PARAMS ((const bfd_target *, PTR)); +static void stricpy PARAMS ((char *, char *)); +static void strcut PARAMS ((char *, char *)); +static int name_compare PARAMS ((char *, char *)); +static int closest_target_match PARAMS ((const bfd_target *, PTR)); +static char * get_first_input_target PARAMS ((void)); /* EXPORTS */ lang_output_section_statement_type *abs_output_section; +lang_statement_list_type lang_output_section_statement; lang_statement_list_type *stat_ptr = &statement_list; -lang_statement_list_type file_chain = { 0 }; +lang_statement_list_type file_chain = { NULL, NULL }; const char *entry_symbol = NULL; +const char *entry_section = ".text"; boolean entry_from_cmdline; boolean lang_has_input_file = false; boolean had_output_filename = false; boolean lang_float_flag = false; boolean delete_output_file_on_failure = false; struct lang_nocrossrefs *nocrossref_list; +struct unique_sections *unique_section_list; etree_type *base; /* Relocation base - or null */ - -#if defined(__STDC__) || defined(ALMOST_STDC) +#if defined (__STDC__) || defined (ALMOST_STDC) #define cat(a,b) a##b #else #define cat(a,b) a/**/b #endif -#define new_stat(x,y) (cat(x,_type)*) new_statement(cat(x,_enum), sizeof(cat(x,_type)),y) +/* Don't beautify the line below with "innocent" whitespace, it breaks + the K&R C preprocessor! */ +#define new_stat(x, y) \ + (cat (x,_type)*) new_statement (cat (x,_enum), sizeof (cat (x,_type)), y) -#define outside_section_address(q) ( (q)->output_offset + (q)->output_section->vma) +#define outside_section_address(q) \ + ((q)->output_offset + (q)->output_section->vma) -#define outside_symbol_address(q) ((q)->value + outside_section_address(q->section)) +#define outside_symbol_address(q) \ + ((q)->value + outside_section_address (q->section)) #define SECTION_NAME_MAP_LENGTH (16) @@ -191,17 +222,180 @@ stat_alloc (size) return obstack_alloc (&stat_obstack, size); } -/*---------------------------------------------------------------------- - lang_for_each_statement walks the parse tree and calls the provided - function for each node -*/ +boolean +unique_section_p (secnam) + const char *secnam; +{ + struct unique_sections *unam; + + for (unam = unique_section_list; unam; unam = unam->next) + if (wildcardp (unam->name) + ? fnmatch (unam->name, secnam, 0) == 0 + : strcmp (unam->name, secnam) == 0) + { + return true; + } + + return false; +} + +/* Generic traversal routines for finding matching sections. */ + +static void +walk_wild_section (ptr, file, callback, data) + lang_wild_statement_type *ptr; + lang_input_statement_type *file; + callback_t callback; + PTR data; +{ + asection *s; + + if (file->just_syms_flag) + return; + + for (s = file->the_bfd->sections; s != NULL; s = s->next) + { + struct wildcard_list *sec; + + sec = ptr->section_list; + if (sec == NULL) + (*callback) (ptr, sec, s, file, data); + + while (sec != NULL) + { + boolean skip = false; + struct name_list *list_tmp; + + /* Don't process sections from files which were + excluded. */ + for (list_tmp = sec->spec.exclude_name_list; + list_tmp; + list_tmp = list_tmp->next) + { + if (wildcardp (list_tmp->name)) + skip = fnmatch (list_tmp->name, file->filename, 0) == 0; + else + skip = strcmp (list_tmp->name, file->filename) == 0; + + /* If this file is part of an archive, and the archive is + excluded, exclude this file. */ + if (! skip && file->the_bfd != NULL + && file->the_bfd->my_archive != NULL + && file->the_bfd->my_archive->filename != NULL) + { + if (wildcardp (list_tmp->name)) + skip = fnmatch (list_tmp->name, + file->the_bfd->my_archive->filename, + 0) == 0; + else + skip = strcmp (list_tmp->name, + file->the_bfd->my_archive->filename) == 0; + } + + if (skip) + break; + } + + if (!skip && sec->spec.name != NULL) + { + const char *sname = bfd_get_section_name (file->the_bfd, s); + + if (wildcardp (sec->spec.name)) + skip = fnmatch (sec->spec.name, sname, 0) != 0; + else + skip = strcmp (sec->spec.name, sname) != 0; + } + + if (!skip) + (*callback) (ptr, sec, s, file, data); + + sec = sec->next; + } + } +} + +/* Handle a wild statement for a single file F. */ + +static void +walk_wild_file (s, f, callback, data) + lang_wild_statement_type *s; + lang_input_statement_type *f; + callback_t callback; + PTR data; +{ + if (f->the_bfd == NULL + || ! bfd_check_format (f->the_bfd, bfd_archive)) + walk_wild_section (s, f, callback, data); + 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) + { + walk_wild_section (s, + (lang_input_statement_type *) member->usrdata, + callback, data); + } + + member = bfd_openr_next_archived_file (f->the_bfd, member); + } + } +} + +static void +walk_wild (s, callback, data) + lang_wild_statement_type *s; + callback_t callback; + PTR data; +{ + const char *file_spec = s->filename; + + if (file_spec == NULL) + { + /* Perform the iteration over all files in the list. */ + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + walk_wild_file (s, f, callback, data); + } + } + else if (wildcardp (file_spec)) + { + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + if (fnmatch (file_spec, f->filename, FNM_FILE_NAME) == 0) + walk_wild_file (s, f, callback, data); + } + } + else + { + lang_input_statement_type *f; + + /* Perform the iteration over a single file. */ + f = lookup_name (file_spec); + if (f) + walk_wild_file (s, f, callback, data); + } +} + +/* lang_for_each_statement walks the parse tree and calls the provided + function for each node. */ static void lang_for_each_statement_worker (func, s) void (*func) PARAMS ((lang_statement_union_type *)); lang_statement_union_type *s; { - for (; s != (lang_statement_union_type *) NULL; s = s->next) + for (; s != (lang_statement_union_type *) NULL; s = s->header.next) { func (s); @@ -247,11 +441,11 @@ void lang_for_each_statement (func) void (*func) PARAMS ((lang_statement_union_type *)); { - lang_for_each_statement_worker (func, - statement_list.head); + lang_for_each_statement_worker (func, statement_list.head); } /*----------------------------------------------------------------------*/ + void lang_list_init (list) lang_statement_list_type *list; @@ -260,18 +454,13 @@ lang_list_init (list) list->tail = &list->head; } -/*---------------------------------------------------------------------- - - build a new statement node for the parse tree +/* Build a new statement node for the parse tree. */ - */ - -static -lang_statement_union_type * +static lang_statement_union_type * new_statement (type, size, list) enum statement_enum type; size_t size; - lang_statement_list_type * list; + lang_statement_list_type *list; { lang_statement_union_type *new = (lang_statement_union_type *) stat_alloc (size); @@ -282,22 +471,20 @@ new_statement (type, size, list) return new; } -/* - Build a new input file node for the language. There are several ways - in which we treat an input file, eg, we only look at symbols, or - prefix it with a -l etc. +/* Build a new input file node for the language. There are several + ways in which we treat an input file, eg, we only look at symbols, + or prefix it with a -l etc. - We can be supplied with requests for input files more than once; - they may, for example be split over serveral lines like foo.o(.text) - foo.o(.data) etc, so when asked for a file we check that we havn't - got it already so we don't duplicate the bfd. + We can be supplied with requests for input files more than once; + they may, for example be split over serveral lines like foo.o(.text) + foo.o(.data) etc, so when asked for a file we check that we haven't + got it already so we don't duplicate the bfd. */ - */ static lang_input_statement_type * new_afile (name, file_type, target, add_to_list) - CONST char *name; + const char *name; lang_input_file_enum_type file_type; - CONST char *target; + const char *target; boolean add_to_list; { lang_input_statement_type *p; @@ -382,15 +569,16 @@ new_afile (name, file_type, target, add_to_list) lang_input_statement_type * lang_add_input_file (name, file_type, target) - CONST char *name; + const char *name; lang_input_file_enum_type file_type; - CONST char *target; + const char *target; { lang_has_input_file = true; return new_afile (name, file_type, target, true); } -/* Build enough state so that the parser can build its tree */ +/* Build enough state so that the parser can build its tree. */ + void lang_init () { @@ -406,32 +594,36 @@ lang_init () first_file = lang_add_input_file ((char *) NULL, lang_input_file_is_marker_enum, (char *) NULL); - abs_output_section = lang_output_section_statement_lookup (BFD_ABS_SECTION_NAME); + abs_output_section = + lang_output_section_statement_lookup (BFD_ABS_SECTION_NAME); abs_output_section->bfd_section = bfd_abs_section_ptr; } /*---------------------------------------------------------------------- - A region is an area of memory declared with the - MEMORY { name:org=exp, len=exp ... } - syntax. + A region is an area of memory declared with the + MEMORY { name:org=exp, len=exp ... } + syntax. - We maintain a list of all the regions here + We maintain a list of all the regions here. - If no regions are specified in the script, then the default is used - which is created when looked up to be the entire data space -*/ + If no regions are specified in the script, then the default is used + which is created when looked up to be the entire data space. */ static lang_memory_region_type *lang_memory_region_list; static lang_memory_region_type **lang_memory_region_list_tail = &lang_memory_region_list; lang_memory_region_type * lang_memory_region_lookup (name) - CONST char *CONST name; + const char *const name; { lang_memory_region_type *p; + /* NAME is NULL for LMA memspecs if no region was specified. */ + if (name == NULL) + return NULL; + for (p = lang_memory_region_list; p != (lang_memory_region_type *) NULL; p = p->next) @@ -462,7 +654,7 @@ lang_memory_region_lookup (name) lang_memory_region_type *new = (lang_memory_region_type *) stat_alloc (sizeof (lang_memory_region_type)); - new->name = buystring (name); + new->name = xstrdup (name); new->next = (lang_memory_region_type *) NULL; *lang_memory_region_list_tail = new; @@ -470,7 +662,7 @@ lang_memory_region_lookup (name) new->origin = 0; new->flags = 0; new->not_flags = 0; - new->length = ~(bfd_size_type)0; + new->length = ~(bfd_size_type) 0; new->current = 0; new->had_full_message = false; @@ -478,8 +670,7 @@ lang_memory_region_lookup (name) } } - -lang_memory_region_type * +static lang_memory_region_type * lang_memory_default (section) asection *section; { @@ -506,7 +697,7 @@ lang_memory_default (section) lang_output_section_statement_type * lang_output_section_find (name) - CONST char *CONST name; + const char *const name; { lang_statement_union_type *u; lang_output_section_statement_type *lookup; @@ -526,7 +717,7 @@ lang_output_section_find (name) lang_output_section_statement_type * lang_output_section_statement_lookup (name) - CONST char *CONST name; + const char *const name; { lang_output_section_statement_type *lookup; @@ -537,7 +728,8 @@ lang_output_section_statement_lookup (name) lookup = (lang_output_section_statement_type *) new_stat (lang_output_section_statement, stat_ptr); lookup->region = (lang_memory_region_type *) NULL; - lookup->fill = 0; + lookup->lma_region = (lang_memory_region_type *) NULL; + lookup->fill = (fill_type *) 0; lookup->block_value = 1; lookup->name = name; @@ -548,11 +740,12 @@ lang_output_section_statement_lookup (name) lookup->addr_tree = (etree_type *) NULL; lang_list_init (&lookup->children); - lookup->memspec = (CONST char *) NULL; + lookup->memspec = (const char *) NULL; lookup->flags = 0; lookup->subsection_alignment = -1; lookup->section_alignment = -1; lookup->load_base = (union etree_union *) NULL; + lookup->update_dot_tree = NULL; lookup->phdrs = NULL; lang_statement_append (&lang_output_section_statement, @@ -648,7 +841,7 @@ init_os (s) return; if (strcmp (s->name, DISCARD_SECTION_NAME) == 0) - einfo (_("%P%F: Illegal use of `%s' section"), DISCARD_SECTION_NAME); + einfo (_("%P%F: Illegal use of `%s' section\n"), DISCARD_SECTION_NAME); new = ((section_userdata_type *) stat_alloc (sizeof (section_userdata_type))); @@ -663,8 +856,8 @@ init_os (s) } s->bfd_section->output_section = s->bfd_section; - /* We initialize an output sections output offset to minus its own */ - /* vma to allow us to output a section through itself */ + /* We initialize an output sections output offset to minus its own + vma to allow us to output a section through itself. */ s->bfd_section->output_offset = 0; get_userdata (s->bfd_section) = (PTR) new; @@ -722,15 +915,37 @@ exp_init_os (exp) break; } } - + /* Sections marked with the SEC_LINK_ONCE flag should only be linked - once into the output. This routine checks each sections, and - arranges to discard it if a section of the same name has already - been linked. This code assumes that all relevant sections have the - SEC_LINK_ONCE flag set; that is, it does not depend solely upon the - section name. This is called via bfd_map_over_sections. */ + once into the output. This routine checks each section, and + arrange to discard it if a section of the same name has already + been linked. If the section has COMDAT information, then it uses + that to decide whether the section should be included. This code + assumes that all relevant sections have the SEC_LINK_ONCE flag set; + that is, it does not depend solely upon the section name. + section_already_linked is called via bfd_map_over_sections. */ + +/* This is the shape of the elements inside the already_linked hash + table. It maps a name onto a list of already_linked elements with + the same name. It's possible to get more than one element in a + list if the COMDAT sections have different names. */ + +struct already_linked_hash_entry +{ + struct bfd_hash_entry root; + struct already_linked *entry; +}; + +struct already_linked +{ + struct already_linked *next; + asection *sec; +}; + +/* The hash table. */ + +static struct bfd_hash_table already_linked_table; -/*ARGSUSED*/ static void section_already_linked (abfd, sec, data) bfd *abfd; @@ -738,22 +953,16 @@ section_already_linked (abfd, sec, data) PTR data; { lang_input_statement_type *entry = (lang_input_statement_type *) data; - struct sec_link_once - { - struct sec_link_once *next; - asection *sec; - }; - static struct sec_link_once *sec_link_once_list; flagword flags; const char *name; - struct sec_link_once *l; + struct already_linked *l; + struct already_linked_hash_entry *already_linked_list; /* If we are only reading symbols from this object, then we want to discard all sections. */ if (entry->just_syms_flag) { - sec->output_section = bfd_abs_section_ptr; - sec->output_offset = sec->vma; + bfd_link_just_syms (sec, &link_info); return; } @@ -762,11 +971,34 @@ section_already_linked (abfd, sec, data) if ((flags & SEC_LINK_ONCE) == 0) return; + /* FIXME: When doing a relocatable link, we may have trouble + copying relocations in other sections that refer to local symbols + in the section being discarded. Those relocations will have to + be converted somehow; as of this writing I'm not sure that any of + the backends handle that correctly. + + It is tempting to instead not discard link once sections when + doing a relocatable link (technically, they should be discarded + whenever we are building constructors). However, that fails, + because the linker winds up combining all the link once sections + into a single large link once section, which defeats the purpose + of having link once sections in the first place. + + Also, not merging link once sections in a relocatable link + causes trouble for MIPS ELF, which relies on link once semantics + to handle the .reginfo section correctly. */ + name = bfd_get_section_name (abfd, sec); - for (l = sec_link_once_list; l != NULL; l = l->next) + already_linked_list = + ((struct already_linked_hash_entry *) + bfd_hash_lookup (&already_linked_table, name, true, false)); + + for (l = already_linked_list->entry; l != NULL; l = l->next) { - if (strcmp (name, bfd_get_section_name (l->sec->owner, l->sec)) == 0) + if (sec->comdat == NULL + || l->sec->comdat == NULL + || strcmp (sec->comdat->name, l->sec->comdat->name) == 0) { /* The section has already been linked. See if we should issue a warning. */ @@ -779,8 +1011,12 @@ section_already_linked (abfd, sec, data) break; case SEC_LINK_DUPLICATES_ONE_ONLY: - einfo (_("%P: %B: warning: ignoring duplicate section `%s'\n"), - abfd, name); + if (sec->comdat == NULL) + einfo (_("%P: %B: warning: ignoring duplicate section `%s'\n"), + abfd, name); + else + einfo (_("%P: %B: warning: ignoring duplicate `%s' section symbol `%s'\n"), + abfd, name, sec->comdat->name); break; case SEC_LINK_DUPLICATES_SAME_CONTENTS: @@ -798,20 +1034,59 @@ section_already_linked (abfd, sec, data) break; } - /* Set the output_section field so that wild_doit does not - create a lang_input_section structure for this section. */ + /* Set the output_section field so that lang_add_section + does not create a lang_input_section structure for this + section. */ sec->output_section = bfd_abs_section_ptr; + if (flags & SEC_GROUP) + bfd_discard_group (abfd, sec); + return; } } - /* This is the first section with this name. Record it. */ + /* This is the first section with this name. Record it. Allocate + the memory from the same obstack as the hash table is kept in. */ + + l = ((struct already_linked *) + bfd_hash_allocate (&already_linked_table, sizeof *l)); - l = (struct sec_link_once *) xmalloc (sizeof *l); l->sec = sec; - l->next = sec_link_once_list; - sec_link_once_list = l; + l->next = already_linked_list->entry; + already_linked_list->entry = l; +} + +/* Support routines for the hash table used by section_already_linked, + initialize the table, fill in an entry and remove the table. */ + +static struct bfd_hash_entry * +already_linked_newfunc (entry, table, string) + struct bfd_hash_entry *entry ATTRIBUTE_UNUSED; + struct bfd_hash_table *table; + const char *string ATTRIBUTE_UNUSED; +{ + struct already_linked_hash_entry *ret = + bfd_hash_allocate (table, sizeof (struct already_linked_hash_entry)); + + ret->entry = NULL; + + return (struct bfd_hash_entry *) ret; +} + +static void +already_linked_table_init () +{ + if (! bfd_hash_table_init_n (&already_linked_table, + already_linked_newfunc, + 42)) + einfo (_("%P%F: Failed to create hash table\n")); +} + +static void +already_linked_table_free () +{ + bfd_hash_table_free (&already_linked_table); } /* The wild routines. @@ -823,7 +1098,7 @@ section_already_linked (abfd, sec, data) /* Return true if the PATTERN argument is a wildcard pattern. Although backslashes are treated specially if a pattern contains wildcards, we do not consider the mere presence of a backslash to - be enough to cause the the pattern to be treated as a wildcard. + be enough to cause the pattern to be treated as a wildcard. That lets us handle DOS filenames more naturally. */ static boolean @@ -845,7 +1120,7 @@ wildcardp (pattern) input file which holds SECTION. */ void -wild_doit (ptr, section, output, file) +lang_add_section (ptr, section, output, file) lang_statement_list_type *ptr; asection *section; lang_output_section_statement_type *output; @@ -892,14 +1167,12 @@ wild_doit (ptr, section, output, file) flagword flags; if (output->bfd_section == NULL) - { - init_os (output); - first = true; - } - else - first = false; + init_os (output); - /* Add a section reference to the list */ + first = ! output->bfd_section->linker_has_input; + output->bfd_section->linker_has_input = 1; + + /* Add a section reference to the list. */ new = new_stat (lang_input_section, ptr); new->section = section; @@ -932,8 +1205,26 @@ wild_doit (ptr, section, output, file) if (! first && (section->output_section->flags & SEC_READONLY) == 0) flags &= ~ SEC_READONLY; + /* Keep SEC_MERGE and SEC_STRINGS only if they are the same. */ + if (! first + && ((section->output_section->flags & (SEC_MERGE | SEC_STRINGS)) + != (flags & (SEC_MERGE | SEC_STRINGS)) + || ((flags & SEC_MERGE) + && section->output_section->entsize != section->entsize))) + { + section->output_section->flags &= ~ (SEC_MERGE | SEC_STRINGS); + flags &= ~ (SEC_MERGE | SEC_STRINGS); + } + + /* For now make .tbss normal section. */ + if (flags & SEC_THREAD_LOCAL) + flags |= SEC_LOAD; + section->output_section->flags |= flags; + if (flags & SEC_MERGE) + section->output_section->entsize = section->entsize; + /* If SEC_READONLY is not set in the input section, then clear it from the output section. */ if ((section->flags & SEC_READONLY) == 0) @@ -955,12 +1246,23 @@ wild_doit (ptr, section, output, file) break; } + /* Copy over SEC_SMALL_DATA. */ + if (section->flags & SEC_SMALL_DATA) + section->output_section->flags |= SEC_SMALL_DATA; + if (section->alignment_power > output->bfd_section->alignment_power) output->bfd_section->alignment_power = section->alignment_power; /* If supplied an aligment, then force it. */ if (output->section_alignment != -1) output->bfd_section->alignment_power = output->section_alignment; + + if (section->flags & SEC_BLOCK) + { + section->output_section->flags |= SEC_BLOCK; + /* FIXME: This value should really be obtained from the bfd... */ + output->block_value = 128; + } } } @@ -970,19 +1272,20 @@ wild_doit (ptr, section, output, file) new section should just go at the end of the current list. */ static lang_statement_union_type * -wild_sort (wild, file, section) +wild_sort (wild, sec, file, section) lang_wild_statement_type *wild; + struct wildcard_list *sec; lang_input_statement_type *file; asection *section; { const char *section_name; lang_statement_union_type *l; - if (! wild->filenames_sorted && ! wild->sections_sorted) + if (!wild->filenames_sorted && (sec == NULL || !sec->spec.sorted)) return NULL; section_name = bfd_get_section_name (file->the_bfd, section); - for (l = wild->children.head; l != NULL; l = l->next) + for (l = wild->children.head; l != NULL; l = l->header.next) { lang_input_section_type *ls; @@ -1052,7 +1355,7 @@ wild_sort (wild, file, section) /* Here either the files are not sorted by name, or we are looking at the sections for this file. */ - if (wild->sections_sorted) + if (sec != NULL && sec->spec.sorted) { if (strcmp (section_name, bfd_get_section_name (ls->ifile->the_bfd, @@ -1069,89 +1372,58 @@ wild_sort (wild, file, section) NULL, in which case it is a wild card. */ static void -wild_section (ptr, section, file, output) +output_section_callback (ptr, sec, section, file, output) lang_wild_statement_type *ptr; - const char *section; + struct wildcard_list *sec; + asection *section; lang_input_statement_type *file; - lang_output_section_statement_type *output; + PTR output; { - 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; - - /* Attach all sections named SECTION. If SECTION is NULL, - then attach all sections. - - Previously, if SECTION was NULL, this code did not call - wild_doit if the SEC_IS_COMMON flag was set for the - section. I did not understand that, and I took it out. - --ian@cygnus.com. */ - - 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; - } + lang_statement_union_type *before; - if (match) - { - lang_statement_union_type *before; + /* Exclude sections that match UNIQUE_SECTION_LIST. */ + if (unique_section_p (bfd_get_section_name (file->the_bfd, section))) + return; - /* If the wild pattern was marked KEEP, the member sections - should be as well. */ - if (ptr->keep_sections) - s->flags |= SEC_KEEP; + /* If the wild pattern was marked KEEP, the member sections + should be as well. */ + if (ptr->keep_sections) + section->flags |= SEC_KEEP; - before = wild_sort (ptr, file, s); + before = wild_sort (ptr, sec, file, section); - /* Here BEFORE points to the lang_input_section which - should follow the one we are about to add. If BEFORE - is NULL, then the section should just go at the end - of the current list. */ + /* Here BEFORE points to the lang_input_section which + should follow the one we are about to add. If BEFORE + is NULL, then the section should just go at the end + of the current list. */ - if (before == NULL) - wild_doit (&ptr->children, s, output, file); - else - { - lang_statement_list_type list; - lang_statement_union_type **pp; + if (before == NULL) + lang_add_section (&ptr->children, section, + (lang_output_section_statement_type *) output, + file); + else + { + lang_statement_list_type list; + lang_statement_union_type **pp; - lang_list_init (&list); - wild_doit (&list, s, output, file); + lang_list_init (&list); + lang_add_section (&list, section, + (lang_output_section_statement_type *) output, + file); - /* If we are discarding the section, LIST.HEAD will - be NULL. */ - if (list.head != NULL) - { - ASSERT (list.head->next == NULL); + /* If we are discarding the section, LIST.HEAD will + be NULL. */ + if (list.head != NULL) + { + ASSERT (list.head->header.next == NULL); - for (pp = &ptr->children.head; - *pp != before; - pp = &(*pp)->next) - ASSERT (*pp != NULL); + for (pp = &ptr->children.head; + *pp != before; + pp = &(*pp)->header.next) + ASSERT (*pp != NULL); - list.head->next = *pp; - *pp = list.head; - } - } - } + list.head->header.next = *pp; + *pp = list.head; } } } @@ -1190,14 +1462,15 @@ lookup_name (name) || search->filename == (const char *) NULL) return search; - load_symbols (search, (lang_statement_list_type *) NULL); + if (! load_symbols (search, (lang_statement_list_type *) NULL)) + return NULL; return search; } /* Get the symbols for an input file. */ -static void +static boolean load_symbols (entry, place) lang_input_statement_type *entry; lang_statement_list_type *place; @@ -1205,7 +1478,7 @@ load_symbols (entry, place) char **matching; if (entry->loaded) - return; + return true; ldfile_open_file (entry); @@ -1214,8 +1487,14 @@ load_symbols (entry, place) { bfd_error_type err; lang_statement_list_type *hold; + boolean bad_load = true; err = bfd_get_error (); + + /* See if the emulation has some special knowledge. */ + if (ldemul_unrecognized_file (entry)) + return true; + if (err == bfd_error_file_ambiguously_recognized) { char **p; @@ -1228,18 +1507,14 @@ load_symbols (entry, place) } else if (err != bfd_error_file_not_recognized || place == NULL) - einfo (_("%F%B: file not recognized: %E\n"), entry->the_bfd); + einfo (_("%F%B: file not recognized: %E\n"), entry->the_bfd); + else + bad_load = false; bfd_close (entry->the_bfd); entry->the_bfd = NULL; - /* See if the emulation has some special knowledge. */ - - if (ldemul_unrecognized_file (entry)) - return; - /* Try to interpret the file as a linker script. */ - ldfile_open_command_file (entry->filename); hold = stat_ptr; @@ -1252,11 +1527,11 @@ load_symbols (entry, place) stat_ptr = hold; - return; + return ! bad_load; } if (ldemul_recognized_file (entry)) - return; + return true; /* We don't call ldlang_add_file for an archive. Instead, the add_symbols entry point will call ldlang_add_file, via the @@ -1276,122 +1551,235 @@ load_symbols (entry, place) case bfd_archive: if (entry->whole_archive) { - bfd *member = bfd_openr_next_archived_file (entry->the_bfd, - (bfd *) NULL); - while (member != NULL) + bfd *member = NULL; + boolean loaded = true; + + for (;;) { + member = bfd_openr_next_archived_file (entry->the_bfd, member); + + if (member == NULL) + break; + if (! bfd_check_format (member, bfd_object)) - einfo (_("%F%B: object %B in archive is not object\n"), - entry->the_bfd, member); + { + einfo (_("%F%B: member %B in archive is not an object\n"), + entry->the_bfd, member); + loaded = false; + } + if (! ((*link_info.callbacks->add_archive_element) (&link_info, member, "--whole-archive"))) abort (); + if (! bfd_link_add_symbols (member, &link_info)) - einfo (_("%F%B: could not read symbols: %E\n"), member); - member = bfd_openr_next_archived_file (entry->the_bfd, - member); + { + einfo (_("%F%B: could not read symbols: %E\n"), member); + loaded = false; + } } - entry->loaded = true; - - return; + entry->loaded = loaded; + return loaded; } + break; } - if (! bfd_link_add_symbols (entry->the_bfd, &link_info)) + if (bfd_link_add_symbols (entry->the_bfd, &link_info)) + entry->loaded = true; + else einfo (_("%F%B: could not read symbols: %E\n"), entry->the_bfd); - entry->loaded = true; + return entry->loaded; } -/* Handle a wild statement for a single file F. */ +/* Handle a wild statement. S->FILENAME or S->SECTION_LIST or both + may be NULL, indicating that it is a wildcard. Separate + lang_input_section statements are created for each part of the + expansion; they are added after the wild statement S. OUTPUT is + the output section. */ static void -wild_file (s, section, f, output) +wild (s, target, output) lang_wild_statement_type *s; - const char *section; - lang_input_statement_type *f; + const char *target ATTRIBUTE_UNUSED; lang_output_section_statement_type *output; { - if (f->the_bfd == NULL - || ! bfd_check_format (f->the_bfd, bfd_archive)) - wild_section (s, section, f, output); - else - { - bfd *member; + struct wildcard_list *sec; - /* 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) - { - wild_section (s, section, - (lang_input_statement_type *) member->usrdata, - output); - } + walk_wild (s, output_section_callback, (PTR) output); - member = bfd_openr_next_archived_file (f->the_bfd, member); + for (sec = s->section_list; sec != NULL; sec = sec->next) + { + if (default_common_section != NULL) + break; + if (sec->spec.name != NULL && strcmp (sec->spec.name, "COMMON") == 0) + { + /* Remember the section that common is going to in case we + later get something which doesn't know where to put it. */ + default_common_section = output; } } } -/* Handle a wild statement. SECTION or FILE or both may be NULL, - indicating that it is a wildcard. Separate lang_input_section - statements are created for each part of the expansion; they are - added after the wild statement S. OUTPUT is the output section. */ +/* Return true iff target is the sought target. */ + +static int +get_target (target, data) + const bfd_target *target; + PTR data; +{ + const char *sought = (const char *) data; + + return strcmp (target->name, sought) == 0; +} + +/* Like strcpy() but convert to lower case as well. */ static void -wild (s, section, file, target, output) - lang_wild_statement_type *s; - const char *section; - const char *file; - const char *target; - lang_output_section_statement_type *output; +stricpy (dest, src) + char *dest; + char *src; { - lang_input_statement_type *f; + char c; - 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) - { - wild_file (s, section, f, output); - } - } - else if (wildcardp (file)) + while ((c = *src++) != 0) + *dest++ = TOLOWER (c); + + *dest = 0; +} + +/* Remove the first occurance of needle (if any) in haystack + from haystack. */ + +static void +strcut (haystack, needle) + char *haystack; + char *needle; +{ + haystack = strstr (haystack, needle); + + if (haystack) { - 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) - wild_file (s, section, f, output); - } + char *src; + + for (src = haystack + strlen (needle); *src;) + *haystack++ = *src++; + + *haystack = 0; } - else +} + +/* Compare two target format name strings. + Return a value indicating how "similar" they are. */ + +static int +name_compare (first, second) + char *first; + char *second; +{ + char *copy1; + char *copy2; + int result; + + copy1 = xmalloc (strlen (first) + 1); + copy2 = xmalloc (strlen (second) + 1); + + /* Convert the names to lower case. */ + stricpy (copy1, first); + stricpy (copy2, second); + + /* Remove and endian strings from the name. */ + strcut (copy1, "big"); + strcut (copy1, "little"); + strcut (copy2, "big"); + strcut (copy2, "little"); + + /* Return a value based on how many characters match, + starting from the beginning. If both strings are + the same then return 10 * their length. */ + for (result = 0; copy1[result] == copy2[result]; result++) + if (copy1[result] == 0) + { + result *= 10; + break; + } + + free (copy1); + free (copy2); + + return result; +} + +/* Set by closest_target_match() below. */ +static const bfd_target *winner; + +/* Scan all the valid bfd targets looking for one that has the endianness + requirement that was specified on the command line, and is the nearest + match to the original output target. */ + +static int +closest_target_match (target, data) + const bfd_target *target; + PTR data; +{ + const bfd_target *original = (const bfd_target *) data; + + if (command_line.endian == ENDIAN_BIG + && target->byteorder != BFD_ENDIAN_BIG) + return 0; + + if (command_line.endian == ENDIAN_LITTLE + && target->byteorder != BFD_ENDIAN_LITTLE) + return 0; + + /* Must be the same flavour. */ + if (target->flavour != original->flavour) + return 0; + + /* If we have not found a potential winner yet, then record this one. */ + if (winner == NULL) { - /* Perform the iteration over a single file */ - f = lookup_name (file); - wild_file (s, section, f, output); + winner = target; + return 0; } - if (section != (char *) NULL - && strcmp (section, "COMMON") == 0 - && default_common_section == NULL) + /* Oh dear, we now have two potential candidates for a successful match. + Compare their names and choose the better one. */ + if (name_compare (target->name, original->name) + > name_compare (winner->name, original->name)) + winner = target; + + /* Keep on searching until wqe have checked them all. */ + return 0; +} + +/* Return the BFD target format of the first input file. */ + +static char * +get_first_input_target () +{ + char *target = NULL; + + LANG_FOR_EACH_INPUT_STATEMENT (s) { - /* Remember the section that common is going to in case we later - get something which doesn't know where to put it. */ - default_common_section = output; + if (s->header.type == lang_input_statement_enum + && s->real) + { + ldfile_open_file (s); + + if (s->the_bfd != NULL + && bfd_check_format (s->the_bfd, bfd_object)) + { + target = bfd_get_target (s->the_bfd); + + if (target != NULL) + break; + } + } } + + return target; } /* Open the output file. */ @@ -1402,27 +1790,88 @@ open_output (name) { bfd *output; + /* Has the user told us which output format to use? */ if (output_target == (char *) NULL) { - if (current_target != (char *) NULL) + /* No - has the current target been set to something other than + the default? */ + if (current_target != default_target) output_target = current_target; + + /* No - can we determine the format of the first input file? */ else - output_target = default_target; + { + output_target = get_first_input_target (); + + /* Failed - use the default output target. */ + if (output_target == NULL) + output_target = default_target; + } } + + /* Has the user requested a particular endianness on the command + line? */ + if (command_line.endian != ENDIAN_UNSET) + { + const bfd_target *target; + enum bfd_endian desired_endian; + + /* Get the chosen target. */ + target = bfd_search_for_target (get_target, (PTR) output_target); + + /* If the target is not supported, we cannot do anything. */ + if (target != NULL) + { + if (command_line.endian == ENDIAN_BIG) + desired_endian = BFD_ENDIAN_BIG; + else + desired_endian = BFD_ENDIAN_LITTLE; + + /* See if the target has the wrong endianness. This should + not happen if the linker script has provided big and + little endian alternatives, but some scrips don't do + this. */ + if (target->byteorder != desired_endian) + { + /* If it does, then see if the target provides + an alternative with the correct endianness. */ + if (target->alternative_target != NULL + && (target->alternative_target->byteorder == desired_endian)) + output_target = target->alternative_target->name; + else + { + /* Try to find a target as similar as possible to + the default target, but which has the desired + endian characteristic. */ + (void) bfd_search_for_target (closest_target_match, + (PTR) target); + + /* Oh dear - we could not find any targets that + satisfy our requirements. */ + if (winner == NULL) + einfo (_("%P: warning: could not find any targets that match endianness requirement\n")); + else + output_target = winner->name; + } + } + } + } + output = bfd_openw (name, output_target); if (output == (bfd *) NULL) { if (bfd_get_error () == bfd_error_invalid_target) - { - einfo (_("%P%F: target %s not found\n"), output_target); - } + einfo (_("%P%F: target %s not found\n"), output_target); + einfo (_("%P%F: cannot open output file %s: %E\n"), name); } delete_output_file_on_failure = true; - /* output->flags |= D_PAGED;*/ +#if 0 + output->flags |= D_PAGED; +#endif if (! bfd_set_format (output, bfd_object)) einfo (_("%P%F:%s: can not make object file: %E\n"), name); @@ -1439,12 +1888,9 @@ open_output (name) return output; } - - - static void ldlang_open_output (statement) - lang_statement_union_type * statement; + lang_statement_union_type *statement; { switch (statement->header.type) { @@ -1481,7 +1927,7 @@ open_input_bfds (s, force) lang_statement_union_type *s; boolean force; { - for (; s != (lang_statement_union_type *) NULL; s = s->next) + for (; s != (lang_statement_union_type *) NULL; s = s->header.next) { switch (s->header.type) { @@ -1492,7 +1938,7 @@ open_input_bfds (s, force) open_input_bfds (s->output_section_statement.children.head, force); break; case lang_wild_statement_enum: - /* Maybe we should load the file's symbols */ + /* Maybe we should load the file's symbols. */ if (s->wild_statement.filename && ! wildcardp (s->wild_statement.filename)) (void) lookup_name (s->wild_statement.filename); @@ -1503,8 +1949,8 @@ open_input_bfds (s, force) struct bfd_link_hash_entry *undefs; /* We must continually search the entries in the group - until no new symbols are added to the list of undefined - symbols. */ + until no new symbols are added to the list of undefined + symbols. */ do { @@ -1518,7 +1964,7 @@ open_input_bfds (s, force) current_target = s->target_statement.target; break; case lang_input_statement_enum: - if (s->input_statement.real == true) + if (s->input_statement.real) { lang_statement_list_type add; @@ -1526,8 +1972,10 @@ open_input_bfds (s, force) /* If we are being called from within a group, and this is an archive which has already been searched, then - force it to be researched. */ + force it to be researched unless the whole archive + has been loaded already. */ if (force + && !s->input_statement.whole_archive && s->input_statement.loaded && bfd_check_format (s->input_statement.the_bfd, bfd_archive)) @@ -1535,12 +1983,13 @@ open_input_bfds (s, force) lang_list_init (&add); - load_symbols (&s->input_statement, &add); + if (! load_symbols (&s->input_statement, &add)) + config.make_executable = false; if (add.head != NULL) { - *add.tail = s->next; - s->next = add.head; + *add.tail = s->header.next; + s->header.next = add.head; } } break; @@ -1550,7 +1999,8 @@ open_input_bfds (s, force) } } -/* If there are [COMMONS] statements, put a wild one into the bss section */ +/* If there are [COMMONS] statements, put a wild one into the bss + section. */ static void lang_reasonable_defaults () @@ -1559,9 +2009,7 @@ lang_reasonable_defaults () lang_output_section_statement_lookup (".text"); lang_output_section_statement_lookup (".data"); - default_common_section = - lang_output_section_statement_lookup (".bss"); - + default_common_section = lang_output_section_statement_lookup (".bss"); if (placed_commons == false) { @@ -1574,13 +2022,14 @@ lang_reasonable_defaults () lang_list_init (&new->children); } #endif - } -/* - Add the supplied name to the symbol table as an undefined reference. - Remove items from the chain as we open input bfds - */ +/* Add the supplied name to the symbol table as an undefined reference. + This is a two step process as the symbol table doesn't even exist at + the time the ld command line is processed. First we put the name + on a list, then, once the output file has been opened, transfer the + name to the symbol table. */ + typedef struct ldlang_undef_chain_list { struct ldlang_undef_chain_list *next; @@ -1591,7 +2040,7 @@ static ldlang_undef_chain_list_type *ldlang_undef_chain_list_head; void ldlang_add_undef (name) - CONST char *CONST name; + const char *const name; { ldlang_undef_chain_list_type *new = ((ldlang_undef_chain_list_type *) @@ -1600,13 +2049,35 @@ ldlang_add_undef (name) new->next = ldlang_undef_chain_list_head; ldlang_undef_chain_list_head = new; - new->name = buystring (name); + new->name = xstrdup (name); + + if (output_bfd != NULL) + insert_undefined (new->name); +} + +/* Insert NAME as undefined in the symbol table. */ + +static void +insert_undefined (name) + const char *name; +{ + struct bfd_link_hash_entry *h; + + h = bfd_link_hash_lookup (link_info.hash, name, true, false, true); + if (h == (struct bfd_link_hash_entry *) NULL) + einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n")); + if (h->type == bfd_link_hash_new) + { + h->type = bfd_link_hash_undefined; + h->u.undef.abfd = NULL; + bfd_link_add_undef (link_info.hash, h); + } } /* Run through the list of undefineds created above and place them into the linker hash table as undefined symbols belonging to the - script file. -*/ + script file. */ + static void lang_place_undefineds () { @@ -1616,38 +2087,24 @@ lang_place_undefineds () ptr != (ldlang_undef_chain_list_type *) NULL; ptr = ptr->next) { - struct bfd_link_hash_entry *h; - - h = bfd_link_hash_lookup (link_info.hash, ptr->name, true, false, true); - if (h == (struct bfd_link_hash_entry *) NULL) - einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n")); - if (h->type == bfd_link_hash_new) - { - h->type = bfd_link_hash_undefined; - h->u.undef.abfd = NULL; - bfd_link_add_undef (link_info.hash, h); - } + insert_undefined (ptr->name); } } -/* Open input files and attatch to output sections */ +/* Open input files and attatch to output sections. */ + static void map_input_to_output_sections (s, target, output_section_statement) - lang_statement_union_type * s; - CONST char *target; - lang_output_section_statement_type * output_section_statement; + lang_statement_union_type *s; + const char *target; + lang_output_section_statement_type *output_section_statement; { - for (; s != (lang_statement_union_type *) NULL; s = s->next) + for (; s != (lang_statement_union_type *) NULL; s = s->header.next) { switch (s->header.type) { - - case lang_wild_statement_enum: - wild (&s->wild_statement, s->wild_statement.section_name, - s->wild_statement.filename, target, - output_section_statement); - + wild (&s->wild_statement, target, output_section_statement); break; case lang_constructors_statement_enum: map_input_to_output_sections (constructor_list.head, @@ -1686,14 +2143,14 @@ map_input_to_output_sections (s, target, output_section_statement) init_os (output_section_statement); /* Make sure that any sections mentioned in the assignment - are initialized. */ + are initialized. */ exp_init_os (s->assignment_statement.exp); break; case lang_afile_asection_pair_statement_enum: FAIL (); break; case lang_address_statement_enum: - /* Mark the specified section with the supplied address */ + /* Mark the specified section with the supplied address. */ { lang_output_section_statement_type *os = lang_output_section_statement_lookup @@ -1710,7 +2167,7 @@ map_input_to_output_sections (s, target, output_section_statement) static void print_output_section_statement (output_section_statement) - lang_output_section_statement_type * output_section_statement; + lang_output_section_statement_type *output_section_statement; { asection *section = output_section_statement->bfd_section; int len; @@ -1756,8 +2213,8 @@ print_output_section_statement (output_section_statement) static void print_assignment (assignment, output_section) - lang_assignment_statement_type * assignment; - lang_output_section_statement_type * output_section; + lang_assignment_statement_type *assignment; + lang_output_section_statement_type *output_section; { int i; etree_value_type result; @@ -1767,8 +2224,18 @@ print_assignment (assignment, output_section) result = exp_fold_tree (assignment->exp->assign.src, output_section, lang_final_phase_enum, print_dot, &print_dot); - if (result.valid) - minfo ("0x%V", result.value + result.section->bfd_section->vma); + if (result.valid_p) + { + const char *dst; + bfd_vma value; + + value = result.value + result.section->bfd_section->vma; + dst = assignment->exp->assign.dst; + + minfo ("0x%V", value); + if (dst[0] == '.' && dst[1] == 0) + print_dot = value; + } else { minfo ("*undef* "); @@ -1786,7 +2253,7 @@ print_assignment (assignment, output_section) static void print_input_statement (statm) - lang_input_statement_type * statm; + lang_input_statement_type *statm; { if (statm->filename != (char *) NULL) { @@ -1797,7 +2264,7 @@ print_input_statement (statm) /* Print all symbols defined in a particular section. This is called via bfd_link_hash_traverse. */ -static boolean +static boolean print_one_symbol (hash_entry, ptr) struct bfd_link_hash_entry *hash_entry; PTR ptr; @@ -1827,11 +2294,12 @@ print_one_symbol (hash_entry, ptr) static void print_input_section (in) - lang_input_section_type * in; + lang_input_section_type *in; { asection *i = in->section; bfd_size_type size = i->_cooked_size != 0 ? i->_cooked_size : i->_raw_size; - + unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); if (size != 0) { print_space (); @@ -1855,7 +2323,7 @@ print_input_section (in) } minfo ("0x%V %W %B\n", - i->output_section->vma + i->output_offset, size, + i->output_section->vma + i->output_offset, size / opb, i->owner); if (i->_cooked_size != 0 && i->_cooked_size != i->_raw_size) @@ -1877,26 +2345,33 @@ print_input_section (in) bfd_link_hash_traverse (link_info.hash, print_one_symbol, (PTR) i); - print_dot = i->output_section->vma + i->output_offset + size; + print_dot = i->output_section->vma + i->output_offset + size / opb; } } } static void print_fill_statement (fill) - lang_fill_statement_type * fill; + lang_fill_statement_type *fill; { - fprintf (config.map_file, " FILL mask 0x%x\n", fill->fill); + size_t size; + unsigned char *p; + fputs (" FILL mask 0x", config.map_file); + for (p = fill->fill->data, size = fill->fill->size; size != 0; p++, size--) + fprintf (config.map_file, "%02x", *p); + fputs ("\n", config.map_file); } static void print_data_statement (data) - lang_data_statement_type * data; + lang_data_statement_type *data; { int i; bfd_vma addr; bfd_size_type size; const char *name; + unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++) print_space (); @@ -1941,7 +2416,8 @@ print_data_statement (data) print_nl (); - print_dot = addr + size; + print_dot = addr + size / opb; + } /* Print an address statement. These are generated by options like @@ -1965,6 +2441,8 @@ print_reloc_statement (reloc) int i; bfd_vma addr; bfd_size_type size; + unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++) print_space (); @@ -1986,8 +2464,8 @@ print_reloc_statement (reloc) print_nl (); - print_dot = addr + size; -} + print_dot = addr + size / opb; +} static void print_padding_statement (s) @@ -1995,6 +2473,8 @@ print_padding_statement (s) { int len; bfd_vma addr; + unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); minfo (" *fill*"); @@ -2008,21 +2488,28 @@ print_padding_statement (s) addr = s->output_offset; if (s->output_section != NULL) addr += s->output_section->vma; - minfo ("0x%V %W", addr, s->size); + minfo ("0x%V %W ", addr, s->size); - if (s->fill != 0) - minfo (" %u", s->fill); + if (s->fill->size != 0) + { + size_t size; + unsigned char *p; + for (p = s->fill->data, size = s->fill->size; size != 0; p++, size--) + fprintf (config.map_file, "%02x", *p); + } print_nl (); - print_dot = addr + s->size; + print_dot = addr + s->size / opb; } static void print_wild_statement (w, os) - lang_wild_statement_type * w; - lang_output_section_statement_type * os; + lang_wild_statement_type *w; + lang_output_section_statement_type *os; { + struct wildcard_list *sec; + print_space (); if (w->filenames_sorted) @@ -2035,14 +2522,25 @@ print_wild_statement (w, os) minfo (")"); minfo ("("); - if (w->sections_sorted) - minfo ("SORT("); - if (w->section_name != NULL) - minfo ("%s", w->section_name); - else - minfo ("*"); - if (w->sections_sorted) - minfo (")"); + for (sec = w->section_list; sec; sec = sec->next) + { + if (sec->spec.sorted) + minfo ("SORT("); + if (sec->spec.exclude_name_list != NULL) + { + name_list *tmp; + minfo ("EXCLUDE_FILE ( %s", sec->spec.exclude_name_list->name); + for (tmp = sec->spec.exclude_name_list->next; tmp; tmp = tmp->next) + minfo (", %s", tmp->name); + minfo (")"); + } + if (sec->spec.name != NULL) + minfo ("%s", sec->spec.name); + else + minfo ("*"); + if (sec->spec.sorted) + minfo (")"); + } minfo (")"); print_nl (); @@ -2073,7 +2571,7 @@ print_statement_list (s, os) while (s != NULL) { print_statement (s, os); - s = s->next; + s = s->header.next; } } @@ -2165,7 +2663,7 @@ print_statements () void dprint_statement (s, n) - lang_statement_union_type * s; + lang_statement_union_type *s; int n; { FILE *map_save = config.map_file; @@ -2179,91 +2677,100 @@ dprint_statement (s, n) while (s && --n >= 0) { print_statement (s, abs_output_section); - s = s->next; + s = s->header.next; } } config.map_file = map_save; } -static bfd_vma -insert_pad (this_ptr, fill, power, output_section_statement, dot) - lang_statement_union_type ** this_ptr; - fill_type fill; - unsigned int power; - asection * output_section_statement; +static void +insert_pad (ptr, fill, alignment_needed, output_section, dot) + lang_statement_union_type **ptr; + fill_type *fill; + unsigned int alignment_needed; + asection *output_section; bfd_vma dot; { - /* Align this section first to the - input sections requirement, then - to the output section's requirement. - If this alignment is > than any seen before, - then record it too. Perform the alignment by - inserting a magic 'padding' statement. - */ - - unsigned int alignment_needed = align_power (dot, power) - dot; - - if (alignment_needed != 0) + static fill_type zero_fill = { 1, { 0 } }; + lang_statement_union_type *pad; + + pad = ((lang_statement_union_type *) + ((char *) ptr - offsetof (lang_statement_union_type, header.next))); + if (ptr != &statement_list.head + && pad->header.type == lang_padding_statement_enum + && pad->padding_statement.output_section == output_section) { - lang_statement_union_type *new = - ((lang_statement_union_type *) - stat_alloc (sizeof (lang_padding_statement_type))); - - /* Link into existing chain */ - new->header.next = *this_ptr; - *this_ptr = new; - new->header.type = lang_padding_statement_enum; - new->padding_statement.output_section = output_section_statement; - new->padding_statement.output_offset = - dot - output_section_statement->vma; - new->padding_statement.fill = fill; - new->padding_statement.size = alignment_needed; + /* Use the existing pad statement. The above test on output + section is probably redundant, but it doesn't hurt to check. */ } - - - /* Remember the most restrictive alignment */ - if (power > output_section_statement->alignment_power) + else { - output_section_statement->alignment_power = power; + /* Make a new padding statement, linked into existing chain. */ + pad = ((lang_statement_union_type *) + stat_alloc (sizeof (lang_padding_statement_type))); + pad->header.next = *ptr; + *ptr = pad; + pad->header.type = lang_padding_statement_enum; + pad->padding_statement.output_section = output_section; + if (fill == (fill_type *) 0) + fill = &zero_fill; + pad->padding_statement.fill = fill; } - output_section_statement->_raw_size += alignment_needed; - return alignment_needed + dot; - + pad->padding_statement.output_offset = dot - output_section->vma; + pad->padding_statement.size = alignment_needed; + output_section->_raw_size += alignment_needed; } -/* Work out how much this section will move the dot point */ +/* Work out how much this section will move the dot point. */ + static bfd_vma -size_input_section (this_ptr, output_section_statement, fill, dot, relax) - lang_statement_union_type ** this_ptr; - lang_output_section_statement_type * output_section_statement; - fill_type fill; +size_input_section (this_ptr, output_section_statement, fill, dot) + lang_statement_union_type **this_ptr; + lang_output_section_statement_type *output_section_statement; + fill_type *fill; bfd_vma dot; - boolean relax; { lang_input_section_type *is = &((*this_ptr)->input_section); asection *i = is->section; if (is->ifile->just_syms_flag == false) { + unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); + unsigned int alignment_needed; + asection *o; + + /* Align this section first to the input sections requirement, + then to the output section's requirement. If this alignment + is greater than any seen before, then record it too. Perform + the alignment by inserting a magic 'padding' statement. */ + if (output_section_statement->subsection_alignment != -1) - i->alignment_power = - output_section_statement->subsection_alignment; + i->alignment_power = output_section_statement->subsection_alignment; - dot = insert_pad (this_ptr, fill, i->alignment_power, - output_section_statement->bfd_section, dot); + o = output_section_statement->bfd_section; + if (o->alignment_power < i->alignment_power) + o->alignment_power = i->alignment_power; - /* Remember where in the output section this input section goes */ + alignment_needed = align_power (dot, i->alignment_power) - dot; - i->output_offset = dot - output_section_statement->bfd_section->vma; + if (alignment_needed != 0) + { + insert_pad (this_ptr, fill, alignment_needed * opb, o, dot); + dot += alignment_needed; + } + + /* Remember where in the output section this input section goes. */ - /* Mark how big the output section must be to contain this now - */ + i->output_offset = dot - o->vma; + + /* Mark how big the output section must be to contain this now. */ if (i->_cooked_size != 0) - dot += i->_cooked_size; + dot += i->_cooked_size / opb; else - dot += i->_raw_size; - output_section_statement->bfd_section->_raw_size = dot - output_section_statement->bfd_section->vma; + dot += i->_raw_size / opb; + o->_raw_size = (dot - o->vma) * opb; } else { @@ -2273,101 +2780,151 @@ size_input_section (this_ptr, output_section_statement, fill, dot, relax) return dot; } +#define IGNORE_SECTION(bfd, s) \ + (((bfd_get_section_flags (bfd, s) & (SEC_ALLOC | SEC_LOAD)) \ + != (SEC_ALLOC | SEC_LOAD)) \ + || bfd_section_size (bfd, s) == 0) + /* Check to see if any allocated sections overlap with other allocated sections. This can happen when the linker script specifically specifies the output section addresses of the two sections. */ + static void lang_check_section_addresses () { - asection * s; + asection *s; + unsigned opb = bfd_octets_per_byte (output_bfd); /* Scan all sections in the output list. */ for (s = output_bfd->sections; s != NULL; s = s->next) - /* Ignore sections which are not loaded or which have no contents. */ - if ((bfd_get_section_flags (output_bfd, s) & (SEC_ALLOC | SEC_LOAD)) - && bfd_section_size (output_bfd, s) != 0) - { - asection * os; + { + asection *os; - /* Once we reach section 's' stop our seach. This prevents two - warning messages from being produced, one for 'section A overlaps - section B' and one for 'section B overlaps section A'. */ - for (os = output_bfd->sections; os != s; os = os->next) - { - bfd_vma s_start; - bfd_vma s_end; - bfd_vma os_start; - bfd_vma os_end; - - /* Only consider loadable sections with real contents. */ - if (((bfd_get_section_flags (output_bfd, os) - & (SEC_ALLOC | SEC_LOAD)) == 0) - || bfd_section_size (output_bfd, os) == 0) - continue; - - /* We must check the sections' LMA addresses not their - VMA addresses because overlay sections can have - overlapping VMAs but they must have distinct LMAs. */ - s_start = bfd_section_lma (output_bfd, s); - os_start = bfd_section_lma (output_bfd, os); - s_end = s_start + bfd_section_size (output_bfd, s) - 1; - os_end = os_start + bfd_section_size (output_bfd, os) - 1; - - /* Look for an overlap. */ - if ((s_end < os_start) || (s_start > os_end)) - continue; - - einfo (_(\ -"%X%P: section %s [%V -> %V] overlaps section %s [%V -> %V]\n"), - s->name, s_start, s_end, os->name, os_start, os_end); - - /* Once we have found one overlap for this section, - stop looking for others. */ - break; - } - } + /* Ignore sections which are not loaded or which have no contents. */ + if (IGNORE_SECTION (output_bfd, s)) + continue; + + /* Once we reach section 's' stop our seach. This prevents two + warning messages from being produced, one for 'section A overlaps + section B' and one for 'section B overlaps section A'. */ + for (os = output_bfd->sections; os != s; os = os->next) + { + bfd_vma s_start; + bfd_vma s_end; + bfd_vma os_start; + bfd_vma os_end; + + /* Only consider loadable sections with real contents. */ + if (IGNORE_SECTION (output_bfd, os)) + continue; + + /* We must check the sections' LMA addresses not their + VMA addresses because overlay sections can have + overlapping VMAs but they must have distinct LMAs. */ + s_start = bfd_section_lma (output_bfd, s); + os_start = bfd_section_lma (output_bfd, os); + s_end = s_start + bfd_section_size (output_bfd, s) / opb - 1; + os_end = os_start + bfd_section_size (output_bfd, os) / opb - 1; + + /* Look for an overlap. */ + if ((s_end < os_start) || (s_start > os_end)) + continue; + + einfo ( +_("%X%P: section %s [%V -> %V] overlaps section %s [%V -> %V]\n"), + s->name, s_start, s_end, os->name, os_start, os_end); + + /* Once we have found one overlap for this section, + stop looking for others. */ + break; + } + } } -/* This variable indicates whether bfd_relax_section should be called - again. */ +/* Make sure the new address is within the region. We explicitly permit the + current address to be at the exact end of the region when the address is + non-zero, in case the region is at the end of addressable memory and the + calculation wraps around. */ -static boolean relax_again; +static void +os_region_check (os, region, tree, base) + lang_output_section_statement_type *os; + struct memory_region_struct *region; + etree_type *tree; + bfd_vma base; +{ + if ((region->current < region->origin + || (region->current - region->origin > region->length)) + && ((region->current != region->origin + region->length) + || base == 0)) + { + if (tree != (etree_type *) NULL) + { + einfo (_("%X%P: address 0x%v of %B section %s is not within region %s\n"), + region->current, + os->bfd_section->owner, + os->bfd_section->name, + region->name); + } + else + { + einfo (_("%X%P: region %s is full (%B section %s)\n"), + region->name, + os->bfd_section->owner, + os->bfd_section->name); + } + /* Reset the region pointer. */ + region->current = region->origin; + } +} /* Set the sizes for all the output sections. */ -bfd_vma -lang_size_sections (s, output_section_statement, prev, fill, dot, relax) - lang_statement_union_type * s; - lang_output_section_statement_type * output_section_statement; - lang_statement_union_type ** prev; - fill_type fill; +static bfd_vma +lang_size_sections_1 (s, output_section_statement, prev, fill, dot, relax) + lang_statement_union_type *s; + lang_output_section_statement_type *output_section_statement; + lang_statement_union_type **prev; + fill_type *fill; bfd_vma dot; - boolean relax; + boolean *relax; { + unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); + /* Size up the sections from their constituent parts. */ - for (; s != (lang_statement_union_type *) NULL; s = s->next) + for (; s != (lang_statement_union_type *) NULL; s = s->header.next) { switch (s->header.type) { case lang_output_section_statement_enum: { bfd_vma after; - lang_output_section_statement_type *os = &s->output_section_statement; + lang_output_section_statement_type *os; + os = &s->output_section_statement; if (os->bfd_section == NULL) /* This section was never actually created. */ break; + /* The section might have been removed after its statement was + added. For example, ldemul_before_allocation can remove + dynamic sections if they turn out not to be needed. */ + if (!link_info.relocateable + && (bfd_get_section_flags (output_bfd, os->bfd_section) + & SEC_EXCLUDE) != 0) + break; + /* If this is a COFF shared library section, use the size and address from the input section. FIXME: This is COFF specific; it would be cleaner if there were some other way to do this, but nothing simple comes to mind. */ if ((os->bfd_section->flags & SEC_COFF_SHARED_LIBRARY) != 0) { - asection * input; + asection *input; if (os->children.head == NULL - || os->children.head->next != NULL + || os->children.head->header.next != NULL || os->children.head->header.type != lang_input_section_enum) einfo (_("%P%X: Internal error on COFF shared library section %s\n"), os->name); @@ -2405,22 +2962,27 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax) defined, issue a warning. */ if ((bfd_get_section_flags (output_bfd, os->bfd_section) & (SEC_ALLOC | SEC_LOAD)) != 0 + && (bfd_get_section_flags (output_bfd, os->bfd_section) + & SEC_NEVER_LOAD) == 0 && ! link_info.relocateable && strcmp (os->region->name, "*default*") == 0 && lang_memory_region_list != NULL - && (strcmp (lang_memory_region_list->name, "*default*") != 0 + && (strcmp (lang_memory_region_list->name, + "*default*") != 0 || lang_memory_region_list->next != NULL)) einfo (_("%P: warning: no memory region specified for section `%s'\n"), - bfd_get_section_name (output_bfd, os->bfd_section)); + bfd_get_section_name (output_bfd, + os->bfd_section)); dot = os->region->current; - + if (os->section_alignment == -1) { bfd_vma olddot; olddot = dot; - dot = align_power (dot, os->bfd_section->alignment_power); + dot = align_power (dot, + os->bfd_section->alignment_power); if (dot != olddot && config.warn_section_align) einfo (_("%P: warning: changing start of section %s by %u bytes\n"), @@ -2435,14 +2997,14 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax) abs_output_section, lang_allocating_phase_enum, dot, &dot); - if (r.valid == false) + if (r.valid_p == false) { einfo (_("%F%S: non constant address expression for section %s\n"), os->name); } dot = r.value + r.section->bfd_section->vma; } - + /* The section starts here. First, align to what the section needs. */ @@ -2450,83 +3012,94 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax) dot = align_power (dot, os->section_alignment); bfd_set_section_vma (0, os->bfd_section, dot); - + os->bfd_section->output_offset = 0; } - (void) lang_size_sections (os->children.head, os, &os->children.head, - os->fill, dot, relax); - - /* Ignore the size of the input sections, use the vma and size to - align against. */ + lang_size_sections_1 (os->children.head, os, &os->children.head, + os->fill, dot, relax); - after = ALIGN_N (os->bfd_section->vma + - os->bfd_section->_raw_size, + /* Put the section within the requested block size, or + align at the block boundary. */ + after = ALIGN_N (os->bfd_section->vma + + os->bfd_section->_raw_size / opb, /* The coercion here is important, see ld.h. */ (bfd_vma) os->block_value); if (bfd_is_abs_section (os->bfd_section)) ASSERT (after == os->bfd_section->vma); + else if ((os->bfd_section->flags & SEC_HAS_CONTENTS) == 0 + && (os->bfd_section->flags & SEC_THREAD_LOCAL)) + os->bfd_section->_raw_size = 0; else - os->bfd_section->_raw_size = after - os->bfd_section->vma; - dot = os->bfd_section->vma + os->bfd_section->_raw_size; + os->bfd_section->_raw_size = + (after - os->bfd_section->vma) * opb; + + dot = os->bfd_section->vma + os->bfd_section->_raw_size / opb; os->processed = true; + if (os->update_dot_tree != 0) + exp_fold_tree (os->update_dot_tree, abs_output_section, + lang_allocating_phase_enum, dot, &dot); + /* Update dot in the region ? We only do this if the section is going to be allocated, since unallocated sections do not contribute to the region's - overall size in memory. */ + overall size in memory. + + If the SEC_NEVER_LOAD bit is not set, it will affect the + addresses of sections after it. We have to update + dot. */ if (os->region != (lang_memory_region_type *) NULL - && (bfd_get_section_flags (output_bfd, os->bfd_section) - & (SEC_ALLOC | SEC_LOAD))) + && ((bfd_get_section_flags (output_bfd, os->bfd_section) + & SEC_NEVER_LOAD) == 0 + || (bfd_get_section_flags (output_bfd, os->bfd_section) + & (SEC_ALLOC | SEC_LOAD)))) { os->region->current = dot; - - /* Make sure this isn't silly. */ - if (os->region->current < os->region->origin - || (os->region->current - os->region->origin - > os->region->length)) + + /* Make sure the new address is within the region. */ + os_region_check (os, os->region, os->addr_tree, + os->bfd_section->vma); + + /* If there's no load address specified, use the run + region as the load region. */ + if (os->lma_region == NULL && os->load_base == NULL) + os->lma_region = os->region; + + if (os->lma_region != NULL && os->lma_region != os->region) { - if (os->addr_tree != (etree_type *) NULL) - { - einfo (_("%X%P: address 0x%v of %B section %s is not within region %s\n"), - os->region->current, - os->bfd_section->owner, - os->bfd_section->name, - os->region->name); - } - else - { - einfo (_("%X%P: region %s is full (%B section %s)\n"), - os->region->name, - os->bfd_section->owner, - os->bfd_section->name); - } - /* Reset the region pointer. */ - os->region->current = os->region->origin; + /* Set load_base, which will be handled later. */ + os->load_base = exp_intop (os->lma_region->current); + os->lma_region->current += + os->bfd_section->_raw_size / opb; + os_region_check (os, os->lma_region, NULL, + os->bfd_section->lma); } } } break; case lang_constructors_statement_enum: - dot = lang_size_sections (constructor_list.head, - output_section_statement, - &s->wild_statement.children.head, - fill, - dot, relax); + dot = lang_size_sections_1 (constructor_list.head, + output_section_statement, + &s->wild_statement.children.head, + fill, dot, relax); break; case lang_data_statement_enum: { unsigned int size = 0; - s->data_statement.output_vma = dot - output_section_statement->bfd_section->vma; + s->data_statement.output_vma = + dot - output_section_statement->bfd_section->vma; s->data_statement.output_section = output_section_statement->bfd_section; switch (s->data_statement.type) { + default: + abort (); case QUAD: case SQUAD: size = QUAD_SIZE; @@ -2541,15 +3114,18 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax) size = BYTE_SIZE; break; } - - dot += size; + if (size < opb) + size = opb; + dot += size / opb; output_section_statement->bfd_section->_raw_size += size; /* The output section gets contents, and then we inspect for any flags set in the input script which override any ALLOC. */ output_section_statement->bfd_section->flags |= SEC_HAS_CONTENTS; - if (!(output_section_statement->flags & SEC_NEVER_LOAD)) { - output_section_statement->bfd_section->flags |= SEC_ALLOC | SEC_LOAD; - } + if (!(output_section_statement->flags & SEC_NEVER_LOAD)) + { + output_section_statement->bfd_section->flags |= + SEC_ALLOC | SEC_LOAD; + } } break; @@ -2562,18 +3138,17 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax) s->reloc_statement.output_section = output_section_statement->bfd_section; size = bfd_get_reloc_size (s->reloc_statement.howto); - dot += size; + dot += size / opb; output_section_statement->bfd_section->_raw_size += size; } break; - - case lang_wild_statement_enum: - dot = lang_size_sections (s->wild_statement.children.head, - output_section_statement, - &s->wild_statement.children.head, + case lang_wild_statement_enum: - fill, dot, relax); + dot = lang_size_sections_1 (s->wild_statement.children.head, + output_section_statement, + &s->wild_statement.children.head, + fill, dot, relax); break; @@ -2601,18 +3176,17 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax) if (! bfd_relax_section (i->owner, i, &link_info, &again)) einfo (_("%P%F: can't relax section: %E\n")); if (again) - relax_again = true; + *relax = true; } - dot = size_input_section (prev, - output_section_statement, - output_section_statement->fill, - dot, relax); + dot = size_input_section (prev, output_section_statement, + output_section_statement->fill, dot); } break; case lang_input_statement_enum: break; case lang_fill_statement_enum: - s->fill_statement.output_section = output_section_statement->bfd_section; + s->fill_statement.output_section = + output_section_statement->bfd_section; fill = s->fill_statement.fill; break; @@ -2628,31 +3202,22 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax) if (newdot != dot) { - /* The assignment changed dot. Insert a pad. */ if (output_section_statement == abs_output_section) { /* If we don't have an output section, then just adjust the default memory address. */ lang_memory_region_lookup ("*default*")->current = newdot; } - else if (!relax) + else { - lang_statement_union_type *new = - ((lang_statement_union_type *) - stat_alloc (sizeof (lang_padding_statement_type))); - - /* Link into existing chain. */ - new->header.next = *prev; - *prev = new; - new->header.type = lang_padding_statement_enum; - new->padding_statement.output_section = - output_section_statement->bfd_section; - new->padding_statement.output_offset = - dot - output_section_statement->bfd_section->vma; - new->padding_statement.fill = fill; - new->padding_statement.size = newdot - dot; - output_section_statement->bfd_section->_raw_size += - new->padding_statement.size; + /* Insert a pad after this statement. We can't + put the pad before when relaxing, in case the + assignment references dot. */ + insert_pad (&s->header.next, fill, (newdot - dot) * opb, + output_section_statement->bfd_section, dot); + + /* Don't neuter the pad below when relaxing. */ + s = s->header.next; } dot = newdot; @@ -2661,31 +3226,34 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax) break; case lang_padding_statement_enum: - /* If we are relaxing, and this is not the first pass, some - padding statements may have been inserted during previous - passes. We may have to move the padding statement to a new - location if dot has a different value at this point in this - pass than it did at this point in the previous pass. */ - s->padding_statement.output_offset = - dot - output_section_statement->bfd_section->vma; - dot += s->padding_statement.size; - output_section_statement->bfd_section->_raw_size += - s->padding_statement.size; + /* If this is the first time lang_size_sections is called, + we won't have any padding statements. If this is the + second or later passes when relaxing, we should allow + padding to shrink. If padding is needed on this pass, it + will be added back in. */ + s->padding_statement.size = 0; + + /* Make sure output_offset is valid. If relaxation shrinks + the section and this pad isn't needed, it's possible to + have output_offset larger than the final size of the + section. bfd_set_section_contents will complain even for + a pad size of zero. */ + s->padding_statement.output_offset + = dot - output_section_statement->bfd_section->vma; break; case lang_group_statement_enum: - dot = lang_size_sections (s->group_statement.children.head, - output_section_statement, - &s->group_statement.children.head, - fill, dot, relax); + dot = lang_size_sections_1 (s->group_statement.children.head, + output_section_statement, + &s->group_statement.children.head, + fill, dot, relax); break; default: FAIL (); break; - /* This can only get here when relaxing is turned on. */ - + /* We can only get here when relaxing is turned on. */ case lang_address_statement_enum: break; } @@ -2694,14 +3262,53 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax) return dot; } +bfd_vma +lang_size_sections (s, output_section_statement, prev, fill, dot, relax) + lang_statement_union_type *s; + lang_output_section_statement_type *output_section_statement; + lang_statement_union_type **prev; + fill_type *fill; + bfd_vma dot; + boolean *relax; +{ + bfd_vma result; + + exp_data_seg.phase = exp_dataseg_none; + result = lang_size_sections_1 (s, output_section_statement, prev, fill, + dot, relax); + if (exp_data_seg.phase == exp_dataseg_end_seen) + { + /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_END pair was seen, check whether + a page could be saved in the data segment. */ + bfd_vma first, last; + + first = -exp_data_seg.base & (exp_data_seg.pagesize - 1); + last = exp_data_seg.end & (exp_data_seg.pagesize - 1); + if (first && last + && ((exp_data_seg.base & ~(exp_data_seg.pagesize - 1)) + != (exp_data_seg.end & ~(exp_data_seg.pagesize - 1))) + && first + last <= exp_data_seg.pagesize) + { + exp_data_seg.phase = exp_dataseg_adjust; + result = lang_size_sections_1 (s, output_section_statement, prev, + fill, dot, relax); + } + } + + return result; +} + bfd_vma lang_do_assignments (s, output_section_statement, fill, dot) - lang_statement_union_type * s; - lang_output_section_statement_type * output_section_statement; - fill_type fill; + lang_statement_union_type *s; + lang_output_section_statement_type *output_section_statement; + fill_type *fill; bfd_vma dot; { - for (; s != (lang_statement_union_type *) NULL; s = s->next) + unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); + + for (; s != (lang_statement_union_type *) NULL; s = s->header.next) { switch (s->header.type) { @@ -2714,24 +3321,26 @@ lang_do_assignments (s, output_section_statement, fill, dot) case lang_output_section_statement_enum: { - lang_output_section_statement_type *os = - &(s->output_section_statement); + lang_output_section_statement_type *os; + os = &(s->output_section_statement); if (os->bfd_section != NULL) { dot = os->bfd_section->vma; (void) lang_do_assignments (os->children.head, os, os->fill, dot); - dot = os->bfd_section->vma + os->bfd_section->_raw_size; + dot = os->bfd_section->vma + os->bfd_section->_raw_size / opb; + } - if (os->load_base) + if (os->load_base) { /* If nothing has been placed into the output section then - it won't have a bfd_section. */ - if (os->bfd_section) + it won't have a bfd_section. */ + if (os->bfd_section) { - os->bfd_section->lma - = exp_get_abs_int(os->load_base, 0,"load base", lang_final_phase_enum); + os->bfd_section->lma + = exp_get_abs_int (os->load_base, 0, "load base", + lang_final_phase_enum); } } } @@ -2759,25 +3368,33 @@ lang_do_assignments (s, output_section_statement, fill, dot) abs_output_section, lang_final_phase_enum, dot, &dot); s->data_statement.value = value.value; - if (value.valid == false) + if (value.valid_p == false) einfo (_("%F%P: invalid data statement\n")); } - switch (s->data_statement.type) - { - case QUAD: - case SQUAD: - dot += QUAD_SIZE; - break; - case LONG: - dot += LONG_SIZE; - break; - case SHORT: - dot += SHORT_SIZE; - break; - case BYTE: - dot += BYTE_SIZE; - break; - } + { + unsigned int size; + switch (s->data_statement.type) + { + default: + abort (); + case QUAD: + case SQUAD: + size = QUAD_SIZE; + break; + case LONG: + size = LONG_SIZE; + break; + case SHORT: + size = SHORT_SIZE; + break; + case BYTE: + size = BYTE_SIZE; + break; + } + if (size < opb) + size = opb; + dot += size / opb; + } break; case lang_reloc_statement_enum: @@ -2788,10 +3405,10 @@ lang_do_assignments (s, output_section_statement, fill, dot) abs_output_section, lang_final_phase_enum, dot, &dot); s->reloc_statement.addend_value = value.value; - if (value.valid == false) + if (value.valid_p == false) einfo (_("%F%P: invalid reloc statement\n")); } - dot += bfd_get_reloc_size (s->reloc_statement.howto); + dot += bfd_get_reloc_size (s->reloc_statement.howto) / opb; break; case lang_input_section_enum: @@ -2799,9 +3416,9 @@ lang_do_assignments (s, output_section_statement, fill, dot) asection *in = s->input_section.section; if (in->_cooked_size != 0) - dot += in->_cooked_size; + dot += in->_cooked_size / opb; else - dot += in->_raw_size; + dot += in->_raw_size / opb; } break; @@ -2821,7 +3438,7 @@ lang_do_assignments (s, output_section_statement, fill, dot) break; case lang_padding_statement_enum: - dot += s->padding_statement.size; + dot += s->padding_statement.size / opb; break; case lang_group_statement_enum: @@ -2879,11 +3496,15 @@ lang_set_startof () h = bfd_link_hash_lookup (link_info.hash, buf, false, false, true); if (h != NULL && h->type == bfd_link_hash_undefined) { + unsigned opb; + + opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); h->type = bfd_link_hash_defined; if (s->_cooked_size != 0) - h->u.def.value = s->_cooked_size; + h->u.def.value = s->_cooked_size / opb; else - h->u.def.value = s->_raw_size; + h->u.def.value = s->_raw_size / opb; h->u.def.section = bfd_abs_section_ptr; } @@ -2928,7 +3549,7 @@ lang_finish () else { bfd_vma val; - CONST char *send; + const char *send; /* We couldn't find the entry symbol. Try parsing it as a number. */ @@ -2944,7 +3565,7 @@ lang_finish () /* Can't find the entry symbol, and it's not a number. Use the first address in the text section. */ - ts = bfd_get_section_by_name (output_bfd, ".text"); + ts = bfd_get_section_by_name (output_bfd, entry_section); if (ts != (asection *) NULL) { if (warn) @@ -2970,10 +3591,10 @@ lang_finish () static void #ifdef ANSI_PROTOTYPES -ignore_bfd_errors (const char *s, ...) +ignore_bfd_errors (const char *s ATTRIBUTE_UNUSED, ...) #else ignore_bfd_errors (s) - const char *s; + const char *s ATTRIBUTE_UNUSED; #endif { /* Don't do anything. */ @@ -2988,15 +3609,32 @@ lang_check () { lang_statement_union_type *file; bfd *input_bfd; - CONST bfd_arch_info_type *compatible; + const bfd_arch_info_type *compatible; for (file = file_chain.head; file != (lang_statement_union_type *) NULL; file = file->input_statement.next) { input_bfd = file->input_statement.the_bfd; - compatible = bfd_arch_get_compatible (input_bfd, - output_bfd); + compatible = bfd_arch_get_compatible (input_bfd, output_bfd); + + /* In general it is not possible to perform a relocatable + link between differing object formats when the input + file has relocations, because the relocations in the + input format may not have equivalent representations in + the output format (and besides BFD does not translate + relocs for other link purposes than a final link). */ + if ((link_info.relocateable || link_info.emitrelocations) + && (compatible == NULL + || bfd_get_flavour (input_bfd) != bfd_get_flavour (output_bfd)) + && (bfd_get_file_flags (input_bfd) & HAS_RELOC) != 0) + { + einfo (_("%P%F: Relocatable linking with relocations from format %s (%B) to format %s (%B) is not supported\n"), + bfd_get_target (input_bfd), input_bfd, + bfd_get_target (output_bfd), output_bfd); + /* einfo with %F exits. */ + } + if (compatible == NULL) { if (command_line.warn_mismatch) @@ -3004,8 +3642,11 @@ lang_check () bfd_printable_name (input_bfd), input_bfd, bfd_printable_name (output_bfd)); } - else + else if (bfd_count_sections (input_bfd)) { + /* If the input bfd has no contents, it shouldn't set the + private data of the output bfd. */ + bfd_error_handler_type pfn = NULL; /* If we aren't supposed to warn about mismatched input @@ -3034,6 +3675,8 @@ lang_check () static void lang_common () { + if (command_line.inhibit_common_definition) + return; if (link_info.relocateable && ! command_line.force_common_definition) return; @@ -3060,6 +3703,8 @@ lang_one_common (h, info) unsigned int power_of_two; bfd_vma size; asection *section; + unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); if (h->type != bfd_link_hash_common) return true; @@ -3074,8 +3719,8 @@ lang_one_common (h, info) section = h->u.c.p->section; /* Increase the size of the section. */ - section->_cooked_size = ALIGN_N (section->_cooked_size, - (bfd_size_type) (1 << power_of_two)); + section->_cooked_size = ALIGN_N ((section->_cooked_size + opb - 1) / opb, + (bfd_size_type) (1 << power_of_two)) * opb; /* Adjust the alignment if necessary. */ if (power_of_two > section->alignment_power) @@ -3092,7 +3737,7 @@ lang_one_common (h, info) /* Make sure the section is allocated in memory, and make sure that it is no longer a common section. */ section->flags |= SEC_ALLOC; - section->flags &= ~ SEC_IS_COMMON; + section->flags &= ~SEC_IS_COMMON; if (config.map_file != NULL) { @@ -3144,21 +3789,14 @@ lang_one_common (h, info) return true; } -/* -run through the input files and ensure that every input -section has somewhere to go. If one is found without -a destination then create an input request and place it -into the statement tree. -*/ +/* Run through the input files and ensure that every input section has + somewhere to go. If one is found without a destination then create + an input request and place it into the statement tree. */ static void lang_place_orphans () { - lang_input_statement_type *file; - - for (file = (lang_input_statement_type *) file_chain.head; - file != (lang_input_statement_type *) NULL; - file = (lang_input_statement_type *) file->next) + LANG_FOR_EACH_INPUT_STATEMENT (file) { asection *s; @@ -3169,15 +3807,11 @@ lang_place_orphans () if (s->output_section == (asection *) NULL) { /* This section of the file is not attatched, root - around for a sensible place for it to go */ + around for a sensible place for it to go. */ if (file->just_syms_flag) { - /* We are only retrieving symbol values from this - file. We want the symbols to act as though the - values in the file are absolute. */ - s->output_section = bfd_abs_section_ptr; - s->output_offset = s->vma; + abort (); } else if (strcmp (s->name, "COMMON") == 0) { @@ -3199,41 +3833,37 @@ lang_place_orphans () lang_output_section_statement_lookup (".bss"); } - wild_doit (&default_common_section->children, s, - default_common_section, file); + lang_add_section (&default_common_section->children, s, + default_common_section, file); } } else if (ldemul_place_orphan (file, s)) ; else { - lang_output_section_statement_type *os = - lang_output_section_statement_lookup (s->name); + lang_output_section_statement_type *os; - wild_doit (&os->children, s, os, file); + os = lang_output_section_statement_lookup (s->name); + lang_add_section (&os->children, s, os, file); } } } } } - void -lang_set_flags (ptr, flags) +lang_set_flags (ptr, flags, invert) lang_memory_region_type *ptr; - CONST char *flags; + const char *flags; + int invert; { - flagword *ptr_flags = &ptr->flags; + flagword *ptr_flags; - ptr->flags = ptr->not_flags = 0; + ptr_flags = invert ? &ptr->not_flags : &ptr->flags; while (*flags) { switch (*flags) { - case '!': - ptr_flags = (ptr_flags == &ptr->flags) ? &ptr->not_flags : &ptr->flags; - break; - case 'A': case 'a': *ptr_flags |= SEC_ALLOC; break; @@ -3286,11 +3916,7 @@ void lang_for_each_file (func) void (*func) PARAMS ((lang_input_statement_type *)); { - lang_input_statement_type *f; - - for (f = (lang_input_statement_type *) file_chain.head; - f != (lang_input_statement_type *) NULL; - f = (lang_input_statement_type *) f->next) + LANG_FOR_EACH_INPUT_STATEMENT (f) { func (f); } @@ -3302,13 +3928,9 @@ lang_for_each_file (func) void lang_for_each_input_section (func) - void (*func) PARAMS ((bfd * ab, asection * as)); + void (*func) PARAMS ((bfd *ab, asection *as)); { - lang_input_statement_type *f; - - for (f = (lang_input_statement_type *) file_chain.head; - f != (lang_input_statement_type *) NULL; - f = (lang_input_statement_type *) f->next) + LANG_FOR_EACH_INPUT_STATEMENT (f) { asection *s; @@ -3325,7 +3947,7 @@ lang_for_each_input_section (func) void ldlang_add_file (entry) - lang_input_statement_type * entry; + lang_input_statement_type *entry; { bfd **pp; @@ -3360,7 +3982,7 @@ ldlang_add_file (entry) void lang_add_output (name, from_script) - CONST char *name; + const char *name; int from_script; { /* Make -o on command line override OUTPUT in script. */ @@ -3371,7 +3993,6 @@ lang_add_output (name, from_script) } } - static lang_output_section_statement_type *current_section; static int @@ -3384,7 +4005,7 @@ topower (x) if (x < 0) return -1; - for (l = 0; l < 32; l++) + for (l = 0; l < 32; l++) { if (i >= (unsigned int) x) return l; @@ -3394,12 +4015,12 @@ topower (x) return 0; } -void +lang_output_section_statement_type * lang_enter_output_section_statement (output_section_statement_name, address_exp, sectype, block_value, align, subalign, ebase) const char *output_section_statement_name; - etree_type * address_exp; + etree_type *address_exp; enum section_type sectype; bfd_vma block_value; etree_type *align; @@ -3412,19 +4033,17 @@ lang_enter_output_section_statement (output_section_statement_name, os = lang_output_section_statement_lookup (output_section_statement_name); + /* Add this statement to tree. */ +#if 0 + add_statement (lang_output_section_statement_enum, + output_section_statement); +#endif + /* Make next things chain into subchain of this. */ - - /* Add this statement to tree */ - /* add_statement(lang_output_section_statement_enum, - output_section_statement);*/ - /* Make next things chain into subchain of this */ - - if (os->addr_tree == - (etree_type *) NULL) - { - os->addr_tree = - address_exp; - } + if (os->addr_tree == (etree_type *) NULL) + { + os->addr_tree = address_exp; + } os->sectype = sectype; if (sectype != noload_section) os->flags = SEC_NO_FLAGS; @@ -3433,18 +4052,15 @@ lang_enter_output_section_statement (output_section_statement_name, os->block_value = block_value ? block_value : 1; stat_ptr = &os->children; - os->subsection_alignment = topower( - exp_get_value_int(subalign, -1, - "subsection alignment", - 0)); - os->section_alignment = topower( - exp_get_value_int(align, -1, - "section alignment", 0)); + os->subsection_alignment = + topower (exp_get_value_int (subalign, -1, "subsection alignment", 0)); + os->section_alignment = + topower (exp_get_value_int (align, -1, "section alignment", 0)); os->load_base = ebase; + return os; } - void lang_final () { @@ -3454,11 +4070,13 @@ lang_final () new->name = output_filename; } -/* Reset the current counters in the regions */ -static void -reset_memory_regions () +/* Reset the current counters in the regions. */ + +void +lang_reset_memory_regions () { lang_memory_region_type *p = lang_memory_region_list; + asection *o; for (p = lang_memory_region_list; p != (lang_memory_region_type *) NULL; @@ -3467,147 +4085,47 @@ reset_memory_regions () p->old_length = (bfd_size_type) (p->current - p->origin); p->current = p->origin; } -} - -/* ??? 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; - } - } - } + for (o = output_bfd->sections; o != NULL; o = o->next) + o->_raw_size = 0; } -/* Handle a wild statement for a single file F. */ +/* If the wild pattern was marked KEEP, the member sections + should be as well. */ static void -lang_gc_wild_file (s, section, f) - lang_wild_statement_type *s; - const char *section; - lang_input_statement_type *f; +gc_section_callback (ptr, sec, section, file, data) + lang_wild_statement_type *ptr; + struct wildcard_list *sec ATTRIBUTE_UNUSED; + asection *section; + lang_input_statement_type *file ATTRIBUTE_UNUSED; + PTR data ATTRIBUTE_UNUSED; { - 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); - } - } + if (ptr->keep_sections) + section->flags |= SEC_KEEP; } -/* Handle a wild statement, marking it against GC. SECTION or FILE or both - may be NULL, indicating that it is a wildcard. */ +/* Handle a wild statement, marking it against GC. */ static void -lang_gc_wild (s, section, file) +lang_gc_wild (s) 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); - } + walk_wild (s, gc_section_callback, NULL); } /* Iterate over sections marking them against GC. */ static void lang_gc_sections_1 (s) - lang_statement_union_type * s; + lang_statement_union_type *s; { - for (; s != (lang_statement_union_type *) NULL; s = s->next) + for (; s != (lang_statement_union_type *) NULL; s = s->header.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); + lang_gc_wild (&s->wild_statement); break; case lang_constructors_statement_enum: lang_gc_sections_1 (constructor_list.head); @@ -3637,17 +4155,23 @@ lang_gc_sections () /* 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 = (char *) entry_symbol; + if (entry_symbol != NULL) + { + fake_list_start.next = ldlang_undef_chain_list_head; + fake_list_start.name = (char *) entry_symbol; + ulist = &fake_list_start; + } + else + ulist = ldlang_undef_chain_list_head; - for (ulist = &fake_list_start; ulist; ulist = ulist->next) + for (; ulist; ulist = ulist->next) { - h = bfd_link_hash_lookup (link_info.hash, ulist->name, + 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) + && (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; @@ -3663,19 +4187,24 @@ lang_process () lang_reasonable_defaults (); current_target = default_target; - lang_for_each_statement (ldlang_open_output); /* Open the output file */ + /* Open the output file. */ + lang_for_each_statement (ldlang_open_output); ldemul_create_output_section_statements (); - /* Add to the hash table all undefineds on the command line */ + /* Add to the hash table all undefineds on the command line. */ lang_place_undefineds (); - /* Create a bfd for each input file */ + already_linked_table_init (); + + /* Create a bfd for each input file. */ current_target = default_target; open_input_bfds (statement_list.head, false); ldemul_after_open (); + already_linked_table_free (); + /* Make sure that we're not mixing architectures. We call this after all the input files have been opened, but before we do any other processing, so that any operations merge_private_bfd_data @@ -3695,66 +4224,81 @@ lang_process () if (command_line.gc_sections) lang_gc_sections (); - /* Size up the common data */ + /* If there were any SEC_MERGE sections, finish their merging, so that + section sizes can be computed. This has to be done after GC of sections, + so that GCed sections are not merged, but before assigning output + sections, since removing whole input sections is hard then. */ + bfd_merge_sections (output_bfd, &link_info); + + /* Size up the common data. */ lang_common (); /* Run through the contours of the script and attach input sections - to the correct output sections - */ + to the correct output sections. */ map_input_to_output_sections (statement_list.head, (char *) NULL, (lang_output_section_statement_type *) NULL); - - /* Find any sections not attached explicitly and handle them */ + /* Find any sections not attached explicitly and handle them. */ lang_place_orphans (); + if (! link_info.relocateable) + { + /* Look for a text section and set the readonly attribute in it. */ + asection *found = bfd_get_section_by_name (output_bfd, ".text"); + + if (found != (asection *) NULL) + { + if (config.text_read_only) + found->flags |= SEC_READONLY; + else + found->flags &= ~SEC_READONLY; + } + } + + /* Do anything special before sizing sections. This is where ELF + and other back-ends size dynamic sections. */ ldemul_before_allocation (); /* We must record the program headers before we try to fix the section positions, since they will affect SIZEOF_HEADERS. */ lang_record_phdrs (); - /* Now run around and relax if we can */ + /* Size up the sections. */ + lang_size_sections (statement_list.head, + abs_output_section, + &statement_list.head, 0, (bfd_vma) 0, NULL); + + /* Now run around and relax if we can. */ if (command_line.relax) { - /* First time round is a trial run to get the 'worst case' - addresses of the objects if there was no relaxing. */ - lang_size_sections (statement_list.head, - abs_output_section, - &(statement_list.head), 0, (bfd_vma) 0, false); - /* Keep relaxing until bfd_relax_section gives up. */ + boolean relax_again; + do { - reset_memory_regions (); + lang_reset_memory_regions (); relax_again = false; /* Note: pe-dll.c does something like this also. If you find you need to change this code, you probably need to change - pe-dll.c also. DJ */ + pe-dll.c also. DJ */ /* Do all the assignments with our current guesses as to section sizes. */ lang_do_assignments (statement_list.head, abs_output_section, - (fill_type) 0, (bfd_vma) 0); + (fill_type *) 0, (bfd_vma) 0); /* Perform another relax pass - this time we know where the - globals are, so can make better guess. */ + globals are, so can make a better guess. */ lang_size_sections (statement_list.head, abs_output_section, - &(statement_list.head), 0, (bfd_vma) 0, true); + &statement_list.head, 0, (bfd_vma) 0, + &relax_again); } while (relax_again); } - else - { - /* Size up the sections. */ - lang_size_sections (statement_list.head, - abs_output_section, - &(statement_list.head), 0, (bfd_vma) 0, false); - } /* See if anything special should be done now we know how big everything is. */ @@ -3763,19 +4307,19 @@ lang_process () /* Fix any .startof. or .sizeof. symbols. */ lang_set_startof (); - /* Do all the assignments, now that we know the final restingplaces - of all the symbols */ + /* Do all the assignments, now that we know the final resting places + of all the symbols. */ lang_do_assignments (statement_list.head, abs_output_section, - (fill_type) 0, (bfd_vma) 0); + (fill_type *) 0, (bfd_vma) 0); /* Make sure that the section addresses make sense. */ if (! link_info.relocateable && command_line.check_section_addresses) lang_check_section_addresses (); - - /* Final stuffs */ + + /* Final stuffs. */ ldemul_finish (); lang_finish (); @@ -3784,40 +4328,55 @@ lang_process () /* EXPORTED TO YACC */ void -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; +lang_add_wild (filespec, section_list, keep_sections) + struct wildcard_spec *filespec; + struct wildcard_list *section_list; boolean keep_sections; { - lang_wild_statement_type *new = new_stat (lang_wild_statement, - stat_ptr); + struct wildcard_list *curr, *next; + lang_wild_statement_type *new; + + /* Reverse the list as the parser puts it back to front. */ + for (curr = section_list, section_list = NULL; + curr != NULL; + section_list = curr, curr = next) + { + if (curr->spec.name != NULL && strcmp (curr->spec.name, "COMMON") == 0) + placed_commons = true; + + next = curr->next; + curr->next = section_list; + } - if (section_name != (char *) NULL && strcmp (section_name, "COMMON") == 0) + if (filespec != NULL && filespec->name != NULL) { - placed_commons = true; + if (strcmp (filespec->name, "*") == 0) + filespec->name = NULL; + else if (! wildcardp (filespec->name)) + lang_has_input_file = true; } - if (filename != NULL && ! wildcardp (filename)) + + new = new_stat (lang_wild_statement, stat_ptr); + new->filename = NULL; + new->filenames_sorted = false; + if (filespec != NULL) { - lang_has_input_file = true; + new->filename = filespec->name; + new->filenames_sorted = filespec->sorted; } - new->section_name = section_name; - new->sections_sorted = sections_sorted; - new->filename = filename; - new->filenames_sorted = filenames_sorted; + new->section_list = section_list; new->keep_sections = keep_sections; lang_list_init (&new->children); } void lang_section_start (name, address) - CONST char *name; - etree_type * address; + const char *name; + etree_type *address; { - lang_address_statement_type *ad = new_stat (lang_address_statement, stat_ptr); + lang_address_statement_type *ad; + ad = new_stat (lang_address_statement, stat_ptr); ad->section_name = name; ad->address = address; } @@ -3829,7 +4388,7 @@ lang_section_start (name, address) void lang_add_entry (name, cmdline) - CONST char *name; + const char *name; boolean cmdline; { if (entry_symbol == NULL @@ -3843,7 +4402,7 @@ lang_add_entry (name, cmdline) void lang_add_target (name) - CONST char *name; + const char *name; { lang_target_statement_type *new = new_stat (lang_target_statement, stat_ptr); @@ -3854,13 +4413,13 @@ lang_add_target (name) void lang_add_map (name) - CONST char *name; + const char *name; { while (*name) { switch (*name) { - case 'F': + case 'F': map_option_f = true; break; } @@ -3869,13 +4428,13 @@ lang_add_map (name) } void -lang_add_fill (exp) - int exp; +lang_add_fill (fill) + fill_type *fill; { lang_fill_statement_type *new = new_stat (lang_fill_statement, stat_ptr); - new->fill = exp; + new->fill = fill; } void @@ -3908,7 +4467,7 @@ lang_add_reloc (reloc, howto, section, name, addend) union etree_union *addend; { lang_reloc_statement_type *p = new_stat (lang_reloc_statement, stat_ptr); - + p->reloc = reloc; p->howto = howto; p->section = section; @@ -3922,7 +4481,7 @@ lang_add_reloc (reloc, howto, section, name, addend) lang_assignment_statement_type * lang_add_assignment (exp) - etree_type * exp; + etree_type *exp; { lang_assignment_statement_type *new = new_stat (lang_assignment_statement, stat_ptr); @@ -3940,7 +4499,7 @@ lang_add_attribute (attribute) void lang_startup (name) - CONST char *name; + const char *name; { if (startup_file != (char *) NULL) { @@ -3960,24 +4519,57 @@ lang_float (maybe) lang_float_flag = maybe; } + +/* Work out the load- and run-time regions from a script statement, and + store them in *LMA_REGION and *REGION respectively. + + MEMSPEC is the name of the run-time region, or "*default*" if the + statement didn't specify one. LMA_MEMSPEC is the name of the + load-time region, or null if the statement didn't specify one. + HAVE_LMA_P is true if the statement had an explicit load address. + + It is an error to specify both a load region and a load address. */ + +static void +lang_get_regions (region, lma_region, memspec, lma_memspec, have_lma_p) + struct memory_region_struct **region, **lma_region; + const char *memspec, *lma_memspec; + int have_lma_p; +{ + *lma_region = lang_memory_region_lookup (lma_memspec); + + /* If no runtime region has been given, but the load region has + been, use the load region. */ + if (lma_memspec != 0 && strcmp (memspec, "*default*") == 0) + *region = *lma_region; + else + *region = lang_memory_region_lookup (memspec); + + if (have_lma_p && lma_memspec != 0) + einfo (_("%X%P:%S: section has both a load address and a load region\n")); +} + void -lang_leave_output_section_statement (fill, memspec, phdrs) - bfd_vma fill; +lang_leave_output_section_statement (fill, memspec, phdrs, lma_memspec) + fill_type *fill; const char *memspec; struct lang_output_section_phdr_list *phdrs; + const char *lma_memspec; { + lang_get_regions (¤t_section->region, + ¤t_section->lma_region, + memspec, lma_memspec, + current_section->load_base != 0); current_section->fill = fill; - current_section->region = lang_memory_region_lookup (memspec); current_section->phdrs = phdrs; stat_ptr = &statement_list; } -/* - Create an absolute symbol with the given name with the value of the - address of first byte of the section named. +/* Create an absolute symbol with the given name with the value of the + address of first byte of the section named. + + If the symbol already exists, then do nothing. */ - If the symbol already exists, then do nothing. -*/ void lang_abs_symbol_at_beginning_of (secname, name) const char *secname; @@ -4006,12 +4598,11 @@ lang_abs_symbol_at_beginning_of (secname, name) } } -/* - Create an absolute symbol with the given name with the value of the - address of the first byte after the end of the section named. +/* Create an absolute symbol with the given name with the value of the + address of the first byte after the end of the section named. + + If the symbol already exists, then do nothing. */ - If the symbol already exists, then do nothing. -*/ void lang_abs_symbol_at_end_of (secname, name) const char *secname; @@ -4035,7 +4626,8 @@ lang_abs_symbol_at_end_of (secname, name) h->u.def.value = 0; else h->u.def.value = (bfd_get_section_vma (output_bfd, sec) - + bfd_section_size (output_bfd, sec)); + + bfd_section_size (output_bfd, sec) / + bfd_octets_per_byte (output_bfd)); h->u.def.section = bfd_abs_section_ptr; } @@ -4043,9 +4635,9 @@ lang_abs_symbol_at_end_of (secname, name) void lang_statement_append (list, element, field) - lang_statement_list_type * list; - lang_statement_union_type * element; - lang_statement_union_type ** field; + lang_statement_list_type *list; + lang_statement_union_type *element; + lang_statement_union_type **field; { *(list->tail) = element; list->tail = field; @@ -4202,9 +4794,7 @@ lang_record_phdrs () lang_final_phase_enum); if (! bfd_record_phdr (output_bfd, l->type, - l->flags == NULL ? false : true, - flags, - l->at == NULL ? false : true, + l->flags != NULL, flags, l->at != NULL, at, l->filehdr, l->phdrs, c, secs)) einfo (_("%F%P: bfd_record_phdr failed: %E\n")); } @@ -4252,19 +4842,12 @@ lang_add_nocrossref (l) /* The overlay virtual address. */ static etree_type *overlay_vma; -/* The overlay load address. */ -static etree_type *overlay_lma; - -/* Whether nocrossrefs is set for this overlay. */ -static int overlay_nocrossrefs; - /* An expression for the maximum section size seen so far. */ static etree_type *overlay_max; /* A list of all the sections in this overlay. */ -struct overlay_list -{ +struct overlay_list { struct overlay_list *next; lang_output_section_statement_type *os; }; @@ -4274,24 +4857,18 @@ static struct overlay_list *overlay_list; /* Start handling an overlay. */ void -lang_enter_overlay (vma_expr, lma_expr, nocrossrefs) +lang_enter_overlay (vma_expr) etree_type *vma_expr; - etree_type *lma_expr; - int nocrossrefs; { /* The grammar should prevent nested overlays from occurring. */ - ASSERT (overlay_vma == NULL - && overlay_lma == NULL - && overlay_list == NULL - && overlay_max == NULL); + ASSERT (overlay_vma == NULL && overlay_max == NULL); overlay_vma = vma_expr; - overlay_lma = lma_expr; - overlay_nocrossrefs = nocrossrefs; } /* Start a section in an overlay. We handle this by calling - lang_enter_output_section_statement with the correct VMA and LMA. */ + lang_enter_output_section_statement with the correct VMA. + lang_leave_overlay sets up the LMA and memory regions. */ void lang_enter_overlay_section (name) @@ -4301,16 +4878,13 @@ lang_enter_overlay_section (name) etree_type *size; lang_enter_output_section_statement (name, overlay_vma, normal_section, - 0, 0, 0, overlay_lma); + 0, 0, 0, 0); - /* If this is the first section, then base the VMA and LMA of future + /* If this is the first section, then base the VMA of future sections on this one. This will work correctly even if `.' is used in the addresses. */ if (overlay_list == NULL) - { - overlay_vma = exp_nameop (ADDR, name); - overlay_lma = exp_nameop (LOADADDR, name); - } + overlay_vma = exp_nameop (ADDR, name); /* Remember the section. */ n = (struct overlay_list *) xmalloc (sizeof *n); @@ -4320,9 +4894,6 @@ lang_enter_overlay_section (name) size = exp_nameop (SIZEOF, name); - /* Adjust the LMA for the next section. */ - overlay_lma = exp_binop ('+', overlay_lma, size); - /* Arrange to work out the maximum section end address. */ if (overlay_max == NULL) overlay_max = size; @@ -4335,7 +4906,7 @@ lang_enter_overlay_section (name) void lang_leave_overlay_section (fill, phdrs) - bfd_vma fill; + fill_type *fill; struct lang_output_section_phdr_list *phdrs; { const char *name; @@ -4345,14 +4916,17 @@ lang_leave_overlay_section (fill, phdrs) name = current_section->name; - lang_leave_output_section_statement (fill, "*default*", phdrs); + /* For now, assume that "*default*" is the run-time memory region and + that no load-time region has been specified. It doesn't really + matter what we say here, since lang_leave_overlay will override it. */ + lang_leave_output_section_statement (fill, "*default*", phdrs, 0); /* Define the magic symbols. */ clean = xmalloc (strlen (name) + 1); s2 = clean; for (s1 = name; *s1 != '\0'; s1++) - if (isalnum ((unsigned char) *s1) || *s1 == '_') + if (ISALNUM (*s1) || *s1 == '_') *s2++ = *s1; *s2 = '\0'; @@ -4375,35 +4949,57 @@ lang_leave_overlay_section (fill, phdrs) looks through all the sections in the overlay and sets them. */ void -lang_leave_overlay (fill, memspec, phdrs) - bfd_vma fill; +lang_leave_overlay (lma_expr, nocrossrefs, fill, memspec, phdrs, lma_memspec) + etree_type *lma_expr; + int nocrossrefs; + fill_type *fill; const char *memspec; struct lang_output_section_phdr_list *phdrs; + const char *lma_memspec; { lang_memory_region_type *region; + lang_memory_region_type *lma_region; struct overlay_list *l; struct lang_nocrossref *nocrossref; - if (memspec == NULL) - region = NULL; - else - region = lang_memory_region_lookup (memspec); + lang_get_regions (®ion, &lma_region, + memspec, lma_memspec, + lma_expr != 0); nocrossref = NULL; + /* After setting the size of the last section, set '.' to end of the + overlay region. */ + if (overlay_list != NULL) + overlay_list->os->update_dot_tree + = exp_assop ('=', ".", exp_binop ('+', overlay_vma, overlay_max)); + l = overlay_list; while (l != NULL) { struct overlay_list *next; - if (fill != 0 && l->os->fill == 0) + if (fill != (fill_type *) 0 && l->os->fill == (fill_type *) 0) l->os->fill = fill; - if (region != NULL && l->os->region == NULL) - l->os->region = region; + + l->os->region = region; + l->os->lma_region = lma_region; + + /* The first section has the load address specified in the + OVERLAY statement. The rest are worked out from that. + The base address is not needed (and should be null) if + an LMA region was specified. */ + if (l->next == 0) + l->os->load_base = lma_expr; + else if (lma_region == 0) + l->os->load_base = exp_binop ('+', + exp_nameop (LOADADDR, l->next->os->name), + exp_nameop (SIZEOF, l->next->os->name)); + if (phdrs != NULL && l->os->phdrs == NULL) l->os->phdrs = phdrs; - if (overlay_nocrossrefs) + if (nocrossrefs) { struct lang_nocrossref *nc; @@ -4421,13 +5017,7 @@ lang_leave_overlay (fill, memspec, phdrs) if (nocrossref != NULL) lang_add_nocrossref (nocrossref); - /* Update . for the end of the overlay. */ - lang_add_assignment (exp_assop ('=', ".", - exp_binop ('+', overlay_vma, overlay_max))); - overlay_vma = NULL; - overlay_lma = NULL; - overlay_nocrossrefs = 0; overlay_list = NULL; overlay_max = NULL; } @@ -4438,19 +5028,98 @@ lang_leave_overlay (fill, memspec, phdrs) struct bfd_elf_version_tree *lang_elf_version_info; +static int +lang_vers_match_lang_c (expr, sym) + struct bfd_elf_version_expr *expr; + const char *sym; +{ + if (expr->pattern[0] == '*' && expr->pattern[1] == '\0') + return 1; + return fnmatch (expr->pattern, sym, 0) == 0; +} + +static int +lang_vers_match_lang_cplusplus (expr, sym) + struct bfd_elf_version_expr *expr; + const char *sym; +{ + char *alt_sym; + int result; + + if (expr->pattern[0] == '*' && expr->pattern[1] == '\0') + return 1; + + alt_sym = cplus_demangle (sym, /* DMGL_NO_TPARAMS */ 0); + if (!alt_sym) + { + /* cplus_demangle (also) returns NULL when it is not a C++ symbol. + Should we early out false in this case? */ + result = fnmatch (expr->pattern, sym, 0) == 0; + } + else + { + result = fnmatch (expr->pattern, alt_sym, 0) == 0; + free (alt_sym); + } + + return result; +} + +static int +lang_vers_match_lang_java (expr, sym) + struct bfd_elf_version_expr *expr; + const char *sym; +{ + char *alt_sym; + int result; + + if (expr->pattern[0] == '*' && expr->pattern[1] == '\0') + return 1; + + alt_sym = cplus_demangle (sym, DMGL_JAVA); + if (!alt_sym) + { + /* cplus_demangle (also) returns NULL when it is not a Java symbol. + Should we early out false in this case? */ + result = fnmatch (expr->pattern, sym, 0) == 0; + } + else + { + result = fnmatch (expr->pattern, alt_sym, 0) == 0; + free (alt_sym); + } + + return result; +} + /* This is called for each variable name or match expression. */ struct bfd_elf_version_expr * -lang_new_vers_regex (orig, new) +lang_new_vers_pattern (orig, new, lang) struct bfd_elf_version_expr *orig; const char *new; + const char *lang; { struct bfd_elf_version_expr *ret; ret = (struct bfd_elf_version_expr *) xmalloc (sizeof *ret); ret->next = orig; - ret->match = new; - return ret; + ret->pattern = new; + + if (lang == NULL || strcasecmp (lang, "C") == 0) + ret->match = lang_vers_match_lang_c; + else if (strcasecmp (lang, "C++") == 0) + ret->match = lang_vers_match_lang_cplusplus; + else if (strcasecmp (lang, "Java") == 0) + ret->match = lang_vers_match_lang_java; + else + { + einfo (_("%X%P: unknown language `%s' in version information\n"), + lang); + ret->match = lang_vers_match_lang_c; + } + + return ldemul_new_vers_pattern (ret); } /* This is called for each set of variable names and match @@ -4491,6 +5160,16 @@ lang_register_vers_node (name, version, deps) struct bfd_elf_version_tree *t, **pp; struct bfd_elf_version_expr *e1; + if (name == NULL) + name = ""; + + if ((name[0] == '\0' && lang_elf_version_info != NULL) + || (lang_elf_version_info && lang_elf_version_info->name[0] == '\0')) + { + einfo (_("%X%P: anonymous version tag cannot be combined with other version tags\n")); + return; + } + /* Make sure this node has a unique name. */ for (t = lang_elf_version_info; t != NULL; t = t->next) if (strcmp (t->name, name) == 0) @@ -4506,9 +5185,9 @@ lang_register_vers_node (name, version, deps) struct bfd_elf_version_expr *e2; for (e2 = t->locals; e2 != NULL; e2 = e2->next) - if (strcmp (e1->match, e2->match) == 0) + if (strcmp (e1->pattern, e2->pattern) == 0) einfo (_("%X%P: duplicate expression `%s' in version information\n"), - e1->match); + e1->pattern); } } @@ -4519,16 +5198,21 @@ lang_register_vers_node (name, version, deps) struct bfd_elf_version_expr *e2; for (e2 = t->globals; e2 != NULL; e2 = e2->next) - if (strcmp (e1->match, e2->match) == 0) + if (strcmp (e1->pattern, e2->pattern) == 0) einfo (_("%X%P: duplicate expression `%s' in version information\n"), - e1->match); + e1->pattern); } } version->deps = deps; version->name = name; - ++version_index; - version->vernum = version_index; + if (name[0] != '\0') + { + ++version_index; + version->vernum = version_index; + } + else + version->vernum = 0; for (pp = &lang_elf_version_info; *pp != NULL; pp = &(*pp)->next) ; @@ -4574,27 +5258,44 @@ lang_do_version_exports_section () bfd_size_type len; if (sec == NULL) - continue; + continue; len = bfd_section_size (is->the_bfd, sec); contents = xmalloc (len); if (!bfd_get_section_contents (is->the_bfd, sec, contents, 0, len)) - einfo (_("%X%P: unable to read .exports section contents"), sec); + einfo (_("%X%P: unable to read .exports section contents\n"), sec); - while (p < contents+len) + p = contents; + while (p < contents + len) { - greg = lang_new_vers_regex (greg, p); + greg = lang_new_vers_pattern (greg, p, NULL); p = strchr (p, '\0') + 1; } - free (contents); + /* Do not free the contents, as we used them creating the regex. */ /* Do not include this section in the link. */ bfd_set_section_flags (is->the_bfd, sec, bfd_get_section_flags (is->the_bfd, sec) | SEC_EXCLUDE); } - lreg = lang_new_vers_regex (NULL, "*"); + lreg = lang_new_vers_pattern (NULL, "*", NULL); lang_register_vers_node (command_line.version_exports_section, lang_new_vers_node (greg, lreg), NULL); } + +void +lang_add_unique (name) + const char *name; +{ + struct unique_sections *ent; + + for (ent = unique_section_list; ent; ent = ent->next) + if (strcmp (ent->name, name) == 0) + return; + + ent = (struct unique_sections *) xmalloc (sizeof *ent); + ent->name = xstrdup (name); + ent->next = unique_section_list; + unique_section_list = ent; +}