/* Local variables. */
static struct obstack stat_obstack;
static struct obstack map_obstack;
+static struct obstack pt_obstack;
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
static lang_input_statement_type *lookup_name (const char *);
static void insert_undefined (const char *);
static bool sort_def_symbol (struct bfd_link_hash_entry *, void *);
+static lang_statement_union_type *new_statement (enum statement_enum type,
+ size_t size,
+ lang_statement_list_type *list);
static void print_statement (lang_statement_union_type *,
lang_output_section_statement_type *);
static void print_statement_list (lang_statement_union_type *,
return obstack_alloc (&stat_obstack, size);
}
+/* Code for handling simple wildcards without going through fnmatch,
+ which can be expensive because of charset translations etc. */
+
+/* A simple wild is a literal string followed by a single '*',
+ where the literal part is at least 4 characters long. */
+
+static bool
+is_simple_wild (const char *name)
+{
+ size_t len = strcspn (name, "*?[");
+ return len >= 4 && name[len] == '*' && name[len + 1] == '\0';
+}
+
+static bool
+match_simple_wild (const char *pattern, const char *name)
+{
+ /* The first four characters of the pattern are guaranteed valid
+ non-wildcard characters. So we can go faster. */
+ if (pattern[0] != name[0] || pattern[1] != name[1]
+ || pattern[2] != name[2] || pattern[3] != name[3])
+ return false;
+
+ pattern += 4;
+ name += 4;
+ while (*pattern != '*')
+ if (*name++ != *pattern++)
+ return false;
+
+ return true;
+}
+
static int
name_match (const char *pattern, const char *name)
{
+ if (is_simple_wild (pattern))
+ return !match_simple_wild (pattern, name);
if (wildcardp (pattern))
return fnmatch (pattern, name, 0);
return strcmp (pattern, name);
}
+/* Given an analyzed wildcard_spec SPEC, match it against NAME,
+ returns zero on a match, non-zero if there's no match. */
+
+static int
+spec_match (const struct wildcard_spec *spec, const char *name)
+{
+ size_t nl = spec->namelen;
+ size_t pl = spec->prefixlen;
+ size_t sl = spec->suffixlen;
+ size_t inputlen = strlen (name);
+ int r;
+
+ if (pl)
+ {
+ if (inputlen < pl)
+ return 1;
+
+ r = memcmp (spec->name, name, pl);
+ if (r)
+ return r;
+ }
+
+ if (sl)
+ {
+ if (inputlen < sl)
+ return 1;
+
+ r = memcmp (spec->name + nl - sl, name + inputlen - sl, sl);
+ if (r)
+ return r;
+ }
+
+ if (nl == pl + sl + 1 && spec->name[pl] == '*')
+ return 0;
+
+ if (nl > pl)
+ return fnmatch (spec->name + pl, name + pl, 0);
+
+ if (inputlen >= nl)
+ return name[nl];
+
+ return 0;
+}
+
static char *
ldirname (const char *name)
{
return false;
}
-/* Try processing a section against a wildcard. This just calls
- the callback unless the filename exclusion list is present
- and excludes the file. It's hardly ever present so this
- function is very fast. */
+/* Add SECTION (from input FILE) to the list of matching sections
+ within PTR (the matching wildcard is SEC). */
static void
-walk_wild_consider_section (lang_wild_statement_type *ptr,
- lang_input_statement_type *file,
- asection *s,
- struct wildcard_list *sec,
- callback_t callback,
- void *data)
-{
- /* Don't process sections from files which were excluded. */
- if (walk_wild_file_in_exclude_list (sec->spec.exclude_name_list, file))
- return;
-
- (*callback) (ptr, sec, s, file, data);
+add_matching_section (lang_wild_statement_type *ptr,
+ struct wildcard_list *sec,
+ asection *section,
+ lang_input_statement_type *file)
+{
+ lang_input_matcher_type *new_section;
+ /* Add a section reference to the list. */
+ new_section = new_stat (lang_input_matcher, &ptr->matching_sections);
+ new_section->section = section;
+ new_section->pattern = sec;
+ new_section->input_stmt = file;
}
-/* Lowest common denominator routine that can handle everything correctly,
- but slowly. */
+/* Process section S (from input file FILE) in relation to wildcard
+ statement PTR. We already know that a prefix of the name of S matches
+ some wildcard in PTR's wildcard list. Here we check if the filename
+ matches as well (if it's specified) and if any of the wildcards in fact
+ does match. */
static void
-walk_wild_section_general (lang_wild_statement_type *ptr,
- lang_input_statement_type *file,
- callback_t callback,
- void *data)
+walk_wild_section_match (lang_wild_statement_type *ptr,
+ lang_input_statement_type *file,
+ asection *s)
{
- asection *s;
struct wildcard_list *sec;
+ const char *file_spec = ptr->filename;
+ char *p;
- for (s = file->the_bfd->sections; s != NULL; s = s->next)
+ /* Check if filenames match. */
+ if (file_spec == NULL)
+ ;
+ else if ((p = archive_path (file_spec)) != NULL)
{
- sec = ptr->section_list;
- if (sec == NULL)
- (*callback) (ptr, sec, s, file, data);
-
- while (sec != NULL)
- {
- bool skip = false;
-
- if (sec->spec.name != NULL)
- {
- const char *sname = bfd_section_name (s);
-
- skip = name_match (sec->spec.name, sname) != 0;
- }
-
- if (!skip)
- walk_wild_consider_section (ptr, file, s, sec, callback, data);
-
- sec = sec->next;
- }
+ if (!input_statement_is_archive_path (file_spec, p, file))
+ return;
}
-}
-
-/* Routines to find a single section given its name. If there's more
- than one section with that name, we report that. */
-
-typedef struct
-{
- asection *found_section;
- bool multiple_sections_found;
-} section_iterator_callback_data;
-
-static bool
-section_iterator_callback (bfd *abfd ATTRIBUTE_UNUSED, asection *s, void *data)
-{
- section_iterator_callback_data *d = (section_iterator_callback_data *) data;
-
- if (d->found_section != NULL)
+ else if (wildcardp (file_spec))
{
- d->multiple_sections_found = true;
- return true;
+ if (fnmatch (file_spec, file->filename, 0) != 0)
+ return;
+ }
+ else
+ {
+ lang_input_statement_type *f;
+ /* Perform the iteration over a single file. */
+ f = lookup_name (file_spec);
+ if (f != file)
+ return;
}
- d->found_section = s;
- return false;
-}
-
-static asection *
-find_section (lang_input_statement_type *file,
- struct wildcard_list *sec,
- bool *multiple_sections_found)
-{
- section_iterator_callback_data cb_data = { NULL, false };
-
- bfd_get_section_by_name_if (file->the_bfd, sec->spec.name,
- section_iterator_callback, &cb_data);
- *multiple_sections_found = cb_data.multiple_sections_found;
- return cb_data.found_section;
-}
-
-/* Code for handling simple wildcards without going through fnmatch,
- which can be expensive because of charset translations etc. */
-
-/* A simple wild is a literal string followed by a single '*',
- where the literal part is at least 4 characters long. */
-
-static bool
-is_simple_wild (const char *name)
-{
- size_t len = strcspn (name, "*?[");
- return len >= 4 && name[len] == '*' && name[len + 1] == '\0';
-}
-
-static bool
-match_simple_wild (const char *pattern, const char *name)
-{
- /* The first four characters of the pattern are guaranteed valid
- non-wildcard characters. So we can go faster. */
- if (pattern[0] != name[0] || pattern[1] != name[1]
- || pattern[2] != name[2] || pattern[3] != name[3])
- return false;
+ /* If filename is excluded we're done. */
+ if (walk_wild_file_in_exclude_list (ptr->exclude_name_list, file))
+ return;
- pattern += 4;
- name += 4;
- while (*pattern != '*')
- if (*name++ != *pattern++)
- return false;
+ /* Check section name against each wildcard spec. If there's no
+ wildcard all sections match. */
+ sec = ptr->section_list;
+ if (sec == NULL)
+ add_matching_section (ptr, sec, s, file);
+ else
+ {
+ const char *sname = bfd_section_name (s);
+ for (; sec != NULL; sec = sec->next)
+ {
+ if (sec->spec.name != NULL
+ && spec_match (&sec->spec, sname) != 0)
+ continue;
- return true;
+ /* Don't process sections from files which were excluded. */
+ if (!walk_wild_file_in_exclude_list (sec->spec.exclude_name_list,
+ file))
+ add_matching_section (ptr, sec, s, file);
+ }
+ }
}
/* Return the numerical value of the init_priority attribute from
return ret;
}
-/* Build a Binary Search Tree to sort sections, unlike insertion sort
- used in wild_sort(). BST is considerably faster if the number of
- of sections are large. */
+/* PE puts the sort key in the input statement. */
+
+static const char *
+sort_filename (bfd *abfd)
+{
+ lang_input_statement_type *is = bfd_usrdata (abfd);
+ if (is->sort_key)
+ return is->sort_key;
+ return bfd_get_filename (abfd);
+}
+
+/* Handle wildcard sorting. This returns the place in a binary search tree
+ where this FILE:SECTION should be inserted for wild statement WILD where
+ the spec SEC was the matching one. The tree is later linearized. */
static lang_section_bst_type **
-wild_sort_fast (lang_wild_statement_type *wild,
- struct wildcard_list *sec,
- lang_input_statement_type *file ATTRIBUTE_UNUSED,
- asection *section)
+wild_sort (lang_wild_statement_type *wild,
+ struct wildcard_list *sec,
+ lang_input_statement_type *file,
+ asection *section)
{
lang_section_bst_type **tree;
- tree = &wild->tree;
if (!wild->filenames_sorted
- && (sec == NULL || sec->spec.sorted == none))
+ && (sec == NULL || sec->spec.sorted == none
+ || sec->spec.sorted == by_none))
{
- /* Append at the right end of tree. */
- while (*tree)
- tree = &((*tree)->right);
- return tree;
+ /* We might be called even if _this_ spec doesn't need sorting,
+ in which case we simply append at the right end of tree. */
+ return wild->rightmost;
}
+ tree = &wild->tree;
while (*tree)
{
+ /* Sorting by filename takes precedence over sorting by section
+ name. */
+
+ if (wild->filenames_sorted)
+ {
+ const char *fn, *ln;
+ bool fa, la;
+ int i;
+ asection *lsec = (*tree)->section;
+
+ /* 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. */
+
+ fa = file->the_bfd->my_archive != NULL;
+ if (fa)
+ fn = sort_filename (file->the_bfd->my_archive);
+ else
+ fn = sort_filename (file->the_bfd);
+
+ la = lsec->owner->my_archive != NULL;
+ if (la)
+ ln = sort_filename (lsec->owner->my_archive);
+ else
+ ln = sort_filename (lsec->owner);
+
+ i = filename_cmp (fn, ln);
+ if (i > 0)
+ { tree = &((*tree)->right); continue; }
+ else if (i < 0)
+ { tree = &((*tree)->left); continue; }
+
+ if (fa || la)
+ {
+ if (fa)
+ fn = sort_filename (file->the_bfd);
+ if (la)
+ ln = sort_filename (lsec->owner);
+
+ i = filename_cmp (fn, ln);
+ if (i > 0)
+ { tree = &((*tree)->right); continue; }
+ else if (i < 0)
+ { tree = &((*tree)->left); continue; }
+ }
+ }
+
+ /* Here either the files are not sorted by name, or we are
+ looking at the sections for this file. */
+
/* Find the correct node to append this section. */
if (compare_section (sec->spec.sorted, section, (*tree)->section) < 0)
tree = &((*tree)->left);
return tree;
}
-/* Use wild_sort_fast to build a BST to sort sections. */
+/* Use wild_sort to build a BST to sort sections. */
static void
-output_section_callback_fast (lang_wild_statement_type *ptr,
+output_section_callback_sort (lang_wild_statement_type *ptr,
struct wildcard_list *sec,
asection *section,
lang_input_statement_type *file,
node->section = section;
node->pattern = ptr->section_list;
- tree = wild_sort_fast (ptr, sec, file, section);
+ tree = wild_sort (ptr, sec, file, section);
if (tree != NULL)
- *tree = node;
+ {
+ *tree = node;
+ if (tree == ptr->rightmost)
+ ptr->rightmost = &node->right;
+ }
}
/* Convert a sorted sections' BST back to list form. */
if (tree->left)
output_section_callback_tree_to_list (ptr, tree->left, output);
- lang_add_section (&ptr->children, tree->section, tree->pattern, NULL,
+ lang_add_section (&ptr->children, tree->section, tree->pattern,
+ ptr->section_flag_list,
(lang_output_section_statement_type *) output);
if (tree->right)
free (tree);
}
-/* Specialized, optimized routines for handling different kinds of
- wildcards */
-
-static void
-walk_wild_section_specs1_wild0 (lang_wild_statement_type *ptr,
- lang_input_statement_type *file,
- callback_t callback,
- void *data)
-{
- /* We can just do a hash lookup for the section with the right name.
- But if that lookup discovers more than one section with the name
- (should be rare), we fall back to the general algorithm because
- we would otherwise have to sort the sections to make sure they
- get processed in the bfd's order. */
- bool multiple_sections_found;
- struct wildcard_list *sec0 = ptr->handler_data[0];
- asection *s0 = find_section (file, sec0, &multiple_sections_found);
-
- if (multiple_sections_found)
- walk_wild_section_general (ptr, file, callback, data);
- else if (s0)
- walk_wild_consider_section (ptr, file, s0, sec0, callback, data);
-}
+\f
+/* Sections are matched against wildcard statements via a prefix tree.
+ The prefix tree holds prefixes of all matching patterns (up to the first
+ wildcard character), and the wild statement from which those patterns
+ came. When matching a section name against the tree we're walking through
+ the tree character by character. Each statement we hit is one that
+ potentially matches. This is checked by actually going through the
+ (glob) matching routines.
+
+ When the section name turns out to actually match we record that section
+ in the wild statements list of matching sections. */
+
+/* A prefix can be matched by multiple statement, so we need a list of them. */
+struct wild_stmt_list
+{
+ lang_wild_statement_type *stmt;
+ struct wild_stmt_list *next;
+};
-static void
-walk_wild_section_specs1_wild1 (lang_wild_statement_type *ptr,
- lang_input_statement_type *file,
- callback_t callback,
- void *data)
+/* The prefix tree itself. */
+struct prefixtree
{
- asection *s;
- struct wildcard_list *wildsec0 = ptr->handler_data[0];
+ /* The list of all children (linked via .next). */
+ struct prefixtree *child;
+ struct prefixtree *next;
+ /* This tree node is responsible for the prefix of parent plus 'c'. */
+ char c;
+ /* The statements that potentially can match this prefix. */
+ struct wild_stmt_list *stmt;
+};
- for (s = file->the_bfd->sections; s != NULL; s = s->next)
- {
- const char *sname = bfd_section_name (s);
- bool skip = !match_simple_wild (wildsec0->spec.name, sname);
+/* We always have a root node in the prefix tree. It corresponds to the
+ empty prefix. E.g. a glob like "*" would sit in this root. */
+static struct prefixtree the_root, *ptroot = &the_root;
- if (!skip)
- walk_wild_consider_section (ptr, file, s, wildsec0, callback, data);
- }
-}
+/* Given a prefix tree in *TREE, corresponding to prefix P, find or
+ INSERT the tree node corresponding to prefix P+C. */
-static void
-walk_wild_section_specs2_wild1 (lang_wild_statement_type *ptr,
- lang_input_statement_type *file,
- callback_t callback,
- void *data)
+static struct prefixtree *
+get_prefix_tree (struct prefixtree **tree, char c, bool insert)
{
- asection *s;
- struct wildcard_list *sec0 = ptr->handler_data[0];
- struct wildcard_list *wildsec1 = ptr->handler_data[1];
- bool multiple_sections_found;
- asection *s0 = find_section (file, sec0, &multiple_sections_found);
-
- if (multiple_sections_found)
- {
- walk_wild_section_general (ptr, file, callback, data);
- return;
- }
+ struct prefixtree *t;
+ for (t = *tree; t; t = t->next)
+ if (t->c == c)
+ return t;
+ if (!insert)
+ return NULL;
+ t = (struct prefixtree *) obstack_alloc (&pt_obstack, sizeof *t);
+ t->child = NULL;
+ t->next = *tree;
+ t->c = c;
+ t->stmt = NULL;
+ *tree = t;
+ return t;
+}
- /* Note that if the section was not found, s0 is NULL and
- we'll simply never succeed the s == s0 test below. */
- for (s = file->the_bfd->sections; s != NULL; s = s->next)
- {
- /* Recall that in this code path, a section cannot satisfy more
- than one spec, so if s == s0 then it cannot match
- wildspec1. */
- if (s == s0)
- walk_wild_consider_section (ptr, file, s, sec0, callback, data);
- else
- {
- const char *sname = bfd_section_name (s);
- bool skip = !match_simple_wild (wildsec1->spec.name, sname);
+/* Add STMT to the set of statements that can be matched by the prefix
+ corresponding to prefix tree T. */
- if (!skip)
- walk_wild_consider_section (ptr, file, s, wildsec1, callback,
- data);
- }
- }
+static void
+pt_add_stmt (struct prefixtree *t, lang_wild_statement_type *stmt)
+{
+ struct wild_stmt_list *sl, **psl;
+ sl = (struct wild_stmt_list *) obstack_alloc (&pt_obstack, sizeof *sl);
+ sl->stmt = stmt;
+ sl->next = NULL;
+ psl = &t->stmt;
+ while (*psl)
+ psl = &(*psl)->next;
+ *psl = sl;
}
+/* Insert STMT into the global prefix tree. */
+
static void
-walk_wild_section_specs3_wild2 (lang_wild_statement_type *ptr,
- lang_input_statement_type *file,
- callback_t callback,
- void *data)
+insert_prefix_tree (lang_wild_statement_type *stmt)
{
- asection *s;
- struct wildcard_list *sec0 = ptr->handler_data[0];
- struct wildcard_list *wildsec1 = ptr->handler_data[1];
- struct wildcard_list *wildsec2 = ptr->handler_data[2];
- bool multiple_sections_found;
- asection *s0 = find_section (file, sec0, &multiple_sections_found);
+ struct wildcard_list *sec;
+ struct prefixtree *t;
- if (multiple_sections_found)
+ if (!stmt->section_list)
{
- walk_wild_section_general (ptr, file, callback, data);
+ /* If we have no section_list (no wildcards in the wild STMT),
+ then every section name will match, so add this to the root. */
+ pt_add_stmt (ptroot, stmt);
return;
}
- for (s = file->the_bfd->sections; s != NULL; s = s->next)
+ for (sec = stmt->section_list; sec; sec = sec->next)
{
- if (s == s0)
- walk_wild_consider_section (ptr, file, s, sec0, callback, data);
- else
+ const char *name = sec->spec.name ? sec->spec.name : "*";
+ char c;
+ t = ptroot;
+ for (; (c = *name); name++)
{
- const char *sname = bfd_section_name (s);
- bool skip = !match_simple_wild (wildsec1->spec.name, sname);
-
- if (!skip)
- walk_wild_consider_section (ptr, file, s, wildsec1, callback, data);
- else
- {
- skip = !match_simple_wild (wildsec2->spec.name, sname);
- if (!skip)
- walk_wild_consider_section (ptr, file, s, wildsec2, callback,
- data);
- }
+ if (c == '*' || c == '[' || c == '?')
+ break;
+ t = get_prefix_tree (&t->child, c, true);
}
+ /* If we hit a glob character, the matching prefix is what we saw
+ until now. If we hit the end of pattern (hence it's no glob) then
+ we can do better: we only need to record a match when a section name
+ completely matches, not merely a prefix, so record the trailing 0
+ as well. */
+ if (!c)
+ t = get_prefix_tree (&t->child, 0, true);
+ pt_add_stmt (t, stmt);
}
}
+/* Dump T indented by INDENT spaces. */
+
static void
-walk_wild_section_specs4_wild2 (lang_wild_statement_type *ptr,
- lang_input_statement_type *file,
- callback_t callback,
- void *data)
+debug_prefix_tree_rec (struct prefixtree *t, int indent)
{
- asection *s;
- struct wildcard_list *sec0 = ptr->handler_data[0];
- struct wildcard_list *sec1 = ptr->handler_data[1];
- struct wildcard_list *wildsec2 = ptr->handler_data[2];
- struct wildcard_list *wildsec3 = ptr->handler_data[3];
- bool multiple_sections_found;
- asection *s0 = find_section (file, sec0, &multiple_sections_found), *s1;
-
- if (multiple_sections_found)
+ for (; t; t = t->next)
{
- walk_wild_section_general (ptr, file, callback, data);
- return;
- }
-
- s1 = find_section (file, sec1, &multiple_sections_found);
- if (multiple_sections_found)
- {
- walk_wild_section_general (ptr, file, callback, data);
- return;
- }
-
- for (s = file->the_bfd->sections; s != NULL; s = s->next)
- {
- if (s == s0)
- walk_wild_consider_section (ptr, file, s, sec0, callback, data);
- else
- if (s == s1)
- walk_wild_consider_section (ptr, file, s, sec1, callback, data);
- else
- {
- const char *sname = bfd_section_name (s);
- bool skip = !match_simple_wild (wildsec2->spec.name, sname);
-
- if (!skip)
- walk_wild_consider_section (ptr, file, s, wildsec2, callback,
- data);
- else
- {
- skip = !match_simple_wild (wildsec3->spec.name, sname);
- if (!skip)
- walk_wild_consider_section (ptr, file, s, wildsec3,
- callback, data);
- }
- }
+ struct wild_stmt_list *sl;
+ printf ("%*s %c", indent, "", t->c);
+ for (sl = t->stmt; sl; sl = sl->next)
+ {
+ struct wildcard_list *curr;
+ printf (" %p ", sl->stmt);
+ for (curr = sl->stmt->section_list; curr; curr = curr->next)
+ printf ("%s ", curr->spec.name ? curr->spec.name : "*");
+ }
+ printf ("\n");
+ debug_prefix_tree_rec (t->child, indent + 2);
}
}
+/* Dump the global prefix tree. */
+
static void
-walk_wild_section (lang_wild_statement_type *ptr,
- lang_input_statement_type *file,
- callback_t callback,
- void *data)
+debug_prefix_tree (void)
{
- if (file->flags.just_syms)
- return;
-
- (*ptr->walk_wild_section_handler) (ptr, file, callback, data);
+ debug_prefix_tree_rec (ptroot, 2);
}
-/* Returns TRUE when name1 is a wildcard spec that might match
- something name2 can match. We're conservative: we return FALSE
- only if the prefixes of name1 and name2 are different up to the
- first wildcard character. */
+/* Like strcspn() but start to look from the end to beginning of
+ S. Returns the length of the suffix of S consisting entirely
+ of characters not in REJECT. */
-static bool
-wild_spec_can_overlap (const char *name1, const char *name2)
+static size_t
+rstrcspn (const char *s, const char *reject)
{
- size_t prefix1_len = strcspn (name1, "?*[");
- size_t prefix2_len = strcspn (name2, "?*[");
- size_t min_prefix_len;
-
- /* Note that if there is no wildcard character, then we treat the
- terminating 0 as part of the prefix. Thus ".text" won't match
- ".text." or ".text.*", for example. */
- if (name1[prefix1_len] == '\0')
- prefix1_len++;
- if (name2[prefix2_len] == '\0')
- prefix2_len++;
-
- min_prefix_len = prefix1_len < prefix2_len ? prefix1_len : prefix2_len;
-
- return memcmp (name1, name2, min_prefix_len) == 0;
+ size_t len = strlen (s), sufflen = 0;
+ while (len--)
+ {
+ char c = s[len];
+ if (strchr (reject, c) != 0)
+ break;
+ sufflen++;
+ }
+ return sufflen;
}
-/* Select specialized code to handle various kinds of wildcard
- statements. */
+/* Analyze the wildcards in wild statement PTR to setup various
+ things for quick matching. */
static void
analyze_walk_wild_section_handler (lang_wild_statement_type *ptr)
{
- int sec_count = 0;
- int wild_name_count = 0;
struct wildcard_list *sec;
- int signature;
- int data_counter;
-
- ptr->walk_wild_section_handler = walk_wild_section_general;
- ptr->handler_data[0] = NULL;
- ptr->handler_data[1] = NULL;
- ptr->handler_data[2] = NULL;
- ptr->handler_data[3] = NULL;
+
ptr->tree = NULL;
+ ptr->rightmost = &ptr->tree;
- /* Count how many wildcard_specs there are, and how many of those
- actually use wildcards in the name. Also, bail out if any of the
- wildcard names are NULL. (Can this actually happen?
- walk_wild_section used to test for it.) And bail out if any
- of the wildcards are more complex than a simple string
- ending in a single '*'. */
for (sec = ptr->section_list; sec != NULL; sec = sec->next)
{
- ++sec_count;
- if (sec->spec.name == NULL)
- return;
- if (wildcardp (sec->spec.name))
+ if (sec->spec.name)
{
- ++wild_name_count;
- if (!is_simple_wild (sec->spec.name))
- return;
+ sec->spec.namelen = strlen (sec->spec.name);
+ sec->spec.prefixlen = strcspn (sec->spec.name, "?*[");
+ sec->spec.suffixlen = rstrcspn (sec->spec.name + sec->spec.prefixlen,
+ "?*]");
}
+ else
+ sec->spec.namelen = sec->spec.prefixlen = sec->spec.suffixlen = 0;
}
- /* The zero-spec case would be easy to optimize but it doesn't
- happen in practice. Likewise, more than 4 specs doesn't
- happen in practice. */
- if (sec_count == 0 || sec_count > 4)
+ insert_prefix_tree (ptr);
+}
+
+/* Match all sections from FILE against the global prefix tree,
+ and record them into each wild statement that has a match. */
+
+static void
+resolve_wild_sections (lang_input_statement_type *file)
+{
+ asection *s;
+
+ if (file->flags.just_syms)
return;
- /* Check that no two specs can match the same section. */
- for (sec = ptr->section_list; sec != NULL; sec = sec->next)
+ for (s = file->the_bfd->sections; s != NULL; s = s->next)
{
- struct wildcard_list *sec2;
- for (sec2 = sec->next; sec2 != NULL; sec2 = sec2->next)
+ const char *sname = bfd_section_name (s);
+ char c = 1;
+ struct prefixtree *t = ptroot;
+ //printf (" YYY consider %s of %s\n", sname, file->the_bfd->filename);
+ do
{
- if (wild_spec_can_overlap (sec->spec.name, sec2->spec.name))
- return;
+ if (t->stmt)
+ {
+ struct wild_stmt_list *sl;
+ for (sl = t->stmt; sl; sl = sl->next)
+ {
+ walk_wild_section_match (sl->stmt, file, s);
+ //printf (" ZZZ maybe place into %p\n", sl->stmt);
+ }
+ }
+ if (!c)
+ break;
+ c = *sname++;
+ t = get_prefix_tree (&t->child, c, false);
}
+ while (t);
}
-
- signature = (sec_count << 8) + wild_name_count;
- switch (signature)
- {
- case 0x0100:
- ptr->walk_wild_section_handler = walk_wild_section_specs1_wild0;
- break;
- case 0x0101:
- ptr->walk_wild_section_handler = walk_wild_section_specs1_wild1;
- break;
- case 0x0201:
- ptr->walk_wild_section_handler = walk_wild_section_specs2_wild1;
- break;
- case 0x0302:
- ptr->walk_wild_section_handler = walk_wild_section_specs3_wild2;
- break;
- case 0x0402:
- ptr->walk_wild_section_handler = walk_wild_section_specs4_wild2;
- break;
- default:
- return;
- }
-
- /* Now fill the data array with pointers to the specs, first the
- specs with non-wildcard names, then the specs with wildcard
- names. It's OK to process the specs in different order from the
- given order, because we've already determined that no section
- will match more than one spec. */
- data_counter = 0;
- for (sec = ptr->section_list; sec != NULL; sec = sec->next)
- if (!wildcardp (sec->spec.name))
- ptr->handler_data[data_counter++] = sec;
- for (sec = ptr->section_list; sec != NULL; sec = sec->next)
- if (wildcardp (sec->spec.name))
- ptr->handler_data[data_counter++] = sec;
}
-/* Handle a wild statement for a single file F. */
+/* Match all sections from all input files against the global prefix tree. */
static void
-walk_wild_file (lang_wild_statement_type *s,
- lang_input_statement_type *f,
- callback_t callback,
- void *data)
+resolve_wilds (void)
{
- if (walk_wild_file_in_exclude_list (s->exclude_name_list, f))
- return;
-
- if (f->the_bfd == NULL
- || !bfd_check_format (f->the_bfd, bfd_archive))
- walk_wild_section (s, f, callback, data);
- else
+ LANG_FOR_EACH_INPUT_STATEMENT (f)
{
- 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, NULL);
- while (member != NULL)
+ //printf("XXX %s\n", f->filename);
+ if (f->the_bfd == NULL
+ || !bfd_check_format (f->the_bfd, bfd_archive))
+ resolve_wild_sections (f);
+ else
{
- /* 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 (bfd_usrdata (member) != NULL)
- walk_wild_section (s, bfd_usrdata (member), callback, data);
+ bfd *member;
- member = bfd_openr_next_archived_file (f->the_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, 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 (bfd_usrdata (member) != NULL)
+ resolve_wild_sections (bfd_usrdata (member));
+
+ member = bfd_openr_next_archived_file (f->the_bfd, member);
+ }
}
}
}
+/* For each input section that matches wild statement S calls
+ CALLBACK with DATA. */
+
static void
walk_wild (lang_wild_statement_type *s, callback_t callback, void *data)
{
- const char *file_spec = s->filename;
- char *p;
+ lang_statement_union_type *l;
- if (file_spec == NULL)
- {
- /* Perform the iteration over all files in the list. */
- LANG_FOR_EACH_INPUT_STATEMENT (f)
- {
- walk_wild_file (s, f, callback, data);
- }
- }
- else if ((p = archive_path (file_spec)) != NULL)
+ for (l = s->matching_sections.head; l; l = l->header.next)
{
- LANG_FOR_EACH_INPUT_STATEMENT (f)
- {
- if (input_statement_is_archive_path (file_spec, p, f))
- walk_wild_file (s, f, callback, data);
- }
- }
- else if (wildcardp (file_spec))
- {
- LANG_FOR_EACH_INPUT_STATEMENT (f)
- {
- if (fnmatch (file_spec, f->filename, 0) == 0)
- walk_wild_file (s, f, callback, data);
- }
- }
- else
- {
- lang_input_statement_type *f;
-
- /* Perform the iteration over a single file. */
- f = lookup_name (file_spec);
- if (f)
- walk_wild_file (s, f, callback, data);
+ (*callback) (s, l->input_matcher.pattern, l->input_matcher.section,
+ l->input_matcher.input_stmt, data);
}
}
p->flags.add_DT_NEEDED_for_regular = input_flags.add_DT_NEEDED_for_regular;
p->flags.whole_archive = input_flags.whole_archive;
p->flags.sysrooted = input_flags.sysrooted;
+ p->sort_key = NULL;
switch (file_type)
{
lang_init (void)
{
obstack_begin (&stat_obstack, 1000);
+ obstack_init (&pt_obstack);
stat_ptr = &statement_list;
case lang_group_statement_enum:
case lang_insert_statement_enum:
continue;
+ case lang_input_matcher_enum:
+ FAIL ();
}
break;
}
address = exp_intop (0);
os_tail = (lang_output_section_statement_type **) lang_os_list.tail;
- os = lang_enter_output_section_statement (secname, address, normal_section,
- NULL, NULL, NULL, constraint, 0);
+ os = lang_enter_output_section_statement (
+ secname, address, normal_section, 0, NULL, NULL, NULL, constraint, 0);
if (add_child == NULL)
add_child = &os->children;
for (m = asneeded_list_head; m != NULL; m = m->next)
{
- size_t len;
+ int len;
minfo ("%s", m->soname);
len = strlen (m->soname);
print_nl ();
len = 0;
}
- while (len < 30)
- {
- print_space ();
- ++len;
- }
+ print_spaces (30 - len);
if (m->ref != NULL)
minfo ("%pB ", m->ref);
for (m = lang_memory_region_list; m != NULL; m = m->next)
{
- char buf[100];
- int len;
-
- fprintf (config.map_file, "%-16s ", m->name_list.name);
+ fprintf (config.map_file, "%-16s", m->name_list.name);
- sprintf_vma (buf, m->origin);
- minfo ("0x%s ", buf);
- len = strlen (buf);
- while (len < 16)
- {
- print_space ();
- ++len;
- }
+ char buf[32];
+ bfd_sprintf_vma (link_info.output_bfd, buf, m->origin);
+ fprintf (config.map_file, " 0x%-16s", buf);
+ bfd_sprintf_vma (link_info.output_bfd, buf, m->length);
+ fprintf (config.map_file,
+ " 0x%*s", m->flags || m->not_flags ? -17 : 0, buf);
+ if (m->flags)
+ lang_map_flags (m->flags);
- minfo ("0x%V", m->length);
- if (m->flags || m->not_flags)
+ if (m->not_flags)
{
-#ifndef BFD64
- minfo (" ");
-#endif
- if (m->flags)
- {
- print_space ();
- lang_map_flags (m->flags);
- }
-
- if (m->not_flags)
- {
- minfo (" !");
- lang_map_flags (m->not_flags);
- }
+ minfo ("!");
+ lang_map_flags (m->not_flags);
}
print_nl ();
{
case ADDR:
case LOADADDR:
- case SIZEOF:
{
lang_output_section_statement_type *os;
case normal_section:
case overlay_section:
case first_overlay_section:
+ case type_section:
break;
case noalloc_section:
flags &= ~SEC_ALLOC;
break;
+ case typed_readonly_section:
case readonly_section:
flags |= SEC_READONLY;
break;
new_section->pattern = pattern;
}
-/* 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 lang_statement_union_type *
-wild_sort (lang_wild_statement_type *wild,
- struct wildcard_list *sec,
- lang_input_statement_type *file,
- asection *section)
-{
- lang_statement_union_type *l;
-
- if (!wild->filenames_sorted
- && (sec == NULL || sec->spec.sorted == none))
- return NULL;
-
- for (l = wild->children.head; l != NULL; l = l->header.next)
- {
- lang_input_section_type *ls;
-
- if (l->header.type != lang_input_section_enum)
- continue;
- ls = &l->input_section;
-
- /* Sorting by filename takes precedence over sorting by section
- name. */
-
- if (wild->filenames_sorted)
- {
- const char *fn, *ln;
- bool fa, la;
- int i;
-
- /* 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. */
-
- if (file->the_bfd != NULL
- && file->the_bfd->my_archive != NULL)
- {
- fn = bfd_get_filename (file->the_bfd->my_archive);
- fa = true;
- }
- else
- {
- fn = file->filename;
- fa = false;
- }
-
- if (ls->section->owner->my_archive != NULL)
- {
- ln = bfd_get_filename (ls->section->owner->my_archive);
- la = true;
- }
- else
- {
- ln = bfd_get_filename (ls->section->owner);
- la = false;
- }
-
- i = filename_cmp (fn, ln);
- if (i > 0)
- continue;
- else if (i < 0)
- break;
-
- if (fa || la)
- {
- if (fa)
- fn = file->filename;
- if (la)
- ln = bfd_get_filename (ls->section->owner);
-
- i = filename_cmp (fn, ln);
- if (i > 0)
- continue;
- else if (i < 0)
- break;
- }
- }
-
- /* Here either the files are not sorted by name, or we are
- looking at the sections for this file. */
-
- if (sec != NULL
- && sec->spec.sorted != none
- && sec->spec.sorted != by_none)
- if (compare_section (sec->spec.sorted, section, 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. */
+ NULL, in which case it is a wild card. This assumes that the
+ wild statement doesn't need any sorting (of filenames or sections). */
static void
-output_section_callback (lang_wild_statement_type *ptr,
- struct wildcard_list *sec,
- asection *section,
- lang_input_statement_type *file,
- void *output)
+output_section_callback_nosort (lang_wild_statement_type *ptr,
+ struct wildcard_list *sec ATTRIBUTE_UNUSED,
+ asection *section,
+ lang_input_statement_type *file ATTRIBUTE_UNUSED,
+ void *output)
{
- lang_statement_union_type *before;
lang_output_section_statement_type *os;
os = (lang_output_section_statement_type *) output;
if (unique_section_p (section, os))
return;
- before = wild_sort (ptr, sec, file, section);
-
- /* Here BEFORE points to the lang_input_section which
- should follow the one we are about to add. If BEFORE
- is NULL, then the section should just go at the end
- of the current list. */
-
- if (before == NULL)
- lang_add_section (&ptr->children, section, ptr->section_list,
- ptr->section_flag_list, os);
- else
- {
- lang_statement_list_type list;
- lang_statement_union_type **pp;
-
- lang_list_init (&list);
- lang_add_section (&list, section, ptr->section_list,
- ptr->section_flag_list, os);
-
- /* If we are discarding the section, LIST.HEAD will
- be NULL. */
- if (list.head != NULL)
- {
- ASSERT (list.head->header.next == NULL);
-
- for (pp = &ptr->children.head;
- *pp != before;
- pp = &(*pp)->header.next)
- ASSERT (*pp != NULL);
-
- list.head->header.next = *pp;
- *pp = list.head;
- }
- }
+ lang_add_section (&ptr->children, section, ptr->section_list,
+ ptr->section_flag_list, os);
}
/* Check if all sections in a wild statement for a particular FILE
/* See if the emulation has some special knowledge. */
if (ldemul_unrecognized_file (entry))
- return true;
+ {
+ if (err == bfd_error_file_ambiguously_recognized)
+ free (matching);
+ return true;
+ }
if (err == bfd_error_file_ambiguously_recognized)
{
" matching formats:"), entry->the_bfd);
for (p = matching; *p != NULL; p++)
einfo (" %s", *p);
+ free (matching);
einfo ("%F\n");
}
else if (err != bfd_error_file_not_recognized
{
struct wildcard_list *sec;
- if (s->handler_data[0]
- && s->handler_data[0]->spec.sorted == by_name
- && !s->filenames_sorted)
+ if (s->filenames_sorted || s->any_specs_sorted)
{
lang_section_bst_type *tree;
- walk_wild (s, output_section_callback_fast, output);
+ walk_wild (s, output_section_callback_sort, output);
tree = s->tree;
if (tree)
{
output_section_callback_tree_to_list (s, tree, output);
s->tree = NULL;
+ s->rightmost = &s->tree;
}
}
else
- walk_wild (s, output_section_callback, output);
+ walk_wild (s, output_section_callback_nosort, output);
if (default_common_section == NULL)
for (sec = s->section_list; sec != NULL; sec = sec->next)
/* Don't sort .init/.fini sections. */
if (strcmp (sec->spec.name, ".init") != 0
&& strcmp (sec->spec.name, ".fini") != 0)
- switch (sec->spec.sorted)
- {
- case none:
- sec->spec.sorted = sort_section;
- break;
- case by_name:
- if (sort_section == by_alignment)
- sec->spec.sorted = by_name_alignment;
- break;
- case by_alignment:
- if (sort_section == by_name)
- sec->spec.sorted = by_alignment_name;
- break;
- default:
- break;
- }
+ {
+ switch (sec->spec.sorted)
+ {
+ case none:
+ sec->spec.sorted = sort_section;
+ break;
+ case by_name:
+ if (sort_section == by_alignment)
+ sec->spec.sorted = by_name_alignment;
+ break;
+ case by_alignment:
+ if (sort_section == by_name)
+ sec->spec.sorted = by_alignment_name;
+ break;
+ default:
+ break;
+ }
+ s->wild_statement.any_specs_sorted = true;
+ }
break;
case lang_constructors_statement_enum:
{
lang_output_section_statement_type *tos;
flagword flags;
+ unsigned int type = 0;
switch (s->header.type)
{
case readonly_section:
flags |= SEC_READONLY;
break;
+ case typed_readonly_section:
+ flags |= SEC_READONLY;
+ /* Fall through. */
+ case type_section:
+ if (os->sectype_value->type.node_class == etree_name
+ && os->sectype_value->type.node_code == NAME)
+ {
+ const char *name = os->sectype_value->name.name;
+ if (strcmp (name, "SHT_PROGBITS") == 0)
+ type = SHT_PROGBITS;
+ else if (strcmp (name, "SHT_STRTAB") == 0)
+ type = SHT_STRTAB;
+ else if (strcmp (name, "SHT_NOTE") == 0)
+ type = SHT_NOTE;
+ else if (strcmp (name, "SHT_NOBITS") == 0)
+ type = SHT_NOBITS;
+ else if (strcmp (name, "SHT_INIT_ARRAY") == 0)
+ type = SHT_INIT_ARRAY;
+ else if (strcmp (name, "SHT_FINI_ARRAY") == 0)
+ type = SHT_FINI_ARRAY;
+ else if (strcmp (name, "SHT_PREINIT_ARRAY") == 0)
+ type = SHT_PREINIT_ARRAY;
+ else
+ einfo (_ ("%F%P: invalid type for output section `%s'\n"),
+ os->name);
+ }
+ else
+ {
+ exp_fold_tree_no_dot (os->sectype_value);
+ if (expld.result.valid_p)
+ type = expld.result.value;
+ else
+ einfo (_ ("%F%P: invalid type for output section `%s'\n"),
+ os->name);
+ }
+ break;
case noload_section:
if (bfd_get_flavour (link_info.output_bfd)
== bfd_target_elf_flavour)
init_os (os, flags | SEC_READONLY);
else
os->bfd_section->flags |= flags;
+ os->bfd_section->type = type;
break;
case lang_input_section_enum:
break;
break;
case lang_insert_statement_enum:
break;
+ case lang_input_matcher_enum:
+ FAIL ();
}
}
}
print_nl ();
len = 0;
}
- while (len < SECTION_NAME_MAP_LENGTH)
- {
- print_space ();
- ++len;
- }
+ print_spaces (SECTION_NAME_MAP_LENGTH - len);
minfo ("0x%V %W", section->vma, TO_ADDR (section->size));
print_assignment (lang_assignment_statement_type *assignment,
lang_output_section_statement_type *output_section)
{
- unsigned int i;
bool is_dot;
etree_type *tree;
asection *osec;
- for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
- print_space ();
+ print_spaces (SECTION_NAME_MAP_LENGTH);
if (assignment->exp->type.node_class == etree_assert)
{
else
expld.result.valid_p = false;
+ char buf[32];
+ const char *str = buf;
if (expld.result.valid_p)
{
bfd_vma value;
if (expld.result.section != NULL)
value += expld.result.section->vma;
- minfo ("0x%V", value);
+ buf[0] = '0';
+ buf[1] = 'x';
+ bfd_sprintf_vma (link_info.output_bfd, buf + 2, value);
if (is_dot)
print_dot = value;
}
value += h->u.def.section->output_section->vma;
value += h->u.def.section->output_offset;
- minfo ("[0x%V]", value);
+ buf[0] = '[';
+ buf[1] = '0';
+ buf[2] = 'x';
+ bfd_sprintf_vma (link_info.output_bfd, buf + 3, value);
+ strcat (buf, "]");
}
else
- minfo ("[unresolved]");
+ str = "[unresolved]";
}
}
else
{
if (assignment->exp->type.node_class == etree_provide)
- minfo ("[!provide]");
+ str = "[!provide]";
else
- minfo ("*undef* ");
-#ifdef BFD64
- minfo (" ");
-#endif
+ str = "*undef*";
}
expld.assign_name = NULL;
- minfo (" ");
+ fprintf (config.map_file, "%-34s", str);
exp_print_tree (assignment->exp);
print_nl ();
}
|| hash_entry->type == bfd_link_hash_defweak)
&& sec == hash_entry->u.def.section)
{
- int i;
-
- for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
- print_space ();
+ print_spaces (SECTION_NAME_MAP_LENGTH);
minfo ("0x%V ",
(hash_entry->u.def.value
+ hash_entry->u.def.section->output_offset
init_opb (i);
- print_space ();
- minfo ("%s", i->name);
+ minfo (" %s", i->name);
len = 1 + strlen (i->name);
if (len >= SECTION_NAME_MAP_LENGTH - 1)
print_nl ();
len = 0;
}
- while (len < SECTION_NAME_MAP_LENGTH)
- {
- print_space ();
- ++len;
- }
+ print_spaces (SECTION_NAME_MAP_LENGTH - len);
if (i->output_section != NULL
&& i->output_section->owner == link_info.output_bfd)
size = 0;
}
- minfo ("0x%V %W %pB\n", addr, TO_ADDR (size), i->owner);
+ char buf[32];
+ bfd_sprintf_vma (link_info.output_bfd, buf, addr);
+ minfo ("0x%s %W %pB\n", buf, TO_ADDR (size), i->owner);
if (size != i->rawsize && i->rawsize != 0)
{
- len = SECTION_NAME_MAP_LENGTH + 3;
-#ifdef BFD64
- len += 16;
-#else
- len += 8;
-#endif
- while (len > 0)
- {
- print_space ();
- --len;
- }
-
+ len = SECTION_NAME_MAP_LENGTH + 3 + strlen (buf);
+ print_spaces (len);
minfo (_("%W (size before relaxing)\n"), TO_ADDR (i->rawsize));
}
static void
print_data_statement (lang_data_statement_type *data)
{
- int i;
bfd_vma addr;
bfd_size_type size;
const char *name;
init_opb (data->output_section);
- for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
- print_space ();
+ print_spaces (SECTION_NAME_MAP_LENGTH);
addr = data->output_offset;
if (data->output_section != NULL)
static void
print_reloc_statement (lang_reloc_statement_type *reloc)
{
- int i;
bfd_vma addr;
bfd_size_type size;
init_opb (reloc->output_section);
- for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
- print_space ();
+ print_spaces (SECTION_NAME_MAP_LENGTH);
addr = reloc->output_offset;
if (reloc->output_section != NULL)
minfo (" *fill*");
len = sizeof " *fill*" - 1;
- while (len < SECTION_NAME_MAP_LENGTH)
- {
- print_space ();
- ++len;
- }
+ print_spaces (SECTION_NAME_MAP_LENGTH - len);
addr = s->output_offset;
if (s->output_section != NULL)
}
static void
-ldlang_check_relro_region (lang_statement_union_type *s,
- seg_align_type *seg)
+ldlang_check_relro_region (lang_statement_union_type *s)
{
+ seg_align_type *seg = &expld.dataseg;
+
if (seg->relro == exp_seg_relro_start)
{
if (!seg->relro_start_stat)
os->addr_tree = exp_intop (0);
if (os->addr_tree != NULL)
{
- os->processed_vma = false;
exp_fold_tree (os->addr_tree, bfd_abs_section_ptr, &dot);
if (expld.result.valid_p)
output_section_statement->bfd_section,
&newdot);
- ldlang_check_relro_region (s, &expld.dataseg);
+ ldlang_check_relro_region (s);
expld.dataseg.relro = exp_seg_relro_none;
}
static bool
-lang_size_segment (seg_align_type *seg)
+lang_size_segment (void)
{
/* If XXX_SEGMENT_ALIGN XXX_SEGMENT_END pair was seen, check whether
a page could be saved in the data segment. */
+ seg_align_type *seg = &expld.dataseg;
bfd_vma first, last;
- first = -seg->base & (seg->pagesize - 1);
- last = seg->end & (seg->pagesize - 1);
+ first = -seg->base & (seg->commonpagesize - 1);
+ last = seg->end & (seg->commonpagesize - 1);
if (first && last
- && ((seg->base & ~(seg->pagesize - 1))
- != (seg->end & ~(seg->pagesize - 1)))
- && first + last <= seg->pagesize)
+ && ((seg->base & ~(seg->commonpagesize - 1))
+ != (seg->end & ~(seg->commonpagesize - 1)))
+ && first + last <= seg->commonpagesize)
{
seg->phase = exp_seg_adjust;
return true;
}
static bfd_vma
-lang_size_relro_segment_1 (seg_align_type *seg)
+lang_size_relro_segment_1 (void)
{
+ seg_align_type *seg = &expld.dataseg;
bfd_vma relro_end, desired_end;
- asection *sec, *prev_sec = NULL;
- bool remove_page_gap = false;
- unsigned int max_alignment_power = 0;
+ asection *sec;
/* Compute the expected PT_GNU_RELRO/PT_LOAD segment end. */
- relro_end = ((seg->relro_end + seg->pagesize - 1)
- & ~(seg->pagesize - 1));
+ relro_end = (seg->relro_end + seg->relropagesize - 1) & -seg->relropagesize;
/* Adjust by the offset arg of XXX_SEGMENT_RELRO_END. */
desired_end = relro_end - seg->relro_offset;
/* For sections in the relro segment.. */
for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev)
- if ((sec->flags & SEC_ALLOC) != 0)
+ if ((sec->flags & SEC_ALLOC) != 0
+ && sec->vma >= seg->base
+ && sec->vma < seg->relro_end - seg->relro_offset)
{
- if (sec->alignment_power > max_alignment_power)
- max_alignment_power = sec->alignment_power;
-
- if (sec->vma >= seg->base
- && sec->vma < seg->relro_end - seg->relro_offset)
- {
- /* Where do we want to put this section so that it ends as
- desired? */
- bfd_vma start, end, bump;
-
- end = start = sec->vma;
- if (!IS_TBSS (sec))
- end += TO_ADDR (sec->size);
- bump = desired_end - end;
- /* We'd like to increase START by BUMP, but we must heed
- alignment so the increase might be less than optimum. */
- start += bump;
- start &= ~(((bfd_vma) 1 << sec->alignment_power) - 1);
- /* This is now the desired end for the previous section. */
- desired_end = start;
- prev_sec = sec->prev;
- }
+ /* Where do we want to put this section so that it ends as
+ desired? */
+ bfd_vma start, end, bump;
+
+ end = start = sec->vma;
+ if (!IS_TBSS (sec))
+ end += TO_ADDR (sec->size);
+ bump = desired_end - end;
+ /* We'd like to increase START by BUMP, but we must heed
+ alignment so the increase might be less than optimum. */
+ start += bump;
+ start &= ~(((bfd_vma) 1 << sec->alignment_power) - 1);
+ /* This is now the desired end for the previous section. */
+ desired_end = start;
}
seg->phase = exp_seg_relro_adjust;
ASSERT (desired_end >= seg->base);
-
- for (; prev_sec; prev_sec = prev_sec->prev)
- if ((prev_sec->flags & SEC_ALLOC) != 0)
- {
- if (prev_sec->alignment_power > max_alignment_power)
- max_alignment_power = prev_sec->alignment_power;
-
- if (prev_sec->size != 0)
- {
- /* The 1-page gap before the RELRO segment may be removed. */
- remove_page_gap = ((prev_sec->vma + prev_sec->size
- + seg->maxpagesize) < desired_end);
-
- break;
- }
- }
-
- if (remove_page_gap)
- {
- /* Find the maximum section alignment. */
- for (sec = prev_sec; sec; sec = sec->prev)
- if ((sec->flags & SEC_ALLOC) != 0
- && sec->alignment_power > max_alignment_power)
- max_alignment_power = sec->alignment_power;
-
- /* Remove the 1-page gap before the RELRO segment only if the
- maximum page size >= the maximum section alignment. */
- if (seg->maxpagesize >= (1U << max_alignment_power))
- {
- /* If the preceding section size is greater than the maximum
- page size, subtract the maximum page size. Otherwise,
- align the RELRO segment to the maximum page size. */
- if (prev_sec->size > seg->maxpagesize)
- {
- desired_end -= seg->maxpagesize;
- relro_end -= seg->maxpagesize;
- }
- else
- {
- desired_end &= ~(seg->maxpagesize - 1);
- relro_end &= ~(seg->maxpagesize - 1);
- }
- }
- }
-
seg->base = desired_end;
return relro_end;
}
lang_size_relro_segment (bool *relax, bool check_regions)
{
bool do_reset = false;
- bool do_data_relro;
- bfd_vma data_initial_base, data_relro_end;
if (link_info.relro && expld.dataseg.relro_end)
{
- do_data_relro = true;
- data_initial_base = expld.dataseg.base;
- data_relro_end = lang_size_relro_segment_1 (&expld.dataseg);
- }
- else
- {
- do_data_relro = false;
- data_initial_base = data_relro_end = 0;
- }
+ bfd_vma data_initial_base = expld.dataseg.base;
+ bfd_vma data_relro_end = lang_size_relro_segment_1 ();
- if (do_data_relro)
- {
lang_reset_memory_regions ();
one_lang_size_sections_pass (relax, check_regions);
/* Assignments to dot, or to output section address in a user
script have increased padding over the original. Revert. */
- if (do_data_relro && expld.dataseg.relro_end > data_relro_end)
+ if (expld.dataseg.relro_end > data_relro_end)
{
- expld.dataseg.base = data_initial_base;;
+ expld.dataseg.base = data_initial_base;
do_reset = true;
}
}
-
- if (!do_data_relro && lang_size_segment (&expld.dataseg))
+ else if (lang_size_segment ())
do_reset = true;
return do_reset;
if (stmt->header.type == lang_output_section_statement_enum)
break;
- os = &stmt->output_section_statement;
+ os = stmt ? &stmt->output_section_statement : NULL;
while (os != NULL
&& !os->after_end
&& (os->bfd_section == NULL
foreach_start_stop (set_start_stop);
}
+static void
+lang_symbol_tweaks (void)
+{
+ /* Give initial values for __start and __stop symbols, so that ELF
+ gc_sections will keep sections referenced by these symbols. Must
+ be done before lang_do_assignments. */
+ if (config.build_constructors)
+ lang_init_start_stop ();
+
+ /* Make __ehdr_start hidden, and set def_regular even though it is
+ likely undefined at this stage. For lang_check_relocs. */
+ if (is_elf_hash_table (link_info.hash)
+ && !bfd_link_relocatable (&link_info))
+ {
+ struct elf_link_hash_entry *h = (struct elf_link_hash_entry *)
+ bfd_link_hash_lookup (link_info.hash, "__ehdr_start",
+ false, false, true);
+
+ /* Only adjust the export class if the symbol was referenced
+ and not defined, otherwise leave it alone. */
+ if (h != NULL
+ && (h->root.type == bfd_link_hash_new
+ || h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak
+ || h->root.type == bfd_link_hash_common))
+ {
+ const struct elf_backend_data *bed;
+ bed = get_elf_backend_data (link_info.output_bfd);
+ (*bed->elf_backend_hide_symbol) (&link_info, h, true);
+ if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL)
+ h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
+ h->def_regular = 1;
+ h->root.linker_def = 1;
+ h->root.rel_from_abs = 1;
+ }
+ }
+}
+
static void
lang_end (void)
{
static bool header_printed;
int len;
char *name;
- char buf[50];
+ char buf[32];
if (!header_printed)
{
print_nl ();
len = 0;
}
- while (len < 20)
- {
- print_space ();
- ++len;
- }
- minfo ("0x");
- if (size <= 0xffffffff)
- sprintf (buf, "%lx", (unsigned long) size);
- else
- sprintf_vma (buf, size);
- minfo ("%s", buf);
- len = strlen (buf);
-
- while (len < 16)
- {
- print_space ();
- ++len;
- }
+ sprintf (buf, "%" PRIx64, (uint64_t) size);
+ fprintf (config.map_file, "%*s0x%-16s", 20 - len, "", buf);
minfo ("%pB\n", section->owner);
}
lang_enter_output_section_statement (const char *output_section_statement_name,
etree_type *address_exp,
enum section_type sectype,
+ etree_type *sectype_value,
etree_type *align,
etree_type *subalign,
etree_type *ebase,
os->addr_tree = address_exp;
}
os->sectype = sectype;
- if (sectype != noload_section)
- os->flags = SEC_NO_FLAGS;
- else
+ if (sectype == type_section || sectype == typed_readonly_section)
+ os->sectype_value = sectype_value;
+ else if (sectype == noload_section)
os->flags = SEC_NEVER_LOAD;
+ else
+ os->flags = SEC_NO_FLAGS;
os->block_value = 1;
/* Make next things chain into subchain of this. */
static void
lang_find_relro_sections_1 (lang_statement_union_type *s,
- seg_align_type *seg,
bool *has_relro_section)
{
if (*has_relro_section)
for (; s != NULL; s = s->header.next)
{
- if (s == seg->relro_end_stat)
+ if (s == expld.dataseg.relro_end_stat)
break;
switch (s->header.type)
break;
case lang_constructors_statement_enum:
lang_find_relro_sections_1 (constructor_list.head,
- seg, has_relro_section);
+ has_relro_section);
break;
case lang_output_section_statement_enum:
lang_find_relro_sections_1 (s->output_section_statement.children.head,
- seg, has_relro_section);
+ has_relro_section);
break;
case lang_group_statement_enum:
lang_find_relro_sections_1 (s->group_statement.children.head,
- seg, has_relro_section);
+ has_relro_section);
break;
default:
break;
/* Check all sections in the link script. */
lang_find_relro_sections_1 (expld.dataseg.relro_start_stat,
- &expld.dataseg, &has_relro_section);
+ &has_relro_section);
if (!has_relro_section)
link_info.relro = false;
}
}
+static void
+reset_one_wild (lang_statement_union_type *statement)
+{
+ if (statement->header.type == lang_wild_statement_enum)
+ {
+ lang_wild_statement_type *stmt = &statement->wild_statement;
+ lang_list_init (&stmt->matching_sections);
+ }
+}
+
+static void
+reset_resolved_wilds (void)
+{
+ lang_for_each_statement (reset_one_wild);
+}
+
void
lang_process (void)
{
lang_statement_list_type added;
lang_statement_list_type files, inputfiles;
+ ldemul_before_plugin_all_symbols_read ();
+
/* Now all files are read, let the plugin(s) decide if there
are any more to be added to the link before we call the
emulation's after_open hook. We create a private list of
files. */
ldctor_build_sets ();
- /* Give initial values for __start and __stop symbols, so that ELF
- gc_sections will keep sections referenced by these symbols. Must
- be done before lang_do_assignments below. */
- if (config.build_constructors)
- lang_init_start_stop ();
+ lang_symbol_tweaks ();
/* PR 13683: We must rerun the assignments prior to running garbage
collection in order to make sure that all symbol aliases are resolved. */
/* Size up the common data. */
lang_common ();
+ if (0)
+ debug_prefix_tree ();
+
+ resolve_wilds ();
+
/* Remove unreferenced sections if asked to. */
lang_gc_sections ();
ldemul_after_check_relocs ();
- /* Update wild statements. */
+ /* There might have been new sections created (e.g. as result of
+ checking relocs to need a .got, or suchlike), so to properly order
+ them into our lists of matching sections reset them here. */
+ reset_resolved_wilds ();
+ resolve_wilds ();
+
+ /* Update wild statements in case the user gave --sort-section.
+ Note how the option might have come after the linker script and
+ so couldn't have been set when the wild statements were created. */
update_wild_statements (statement_list.head);
/* Run through the contours of the script and attach input sections
{
struct wildcard_list *curr, *next;
lang_wild_statement_type *new_stmt;
+ bool any_specs_sorted = false;
/* Reverse the list as the parser puts it back to front. */
for (curr = section_list, section_list = NULL;
curr != NULL;
section_list = curr, curr = next)
{
+ if (curr->spec.sorted != none && curr->spec.sorted != by_none)
+ any_specs_sorted = true;
next = curr->next;
curr->next = section_list;
}
new_stmt = new_stat (lang_wild_statement, stat_ptr);
new_stmt->filename = NULL;
new_stmt->filenames_sorted = false;
+ new_stmt->any_specs_sorted = any_specs_sorted;
new_stmt->section_flag_list = NULL;
new_stmt->exclude_name_list = NULL;
if (filespec != NULL)
new_stmt->section_list = section_list;
new_stmt->keep_sections = keep_sections;
lang_list_init (&new_stmt->children);
+ lang_list_init (&new_stmt->matching_sections);
analyze_walk_wild_section_handler (new_stmt);
+ if (0)
+ {
+ printf ("wild %s(", new_stmt->filename ? new_stmt->filename : "*");
+ for (curr = new_stmt->section_list; curr; curr = curr->next)
+ printf ("%s ", curr->spec.name ? curr->spec.name : "*");
+ printf (")\n");
+ }
}
void
etree_type *size;
lang_enter_output_section_statement (name, overlay_vma, overlay_section,
- 0, overlay_subalign, 0, 0, 0);
+ 0, 0, overlay_subalign, 0, 0, 0);
/* If this is the first section, then base the VMA of future
sections on this one. This will work correctly even if `.' is
/* Pretty print memory amount. */
static void
-lang_print_memory_size (bfd_vma sz)
+lang_print_memory_size (uint64_t sz)
{
if ((sz & 0x3fffffff) == 0)
- printf ("%10" BFD_VMA_FMT "u GB", sz >> 30);
+ printf ("%10" PRIu64 " GB", sz >> 30);
else if ((sz & 0xfffff) == 0)
- printf ("%10" BFD_VMA_FMT "u MB", sz >> 20);
+ printf ("%10" PRIu64 " MB", sz >> 20);
else if ((sz & 0x3ff) == 0)
- printf ("%10" BFD_VMA_FMT "u KB", sz >> 10);
+ printf ("%10" PRIu64 " KB", sz >> 10);
else
- printf (" %10" BFD_VMA_FMT "u B", sz);
+ printf (" %10" PRIu64 " B", sz);
}
/* Implement --print-memory-usage: disply per region memory usage. */
printf ("%16s: ",r->name_list.name);
lang_print_memory_size (used_length);
- lang_print_memory_size ((bfd_vma) r->length);
+ lang_print_memory_size (r->length);
if (r->length != 0)
{