1,5 → 1,5 |
/* Linker command language support. |
Copyright 1991-2013 Free Software Foundation, Inc. |
Copyright (C) 1991-2015 Free Software Foundation, Inc. |
|
This file is part of the GNU Binutils. |
|
40,13 → 40,11 |
#include "demangle.h" |
#include "hashtab.h" |
#include "libbfd.h" |
#include "elf-bfd.h" |
#ifdef ENABLE_PLUGINS |
#include "plugin.h" |
#endif /* ENABLE_PLUGINS */ |
|
#include <limits.h> |
|
|
#ifndef offsetof |
#define offsetof(TYPE, MEMBER) ((size_t) & (((TYPE*) 0)->MEMBER)) |
#endif |
59,7 → 57,7 |
#define obstack_chunk_free free |
static const char *entry_symbol_default = "start"; |
static bfd_boolean placed_commons = FALSE; |
static bfd_boolean stripped_excluded_sections = FALSE; |
static bfd_boolean map_head_is_link_order = FALSE; |
static lang_output_section_statement_type *default_common_section; |
static bfd_boolean map_option_f; |
static bfd_vma print_dot; |
66,17 → 64,14 |
static lang_input_statement_type *first_file; |
static const char *current_target; |
static lang_statement_list_type statement_list; |
static struct bfd_hash_table lang_definedness_table; |
static lang_statement_list_type *stat_save[10]; |
static lang_statement_list_type **stat_save_ptr = &stat_save[0]; |
static struct unique_sections *unique_section_list; |
static struct asneeded_minfo *asneeded_list_head; |
|
/* Forward declarations. */ |
static void exp_init_os (etree_type *); |
static void init_map_userdata (bfd *, asection *, void *); |
static lang_input_statement_type *lookup_name (const char *); |
static struct bfd_hash_entry *lang_definedness_newfunc |
(struct bfd_hash_entry *, struct bfd_hash_table *, const char *); |
static void insert_undefined (const char *); |
static bfd_boolean sort_def_symbol (struct bfd_link_hash_entry *, void *); |
static void print_statement (lang_statement_union_type *, |
90,6 → 85,7 |
static void lang_do_version_exports_section (void); |
static void lang_finalize_version_expr_head |
(struct bfd_elf_version_expr_head *); |
static void lang_do_memory_regions (void); |
|
/* Exported variables. */ |
const char *output_target; |
109,13 → 105,12 |
bfd_boolean delete_output_file_on_failure = FALSE; |
struct lang_phdr *lang_phdr_list; |
struct lang_nocrossrefs *nocrossref_list; |
struct asneeded_minfo **asneeded_list_tail; |
|
/* Functions that traverse the linker script and might evaluate |
DEFINED() need to increment this. */ |
DEFINED() need to increment this at the start of the traversal. */ |
int lang_statement_iteration = 0; |
|
etree_type *base; /* Relocation base - or null */ |
|
/* Return TRUE if the PATTERN argument is a wildcard pattern. |
Although backslashes are treated specially if a pattern contains |
wildcards, we do not consider the mere presence of a backslash to |
206,7 → 201,7 |
struct unique_sections *unam; |
const char *secnam; |
|
if (link_info.relocatable |
if (bfd_link_relocatable (&link_info) |
&& sec->owner != NULL |
&& bfd_is_group_section (sec->owner, sec)) |
return !(os != NULL |
1065,13 → 1060,6 |
p->flags.whole_archive = input_flags.whole_archive; |
p->flags.sysrooted = input_flags.sysrooted; |
|
if (file_type == lang_input_file_is_l_enum |
&& name[0] == ':' && name[1] != '\0') |
{ |
file_type = lang_input_file_is_search_file_enum; |
name = name + 1; |
} |
|
switch (file_type) |
{ |
case lang_input_file_is_symbols_only_enum: |
1085,6 → 1073,12 |
p->local_sym_name = name; |
break; |
case lang_input_file_is_l_enum: |
if (name[0] == ':' && name[1] != '\0') |
{ |
p->filename = name + 1; |
p->flags.full_name_provided = TRUE; |
} |
else |
p->filename = name; |
p->local_sym_name = concat ("-l", name, (const char *) NULL); |
p->flags.maybe_archive = TRUE; |
1122,6 → 1116,26 |
lang_input_file_enum_type file_type, |
const char *target) |
{ |
if (name != NULL && *name == '=') |
{ |
lang_input_statement_type *ret; |
char *sysrooted_name |
= concat (ld_sysroot, name + 1, (const char *) NULL); |
|
/* We've now forcibly prepended the sysroot, making the input |
file independent of the context. Therefore, temporarily |
force a non-sysrooted context for this statement, so it won't |
get the sysroot prepended again when opened. (N.B. if it's a |
script, any child nodes with input files starting with "/" |
will be handled as "sysrooted" as they'll be found to be |
within the sysroot subdirectory.) */ |
unsigned int outer_sysrooted = input_flags.sysrooted; |
input_flags.sysrooted = 0; |
ret = new_afile (sysrooted_name, file_type, target, TRUE); |
input_flags.sysrooted = outer_sysrooted; |
return ret; |
} |
|
return new_afile (name, file_type, target, TRUE); |
} |
|
1225,24 → 1239,13 |
|
abs_output_section->bfd_section = bfd_abs_section_ptr; |
|
/* The value "3" is ad-hoc, somewhat related to the expected number of |
DEFINED expressions in a linker script. For most default linker |
scripts, there are none. Why a hash table then? Well, it's somewhat |
simpler to re-use working machinery than using a linked list in terms |
of code-complexity here in ld, besides the initialization which just |
looks like other code here. */ |
if (!bfd_hash_table_init_n (&lang_definedness_table, |
lang_definedness_newfunc, |
sizeof (struct lang_definedness_hash_entry), |
3)) |
einfo (_("%P%F: can not create hash table: %E\n")); |
asneeded_list_head = NULL; |
asneeded_list_tail = &asneeded_list_head; |
} |
|
void |
lang_finish (void) |
{ |
bfd_link_hash_table_free (link_info.output_bfd, link_info.hash); |
bfd_hash_table_free (&lang_definedness_table); |
output_section_statement_table_free (); |
} |
|
1303,7 → 1306,9 |
new_region->name_list.name = xstrdup (name); |
new_region->name_list.next = NULL; |
new_region->next = NULL; |
new_region->origin_exp = NULL; |
new_region->origin = 0; |
new_region->length_exp = NULL; |
new_region->length = ~(bfd_size_type) 0; |
new_region->current = 0; |
new_region->last_os = NULL; |
1380,6 → 1385,14 |
return lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE); |
} |
|
/* Get the output section statement directly from the userdata. */ |
|
lang_output_section_statement_type * |
lang_output_section_get (const asection *output_section) |
{ |
return get_userdata (output_section); |
} |
|
/* Find or create an output_section_statement with the given NAME. |
If CONSTRAINT is non-zero match one with that constraint, otherwise |
match any non-negative constraint. If CREATE, always make a |
1486,11 → 1499,12 |
|
lang_output_section_statement_type * |
lang_output_section_find_by_flags (const asection *sec, |
flagword sec_flags, |
lang_output_section_statement_type **exact, |
lang_match_sec_type_func match_type) |
{ |
lang_output_section_statement_type *first, *look, *found; |
flagword flags; |
flagword look_flags, differ; |
|
/* We know the first statement on this list is *ABS*. May as well |
skip it. */ |
1501,17 → 1515,17 |
found = NULL; |
for (look = first; look; look = look->next) |
{ |
flags = look->flags; |
look_flags = look->flags; |
if (look->bfd_section != NULL) |
{ |
flags = look->bfd_section->flags; |
look_flags = look->bfd_section->flags; |
if (match_type && !match_type (link_info.output_bfd, |
look->bfd_section, |
sec->owner, sec)) |
continue; |
} |
flags ^= sec->flags; |
if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY |
differ = look_flags ^ sec_flags; |
if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY |
| SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL))) |
found = look; |
} |
1522,115 → 1536,144 |
return found; |
} |
|
if ((sec->flags & SEC_CODE) != 0 |
&& (sec->flags & SEC_ALLOC) != 0) |
if ((sec_flags & SEC_CODE) != 0 |
&& (sec_flags & SEC_ALLOC) != 0) |
{ |
/* Try for a rw code section. */ |
for (look = first; look; look = look->next) |
{ |
flags = look->flags; |
look_flags = look->flags; |
if (look->bfd_section != NULL) |
{ |
flags = look->bfd_section->flags; |
look_flags = look->bfd_section->flags; |
if (match_type && !match_type (link_info.output_bfd, |
look->bfd_section, |
sec->owner, sec)) |
continue; |
} |
flags ^= sec->flags; |
if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD |
differ = look_flags ^ sec_flags; |
if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD |
| SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL))) |
found = look; |
} |
} |
else if ((sec->flags & (SEC_READONLY | SEC_THREAD_LOCAL)) != 0 |
&& (sec->flags & SEC_ALLOC) != 0) |
else if ((sec_flags & SEC_READONLY) != 0 |
&& (sec_flags & SEC_ALLOC) != 0) |
{ |
/* .rodata can go after .text, .sdata2 after .rodata. */ |
for (look = first; look; look = look->next) |
{ |
flags = look->flags; |
look_flags = look->flags; |
if (look->bfd_section != NULL) |
{ |
flags = look->bfd_section->flags; |
look_flags = look->bfd_section->flags; |
if (match_type && !match_type (link_info.output_bfd, |
look->bfd_section, |
sec->owner, sec)) |
continue; |
} |
flags ^= sec->flags; |
if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD |
differ = look_flags ^ sec_flags; |
if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD |
| SEC_READONLY | SEC_SMALL_DATA)) |
|| (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD |
|| (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD |
| SEC_READONLY)) |
&& !(look->flags & SEC_SMALL_DATA)) |
|| (!(flags & (SEC_THREAD_LOCAL | SEC_ALLOC)) |
&& (look->flags & SEC_THREAD_LOCAL) |
&& (!(flags & SEC_LOAD) |
|| (look->flags & SEC_LOAD)))) |
&& !(look_flags & SEC_SMALL_DATA))) |
found = look; |
} |
} |
else if ((sec->flags & SEC_SMALL_DATA) != 0 |
&& (sec->flags & SEC_ALLOC) != 0) |
else if ((sec_flags & SEC_THREAD_LOCAL) != 0 |
&& (sec_flags & SEC_ALLOC) != 0) |
{ |
/* .tdata can go after .data, .tbss after .tdata. Treat .tbss |
as if it were a loaded section, and don't use match_type. */ |
bfd_boolean seen_thread_local = FALSE; |
|
match_type = NULL; |
for (look = first; look; look = look->next) |
{ |
look_flags = look->flags; |
if (look->bfd_section != NULL) |
look_flags = look->bfd_section->flags; |
|
differ = look_flags ^ (sec_flags | SEC_LOAD | SEC_HAS_CONTENTS); |
if (!(differ & (SEC_THREAD_LOCAL | SEC_ALLOC))) |
{ |
/* .tdata and .tbss must be adjacent and in that order. */ |
if (!(look_flags & SEC_LOAD) |
&& (sec_flags & SEC_LOAD)) |
/* ..so if we're at a .tbss section and we're placing |
a .tdata section stop looking and return the |
previous section. */ |
break; |
found = look; |
seen_thread_local = TRUE; |
} |
else if (seen_thread_local) |
break; |
else if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD))) |
found = look; |
} |
} |
else if ((sec_flags & SEC_SMALL_DATA) != 0 |
&& (sec_flags & SEC_ALLOC) != 0) |
{ |
/* .sdata goes after .data, .sbss after .sdata. */ |
for (look = first; look; look = look->next) |
{ |
flags = look->flags; |
look_flags = look->flags; |
if (look->bfd_section != NULL) |
{ |
flags = look->bfd_section->flags; |
look_flags = look->bfd_section->flags; |
if (match_type && !match_type (link_info.output_bfd, |
look->bfd_section, |
sec->owner, sec)) |
continue; |
} |
flags ^= sec->flags; |
if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD |
differ = look_flags ^ sec_flags; |
if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD |
| SEC_THREAD_LOCAL)) |
|| ((look->flags & SEC_SMALL_DATA) |
&& !(sec->flags & SEC_HAS_CONTENTS))) |
|| ((look_flags & SEC_SMALL_DATA) |
&& !(sec_flags & SEC_HAS_CONTENTS))) |
found = look; |
} |
} |
else if ((sec->flags & SEC_HAS_CONTENTS) != 0 |
&& (sec->flags & SEC_ALLOC) != 0) |
else if ((sec_flags & SEC_HAS_CONTENTS) != 0 |
&& (sec_flags & SEC_ALLOC) != 0) |
{ |
/* .data goes after .rodata. */ |
for (look = first; look; look = look->next) |
{ |
flags = look->flags; |
look_flags = look->flags; |
if (look->bfd_section != NULL) |
{ |
flags = look->bfd_section->flags; |
look_flags = look->bfd_section->flags; |
if (match_type && !match_type (link_info.output_bfd, |
look->bfd_section, |
sec->owner, sec)) |
continue; |
} |
flags ^= sec->flags; |
if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD |
differ = look_flags ^ sec_flags; |
if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD |
| SEC_SMALL_DATA | SEC_THREAD_LOCAL))) |
found = look; |
} |
} |
else if ((sec->flags & SEC_ALLOC) != 0) |
else if ((sec_flags & SEC_ALLOC) != 0) |
{ |
/* .bss goes after any other alloc section. */ |
for (look = first; look; look = look->next) |
{ |
flags = look->flags; |
look_flags = look->flags; |
if (look->bfd_section != NULL) |
{ |
flags = look->bfd_section->flags; |
look_flags = look->bfd_section->flags; |
if (match_type && !match_type (link_info.output_bfd, |
look->bfd_section, |
sec->owner, sec)) |
continue; |
} |
flags ^= sec->flags; |
if (!(flags & SEC_ALLOC)) |
differ = look_flags ^ sec_flags; |
if (!(differ & SEC_ALLOC)) |
found = look; |
} |
} |
1639,11 → 1682,11 |
/* non-alloc go last. */ |
for (look = first; look; look = look->next) |
{ |
flags = look->flags; |
look_flags = look->flags; |
if (look->bfd_section != NULL) |
flags = look->bfd_section->flags; |
flags ^= sec->flags; |
if (!(flags & SEC_DEBUGGING)) |
look_flags = look->bfd_section->flags; |
differ = look_flags ^ sec_flags; |
if (!(differ & SEC_DEBUGGING)) |
found = look; |
} |
return found; |
1652,7 → 1695,7 |
if (found || !match_type) |
return found; |
|
return lang_output_section_find_by_flags (sec, NULL, NULL); |
return lang_output_section_find_by_flags (sec, sec_flags, NULL, NULL); |
} |
|
/* Find the last output section before given output statement. |
1762,6 → 1805,7 |
{ |
lang_statement_list_type add; |
const char *ps; |
lang_assignment_statement_type *start_assign; |
lang_output_section_statement_type *os; |
lang_output_section_statement_type **os_tail; |
|
1774,7 → 1818,8 |
push_stat_ptr (&add); |
} |
|
if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0) |
if (bfd_link_relocatable (&link_info) |
|| (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0) |
address = exp_intop (0); |
|
os_tail = ((lang_output_section_statement_type **) |
1783,6 → 1828,7 |
NULL, NULL, NULL, constraint, 0); |
|
ps = NULL; |
start_assign = NULL; |
if (config.build_constructors && *os_tail == os) |
{ |
/* If the name of the section is representable in C, then create |
1797,7 → 1843,8 |
symname = (char *) xmalloc (ps - secname + sizeof "__start_" + 1); |
symname[0] = bfd_get_symbol_leading_char (link_info.output_bfd); |
sprintf (symname + (symname[0] != 0), "__start_%s", secname); |
lang_add_assignment (exp_provide (symname, |
start_assign |
= lang_add_assignment (exp_provide (symname, |
exp_nameop (NAME, "."), |
FALSE)); |
} |
1822,16 → 1869,25 |
lang_leave_output_section_statement (NULL, DEFAULT_MEMORY_REGION, NULL, |
NULL); |
|
if (ps != NULL && *ps == '\0') |
if (start_assign != NULL) |
{ |
char *symname; |
lang_assignment_statement_type *stop_assign; |
bfd_vma dot; |
|
symname = (char *) xmalloc (ps - secname + sizeof "__stop_" + 1); |
symname[0] = bfd_get_symbol_leading_char (link_info.output_bfd); |
sprintf (symname + (symname[0] != 0), "__stop_%s", secname); |
lang_add_assignment (exp_provide (symname, |
stop_assign |
= lang_add_assignment (exp_provide (symname, |
exp_nameop (NAME, "."), |
FALSE)); |
/* Evaluate the expression to define the symbol if referenced, |
before sizing dynamic sections. */ |
dot = os->bfd_section->vma; |
exp_fold_tree (start_assign->exp, os->bfd_section, &dot); |
dot += s->size; |
exp_fold_tree (stop_assign->exp, os->bfd_section, &dot); |
} |
|
/* Restore the global list pointer. */ |
1954,6 → 2010,43 |
} |
|
static void |
lang_print_asneeded (void) |
{ |
struct asneeded_minfo *m; |
char buf[100]; |
|
if (asneeded_list_head == NULL) |
return; |
|
sprintf (buf, _("\nAs-needed library included " |
"to satisfy reference by file (symbol)\n\n")); |
minfo ("%s", buf); |
|
for (m = asneeded_list_head; m != NULL; m = m->next) |
{ |
size_t len; |
|
minfo ("%s", m->soname); |
len = strlen (m->soname); |
|
if (len >= 29) |
{ |
print_nl (); |
len = 0; |
} |
while (len < 30) |
{ |
print_space (); |
++len; |
} |
|
if (m->ref != NULL) |
minfo ("%B ", m->ref); |
minfo ("(%T)\n", m->name); |
} |
} |
|
static void |
lang_map_flags (flagword flag) |
{ |
if (flag & SEC_ALLOC) |
1977,7 → 2070,6 |
{ |
lang_memory_region_type *m; |
bfd_boolean dis_header_printed = FALSE; |
bfd *p; |
|
LANG_FOR_EACH_INPUT_STATEMENT (file) |
{ |
2049,27 → 2141,12 |
if (! link_info.reduce_memory_overheads) |
{ |
obstack_begin (&map_obstack, 1000); |
for (p = link_info.input_bfds; p != (bfd *) NULL; p = p->link_next) |
bfd_map_over_sections (p, init_map_userdata, 0); |
bfd_link_hash_traverse (link_info.hash, sort_def_symbol, 0); |
} |
lang_statement_iteration ++; |
print_statements (); |
} |
|
static void |
init_map_userdata (bfd *abfd ATTRIBUTE_UNUSED, |
asection *sec, |
void *data ATTRIBUTE_UNUSED) |
{ |
fat_section_userdata_type *new_data |
= ((fat_section_userdata_type *) (stat_alloc |
(sizeof (fat_section_userdata_type)))); |
|
ASSERT (get_userdata (sec) == NULL); |
get_userdata (sec) = new_data; |
new_data->map_symbol_def_tail = &new_data->map_symbol_def_head; |
new_data->map_symbol_def_count = 0; |
ldemul_extra_map_file_text (link_info.output_bfd, &link_info, config.map_file); |
} |
|
static bfd_boolean |
2076,21 → 2153,22 |
sort_def_symbol (struct bfd_link_hash_entry *hash_entry, |
void *info ATTRIBUTE_UNUSED) |
{ |
if (hash_entry->type == bfd_link_hash_defined |
if ((hash_entry->type == bfd_link_hash_defined |
|| hash_entry->type == bfd_link_hash_defweak) |
&& hash_entry->u.def.section->owner != link_info.output_bfd |
&& hash_entry->u.def.section->owner != NULL) |
{ |
struct fat_user_section_struct *ud; |
input_section_userdata_type *ud; |
struct map_symbol_def *def; |
|
ud = (struct fat_user_section_struct *) |
get_userdata (hash_entry->u.def.section); |
ud = ((input_section_userdata_type *) |
get_userdata (hash_entry->u.def.section)); |
if (! ud) |
{ |
/* ??? What do we have to do to initialize this beforehand? */ |
/* The first time we get here is bfd_abs_section... */ |
init_map_userdata (0, hash_entry->u.def.section, 0); |
ud = (struct fat_user_section_struct *) |
get_userdata (hash_entry->u.def.section); |
ud = (input_section_userdata_type *) stat_alloc (sizeof (*ud)); |
get_userdata (hash_entry->u.def.section) = ud; |
ud->map_symbol_def_tail = &ud->map_symbol_def_head; |
ud->map_symbol_def_count = 0; |
} |
else if (!ud->map_symbol_def_tail) |
ud->map_symbol_def_tail = &ud->map_symbol_def_head; |
2125,13 → 2203,9 |
s->bfd_section->output_section = s->bfd_section; |
s->bfd_section->output_offset = 0; |
|
if (!link_info.reduce_memory_overheads) |
{ |
fat_section_userdata_type *new_userdata = (fat_section_userdata_type *) |
stat_alloc (sizeof (fat_section_userdata_type)); |
memset (new_userdata, 0, sizeof (fat_section_userdata_type)); |
get_userdata (s->bfd_section) = new_userdata; |
} |
/* Set the userdata of the output section to the output section |
statement to avoid lookup. */ |
get_userdata (s->bfd_section) = s; |
|
/* If there is a base address, make sure that any sections it might |
mention are initialized. */ |
2286,7 → 2360,7 |
format targets, .text$foo sections go into .text and it's odd |
to see .text with SEC_LINK_ONCE set. */ |
|
if (!link_info.relocatable) |
if (!bfd_link_relocatable (&link_info)) |
flags &= ~(SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_RELOC); |
|
switch (output->sectype) |
2361,8 → 2435,7 |
|
section->output_section = output->bfd_section; |
|
if (!link_info.relocatable |
&& !stripped_excluded_sections) |
if (!map_head_is_link_order) |
{ |
asection *s = output->bfd_section->map_tail.s; |
output->bfd_section->map_tail.s = section; |
2741,9 → 2814,7 |
break; |
|
case bfd_object: |
#ifdef ENABLE_PLUGINS |
if (!entry->flags.reload) |
#endif |
ldlang_add_file (entry); |
if (trace_files || verbose) |
info_msg ("%I\n", entry); |
3114,7 → 3185,8 |
ASSERT (link_info.output_bfd == NULL); |
open_output (statement->output_statement.name); |
ldemul_set_output_arch (); |
if (config.magic_demand_paged && !link_info.relocatable) |
if (config.magic_demand_paged |
&& !bfd_link_relocatable (&link_info)) |
link_info.output_bfd->flags |= D_PAGED; |
else |
link_info.output_bfd->flags &= ~D_PAGED; |
3219,6 → 3291,7 |
{ |
lang_statement_union_type **os_tail; |
lang_statement_list_type add; |
bfd *abfd; |
|
s->input_statement.target = current_target; |
|
3225,32 → 3298,26 |
/* If we are being called from within a group, and this |
is an archive which has already been searched, then |
force it to be researched unless the whole archive |
has been loaded already. Do the same for a rescan. */ |
has been loaded already. Do the same for a rescan. |
Likewise reload --as-needed shared libs. */ |
if (mode != OPEN_BFD_NORMAL |
#ifdef ENABLE_PLUGINS |
&& ((mode & OPEN_BFD_RESCAN) == 0 |
|| plugin_insert == NULL) |
#endif |
&& !s->input_statement.flags.whole_archive |
&& s->input_statement.flags.loaded |
&& s->input_statement.the_bfd != NULL |
&& bfd_check_format (s->input_statement.the_bfd, |
bfd_archive)) |
s->input_statement.flags.loaded = FALSE; |
#ifdef ENABLE_PLUGINS |
/* When rescanning, reload --as-needed shared libs. */ |
else if ((mode & OPEN_BFD_RESCAN) != 0 |
&& plugin_insert == NULL |
&& s->input_statement.flags.loaded |
&& (abfd = s->input_statement.the_bfd) != NULL |
&& ((bfd_get_format (abfd) == bfd_archive |
&& !s->input_statement.flags.whole_archive) |
|| (bfd_get_format (abfd) == bfd_object |
&& ((abfd->flags) & DYNAMIC) != 0 |
&& s->input_statement.flags.add_DT_NEEDED_for_regular |
&& s->input_statement.the_bfd != NULL |
&& ((s->input_statement.the_bfd->flags) & DYNAMIC) != 0 |
&& plugin_should_reload (s->input_statement.the_bfd)) |
&& bfd_get_flavour (abfd) == bfd_target_elf_flavour |
&& (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0))) |
{ |
s->input_statement.flags.loaded = FALSE; |
s->input_statement.flags.reload = TRUE; |
} |
#endif |
|
os_tail = lang_output_section_statement.tail; |
lang_list_init (&add); |
3303,85 → 3370,6 |
einfo ("%F"); |
} |
|
/* Add a symbol to a hash of symbols used in DEFINED (NAME) expressions. */ |
|
void |
lang_track_definedness (const char *name) |
{ |
if (bfd_hash_lookup (&lang_definedness_table, name, TRUE, FALSE) == NULL) |
einfo (_("%P%F: bfd_hash_lookup failed creating symbol %s\n"), name); |
} |
|
/* New-function for the definedness hash table. */ |
|
static struct bfd_hash_entry * |
lang_definedness_newfunc (struct bfd_hash_entry *entry, |
struct bfd_hash_table *table ATTRIBUTE_UNUSED, |
const char *name ATTRIBUTE_UNUSED) |
{ |
struct lang_definedness_hash_entry *ret |
= (struct lang_definedness_hash_entry *) entry; |
|
if (ret == NULL) |
ret = (struct lang_definedness_hash_entry *) |
bfd_hash_allocate (table, sizeof (struct lang_definedness_hash_entry)); |
|
if (ret == NULL) |
einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name); |
|
ret->iteration = -1; |
return &ret->root; |
} |
|
/* Return the iteration when the definition of NAME was last updated. A |
value of -1 means that the symbol is not defined in the linker script |
or the command line, but may be defined in the linker symbol table. */ |
|
int |
lang_symbol_definition_iteration (const char *name) |
{ |
struct lang_definedness_hash_entry *defentry |
= (struct lang_definedness_hash_entry *) |
bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE); |
|
/* We've already created this one on the presence of DEFINED in the |
script, so it can't be NULL unless something is borked elsewhere in |
the code. */ |
if (defentry == NULL) |
FAIL (); |
|
return defentry->iteration; |
} |
|
/* Update the definedness state of NAME. */ |
|
void |
lang_update_definedness (const char *name, struct bfd_link_hash_entry *h) |
{ |
struct lang_definedness_hash_entry *defentry |
= (struct lang_definedness_hash_entry *) |
bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE); |
|
/* We don't keep track of symbols not tested with DEFINED. */ |
if (defentry == NULL) |
return; |
|
/* If the symbol was already defined, and not from an earlier statement |
iteration, don't update the definedness iteration, because that'd |
make the symbol seem defined in the linker script at this point, and |
it wasn't; it was defined in some object. If we do anyway, DEFINED |
would start to yield false before this point and the construct "sym = |
DEFINED (sym) ? sym : X;" would change sym to X despite being defined |
in an object. */ |
if (h->type != bfd_link_hash_undefined |
&& h->type != bfd_link_hash_common |
&& h->type != bfd_link_hash_new |
&& defentry->iteration == -1) |
return; |
|
defentry->iteration = lang_statement_iteration; |
} |
|
/* Add the supplied name to the symbol table as an undefined reference. |
This is a two step process as the symbol table doesn't even exist at |
the time the ld command line is processed. First we put the name |
3439,6 → 3427,55 |
insert_undefined (ptr->name); |
} |
|
/* Structure used to build the list of symbols that the user has required |
be defined. */ |
|
struct require_defined_symbol |
{ |
const char *name; |
struct require_defined_symbol *next; |
}; |
|
/* The list of symbols that the user has required be defined. */ |
|
static struct require_defined_symbol *require_defined_symbol_list; |
|
/* Add a new symbol NAME to the list of symbols that are required to be |
defined. */ |
|
void |
ldlang_add_require_defined (const char * const name) |
{ |
struct require_defined_symbol *ptr; |
|
ldlang_add_undef (name, TRUE); |
ptr = (struct require_defined_symbol *) stat_alloc (sizeof (*ptr)); |
ptr->next = require_defined_symbol_list; |
ptr->name = strdup (name); |
require_defined_symbol_list = ptr; |
} |
|
/* Check that all symbols the user required to be defined, are defined, |
raise an error if we find a symbol that is not defined. */ |
|
static void |
ldlang_check_require_defined_symbols (void) |
{ |
struct require_defined_symbol *ptr; |
|
for (ptr = require_defined_symbol_list; ptr != NULL; ptr = ptr->next) |
{ |
struct bfd_link_hash_entry *h; |
|
h = bfd_link_hash_lookup (link_info.hash, ptr->name, |
FALSE, FALSE, TRUE); |
if (h == NULL |
|| (h->type != bfd_link_hash_defined |
&& h->type != bfd_link_hash_defweak)) |
einfo(_("%P%X: required symbol `%s' not defined\n"), ptr->name); |
} |
} |
|
/* Check for all readonly or some readwrite sections. */ |
|
static void |
3889,10 → 3926,6 |
} |
} |
|
/* TODO: Don't just junk map_head.s, turn them into link_orders. */ |
output_section->map_head.link_order = NULL; |
output_section->map_tail.link_order = NULL; |
|
if (exclude) |
{ |
/* We don't set bfd_section to NULL since bfd_section of the |
3904,10 → 3937,42 |
link_info.output_bfd->section_count--; |
} |
} |
} |
|
/* Called from ldwrite to clear out asection.map_head and |
asection.map_tail for use as link_orders in ldwrite. |
FIXME: Except for sh64elf.em which starts creating link_orders in |
its after_allocation routine so needs to call it early. */ |
|
void |
lang_clear_os_map (void) |
{ |
lang_output_section_statement_type *os; |
|
if (map_head_is_link_order) |
return; |
|
for (os = &lang_output_section_statement.head->output_section_statement; |
os != NULL; |
os = os->next) |
{ |
asection *output_section; |
|
if (os->constraint < 0) |
continue; |
|
output_section = os->bfd_section; |
if (output_section == NULL) |
continue; |
|
/* TODO: Don't just junk map_head.s, turn them into link_orders. */ |
output_section->map_head.link_order = NULL; |
output_section->map_tail.link_order = NULL; |
} |
|
/* Stop future calls to lang_add_section from messing with map_head |
and map_tail link_order fields. */ |
stripped_excluded_sections = TRUE; |
map_head_is_link_order = TRUE; |
} |
|
static void |
3976,6 → 4041,7 |
const char *dst = assignment->exp->assign.dst; |
|
is_dot = (dst[0] == '.' && dst[1] == 0); |
if (!is_dot) |
expld.assign_name = dst; |
tree = assignment->exp->assign.src; |
} |
3983,7 → 4049,12 |
osec = output_section->bfd_section; |
if (osec == NULL) |
osec = bfd_abs_section_ptr; |
|
if (assignment->exp->type.node_class != etree_provide) |
exp_fold_tree (tree, osec, &print_dot); |
else |
expld.result.valid_p = FALSE; |
|
if (expld.result.valid_p) |
{ |
bfd_vma value; |
4021,6 → 4092,9 |
} |
else |
{ |
if (assignment->exp->type.node_class == etree_provide) |
minfo ("[!provide]"); |
else |
minfo ("*undef* "); |
#ifdef BFD64 |
minfo (" "); |
4086,8 → 4160,8 |
static void |
print_all_symbols (asection *sec) |
{ |
struct fat_user_section_struct *ud = |
(struct fat_user_section_struct *) get_userdata (sec); |
input_section_userdata_type *ud |
= (input_section_userdata_type *) get_userdata (sec); |
struct map_symbol_def *def; |
struct bfd_link_hash_entry **entries; |
unsigned int i; |
4563,12 → 4637,15 |
{ |
lang_input_section_type *is = &((*this_ptr)->input_section); |
asection *i = is->section; |
asection *o = output_section_statement->bfd_section; |
|
if (i->sec_info_type != SEC_INFO_TYPE_JUST_SYMS |
&& (i->flags & SEC_EXCLUDE) == 0) |
if (i->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) |
i->output_offset = i->vma - o->vma; |
else if ((i->flags & SEC_EXCLUDE) != 0) |
i->output_offset = dot - o->vma; |
else |
{ |
bfd_size_type alignment_needed; |
asection *o; |
|
/* Align this section first to the input sections requirement, |
then to the output section's requirement. If this alignment |
4578,7 → 4655,6 |
if (output_section_statement->subsection_alignment != -1) |
i->alignment_power = output_section_statement->subsection_alignment; |
|
o = output_section_statement->bfd_section; |
if (o->alignment_power < i->alignment_power) |
o->alignment_power = i->alignment_power; |
|
4591,7 → 4667,6 |
} |
|
/* Remember where in the output section this input section goes. */ |
|
i->output_offset = dot - o->vma; |
|
/* Mark how big the output section must be to contain this now. */ |
4598,10 → 4673,6 |
dot += TO_ADDR (i->size); |
o->size = TO_SIZE (dot - o->vma); |
} |
else |
{ |
i->output_offset = i->vma - output_section_statement->bfd_section->vma; |
} |
|
return dot; |
} |
4776,7 → 4847,7 |
{ |
case lang_output_section_statement_enum: |
{ |
bfd_vma newdot, after; |
bfd_vma newdot, after, dotdelta; |
lang_output_section_statement_type *os; |
lang_memory_region_type *r; |
int section_alignment = 0; |
4789,7 → 4860,7 |
here, in lang_insert_orphan, or in the default linker scripts. |
This is covering for coff backend linker bugs. See PR6945. */ |
if (os->addr_tree == NULL |
&& link_info.relocatable |
&& bfd_link_relocatable (&link_info) |
&& (bfd_get_flavour (link_info.output_bfd) |
== bfd_target_coff_flavour)) |
os->addr_tree = exp_intop (0); |
4842,6 → 4913,7 |
} |
|
newdot = dot; |
dotdelta = 0; |
if (bfd_is_abs_section (os->bfd_section)) |
{ |
/* No matter what happens, an abs section starts at zero. */ |
4867,7 → 4939,7 |
defined, issue an error message. */ |
if (!os->ignored |
&& !IGNORE_SECTION (os->bfd_section) |
&& ! link_info.relocatable |
&& !bfd_link_relocatable (&link_info) |
&& check_regions |
&& strcmp (os->region->name_list.name, |
DEFAULT_MEMORY_REGION) == 0 |
4910,13 → 4982,14 |
bfd_vma savedot = newdot; |
newdot = align_power (newdot, section_alignment); |
|
if (newdot != savedot |
dotdelta = newdot - savedot; |
if (dotdelta != 0 |
&& (config.warn_section_align |
|| os->addr_tree != NULL) |
&& expld.phase != lang_mark_phase_enum) |
einfo (_("%P: warning: changing start of section" |
" %s by %lu bytes\n"), |
os->name, (unsigned long) (newdot - savedot)); |
os->name, (unsigned long) dotdelta); |
} |
|
bfd_set_section_vma (0, os->bfd_section, newdot); |
4964,15 → 5037,20 |
{ |
bfd_vma lma = os->lma_region->current; |
|
if (os->align_lma_with_input) |
lma += dotdelta; |
else |
{ |
/* When LMA_REGION is the same as REGION, align the LMA |
as we did for the VMA, possibly including alignment |
from the bfd section. If a different region, then |
only align according to the value in the output |
statement unless specified otherwise. */ |
if (os->lma_region != os->region && !os->align_lma_with_input) |
statement. */ |
if (os->lma_region != os->region) |
section_alignment = os->section_alignment; |
if (section_alignment > 0) |
lma = align_power (lma, section_alignment); |
} |
os->bfd_section->lma = lma; |
} |
else if (r->last_os != NULL |
5041,14 → 5119,17 |
&& dot >= (r->last_os->output_section_statement |
.bfd_section->vma))) |
&& os->lma_region == NULL |
&& !link_info.relocatable) |
&& !bfd_link_relocatable (&link_info)) |
r->last_os = s; |
|
/* .tbss sections effectively have zero size. */ |
if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0 |
|| (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0 |
|| link_info.relocatable) |
dot += TO_ADDR (os->bfd_section->size); |
|| bfd_link_relocatable (&link_info)) |
dotdelta = TO_ADDR (os->bfd_section->size); |
else |
dotdelta = 0; |
dot += dotdelta; |
|
if (os->update_dot_tree != 0) |
exp_fold_tree (os->update_dot_tree, bfd_abs_section_ptr, &dot); |
5068,10 → 5149,10 |
os->bfd_section->vma); |
|
if (os->lma_region != NULL && os->lma_region != os->region |
&& (os->bfd_section->flags & SEC_LOAD)) |
&& ((os->bfd_section->flags & SEC_LOAD) |
|| os->align_lma_with_input)) |
{ |
os->lma_region->current |
= os->bfd_section->lma + TO_ADDR (os->bfd_section->size); |
os->lma_region->current = os->bfd_section->lma + dotdelta; |
|
if (check_regions) |
os_region_check (os, os->lma_region, NULL, |
5172,7 → 5253,7 |
*relax = TRUE; |
} |
dot = size_input_section (prev, output_section_statement, |
output_section_statement->fill, dot); |
fill, dot); |
} |
break; |
|
5364,57 → 5445,56 |
if (expld.dataseg.phase == exp_dataseg_end_seen |
&& link_info.relro && expld.dataseg.relro_end) |
{ |
/* If DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END pair was seen, try |
to put expld.dataseg.relro on a (common) page boundary. */ |
bfd_vma min_base, old_base, relro_end, maxpage; |
bfd_vma initial_base, relro_end, desired_end; |
asection *sec; |
|
expld.dataseg.phase = exp_dataseg_relro_adjust; |
maxpage = expld.dataseg.maxpagesize; |
/* MIN_BASE is the absolute minimum address we are allowed to start the |
read-write segment (byte before will be mapped read-only). */ |
min_base = (expld.dataseg.min_base + maxpage - 1) & ~(maxpage - 1); |
/* OLD_BASE is the address for a feasible minimum address which will |
still not cause a data overlap inside MAXPAGE causing file offset skip |
by MAXPAGE. */ |
old_base = expld.dataseg.base; |
expld.dataseg.base += (-expld.dataseg.relro_end |
& (expld.dataseg.pagesize - 1)); |
/* Compute the expected PT_GNU_RELRO segment end. */ |
relro_end = ((expld.dataseg.relro_end + expld.dataseg.pagesize - 1) |
& ~(expld.dataseg.pagesize - 1)); |
if (min_base + maxpage < expld.dataseg.base) |
|
/* Adjust by the offset arg of DATA_SEGMENT_RELRO_END. */ |
desired_end = relro_end - expld.dataseg.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 |
&& sec->vma >= expld.dataseg.base |
&& sec->vma < expld.dataseg.relro_end - expld.dataseg.relro_offset) |
{ |
expld.dataseg.base -= maxpage; |
relro_end -= maxpage; |
/* Where do we want to put this section so that it ends as |
desired? */ |
bfd_vma start, end, bump; |
|
end = start = sec->vma; |
if ((sec->flags & SEC_HAS_CONTENTS) != 0 |
|| (sec->flags & SEC_THREAD_LOCAL) == 0) |
end += 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; |
} |
|
expld.dataseg.phase = exp_dataseg_relro_adjust; |
ASSERT (desired_end >= expld.dataseg.base); |
initial_base = expld.dataseg.base; |
expld.dataseg.base = desired_end; |
lang_reset_memory_regions (); |
one_lang_size_sections_pass (relax, check_regions); |
|
if (expld.dataseg.relro_end > relro_end) |
{ |
/* The alignment of sections between DATA_SEGMENT_ALIGN |
and DATA_SEGMENT_RELRO_END caused huge padding to be |
inserted at DATA_SEGMENT_RELRO_END. Try to start a bit lower so |
that the section alignments will fit in. */ |
asection *sec; |
unsigned int max_alignment_power = 0; |
|
/* Find maximum alignment power of sections between |
DATA_SEGMENT_ALIGN and DATA_SEGMENT_RELRO_END. */ |
for (sec = link_info.output_bfd->sections; sec; sec = sec->next) |
if (sec->vma >= expld.dataseg.base |
&& sec->vma < expld.dataseg.relro_end |
&& sec->alignment_power > max_alignment_power) |
max_alignment_power = sec->alignment_power; |
|
if (((bfd_vma) 1 << max_alignment_power) < expld.dataseg.pagesize) |
{ |
if (expld.dataseg.base - (1 << max_alignment_power) < old_base) |
expld.dataseg.base += expld.dataseg.pagesize; |
expld.dataseg.base -= (1 << max_alignment_power); |
/* Assignments to dot, or to output section address in a |
user script have increased padding over the original. |
Revert. */ |
expld.dataseg.base = initial_base; |
lang_reset_memory_regions (); |
one_lang_size_sections_pass (relax, check_regions); |
} |
} |
|
link_info.relro_start = expld.dataseg.base; |
link_info.relro_end = expld.dataseg.relro_end; |
} |
5485,7 → 5565,7 |
/* .tbss sections effectively have zero size. */ |
if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0 |
|| (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0 |
|| link_info.relocatable) |
|| bfd_link_relocatable (&link_info)) |
dot += TO_ADDR (os->bfd_section->size); |
|
if (os->update_dot_tree != NULL) |
5709,7 → 5789,7 |
{ |
asection *s; |
|
if (link_info.relocatable) |
if (bfd_link_relocatable (&link_info)) |
return; |
|
for (s = link_info.output_bfd->sections; s != NULL; s = s->next) |
5749,8 → 5829,8 |
struct bfd_link_hash_entry *h; |
bfd_boolean warn; |
|
if ((link_info.relocatable && !link_info.gc_sections) |
|| (link_info.shared && !link_info.executable)) |
if ((bfd_link_relocatable (&link_info) && !link_info.gc_sections) |
|| bfd_link_dll (&link_info)) |
warn = entry_from_cmdline; |
else |
warn = TRUE; |
5757,7 → 5837,7 |
|
/* Force the user to specify a root when generating a relocatable with |
--gc-sections. */ |
if (link_info.gc_sections && link_info.relocatable |
if (link_info.gc_sections && bfd_link_relocatable (&link_info) |
&& !(entry_from_cmdline || undef_from_cmdline)) |
einfo (_("%P%F: gc-sections requires either an entry or " |
"an undefined symbol\n")); |
5867,7 → 5947,8 |
input format may not have equivalent representations in |
the output format (and besides BFD does not translate |
relocs for other link purposes than a final link). */ |
if ((link_info.relocatable || link_info.emitrelocations) |
if ((bfd_link_relocatable (&link_info) |
|| link_info.emitrelocations) |
&& (compatible == NULL |
|| (bfd_get_flavour (input_bfd) |
!= bfd_get_flavour (link_info.output_bfd))) |
5923,7 → 6004,7 |
{ |
if (command_line.inhibit_common_definition) |
return; |
if (link_info.relocatable |
if (bfd_link_relocatable (&link_info) |
&& ! command_line.force_common_definition) |
return; |
|
5946,7 → 6027,7 |
for (power = 0; power <= 4; power++) |
bfd_link_hash_traverse (link_info.hash, lang_one_common, &power); |
|
power = UINT_MAX; |
power = (unsigned int) -1; |
bfd_link_hash_traverse (link_info.hash, lang_one_common, &power); |
} |
} |
6038,6 → 6119,55 |
return TRUE; |
} |
|
/* Handle a single orphan section S, placing the orphan into an appropriate |
output section. The effects of the --orphan-handling command line |
option are handled here. */ |
|
static void |
ldlang_place_orphan (asection *s) |
{ |
if (config.orphan_handling == orphan_handling_discard) |
{ |
lang_output_section_statement_type *os; |
os = lang_output_section_statement_lookup (DISCARD_SECTION_NAME, 0, |
TRUE); |
if (os->addr_tree == NULL |
&& (bfd_link_relocatable (&link_info) |
|| (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)) |
os->addr_tree = exp_intop (0); |
lang_add_section (&os->children, s, NULL, os); |
} |
else |
{ |
lang_output_section_statement_type *os; |
const char *name = s->name; |
int constraint = 0; |
|
if (config.orphan_handling == orphan_handling_error) |
einfo ("%X%P: error: unplaced orphan section `%A' from `%B'.\n", |
s, s->owner); |
|
if (config.unique_orphan_sections || unique_section_p (s, NULL)) |
constraint = SPECIAL; |
|
os = ldemul_place_orphan (s, name, constraint); |
if (os == NULL) |
{ |
os = lang_output_section_statement_lookup (name, constraint, TRUE); |
if (os->addr_tree == NULL |
&& (bfd_link_relocatable (&link_info) |
|| (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)) |
os->addr_tree = exp_intop (0); |
lang_add_section (&os->children, s, NULL, os); |
} |
|
if (config.orphan_handling == orphan_handling_warn) |
einfo ("%P: warning: orphan section `%A' from `%B' being " |
"placed in section `%s'.\n", |
s, s->owner, os->name); |
} |
} |
|
/* Run through the input files and ensure that every input section has |
somewhere to go. If one is found without a destination then create |
an input request and place it into the statement tree. */ |
6065,7 → 6195,7 |
/* This is a lonely common section which must have |
come from an archive. We attach to the section |
with the wildcard. */ |
if (! link_info.relocatable |
if (!bfd_link_relocatable (&link_info) |
|| command_line.force_common_definition) |
{ |
if (default_common_section == NULL) |
6077,31 → 6207,11 |
} |
} |
else |
{ |
const char *name = s->name; |
int constraint = 0; |
|
if (config.unique_orphan_sections |
|| unique_section_p (s, NULL)) |
constraint = SPECIAL; |
|
if (!ldemul_place_orphan (s, name, constraint)) |
{ |
lang_output_section_statement_type *os; |
os = lang_output_section_statement_lookup (name, |
constraint, |
TRUE); |
if (os->addr_tree == NULL |
&& (link_info.relocatable |
|| (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)) |
os->addr_tree = exp_intop (0); |
lang_add_section (&os->children, s, NULL, os); |
ldlang_place_orphan (s); |
} |
} |
} |
} |
} |
} |
|
void |
lang_set_flags (lang_memory_region_type *ptr, const char *flags, int invert) |
6109,10 → 6219,18 |
flagword *ptr_flags; |
|
ptr_flags = invert ? &ptr->not_flags : &ptr->flags; |
|
while (*flags) |
{ |
switch (*flags) |
{ |
/* PR 17900: An exclamation mark in the attributes reverses |
the sense of any of the attributes that follow. */ |
case '!': |
invert = ! invert; |
ptr_flags = invert ? &ptr->not_flags : &ptr->flags; |
break; |
|
case 'A': case 'a': |
*ptr_flags |= SEC_ALLOC; |
break; |
6135,7 → 6253,7 |
break; |
|
default: |
einfo (_("%P%F: invalid syntax in flags\n")); |
einfo (_("%P%F: invalid character %c (%d) in flags\n"), * flags, * flags); |
break; |
} |
flags++; |
6178,11 → 6296,11 |
|
/* The BFD linker needs to have a list of all input BFDs involved in |
a link. */ |
ASSERT (entry->the_bfd->link_next == NULL); |
ASSERT (entry->the_bfd->link.next == NULL); |
ASSERT (entry->the_bfd != link_info.output_bfd); |
|
*link_info.input_bfds_tail = entry->the_bfd; |
link_info.input_bfds_tail = &entry->the_bfd->link_next; |
link_info.input_bfds_tail = &entry->the_bfd->link.next; |
entry->the_bfd->usrdata = entry; |
bfd_set_gp_size (entry->the_bfd, g_switch_value); |
|
6279,7 → 6397,6 |
|
new_stmt = new_stat (lang_output_statement, stat_ptr); |
new_stmt->name = output_filename; |
|
} |
|
/* Reset the current counters in the regions. */ |
6366,7 → 6483,7 |
/* SEC_EXCLUDE is ignored when doing a relocatable link, except in |
the special case of debug info. (See bfd/stabs.c) |
Twiddle the flag here, to simplify later linker code. */ |
if (link_info.relocatable) |
if (bfd_link_relocatable (&link_info)) |
{ |
LANG_FOR_EACH_INPUT_STATEMENT (f) |
{ |
6609,7 → 6726,7 |
open_input_bfds (statement_list.head, OPEN_BFD_NORMAL); |
|
#ifdef ENABLE_PLUGINS |
if (plugin_active_plugins_p ()) |
if (link_info.lto_plugin_active) |
{ |
lang_statement_list_type added; |
lang_statement_list_type files, inputfiles; |
6628,7 → 6745,6 |
einfo (_("%P%F: %s: plugin reported error after all symbols read\n"), |
plugin_error_plugin ()); |
/* Open any newly added files, updating the file chains. */ |
link_info.loading_lto_outputs = TRUE; |
open_input_bfds (*added.tail, OPEN_BFD_NORMAL); |
/* Restore the global list pointer now they have all been added. */ |
lang_list_remove_tail (stat_ptr, &added); |
6669,8 → 6785,26 |
link_info.gc_sym_list = &entry_symbol; |
if (entry_symbol.name == NULL) |
link_info.gc_sym_list = ldlang_undef_chain_list_head; |
if (link_info.init_function != NULL) |
{ |
struct bfd_sym_chain *sym |
= (struct bfd_sym_chain *) stat_alloc (sizeof (*sym)); |
sym->next = link_info.gc_sym_list; |
sym->name = link_info.init_function; |
link_info.gc_sym_list = sym; |
} |
if (link_info.fini_function != NULL) |
{ |
struct bfd_sym_chain *sym |
= (struct bfd_sym_chain *) stat_alloc (sizeof (*sym)); |
sym->next = link_info.gc_sym_list; |
sym->name = link_info.fini_function; |
link_info.gc_sym_list = sym; |
} |
|
ldemul_after_open (); |
if (config.map_file != NULL) |
lang_print_asneeded (); |
|
bfd_section_already_linked_table_free (); |
|
6692,14 → 6826,16 |
/* PR 13683: We must rerun the assignments prior to running garbage |
collection in order to make sure that all symbol aliases are resolved. */ |
lang_do_assignments (lang_mark_phase_enum); |
|
lang_do_memory_regions(); |
expld.phase = lang_first_phase_enum; |
|
/* Size up the common data. */ |
lang_common (); |
|
/* Remove unreferenced sections if asked to. */ |
lang_gc_sections (); |
|
/* Size up the common data. */ |
lang_common (); |
|
/* Update wild statements. */ |
update_wild_statements (statement_list.head); |
|
6713,7 → 6849,7 |
/* Find any sections not attached explicitly and handle them. */ |
lang_place_orphans (); |
|
if (! link_info.relocatable) |
if (!bfd_link_relocatable (&link_info)) |
{ |
asection *found; |
|
6744,7 → 6880,7 |
lang_record_phdrs (); |
|
/* Check relro sections. */ |
if (link_info.relro && ! link_info.relocatable) |
if (link_info.relro && !bfd_link_relocatable (&link_info)) |
lang_find_relro_sections (); |
|
/* Size up the sections. */ |
6763,10 → 6899,16 |
|
ldemul_finish (); |
|
/* Convert absolute symbols to section relative. */ |
ldexp_finalize_syms (); |
|
/* Make sure that the section addresses make sense. */ |
if (command_line.check_section_addresses) |
lang_check_section_addresses (); |
|
/* Check any required symbols are known. */ |
ldlang_check_require_defined_symbols (); |
|
lang_end (); |
} |
|
7955,6 → 8097,37 |
lang_new_vers_node (greg, lreg), NULL); |
} |
|
/* Evaluate LENGTH and ORIGIN parts of MEMORY spec */ |
|
static void |
lang_do_memory_regions (void) |
{ |
lang_memory_region_type *r = lang_memory_region_list; |
|
for (; r != NULL; r = r->next) |
{ |
if (r->origin_exp) |
{ |
exp_fold_tree_no_dot (r->origin_exp); |
if (expld.result.valid_p) |
{ |
r->origin = expld.result.value; |
r->current = r->origin; |
} |
else |
einfo (_("%F%P: invalid origin for memory region %s\n"), r->name_list.name); |
} |
if (r->length_exp) |
{ |
exp_fold_tree_no_dot (r->length_exp); |
if (expld.result.valid_p) |
r->length = expld.result.value; |
else |
einfo (_("%F%P: invalid length for memory region %s\n"), r->name_list.name); |
} |
} |
} |
|
void |
lang_add_unique (const char *name) |
{ |
8064,3 → 8237,41 |
p = q; |
} |
} |
|
/* Pretty print memory amount. */ |
|
static void |
lang_print_memory_size (bfd_vma sz) |
{ |
if ((sz & 0x3fffffff) == 0) |
printf ("%10" BFD_VMA_FMT "u GB", sz >> 30); |
else if ((sz & 0xfffff) == 0) |
printf ("%10" BFD_VMA_FMT "u MB", sz >> 20); |
else if ((sz & 0x3ff) == 0) |
printf ("%10" BFD_VMA_FMT "u KB", sz >> 10); |
else |
printf (" %10" BFD_VMA_FMT "u B", sz); |
} |
|
/* Implement --print-memory-usage: disply per region memory usage. */ |
|
void |
lang_print_memory_usage (void) |
{ |
lang_memory_region_type *r; |
|
printf ("Memory region Used Size Region Size %%age Used\n"); |
for (r = lang_memory_region_list; r->next != NULL; r = r->next) |
{ |
bfd_vma used_length = r->current - r->origin; |
double percent; |
|
printf ("%16s: ",r->name_list.name); |
lang_print_memory_size (used_length); |
lang_print_memory_size ((bfd_vma) r->length); |
|
percent = used_length * 100.0 / r->length; |
|
printf (" %6.2f%%\n", percent); |
} |
} |