X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=ld%2Fldlang.c;h=eab4b5f6394f6fcb88fcc190c11cd4506b75891d;hb=feb129926a8d12656f1ca4b7a8bb10268d3af4fb;hp=2106b3e90874f82e5ae22570c52e56ca28bac758;hpb=ae2a2f6cc2e2eb1c8221837814f3a4251de2af13;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/ldlang.c b/ld/ldlang.c index 2106b3e908..eab4b5f639 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -1,5 +1,5 @@ /* Linker command language support. - Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 1998 + Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc. This file is part of GLD, the Gnu Linker. @@ -36,6 +36,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "ldctor.h" #include "ldfile.h" #include "fnmatch.h" +#include "demangle.h" #include @@ -76,16 +77,9 @@ 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, @@ -141,22 +135,34 @@ static int topower PARAMS ((int)); static void lang_set_startof PARAMS ((void)); static void reset_memory_regions PARAMS ((void)); static void lang_record_phdrs PARAMS ((void)); -static void lang_gc_wild_section - PARAMS ((lang_wild_statement_type *, const char *, - lang_input_statement_type *)); -static void lang_gc_wild_file - PARAMS ((lang_wild_statement_type *, const char *, - lang_input_statement_type *)); static void lang_gc_wild PARAMS ((lang_wild_statement_type *, const char *, const char *)); static void lang_gc_sections_1 PARAMS ((lang_statement_union_type *)); static void lang_gc_sections PARAMS ((void)); - +static void lang_do_version_exports_section PARAMS ((void)); +static void lang_check_section_addresses PARAMS ((void)); +typedef void (*callback_t) PARAMS ((lang_wild_statement_type *, + asection *, lang_input_statement_type *, + void *)); +static void walk_wild_section + PARAMS ((lang_wild_statement_type *, const char *, + lang_input_statement_type *, callback_t, void *)); +static void walk_wild_file + PARAMS ((lang_wild_statement_type *, const char *, + lang_input_statement_type *, callback_t, void *)); + +static int get_target PARAMS ((const bfd_target *, void *)); +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 *, void *)); +static char * get_first_input_target PARAMS ((void)); + /* EXPORTS */ lang_output_section_statement_type *abs_output_section; 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; boolean entry_from_cmdline; boolean lang_has_input_file = false; @@ -189,6 +195,138 @@ stat_alloc (size) return obstack_alloc (&stat_obstack, size); } +/*---------------------------------------------------------------------- + Generic traversal routines for finding matching sections. +*/ + +static void +walk_wild_section (ptr, section, file, callback, data) + lang_wild_statement_type *ptr; + const char *section; + lang_input_statement_type *file; + callback_t callback; + void *data; +{ + /* Don't process sections from files which were excluded. */ + if (ptr->exclude_filename != NULL) + { + boolean match; + + if (wildcardp (ptr->exclude_filename)) + match = fnmatch (ptr->exclude_filename, file->filename, 0) == 0 ? true : false; + else + match = strcmp (ptr->exclude_filename, file->filename) == 0 ? true : false; + + if (match) + return; + } + + 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) + (*callback) (ptr, s, file, data); + } + } +} + +/* Handle a wild statement for a single file F. */ + +static void +walk_wild_file (s, section, f, callback, data) + lang_wild_statement_type *s; + const char *section; + lang_input_statement_type *f; + callback_t callback; + void *data; +{ + if (f->the_bfd == NULL + || ! bfd_check_format (f->the_bfd, bfd_archive)) + walk_wild_section (s, section, 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, section, + (lang_input_statement_type *) member->usrdata, + callback, data); + } + + member = bfd_openr_next_archived_file (f->the_bfd, member); + } + } +} + +static void +walk_wild (s, section, file, callback, data) + lang_wild_statement_type *s; + const char *section; + const char *file; + callback_t callback; + void *data; +{ + if (file == (char *) NULL) + { + /* Perform the iteration over all files in the list. */ + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + walk_wild_file (s, section, f, callback, data); + } + } + else if (wildcardp (file)) + { + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + if (fnmatch (file, f->filename, FNM_FILE_NAME) == 0) + walk_wild_file (s, section, f, callback, data); + } + } + else + { + lang_input_statement_type *f; + + /* Perform the iteration over a single file. */ + f = lookup_name (file); + walk_wild_file (s, section, f, callback, data); + } +} + /*---------------------------------------------------------------------- lang_for_each_statement walks the parse tree and calls the provided function for each node @@ -760,6 +898,23 @@ section_already_linked (abfd, sec, data) if ((flags & SEC_LINK_ONCE) == 0) return; + /* FIXME: When doing a relocateable 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 relocateable 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 relocateable link + causes trouble for MIPS ELF, which relies in 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) @@ -953,6 +1108,10 @@ wild_doit (ptr, section, output, file) break; } + /* Copy over SEC_SHORT. */ + if (section->flags & SEC_SHORT) + section->output_section->flags |= SEC_SHORT; + if (section->alignment_power > output->bfd_section->alignment_power) output->bfd_section->alignment_power = section->alignment_power; @@ -1067,89 +1226,53 @@ 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, section, file, output) lang_wild_statement_type *ptr; - const char *section; + asection *section; lang_input_statement_type *file; - lang_output_section_statement_type *output; + void *output; { - if (file->just_syms_flag == false) + lang_statement_union_type *before; + + /* 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, 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. */ + + if (before == NULL) + wild_doit (&ptr->children, section, + (lang_output_section_statement_type *) output, + file); + else { - 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) + lang_statement_list_type list; + lang_statement_union_type **pp; + + lang_list_init (&list); + wild_doit (&list, section, + (lang_output_section_statement_type *) output, + file); + + /* If we are discarding the section, LIST.HEAD will + be NULL. */ + if (list.head != NULL) { - 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; - } - - if (match) - { - lang_statement_union_type *before; - - /* If the wild pattern was marked KEEP, the member sections - should be as well. */ - if (ptr->keep_sections) - s->flags |= SEC_KEEP; - - before = wild_sort (ptr, file, s); - - /* Here BEFORE points to the lang_input_section which - 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; - - lang_list_init (&list); - wild_doit (&list, s, output, file); - - /* If we are discarding the section, LIST.HEAD will - be NULL. */ - if (list.head != NULL) - { - ASSERT (list.head->next == NULL); - - for (pp = &ptr->children.head; - *pp != before; - pp = &(*pp)->next) - ASSERT (*pp != NULL); - - list.head->next = *pp; - *pp = list.head; - } - } - } + ASSERT (list.head->next == NULL); + + for (pp = &ptr->children.head; + *pp != before; + pp = &(*pp)->next) + ASSERT (*pp != NULL); + + list.head->next = *pp; + *pp = list.head; } } } @@ -1253,6 +1376,9 @@ load_symbols (entry, place) return; } + if (ldemul_recognized_file (entry)) + return; + /* We don't call ldlang_add_file for an archive. Instead, the add_symbols entry point will call ldlang_add_file, via the add_archive_element callback, for each element of the archive @@ -1299,43 +1425,7 @@ load_symbols (entry, place) entry->loaded = true; } -/* Handle a wild statement for a single file F. */ - -static void -wild_file (s, section, f, output) - lang_wild_statement_type *s; - const char *section; - lang_input_statement_type *f; - 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; - - /* 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); - } - - member = bfd_openr_next_archived_file (f->the_bfd, member); - } - } -} + /* Handle a wild statement. SECTION or FILE or both may be NULL, indicating that it is a wildcard. Separate lang_input_section @@ -1347,71 +1437,249 @@ wild (s, section, file, target, output) lang_wild_statement_type *s; const char *section; const char *file; - const char *target; + const char *target ATTRIBUTE_UNUSED; lang_output_section_statement_type *output; { - lang_input_statement_type *f; + walk_wild (s, section, file, output_section_callback, (void *) output); - if (file == (char *) NULL) + if (section != (char *) NULL + && strcmp (section, "COMMON") == 0 + && default_common_section == 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); - } + /* 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; } - else if (wildcardp (file)) +} + +/* Return true iff target is the sought target. */ +static int +get_target (target, data) + const bfd_target * target; + void * data; +{ + const char * sought = (const char *) data; + + return strcmp (target->name, sought) == 0; +} + +/* Like strcpy() but convert to lower case as well. */ +static void +stricpy (dest, src) + char * dest; + char * src; +{ + char c; + + while ((c = * src ++) != 0) { - 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); - } + if (isupper ((unsigned char) c)) + c = tolower (c); + + * dest ++ = c; } - else + + * 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) { - /* Perform the iteration over a single file */ - f = lookup_name (file); - wild_file (s, section, f, output); + char * src; + + for (src = haystack + strlen (needle); * src;) + * haystack ++ = * src ++; + + * haystack = 0; } +} - if (section != (char *) NULL - && strcmp (section, "COMMON") == 0 - && default_common_section == NULL) +/* 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; + void * 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) { - /* 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; + winner = target; + return 0; + } + + /* 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) + { + 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. */ static bfd * open_output (name) - const char *name; + const char * name; { - bfd *output; + 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; + int desired_endian; + + /* Get the chosen target. */ + target = bfd_search_for_target (get_target, (void *) output_target); + + 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, (void *) 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); } @@ -1434,9 +1702,6 @@ open_output (name) return output; } - - - static void ldlang_open_output (statement) lang_statement_union_type * statement; @@ -1513,7 +1778,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; @@ -1762,7 +2027,7 @@ 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) + if (result.valid_p) minfo ("0x%V", result.value + result.section->bfd_section->vma); else { @@ -2022,6 +2287,8 @@ print_wild_statement (w, os) if (w->filenames_sorted) minfo ("SORT("); + if (w->exclude_filename != NULL) + minfo ("EXCLUDE_FILE ( %s )", w->exclude_filename); if (w->filename != NULL) minfo ("%s", w->filename); else @@ -2089,7 +2356,10 @@ print_statement (s, os) case lang_constructors_statement_enum: if (constructor_list.head != NULL) { - minfo (" CONSTRUCTORS\n"); + if (constructors_sorted) + minfo (" SORT (CONSTRUCTORS)\n"); + else + minfo (" CONSTRUCTORS\n"); print_statement_list (constructor_list.head, os); } break; @@ -2231,7 +2501,7 @@ size_input_section (this_ptr, output_section_statement, fill, dot, relax) lang_output_section_statement_type * output_section_statement; fill_type fill; bfd_vma dot; - boolean relax; + boolean relax ATTRIBUTE_UNUSED; { lang_input_section_type *is = &((*this_ptr)->input_section); asection *i = is->section; @@ -2265,363 +2535,424 @@ size_input_section (this_ptr, output_section_statement, fill, dot, relax) return dot; } +/* 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; + + /* 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; + + /* 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; + } + } +} + /* This variable indicates whether bfd_relax_section should be called again. */ -static boolean relax_again; +static boolean relax_again; + +/* 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; + bfd_vma dot; + boolean relax; +{ + /* Size up the sections from their constituent parts. */ + for (; s != (lang_statement_union_type *) NULL; s = s->next) + { + switch (s->header.type) + { + case lang_output_section_statement_enum: + { + bfd_vma after; + lang_output_section_statement_type *os = &s->output_section_statement; + + if (os->bfd_section == NULL) + /* This section was never actually created. */ + 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; + + if (os->children.head == NULL + || os->children.head->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); + + input = os->children.head->input_section.section; + bfd_set_section_vma (os->bfd_section->owner, + os->bfd_section, + bfd_section_vma (input->owner, input)); + os->bfd_section->_raw_size = input->_raw_size; + break; + } + + if (bfd_is_abs_section (os->bfd_section)) + { + /* No matter what happens, an abs section starts at zero. */ + ASSERT (os->bfd_section->vma == 0); + } + else + { + if (os->addr_tree == (etree_type *) NULL) + { + /* No address specified for this section, get one + from the region specification. */ + if (os->region == (lang_memory_region_type *) NULL + || (((bfd_get_section_flags (output_bfd, os->bfd_section) + & (SEC_ALLOC | SEC_LOAD)) != 0) + && os->region->name[0] == '*' + && strcmp (os->region->name, "*default*") == 0)) + { + os->region = lang_memory_default (os->bfd_section); + } + + /* If a loadable section is using the default memory + region, and some non default memory regions were + defined, issue a warning. */ + if ((bfd_get_section_flags (output_bfd, os->bfd_section) + & (SEC_ALLOC | SEC_LOAD)) != 0 + && ! link_info.relocateable + && strcmp (os->region->name, "*default*") == 0 + && lang_memory_region_list != NULL + && (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)); + + dot = os->region->current; + + if (os->section_alignment == -1) + { + bfd_vma olddot; + + olddot = dot; + 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"), + os->name, (unsigned int) (dot - olddot)); + } + } + else + { + etree_value_type r; + + r = exp_fold_tree (os->addr_tree, + abs_output_section, + lang_allocating_phase_enum, + dot, &dot); + 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. */ + + if (os->section_alignment != -1) + 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. */ + + after = ALIGN_N (os->bfd_section->vma + + os->bfd_section->_raw_size, + /* 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 + os->bfd_section->_raw_size = after - os->bfd_section->vma; + dot = os->bfd_section->vma + os->bfd_section->_raw_size; + os->processed = true; + + /* 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. */ + if (os->region != (lang_memory_region_type *) NULL + && (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)) + { + 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; + } + } + } + break; -/* Set the sizes for all the output sections. */ + case lang_constructors_statement_enum: + dot = lang_size_sections (constructor_list.head, + output_section_statement, + &s->wild_statement.children.head, + fill, + dot, relax); + break; -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; -{ - /* Size up the sections from their constituent parts */ - for (; s != (lang_statement_union_type *) NULL; s = s->next) - { - switch (s->header.type) - { + case lang_data_statement_enum: + { + unsigned int size = 0; - case lang_output_section_statement_enum: - { - bfd_vma after; - lang_output_section_statement_type *os = &s->output_section_statement; - - if (os->bfd_section == NULL) - { - /* This section was never actually created. */ - 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; - - if (os->children.head == NULL - || os->children.head->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); - - input = os->children.head->input_section.section; - bfd_set_section_vma (os->bfd_section->owner, - os->bfd_section, - bfd_section_vma (input->owner, input)); - os->bfd_section->_raw_size = input->_raw_size; - break; - } - - if (bfd_is_abs_section (os->bfd_section)) - { - /* No matter what happens, an abs section starts at zero */ - ASSERT (os->bfd_section->vma == 0); - } - else - { - if (os->addr_tree == (etree_type *) NULL) - { - /* No address specified for this section, get one - from the region specification - */ - if (os->region == (lang_memory_region_type *) NULL - || (((bfd_get_section_flags (output_bfd, os->bfd_section) - & (SEC_ALLOC | SEC_LOAD)) != 0) - && os->region->name[0] == '*' - && strcmp (os->region->name, "*default*") == 0)) - { - os->region = lang_memory_default (os->bfd_section); - } - - /* If a loadable section is using the default memory - region, and some non default memory regions were - defined, issue a warning. */ - if ((bfd_get_section_flags (output_bfd, os->bfd_section) - & (SEC_ALLOC | SEC_LOAD)) != 0 - && ! link_info.relocateable - && strcmp (os->region->name, "*default*") == 0 - && lang_memory_region_list != NULL - && (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)); - - dot = os->region->current; - if (os->section_alignment == -1) - { - bfd_vma olddot; - - olddot = dot; - 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"), - os->name, (unsigned int) (dot - olddot)); - } - } - else - { - etree_value_type r; - - r = exp_fold_tree (os->addr_tree, - abs_output_section, - lang_allocating_phase_enum, - dot, &dot); - if (r.valid == 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 */ - - if (os->section_alignment != -1) - 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 */ - - after = ALIGN_N (os->bfd_section->vma + - os->bfd_section->_raw_size, - /* 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 - os->bfd_section->_raw_size = after - os->bfd_section->vma; - dot = os->bfd_section->vma + os->bfd_section->_raw_size; - os->processed = true; - - /* Replace into region ? */ - if (os->region != (lang_memory_region_type *) NULL) - { - 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)) - { - 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; - } - } - } - break; - - case lang_constructors_statement_enum: - dot = lang_size_sections (constructor_list.head, - output_section_statement, - &s->wild_statement.children.head, - fill, - dot, relax); - break; + s->data_statement.output_vma = dot - output_section_statement->bfd_section->vma; + s->data_statement.output_section = + output_section_statement->bfd_section; - 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_section = - output_section_statement->bfd_section; - - switch (s->data_statement.type) - { - 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; - } - - dot += size; - 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; - } - } - break; + switch (s->data_statement.type) + { + 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; + } - case lang_reloc_statement_enum: - { - int size; - - s->reloc_statement.output_vma = - dot - output_section_statement->bfd_section->vma; - s->reloc_statement.output_section = - output_section_statement->bfd_section; - size = bfd_get_reloc_size (s->reloc_statement.howto); - dot += size; - output_section_statement->bfd_section->_raw_size += size; - } - break; - - case lang_wild_statement_enum: + dot += size; + 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; + } + } + break; - dot = lang_size_sections (s->wild_statement.children.head, - output_section_statement, - &s->wild_statement.children.head, + case lang_reloc_statement_enum: + { + int size; + + s->reloc_statement.output_vma = + dot - output_section_statement->bfd_section->vma; + s->reloc_statement.output_section = + output_section_statement->bfd_section; + size = bfd_get_reloc_size (s->reloc_statement.howto); + dot += size; + output_section_statement->bfd_section->_raw_size += size; + } + break; + + case lang_wild_statement_enum: - fill, dot, relax); + dot = lang_size_sections (s->wild_statement.children.head, + output_section_statement, + &s->wild_statement.children.head, - break; + fill, dot, relax); - case lang_object_symbols_statement_enum: - link_info.create_object_symbols_section = - output_section_statement->bfd_section; - break; - case lang_output_statement_enum: - case lang_target_statement_enum: - break; - case lang_input_section_enum: - { - asection *i; + break; - i = (*prev)->input_section.section; - if (! relax) + case lang_object_symbols_statement_enum: + link_info.create_object_symbols_section = + output_section_statement->bfd_section; + break; + case lang_output_statement_enum: + case lang_target_statement_enum: + break; + case lang_input_section_enum: { - if (i->_cooked_size == 0) - i->_cooked_size = i->_raw_size; + asection *i; + + i = (*prev)->input_section.section; + if (! relax) + { + if (i->_cooked_size == 0) + i->_cooked_size = i->_raw_size; + } + else + { + boolean again; + + if (! bfd_relax_section (i->owner, i, &link_info, &again)) + einfo (_("%P%F: can't relax section: %E\n")); + if (again) + relax_again = true; + } + dot = size_input_section (prev, + output_section_statement, + output_section_statement->fill, + dot, relax); } - else + break; + case lang_input_statement_enum: + break; + case lang_fill_statement_enum: + s->fill_statement.output_section = output_section_statement->bfd_section; + + fill = s->fill_statement.fill; + break; + case lang_assignment_statement_enum: { - boolean again; + bfd_vma newdot = dot; + + exp_fold_tree (s->assignment_statement.exp, + output_section_statement, + lang_allocating_phase_enum, + dot, + &newdot); + + 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) + { + 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; + } - if (! bfd_relax_section (i->owner, i, &link_info, &again)) - einfo (_("%P%F: can't relax section: %E\n")); - if (again) - relax_again = true; + dot = newdot; + } } - dot = size_input_section (prev, - output_section_statement, - output_section_statement->fill, - dot, relax); - } - break; - case lang_input_statement_enum: - break; - case lang_fill_statement_enum: - s->fill_statement.output_section = output_section_statement->bfd_section; + break; - fill = s->fill_statement.fill; - break; - case lang_assignment_statement_enum: - { - bfd_vma newdot = dot; - - exp_fold_tree (s->assignment_statement.exp, - output_section_statement, - lang_allocating_phase_enum, - dot, - &newdot); - - 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) - { - 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; - } - - dot = newdot; - } - } - 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; - 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); - break; - - default: - FAIL (); - 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; + break; - /* This can only get here when relaxing is turned on */ + 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); + break; - case lang_address_statement_enum: - break; + default: + FAIL (); + break; + + /* This can only get here when relaxing is turned on. */ + + case lang_address_statement_enum: + break; + } + prev = &s->header.next; } - prev = &s->header.next; - } return dot; } @@ -2690,7 +3021,7 @@ 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) @@ -2719,7 +3050,7 @@ 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); @@ -2901,10 +3232,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. */ @@ -3085,11 +3416,7 @@ 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; @@ -3150,21 +3477,18 @@ lang_place_orphans () void -lang_set_flags (ptr, flags) +lang_set_flags (ptr, flags, invert) lang_memory_region_type *ptr; 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; @@ -3217,11 +3541,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); } @@ -3235,13 +3555,9 @@ void lang_for_each_input_section (func) 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; + asection * s; for (s = f->the_bfd->sections; s != (asection *) NULL; @@ -3400,90 +3716,20 @@ reset_memory_regions () } } -/* ??? At some point this traversal for GC should share code with the - traversal for manipulating the output file. */ - /* Expand a wild statement for a particular FILE, marking its sections KEEP as needed. SECTION may be NULL, in which case it is a wild card. */ static void -lang_gc_wild_section (ptr, section, file) +gc_section_callback (ptr, section, file, data) lang_wild_statement_type *ptr; - const char *section; - lang_input_statement_type *file; -{ - if (file->just_syms_flag == false) - { - register asection *s; - boolean wildcard; - - if (section == NULL) - wildcard = false; - else - wildcard = wildcardp (section); - - for (s = file->the_bfd->sections; s != NULL; s = s->next) - { - boolean match; - - if (section == NULL) - match = true; - else - { - const char *name; - - name = bfd_get_section_name (file->the_bfd, s); - if (wildcard) - match = fnmatch (section, name, 0) == 0 ? true : false; - else - match = strcmp (section, name) == 0 ? true : false; - } - - if (match) - { - /* If the wild pattern was marked KEEP, the member sections - should be as well. */ - if (ptr->keep_sections) - s->flags |= SEC_KEEP; - } - } - } -} - -/* Handle a wild statement for a single file F. */ - -static void -lang_gc_wild_file (s, section, f) - lang_wild_statement_type *s; - const char *section; - lang_input_statement_type *f; + asection *section; + lang_input_statement_type *file ATTRIBUTE_UNUSED; + void *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 the wild pattern was marked KEEP, the member sections + should be as well. */ + if (ptr->keep_sections) + section->flags |= SEC_KEEP; } /* Handle a wild statement, marking it against GC. SECTION or FILE or both @@ -3495,34 +3741,7 @@ lang_gc_wild (s, section, file) 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, section, file, gc_section_callback, NULL); } /* Iterate over sections marking them against GC. */ @@ -3549,6 +3768,8 @@ lang_gc_sections_1 (s) case lang_group_statement_enum: lang_gc_sections_1 (s->group_statement.children.head); break; + default: + break; } } } @@ -3565,11 +3786,17 @@ lang_gc_sections () /* Keep all sections containing symbols undefined on the command-line. Handle the entry symbol at the same time. */ + + 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; - fake_list_start.next = ldlang_undef_chain_list_head; - fake_list_start.name = entry_symbol; - - for (ulist = &fake_list_start; ulist; ulist = ulist->next) + for (; ulist; ulist = ulist->next) { h = bfd_link_hash_lookup (link_info.hash, ulist->name, false, false, false); @@ -3612,6 +3839,10 @@ lang_process () link. */ lang_check (); + /* Handle .exports instead of a version script if we're told to do so. */ + if (command_line.version_exports_section) + lang_do_version_exports_section (); + /* Build all sets based on the information gathered from the input files. */ ldctor_build_sets (); @@ -3655,6 +3886,10 @@ lang_process () 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 */ + /* Do all the assignments with our current guesses as to section sizes. */ lang_do_assignments (statement_list.head, @@ -3691,6 +3926,11 @@ lang_process () abs_output_section, (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 */ ldemul_finish (); @@ -3701,12 +3941,13 @@ lang_process () void lang_add_wild (section_name, sections_sorted, filename, filenames_sorted, - keep_sections) + keep_sections, exclude_filename) const char *const section_name; boolean sections_sorted; const char *const filename; boolean filenames_sorted; boolean keep_sections; + const char *exclude_filename; { lang_wild_statement_type *new = new_stat (lang_wild_statement, stat_ptr); @@ -3715,7 +3956,7 @@ lang_add_wild (section_name, sections_sorted, filename, filenames_sorted, { placed_commons = true; } - if (filename != (char *) NULL) + if (filename != NULL && ! wildcardp (filename)) { lang_has_input_file = true; } @@ -3724,6 +3965,7 @@ lang_add_wild (section_name, sections_sorted, filename, filenames_sorted, new->filename = filename; new->filenames_sorted = filenames_sorted; new->keep_sections = keep_sections; + new->exclude_filename = exclude_filename; lang_list_init (&new->children); } @@ -3836,7 +4078,7 @@ lang_add_reloc (reloc, howto, section, name, addend) p->output_vma = 0; } -void +lang_assignment_statement_type * lang_add_assignment (exp) etree_type * exp; { @@ -3844,6 +4086,7 @@ lang_add_assignment (exp) stat_ptr); new->exp = exp; + return new; } void @@ -4353,18 +4596,97 @@ 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_regex (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; + 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 ret; } @@ -4421,9 +4743,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); } } @@ -4434,9 +4756,9 @@ 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); } } @@ -4476,3 +4798,41 @@ lang_add_vers_depend (list, name) return ret; } + +static void +lang_do_version_exports_section () +{ + struct bfd_elf_version_expr *greg = NULL, *lreg; + + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + asection *sec = bfd_get_section_by_name (is->the_bfd, ".exports"); + char *contents, *p; + bfd_size_type len; + + if (sec == NULL) + 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); + + p = contents; + while (p < contents+len) + { + greg = lang_new_vers_regex (greg, p, NULL); + p = strchr (p, '\0') + 1; + } + + /* 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, "*", NULL); + lang_register_vers_node (command_line.version_exports_section, + lang_new_vers_node (greg, lreg), NULL); +}