|
|
|
@ -68,6 +68,7 @@ static struct unique_sections *unique_section_list; |
|
|
|
static bfd_boolean ldlang_sysrooted_script = FALSE; |
|
|
|
|
|
|
|
/* 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 |
|
|
|
@ -2047,8 +2048,12 @@ sort_def_symbol (struct bfd_link_hash_entry *hash_entry, |
|
|
|
/* Initialize an output section. */ |
|
|
|
|
|
|
|
static void |
|
|
|
init_os (lang_output_section_statement_type *s, asection *isec, flagword flags) |
|
|
|
init_os (lang_output_section_statement_type *s, asection *isec, |
|
|
|
flagword flags) |
|
|
|
{ |
|
|
|
if (s->bfd_section != NULL) |
|
|
|
return; |
|
|
|
|
|
|
|
if (strcmp (s->name, DISCARD_SECTION_NAME) == 0) |
|
|
|
einfo (_("%P%F: Illegal use of `%s' section\n"), DISCARD_SECTION_NAME); |
|
|
|
|
|
|
|
@ -2073,6 +2078,14 @@ init_os (lang_output_section_statement_type *s, asection *isec, flagword flags) |
|
|
|
get_userdata (s->bfd_section) = new_userdata; |
|
|
|
} |
|
|
|
|
|
|
|
/* If there is a base address, make sure that any sections it might
|
|
|
|
mention are initialized. */ |
|
|
|
if (s->addr_tree != NULL) |
|
|
|
exp_init_os (s->addr_tree); |
|
|
|
|
|
|
|
if (s->load_base != NULL) |
|
|
|
exp_init_os (s->load_base); |
|
|
|
|
|
|
|
/* If supplied an alignment, set it. */ |
|
|
|
if (s->section_alignment != -1) |
|
|
|
s->bfd_section->alignment_power = s->section_alignment; |
|
|
|
@ -3417,10 +3430,10 @@ map_input_to_output_sections |
|
|
|
(lang_statement_union_type *s, const char *target, |
|
|
|
lang_output_section_statement_type *os) |
|
|
|
{ |
|
|
|
flagword flags; |
|
|
|
|
|
|
|
for (; s != NULL; s = s->header.next) |
|
|
|
{ |
|
|
|
lang_output_section_statement_type *tos; |
|
|
|
|
|
|
|
switch (s->header.type) |
|
|
|
{ |
|
|
|
case lang_wild_statement_enum: |
|
|
|
@ -3432,23 +3445,29 @@ map_input_to_output_sections |
|
|
|
os); |
|
|
|
break; |
|
|
|
case lang_output_section_statement_enum: |
|
|
|
tos = &s->output_section_statement; |
|
|
|
if (tos->constraint != 0) |
|
|
|
if (s->output_section_statement.constraint) |
|
|
|
{ |
|
|
|
if (tos->constraint != ONLY_IF_RW |
|
|
|
&& tos->constraint != ONLY_IF_RO) |
|
|
|
if (s->output_section_statement.constraint != ONLY_IF_RW |
|
|
|
&& s->output_section_statement.constraint != ONLY_IF_RO) |
|
|
|
break; |
|
|
|
tos->all_input_readonly = TRUE; |
|
|
|
check_input_sections (tos->children.head, tos); |
|
|
|
if (tos->all_input_readonly != (tos->constraint == ONLY_IF_RO)) |
|
|
|
s->output_section_statement.all_input_readonly = TRUE; |
|
|
|
check_input_sections (s->output_section_statement.children.head, |
|
|
|
&s->output_section_statement); |
|
|
|
if ((s->output_section_statement.all_input_readonly |
|
|
|
&& s->output_section_statement.constraint == ONLY_IF_RW) |
|
|
|
|| (!s->output_section_statement.all_input_readonly |
|
|
|
&& s->output_section_statement.constraint == ONLY_IF_RO)) |
|
|
|
{ |
|
|
|
tos->constraint = -1; |
|
|
|
s->output_section_statement.constraint = -1; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
map_input_to_output_sections (tos->children.head, |
|
|
|
|
|
|
|
map_input_to_output_sections (s->output_section_statement.children.head, |
|
|
|
target, |
|
|
|
tos); |
|
|
|
&s->output_section_statement); |
|
|
|
break; |
|
|
|
case lang_output_statement_enum: |
|
|
|
break; |
|
|
|
case lang_target_statement_enum: |
|
|
|
target = s->target_statement.target; |
|
|
|
@ -3458,102 +3477,19 @@ map_input_to_output_sections |
|
|
|
target, |
|
|
|
os); |
|
|
|
break; |
|
|
|
case lang_address_statement_enum: |
|
|
|
/* Mark the specified section with the supplied address.
|
|
|
|
If this section was actually a segment marker, then the |
|
|
|
directive is ignored if the linker script explicitly |
|
|
|
processed the segment marker. Originally, the linker |
|
|
|
treated segment directives (like -Ttext on the |
|
|
|
command-line) as section directives. We honor the |
|
|
|
section directive semantics for backwards compatibilty; |
|
|
|
linker scripts that do not specifically check for |
|
|
|
SEGMENT_START automatically get the old semantics. */ |
|
|
|
if (!s->address_statement.segment |
|
|
|
|| !s->address_statement.segment->used) |
|
|
|
{ |
|
|
|
const char *name = s->address_statement.section_name; |
|
|
|
|
|
|
|
/* Create the output section statement here rather than
|
|
|
|
in create_other_output_sections so that orphans with |
|
|
|
a set address will be placed after other script |
|
|
|
sections. If we let the orphan placement code place |
|
|
|
them in amongst other sections then the address will |
|
|
|
affect following script sections, which is likely to |
|
|
|
surprise naive users. */ |
|
|
|
tos = lang_output_section_statement_lookup (name, 0, TRUE); |
|
|
|
tos->addr_tree = s->address_statement.address; |
|
|
|
} |
|
|
|
break; |
|
|
|
case lang_output_statement_enum: |
|
|
|
case lang_data_statement_enum: |
|
|
|
case lang_input_section_enum: |
|
|
|
case lang_fill_statement_enum: |
|
|
|
case lang_object_symbols_statement_enum: |
|
|
|
case lang_reloc_statement_enum: |
|
|
|
case lang_padding_statement_enum: |
|
|
|
case lang_input_statement_enum: |
|
|
|
case lang_assignment_statement_enum: |
|
|
|
case lang_insert_statement_enum: |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* Create any other output sections, such as needed for data statements
|
|
|
|
or those referenced in expressions. */ |
|
|
|
|
|
|
|
static void |
|
|
|
create_other_output_sections |
|
|
|
(lang_statement_union_type *s, |
|
|
|
lang_output_section_statement_type *os) |
|
|
|
{ |
|
|
|
lang_output_section_statement_type *tos; |
|
|
|
flagword flags; |
|
|
|
|
|
|
|
for (; s != NULL; s = s->header.next) |
|
|
|
{ |
|
|
|
switch (s->header.type) |
|
|
|
{ |
|
|
|
case lang_wild_statement_enum: |
|
|
|
break; |
|
|
|
case lang_constructors_statement_enum: |
|
|
|
create_other_output_sections (constructor_list.head, os); |
|
|
|
break; |
|
|
|
case lang_output_section_statement_enum: |
|
|
|
tos = &s->output_section_statement; |
|
|
|
if (tos->constraint != 0 |
|
|
|
&& tos->constraint != ONLY_IF_RW |
|
|
|
&& tos->constraint != ONLY_IF_RO) |
|
|
|
break; |
|
|
|
create_other_output_sections (tos->children.head, tos); |
|
|
|
if (tos->bfd_section != NULL) |
|
|
|
{ |
|
|
|
/* If there is a base address, make sure that any sections
|
|
|
|
it might mention are initialized. */ |
|
|
|
if (tos->addr_tree != NULL) |
|
|
|
exp_init_os (tos->addr_tree); |
|
|
|
if (tos->load_base != NULL) |
|
|
|
exp_init_os (tos->load_base); |
|
|
|
} |
|
|
|
break; |
|
|
|
case lang_output_statement_enum: |
|
|
|
case lang_target_statement_enum: |
|
|
|
break; |
|
|
|
case lang_group_statement_enum: |
|
|
|
create_other_output_sections (s->group_statement.children.head, os); |
|
|
|
break; |
|
|
|
case lang_data_statement_enum: |
|
|
|
/* Make sure that any sections mentioned in the expression
|
|
|
|
are initialized. */ |
|
|
|
exp_init_os (s->data_statement.exp); |
|
|
|
if (os->bfd_section == NULL) |
|
|
|
init_os (os, NULL, 0); |
|
|
|
flags = SEC_HAS_CONTENTS; |
|
|
|
/* The output section gets contents, and then we inspect for
|
|
|
|
any flags set in the input script which override any ALLOC. */ |
|
|
|
if (!(os->flags & SEC_NEVER_LOAD)) |
|
|
|
flags |= SEC_ALLOC | SEC_LOAD; |
|
|
|
os->bfd_section->flags |= flags; |
|
|
|
if (os->bfd_section == NULL) |
|
|
|
init_os (os, NULL, flags); |
|
|
|
else |
|
|
|
os->bfd_section->flags |= flags; |
|
|
|
break; |
|
|
|
case lang_input_section_enum: |
|
|
|
break; |
|
|
|
@ -3574,14 +3510,25 @@ create_other_output_sections |
|
|
|
exp_init_os (s->assignment_statement.exp); |
|
|
|
break; |
|
|
|
case lang_address_statement_enum: |
|
|
|
/* Mark the specified section with the supplied address.
|
|
|
|
If this section was actually a segment marker, then the |
|
|
|
directive is ignored if the linker script explicitly |
|
|
|
processed the segment marker. Originally, the linker |
|
|
|
treated segment directives (like -Ttext on the |
|
|
|
command-line) as section directives. We honor the |
|
|
|
section directive semantics for backwards compatibilty; |
|
|
|
linker scripts that do not specifically check for |
|
|
|
SEGMENT_START automatically get the old semantics. */ |
|
|
|
if (!s->address_statement.segment |
|
|
|
|| !s->address_statement.segment->used) |
|
|
|
{ |
|
|
|
const char *name = s->address_statement.section_name; |
|
|
|
lang_output_section_statement_type *aos |
|
|
|
= (lang_output_section_statement_lookup |
|
|
|
(s->address_statement.section_name, 0, TRUE)); |
|
|
|
|
|
|
|
tos = lang_output_section_find (name); |
|
|
|
if (tos->bfd_section == NULL) |
|
|
|
init_os (tos, NULL, 0); |
|
|
|
if (aos->bfd_section == NULL) |
|
|
|
init_os (aos, NULL, 0); |
|
|
|
aos->addr_tree = s->address_statement.address; |
|
|
|
} |
|
|
|
break; |
|
|
|
case lang_insert_statement_enum: |
|
|
|
@ -6400,10 +6347,6 @@ lang_process (void) |
|
|
|
/* Find any sections not attached explicitly and handle them. */ |
|
|
|
lang_place_orphans (); |
|
|
|
|
|
|
|
/* Create sections for data statements and those referenced in
|
|
|
|
expressions but otherwise empty. */ |
|
|
|
create_other_output_sections (statement_list.head, NULL); |
|
|
|
|
|
|
|
if (! link_info.relocatable) |
|
|
|
{ |
|
|
|
asection *found; |
|
|
|
|