summaryrefslogtreecommitdiffstats
path: root/contrib/binutils/ld/ldlang.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/binutils/ld/ldlang.c')
-rw-r--r--contrib/binutils/ld/ldlang.c2165
1 files changed, 1538 insertions, 627 deletions
diff --git a/contrib/binutils/ld/ldlang.c b/contrib/binutils/ld/ldlang.c
index 6cdab2b..d40ff07 100644
--- a/contrib/binutils/ld/ldlang.c
+++ b/contrib/binutils/ld/ldlang.c
@@ -1,12 +1,12 @@
/* Linker command language support.
- Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 1998
+ Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000
Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 1, or (at your option)
+the Free Software Foundation; either version 2, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
@@ -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 <ctype.h>
@@ -72,17 +73,18 @@ static lang_input_statement_type *new_afile
static void init_os PARAMS ((lang_output_section_statement_type *s));
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 *string));
+static void already_linked_table_init PARAMS ((void));
+static void already_linked_table_free PARAMS ((void));
static boolean wildcardp PARAMS ((const char *));
-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_statement_union_type *wild_sort
+ PARAMS ((lang_wild_statement_type *, lang_input_statement_type *,
+ asection *));
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,
@@ -138,11 +140,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
+ 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;
@@ -176,6 +201,142 @@ stat_alloc (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_list != NULL)
+ {
+ struct name_list *list_tmp;
+ for (list_tmp = ptr->exclude_filename_list; list_tmp; list_tmp = list_tmp->next)
+ {
+ boolean match;
+
+ if (wildcardp (list_tmp->name))
+ match = fnmatch (list_tmp->name, file->filename, 0) == 0 ? true : false;
+ else
+ match = strcmp (list_tmp->name, 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
*/
@@ -521,6 +682,7 @@ 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->lma_region = (lang_memory_region_type *) NULL;
lookup->fill = 0;
lookup->block_value = 1;
lookup->name = name;
@@ -571,9 +733,9 @@ lang_map ()
{
lang_memory_region_type *m;
- minfo ("\nMemory Configuration\n\n");
+ minfo (_("\nMemory Configuration\n\n"));
fprintf (config.map_file, "%-16s %-18s %-18s %s\n",
- "Name", "Origin", "Length", "Attributes");
+ _("Name"), _("Origin"), _("Length"), _("Attributes"));
for (m = lang_memory_region_list;
m != (lang_memory_region_type *) NULL;
@@ -615,7 +777,7 @@ lang_map ()
print_nl ();
}
- fprintf (config.map_file, "\nLinker script and memory map\n\n");
+ fprintf (config.map_file, _("\nLinker script and memory map\n\n"));
print_statements ();
}
@@ -632,7 +794,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"), DISCARD_SECTION_NAME);
new = ((section_userdata_type *)
stat_alloc (sizeof (section_userdata_type)));
@@ -642,7 +804,7 @@ init_os (s)
s->bfd_section = bfd_make_section (output_bfd, s->name);
if (s->bfd_section == (asection *) NULL)
{
- einfo ("%P%F: output format %s cannot represent section called %s\n",
+ einfo (_("%P%F: output format %s cannot represent section called %s\n"),
output_bfd->xvec->name, s->name);
}
s->bfd_section->output_section = s->bfd_section;
@@ -706,13 +868,36 @@ 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
@@ -722,15 +907,10 @@ 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. */
@@ -746,11 +926,34 @@ 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)
+ 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. */
@@ -763,8 +966,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:
@@ -777,25 +984,65 @@ section_already_linked (abfd, sec, data)
case SEC_LINK_DUPLICATES_SAME_SIZE:
if (bfd_section_size (abfd, sec)
!= bfd_section_size (l->sec->owner, l->sec))
- einfo ("%P: %B: warning: duplicate section `%s' has different size\n",
+ einfo (_("%P: %B: warning: duplicate section `%s' has different size\n"),
abfd, name);
break;
}
/* Set the output_section field so that wild_doit does not
- create a lang_input_section structure for this section. */
+ create a lang_input_section structure for this section.
+ Since there might be a symbol in the section being
+ discarded, we must retain a pointer to the section which
+ we are really going to use. */
sec->output_section = bfd_abs_section_ptr;
+ if (sec->comdat != NULL)
+ sec->comdat->sec = l->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.
@@ -939,6 +1186,10 @@ 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;
@@ -948,52 +1199,158 @@ wild_doit (ptr, section, output, file)
}
}
-/* Expand a wild statement for a particular FILE. SECTION may be
- NULL, in which case it is a wild card. */
+/* Handle wildcard sorting. This returns the lang_input_section which
+ should follow the one we are going to create for SECTION and FILE,
+ based on the sorting requirements of WILD. It returns NULL if the
+ new section should just go at the end of the current list. */
-static void
-wild_section (ptr, section, file, output)
- lang_wild_statement_type *ptr;
- const char *section;
+static lang_statement_union_type *
+wild_sort (wild, file, section)
+ lang_wild_statement_type *wild;
lang_input_statement_type *file;
- lang_output_section_statement_type *output;
+ asection *section;
{
- if (file->just_syms_flag == false)
+ const char *section_name;
+ lang_statement_union_type *l;
+
+ if (! wild->filenames_sorted && ! wild->sections_sorted)
+ return NULL;
+
+ section_name = bfd_get_section_name (file->the_bfd, section);
+ for (l = wild->children.head; l != NULL; l = l->next)
{
- register asection *s;
- boolean wildcard;
+ lang_input_section_type *ls;
- if (section == NULL)
- wildcard = false;
- else
- wildcard = wildcardp (section);
+ if (l->header.type != lang_input_section_enum)
+ continue;
+ ls = &l->input_section;
- for (s = file->the_bfd->sections; s != NULL; s = s->next)
+ /* Sorting by filename takes precedence over sorting by section
+ name. */
+
+ if (wild->filenames_sorted)
{
- boolean match;
+ const char *fn, *ln;
+ boolean fa, la;
+ int i;
- /* Attach all sections named SECTION. If SECTION is NULL,
- then attach all sections.
+ /* The PE support for the .idata section as generated by
+ dlltool assumes that files will be sorted by the name of
+ the archive and then the name of the file within the
+ archive. */
- 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 (file->the_bfd != NULL
+ && bfd_my_archive (file->the_bfd) != NULL)
+ {
+ fn = bfd_get_filename (bfd_my_archive (file->the_bfd));
+ fa = true;
+ }
+ else
+ {
+ fn = file->filename;
+ fa = false;
+ }
- if (section == NULL)
- match = true;
+ if (ls->ifile->the_bfd != NULL
+ && bfd_my_archive (ls->ifile->the_bfd) != NULL)
+ {
+ ln = bfd_get_filename (bfd_my_archive (ls->ifile->the_bfd));
+ la = true;
+ }
else
{
- const char *name;
+ ln = ls->ifile->filename;
+ la = false;
+ }
- 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;
+ i = strcmp (fn, ln);
+ if (i > 0)
+ continue;
+ else if (i < 0)
+ break;
+
+ if (fa || la)
+ {
+ if (fa)
+ fn = file->filename;
+ if (la)
+ ln = ls->ifile->filename;
+
+ i = strcmp (fn, ln);
+ if (i > 0)
+ continue;
+ else if (i < 0)
+ break;
}
- if (match)
- wild_doit (&ptr->children, s, output, file);
+ }
+
+ /* Here either the files are not sorted by name, or we are
+ looking at the sections for this file. */
+
+ if (wild->sections_sorted)
+ {
+ if (strcmp (section_name,
+ bfd_get_section_name (ls->ifile->the_bfd,
+ ls->section))
+ < 0)
+ break;
+ }
+ }
+
+ return l;
+}
+
+/* Expand a wild statement for a particular FILE. SECTION may be
+ NULL, in which case it is a wild card. */
+
+static void
+output_section_callback (ptr, section, file, output)
+ lang_wild_statement_type *ptr;
+ asection *section;
+ lang_input_statement_type *file;
+ void *output;
+{
+ 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
+ {
+ 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)
+ {
+ 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;
}
}
}
@@ -1062,15 +1419,15 @@ load_symbols (entry, place)
{
char **p;
- einfo ("%B: file not recognized: %E\n", entry->the_bfd);
- einfo ("%B: matching formats:", entry->the_bfd);
+ einfo (_("%B: file not recognized: %E\n"), entry->the_bfd);
+ einfo (_("%B: matching formats:"), entry->the_bfd);
for (p = matching; *p != NULL; p++)
einfo (" %s", *p);
einfo ("%F\n");
}
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);
bfd_close (entry->the_bfd);
entry->the_bfd = NULL;
@@ -1097,6 +1454,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
@@ -1120,13 +1480,13 @@ load_symbols (entry, place)
while (member != NULL)
{
if (! bfd_check_format (member, bfd_object))
- einfo ("%F%B: object %B in archive is not object\n",
+ einfo (_("%F%B: object %B in archive is not object\n"),
entry->the_bfd, member);
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);
+ einfo (_("%F%B: could not read symbols: %E\n"), member);
member = bfd_openr_next_archived_file (entry->the_bfd,
member);
}
@@ -1138,48 +1498,12 @@ load_symbols (entry, place)
}
if (! bfd_link_add_symbols (entry->the_bfd, &link_info))
- einfo ("%F%B: could not read symbols: %E\n", entry->the_bfd);
+ einfo (_("%F%B: could not read symbols: %E\n"), entry->the_bfd);
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
@@ -1191,72 +1515,250 @@ 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 = 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, (void *) output_target);
+
+ if (command_line.endian == ENDIAN_BIG)
+ desired_endian = BFD_ENDIAN_BIG;
else
- output_target = default_target;
+ 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: cannot open output file %s: %E\n", name);
+ 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;
@@ -1264,23 +1766,20 @@ open_output (name)
/* output->flags |= D_PAGED;*/
if (! bfd_set_format (output, bfd_object))
- einfo ("%P%F:%s: can not make object file: %E\n", name);
+ einfo (_("%P%F:%s: can not make object file: %E\n"), name);
if (! bfd_set_arch_mach (output,
ldfile_output_architecture,
ldfile_output_machine))
- einfo ("%P%F:%s: can not set architecture: %E\n", name);
+ einfo (_("%P%F:%s: can not set architecture: %E\n"), name);
link_info.hash = bfd_link_hash_table_create (output);
if (link_info.hash == (struct bfd_link_hash_table *) NULL)
- einfo ("%P%F: can not create link hash table: %E\n");
+ einfo (_("%P%F: can not create link hash table: %E\n"));
bfd_set_gp_size (output, g_switch_value);
return output;
}
-
-
-
static void
ldlang_open_output (statement)
lang_statement_union_type * statement;
@@ -1357,7 +1856,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;
@@ -1459,7 +1958,7 @@ lang_place_undefineds ()
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");
+ einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
if (h->type == bfd_link_hash_new)
{
h->type = bfd_link_hash_undefined;
@@ -1582,7 +2081,7 @@ print_output_section_statement (output_section_statement)
addr = exp_get_abs_int (output_section_statement->load_base, 0,
"load base", lang_final_phase_enum);
- minfo (" load address 0x%V", addr);
+ minfo (_(" load address 0x%V"), addr);
}
}
@@ -1606,7 +2105,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
{
@@ -1670,7 +2169,8 @@ print_input_section (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 ();
@@ -1694,7 +2194,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)
@@ -1711,12 +2211,12 @@ print_input_section (in)
--len;
}
- minfo ("%W (size before relaxing)\n", i->_raw_size);
+ minfo (_("%W (size before relaxing)\n"), i->_raw_size);
}
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;
}
}
}
@@ -1736,6 +2236,8 @@ print_data_statement (data)
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 ();
@@ -1780,7 +2282,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
@@ -1790,7 +2293,7 @@ static void
print_address_statement (address)
lang_address_statement_type *address;
{
- minfo ("Address of section %s set to ", address->section_name);
+ minfo (_("Address of section %s set to "), address->section_name);
exp_print_tree (address->address);
print_nl ();
}
@@ -1804,6 +2307,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 ();
@@ -1825,7 +2330,7 @@ print_reloc_statement (reloc)
print_nl ();
- print_dot = addr + size;
+ print_dot = addr + size / opb;
}
static void
@@ -1834,6 +2339,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*");
@@ -1854,7 +2361,7 @@ print_padding_statement (s)
print_nl ();
- print_dot = addr + s->size;
+ print_dot = addr + s->size / opb;
}
static void
@@ -1864,15 +2371,33 @@ print_wild_statement (w, os)
{
print_space ();
- if (w->filename != NULL)
+ if (w->filenames_sorted)
+ minfo ("SORT(");
+ if (w->exclude_filename_list != NULL)
+ {
+ name_list *tmp;
+ minfo ("EXCLUDE_FILE ( %s", w->exclude_filename_list->name);
+ for (tmp=w->exclude_filename_list->next; tmp; tmp = tmp->next)
+ minfo (", %s", tmp->name);
+ minfo (")");
+ }
+ if (w->filename != NULL)
minfo ("%s", w->filename);
else
minfo ("*");
+ if (w->filenames_sorted)
+ minfo (")");
+ minfo ("(");
+ if (w->sections_sorted)
+ minfo ("SORT(");
if (w->section_name != NULL)
- minfo ("(%s)", w->section_name);
+ minfo ("%s", w->section_name);
else
- minfo ("(*)");
+ minfo ("*");
+ if (w->sections_sorted)
+ minfo (")");
+ minfo (")");
print_nl ();
@@ -1917,13 +2442,16 @@ print_statement (s, os)
switch (s->header.type)
{
default:
- fprintf (config.map_file, "Fail with %d\n", s->header.type);
+ fprintf (config.map_file, _("Fail with %d\n"), s->header.type);
FAIL ();
break;
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;
@@ -2028,6 +2556,8 @@ insert_pad (this_ptr, fill, power, output_section_statement, dot)
inserting a magic 'padding' statement.
*/
+ unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
+ ldfile_output_machine);
unsigned int alignment_needed = align_power (dot, power) - dot;
if (alignment_needed != 0)
@@ -2044,7 +2574,7 @@ insert_pad (this_ptr, fill, power, output_section_statement, dot)
new->padding_statement.output_offset =
dot - output_section_statement->vma;
new->padding_statement.fill = fill;
- new->padding_statement.size = alignment_needed;
+ new->padding_statement.size = alignment_needed * opb;
}
@@ -2053,9 +2583,9 @@ insert_pad (this_ptr, fill, power, output_section_statement, dot)
{
output_section_statement->alignment_power = power;
}
- output_section_statement->_raw_size += alignment_needed;
- return alignment_needed + dot;
+ output_section_statement->_raw_size += alignment_needed * opb;
+ return dot + alignment_needed;
}
/* Work out how much this section will move the dot point */
@@ -2065,10 +2595,12 @@ 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;
+ unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
+ ldfile_output_machine);
if (is->ifile->just_syms_flag == false)
{
@@ -2086,10 +2618,11 @@ size_input_section (this_ptr, output_section_statement, fill, dot, relax)
/* 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;
+ output_section_statement->bfd_section->_raw_size =
+ (dot - output_section_statement->bfd_section->vma) * opb;
}
else
{
@@ -2099,11 +2632,107 @@ 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;
+ 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)
+ {
+ asection * os;
+
+ /* 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. */
static boolean relax_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 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
@@ -2115,347 +2744,371 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
bfd_vma dot;
boolean relax;
{
- /* Size up the sections from their constituent parts */
+ 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)
- {
- switch (s->header.type)
{
+ switch (s->header.type)
+ {
+ case lang_output_section_statement_enum:
+ {
+ bfd_vma after;
+ lang_output_section_statement_type *os = &s->output_section_statement;
- 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;
+ if (os->bfd_section == NULL)
+ /* This section was never actually created. */
+ 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_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;
+ /* 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;
+ }
- 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:
+ 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. */
- dot = lang_size_sections (s->wild_statement.children.head,
- output_section_statement,
- &s->wild_statement.children.head,
+ if (os->section_alignment != -1)
+ dot = align_power (dot, os->section_alignment);
- fill, dot, relax);
+ bfd_set_section_vma (0, os->bfd_section, dot);
+
+ os->bfd_section->output_offset = 0;
+ }
- break;
+ (void) lang_size_sections (os->children.head, os, &os->children.head,
+ os->fill, dot, relax);
+
+ /* 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
+ 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;
+
+ /* 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 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_NEVER_LOAD) == 0
+ || (bfd_get_section_flags (output_bfd, os->bfd_section)
+ & (SEC_ALLOC | SEC_LOAD))))
+ {
+ os->region->current = dot;
+
+ /* 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)
+ {
+ if (os->load_base != NULL)
+ {
+ einfo (_("%X%P: use an absolute load address or a load memory region, not both\n"));
+ }
+ else
+ {
+ /* don't allocate twice */
+ if (os->lma_region != os->region)
+ {
+ /* 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_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;
+ case lang_constructors_statement_enum:
+ dot = lang_size_sections (constructor_list.head,
+ output_section_statement,
+ &s->wild_statement.children.head,
+ fill,
+ dot, relax);
+ break;
- i = (*prev)->input_section.section;
- if (! relax)
+ case lang_data_statement_enum:
{
- if (i->_cooked_size == 0)
- i->_cooked_size = i->_raw_size;
+ 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)
+ {
+ 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;
+ 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;
+ }
}
- else
+ break;
+
+ case lang_reloc_statement_enum:
{
- boolean again;
+ 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 / 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,
+
+ 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;
+ break;
+
+ 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;
+
+ 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);
}
- 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;
+ 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:
- {
- bfd_vma newdot = dot;
-
- exp_fold_tree (s->assignment_statement.exp,
- output_section_statement,
- lang_allocating_phase_enum,
- dot,
- &newdot);
-
- if (newdot != dot && !relax)
- {
- /* 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
- {
- 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;
+ fill = s->fill_statement.fill;
+ break;
+ case lang_assignment_statement_enum:
+ {
+ bfd_vma newdot = dot;
- /* This can only get here when relaxing is turned on */
+ exp_fold_tree (s->assignment_statement.exp,
+ output_section_statement,
+ lang_allocating_phase_enum,
+ dot,
+ &newdot);
- case lang_address_statement_enum:
- break;
+ 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) * opb;
+ 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 / opb;
+ 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;
+
+ /* 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;
}
@@ -2466,6 +3119,9 @@ lang_do_assignments (s, output_section_statement, fill, dot)
fill_type fill;
bfd_vma dot;
{
+ unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
+ ldfile_output_machine);
+
for (; s != (lang_statement_union_type *) NULL; s = s->next)
{
switch (s->header.type)
@@ -2487,7 +3143,8 @@ lang_do_assignments (s, output_section_statement, fill, dot)
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)
{
@@ -2524,25 +3181,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)
- einfo ("%F%P: invalid data statement\n");
+ 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:
@@ -2553,10 +3218,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)
- einfo ("%F%P: invalid reloc statement\n");
+ 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:
@@ -2564,9 +3229,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;
@@ -2586,7 +3251,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:
@@ -2644,11 +3309,13 @@ 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 = 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;
}
@@ -2688,29 +3355,44 @@ lang_finish ()
h->u.def.section->output_section)
+ h->u.def.section->output_offset);
if (! bfd_set_start_address (output_bfd, val))
- einfo ("%P%F:%s: can't set start address\n", entry_symbol);
+ einfo (_("%P%F:%s: can't set start address\n"), entry_symbol);
}
else
{
- asection *ts;
+ bfd_vma val;
+ CONST char *send;
- /* Can't find the entry symbol. Use the first address in the
- text section. */
- ts = bfd_get_section_by_name (output_bfd, ".text");
- if (ts != (asection *) NULL)
+ /* We couldn't find the entry symbol. Try parsing it as a
+ number. */
+ val = bfd_scan_vma (entry_symbol, &send, 0);
+ if (*send == '\0')
{
- if (warn)
- einfo ("%P: warning: cannot find entry symbol %s; defaulting to %V\n",
- entry_symbol, bfd_get_section_vma (output_bfd, ts));
- if (! bfd_set_start_address (output_bfd,
- bfd_get_section_vma (output_bfd, ts)))
- einfo ("%P%F: can't set start address\n");
+ if (! bfd_set_start_address (output_bfd, val))
+ einfo (_("%P%F: can't set start address\n"));
}
else
{
- if (warn)
- einfo ("%P: warning: cannot find entry symbol %s; not setting start address\n",
- entry_symbol);
+ asection *ts;
+
+ /* 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");
+ if (ts != (asection *) NULL)
+ {
+ if (warn)
+ einfo (_("%P: warning: cannot find entry symbol %s; defaulting to %V\n"),
+ entry_symbol, bfd_get_section_vma (output_bfd, ts));
+ if (! bfd_set_start_address (output_bfd,
+ bfd_get_section_vma (output_bfd,
+ ts)))
+ einfo (_("%P%F: can't set start address\n"));
+ }
+ else
+ {
+ if (warn)
+ einfo (_("%P: warning: cannot find entry symbol %s; not setting start address\n"),
+ entry_symbol);
+ }
}
}
}
@@ -2720,10 +3402,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. */
@@ -2750,7 +3432,7 @@ lang_check ()
if (compatible == NULL)
{
if (command_line.warn_mismatch)
- einfo ("%P: warning: %s architecture of input file `%B' is incompatible with %s output\n",
+ einfo (_("%P: warning: %s architecture of input file `%B' is incompatible with %s output\n"),
bfd_printable_name (input_bfd), input_bfd,
bfd_printable_name (output_bfd));
}
@@ -2768,7 +3450,7 @@ lang_check ()
if (! bfd_merge_private_bfd_data (input_bfd, output_bfd))
{
if (command_line.warn_mismatch)
- einfo ("%E%X: failed to merge target specific data of file %B\n",
+ einfo (_("%E%X: failed to merge target specific data of file %B\n"),
input_bfd);
}
if (! command_line.warn_mismatch)
@@ -2810,6 +3492,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;
@@ -2824,8 +3508,8 @@ lang_one_common (h, info)
section = h->u.c.p->section;
/* Increase the size of the section. */
- section->_raw_size = ALIGN_N (section->_raw_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)
@@ -2834,10 +3518,10 @@ lang_one_common (h, info)
/* Change the symbol from common to defined. */
h->type = bfd_link_hash_defined;
h->u.def.section = section;
- h->u.def.value = section->_raw_size;
+ h->u.def.value = section->_cooked_size;
/* Increase the size of the section. */
- section->_raw_size += size;
+ section->_cooked_size += size;
/* Make sure the section is allocated in memory, and make sure that
it is no longer a common section. */
@@ -2853,8 +3537,8 @@ lang_one_common (h, info)
if (! header_printed)
{
- minfo ("\nAllocating common symbols\n");
- minfo ("Common symbol size file\n\n");
+ minfo (_("\nAllocating common symbols\n"));
+ minfo (_("Common symbol size file\n\n"));
header_printed = true;
}
@@ -2904,11 +3588,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;
@@ -2943,7 +3623,7 @@ lang_place_orphans ()
/* This message happens when using the
svr3.ifile linker script, so I have
disabled it. */
- info_msg ("%P: no [COMMON] command, defaulting to .bss\n");
+ info_msg (_("%P: no [COMMON] command, defaulting to .bss\n"));
#endif
default_common_section =
lang_output_section_statement_lookup (".bss");
@@ -2969,21 +3649,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;
@@ -3006,7 +3683,7 @@ lang_set_flags (ptr, flags)
break;
default:
- einfo ("%P%F: invalid syntax in flags\n");
+ einfo (_("%P%F: invalid syntax in flags\n"));
break;
}
flags++;
@@ -3036,11 +3713,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);
}
@@ -3054,13 +3727,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;
@@ -3219,6 +3888,103 @@ reset_memory_regions ()
}
}
+/* 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
+gc_section_callback (ptr, section, file, data)
+ lang_wild_statement_type *ptr;
+ asection *section;
+ lang_input_statement_type *file ATTRIBUTE_UNUSED;
+ void *data ATTRIBUTE_UNUSED;
+{
+ /* 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
+ may be NULL, indicating that it is a wildcard. */
+
+static void
+lang_gc_wild (s, section, file)
+ lang_wild_statement_type *s;
+ const char *section;
+ const char *file;
+{
+ walk_wild (s, section, file, gc_section_callback, NULL);
+}
+
+/* Iterate over sections marking them against GC. */
+
+static void
+lang_gc_sections_1 (s)
+ lang_statement_union_type * s;
+{
+ for (; s != (lang_statement_union_type *) NULL; s = s->next)
+ {
+ switch (s->header.type)
+ {
+ case lang_wild_statement_enum:
+ lang_gc_wild (&s->wild_statement,
+ s->wild_statement.section_name,
+ s->wild_statement.filename);
+ break;
+ case lang_constructors_statement_enum:
+ lang_gc_sections_1 (constructor_list.head);
+ break;
+ case lang_output_section_statement_enum:
+ lang_gc_sections_1 (s->output_section_statement.children.head);
+ break;
+ case lang_group_statement_enum:
+ lang_gc_sections_1 (s->group_statement.children.head);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void
+lang_gc_sections ()
+{
+ struct bfd_link_hash_entry *h;
+ ldlang_undef_chain_list_type *ulist, fake_list_start;
+
+ /* Keep all sections so marked in the link script. */
+
+ lang_gc_sections_1 (statement_list.head);
+
+ /* Keep all sections containing symbols undefined on the command-line.
+ Handle the entry symbol at the same time. */
+
+ 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; ulist = ulist->next)
+ {
+ h = bfd_link_hash_lookup (link_info.hash, ulist->name,
+ false, false, false);
+
+ if (h != (struct bfd_link_hash_entry *) NULL
+ && (h->type == bfd_link_hash_defined
+ || h->type == bfd_link_hash_defweak)
+ && ! bfd_is_abs_section (h->u.def.section))
+ {
+ h->u.def.section->flags |= SEC_KEEP;
+ }
+ }
+
+ bfd_gc_sections (output_bfd, &link_info);
+}
+
void
lang_process ()
{
@@ -3232,12 +3998,16 @@ lang_process ()
/* Add to the hash table all undefineds on the command line */
lang_place_undefineds ();
+ 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
@@ -3245,10 +4015,18 @@ 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 ();
+ /* Remove unreferenced sections if asked to. */
+ if (command_line.gc_sections)
+ lang_gc_sections ();
+
/* Size up the common data */
lang_common ();
@@ -3284,6 +4062,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,
@@ -3320,6 +4102,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 ();
@@ -3329,9 +4116,14 @@ lang_process ()
/* EXPORTED TO YACC */
void
-lang_add_wild (section_name, filename)
- CONST char *CONST section_name;
- CONST char *CONST filename;
+lang_add_wild (section_name, sections_sorted, filename, filenames_sorted,
+ keep_sections, exclude_filename_list)
+ const char *const section_name;
+ boolean sections_sorted;
+ const char *const filename;
+ boolean filenames_sorted;
+ boolean keep_sections;
+ struct name_list *exclude_filename_list;
{
lang_wild_statement_type *new = new_stat (lang_wild_statement,
stat_ptr);
@@ -3340,12 +4132,16 @@ lang_add_wild (section_name, filename)
{
placed_commons = true;
}
- if (filename != (char *) NULL)
+ if (filename != NULL && ! wildcardp (filename))
{
lang_has_input_file = true;
}
new->section_name = section_name;
+ new->sections_sorted = sections_sorted;
new->filename = filename;
+ new->filenames_sorted = filenames_sorted;
+ new->keep_sections = keep_sections;
+ new->exclude_filename_list = exclude_filename_list;
lang_list_init (&new->children);
}
@@ -3365,21 +4161,6 @@ lang_section_start (name, address)
called by ENTRY in a linker script. Command line arguments take
precedence. */
-/* WINDOWS_NT. When an entry point has been specified, we will also force
- this symbol to be defined by calling ldlang_add_undef (equivalent to
- having switch -u entry_name on the command line). The reason we do
- this is so that the user doesn't have to because they would have to use
- the -u switch if they were specifying an entry point other than
- _mainCRTStartup. Specifically, if creating a windows application, entry
- point _WinMainCRTStartup must be specified.
- What I have found for non console applications (entry not _mainCRTStartup)
- is that the .obj that contains mainCRTStartup is brought in since it is
- the first encountered in libc.lib and it has other symbols in it which will
- be pulled in by the link process. To avoid this, adding -u with the entry
- point name specified forces the correct .obj to be used. We can avoid
- making the user do this by always adding the entry point name as an
- undefined symbol. */
-
void
lang_add_entry (name, cmdline)
CONST char *name;
@@ -3392,14 +4173,6 @@ lang_add_entry (name, cmdline)
entry_symbol = name;
entry_from_cmdline = cmdline;
}
-#if 0
- /* don't do this yet. It seems to work (the executables run), but the
- image created is very different from what I was getting before indicating
- that something else is being pulled in. When everything else is working,
- then try to put this back in to see if it will do the right thing for
- other more complicated applications */
- ldlang_add_undef (name);
-#endif
}
void
@@ -3481,7 +4254,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;
{
@@ -3489,6 +4262,7 @@ lang_add_assignment (exp)
stat_ptr);
new->exp = exp;
+ return new;
}
void
@@ -3504,7 +4278,7 @@ lang_startup (name)
{
if (startup_file != (char *) NULL)
{
- einfo ("%P%Fmultiple STARTUP files\n");
+ einfo (_("%P%Fmultiple STARTUP files\n"));
}
first_file->filename = name;
first_file->local_sym_name = name;
@@ -3521,13 +4295,22 @@ lang_float (maybe)
}
void
-lang_leave_output_section_statement (fill, memspec, phdrs)
+lang_leave_output_section_statement (fill, memspec, phdrs, lma_memspec)
bfd_vma fill;
const char *memspec;
struct lang_output_section_phdr_list *phdrs;
+ const char *lma_memspec;
{
current_section->fill = fill;
current_section->region = lang_memory_region_lookup (memspec);
+ if (strcmp (lma_memspec, "*default*") != 0)
+ {
+ current_section->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 (strcmp (memspec, "*default*") == 0)
+ current_section->region = lang_memory_region_lookup (lma_memspec);
+ }
current_section->phdrs = phdrs;
stat_ptr = &statement_list;
}
@@ -3547,7 +4330,7 @@ lang_abs_symbol_at_beginning_of (secname, name)
h = bfd_link_hash_lookup (link_info.hash, name, true, true, true);
if (h == (struct bfd_link_hash_entry *) NULL)
- einfo ("%P%F: bfd_link_hash_lookup failed: %E\n");
+ einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
if (h->type == bfd_link_hash_new
|| h->type == bfd_link_hash_undefined)
@@ -3581,7 +4364,7 @@ lang_abs_symbol_at_end_of (secname, name)
h = bfd_link_hash_lookup (link_info.hash, name, true, true, true);
if (h == (struct bfd_link_hash_entry *) NULL)
- einfo ("%P%F: bfd_link_hash_lookup failed: %E\n");
+ einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
if (h->type == bfd_link_hash_new
|| h->type == bfd_link_hash_undefined)
@@ -3595,7 +4378,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;
}
@@ -3766,7 +4550,7 @@ lang_record_phdrs ()
flags,
l->at == NULL ? false : true,
at, l->filehdr, l->phdrs, c, secs))
- einfo ("%F%P: bfd_record_phdr failed: %E\n");
+ einfo (_("%F%P: bfd_record_phdr failed: %E\n"));
}
free (secs);
@@ -3785,7 +4569,7 @@ lang_record_phdrs ()
pl != NULL;
pl = pl->next)
if (! pl->used && strcmp (pl->name, "NONE") != 0)
- einfo ("%X%P: section `%s' assigned to non-existent phdr `%s'\n",
+ einfo (_("%X%P: section `%s' assigned to non-existent phdr `%s'\n"),
u->output_section_statement.name, pl->name);
}
}
@@ -3887,7 +4671,7 @@ lang_enter_overlay_section (name)
if (overlay_max == NULL)
overlay_max = size;
else
- overlay_max = exp_binop (MAX, overlay_max, size);
+ overlay_max = exp_binop (MAX_K, overlay_max, size);
}
/* Finish a section in an overlay. There isn't any special to do
@@ -3905,7 +4689,8 @@ lang_leave_overlay_section (fill, phdrs)
name = current_section->name;
- lang_leave_output_section_statement (fill, "*default*", phdrs);
+ lang_leave_output_section_statement (fill, "*default*",
+ phdrs, "*default*");
/* Define the magic symbols. */
@@ -3935,12 +4720,14 @@ lang_leave_overlay_section (fill, phdrs)
looks through all the sections in the overlay and sets them. */
void
-lang_leave_overlay (fill, memspec, phdrs)
+lang_leave_overlay (fill, memspec, phdrs, lma_memspec)
bfd_vma 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;
@@ -3949,6 +4736,11 @@ lang_leave_overlay (fill, memspec, phdrs)
else
region = lang_memory_region_lookup (memspec);
+ if (lma_memspec == NULL)
+ lma_region = NULL;
+ else
+ lma_region = lang_memory_region_lookup (lma_memspec);
+
nocrossref = NULL;
l = overlay_list;
@@ -3960,6 +4752,8 @@ lang_leave_overlay (fill, memspec, phdrs)
l->os->fill = fill;
if (region != NULL && l->os->region == NULL)
l->os->region = region;
+ if (lma_region != NULL && l->os->lma_region == NULL)
+ l->os->lma_region = lma_region;
if (phdrs != NULL && l->os->phdrs == NULL)
l->os->phdrs = phdrs;
@@ -3998,18 +4792,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;
}
@@ -4054,7 +4927,7 @@ lang_register_vers_node (name, version, deps)
/* 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)
- einfo ("%X%P: duplicate version tag `%s'\n", name);
+ einfo (_("%X%P: duplicate version tag `%s'\n"), name);
/* Check the global and local match names, and make sure there
aren't any duplicates. */
@@ -4066,9 +4939,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)
- einfo ("%X%P: duplicate expression `%s' in version information\n",
- e1->match);
+ if (strcmp (e1->pattern, e2->pattern) == 0)
+ einfo (_("%X%P: duplicate expression `%s' in version information\n"),
+ e1->pattern);
}
}
@@ -4079,9 +4952,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)
- einfo ("%X%P: duplicate expression `%s' in version information\n",
- e1->match);
+ if (strcmp (e1->pattern, e2->pattern) == 0)
+ einfo (_("%X%P: duplicate expression `%s' in version information\n"),
+ e1->pattern);
}
}
@@ -4117,7 +4990,45 @@ lang_add_vers_depend (list, name)
}
}
- einfo ("%X%P: unable to find version dependency `%s'\n", name);
+ einfo (_("%X%P: unable to find version dependency `%s'\n"), 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);
+}
OpenPOWER on IntegriCloud