/* Linker command language support.
- Copyright (C) 1991-2018 Free Software Foundation, Inc.
+ Copyright (C) 1991-2019 Free Software Foundation, Inc.
This file is part of the GNU Binutils.
static bfd_vma print_dot;
static lang_input_statement_type *first_file;
static const char *current_target;
+/* Header for list of statements corresponding to any files involved in the
+ link, either specified from the command-line or added implicitely (eg.
+ archive member used to resolved undefined symbol, wildcard statement from
+ linker script, etc.). Next pointer is in next field of a
+ lang_statement_header_type (reached via header field in a
+ lang_statement_union). */
static lang_statement_list_type statement_list;
static lang_statement_list_type *stat_save[10];
static lang_statement_list_type **stat_save_ptr = &stat_save[0];
lang_output_section_statement_type *abs_output_section;
lang_statement_list_type lang_output_section_statement;
lang_statement_list_type *stat_ptr = &statement_list;
+/* Header for list of statements corresponding to files used in the final
+ executable. This can be either object file specified on the command-line
+ or library member resolving an undefined reference. Next pointer is in next
+ field of a lang_input_statement_type (reached via input_statement field in a
+ lang_statement_union). */
lang_statement_list_type file_chain = { NULL, NULL };
+/* Header for list of statements corresponding to files specified on the
+ command-line for linking. It thus contains real object files and archive
+ but not archive members. Next pointer is in next_real_file field of a
+ lang_input_statement_type statement (reached via input_statement field in a
+ lang_statement_union). */
lang_statement_list_type input_file_chain;
struct bfd_sym_chain entry_symbol = { NULL, NULL };
const char *entry_section = ".text";
{
asection *snew, *as;
bfd_boolean place_after = place->stmt == NULL;
+ bfd_boolean insert_after = TRUE;
snew = os->bfd_section;
asection *after_sec;
/* True if we need to insert the orphan section after a
specific section to maintain output note section order. */
- bfd_boolean after_sec_note;
+ bfd_boolean after_sec_note = FALSE;
+
+ static asection *first_orphan_note = NULL;
/* Group and sort output note section by alignments in
ascending order. */
if (elf_section_type (s) == SHT_NOTE
&& (s->flags & SEC_LOAD) != 0)
{
- /* Search forward for the last output note section
- with equal or larger alignments. */
- asection *first_note = NULL;
+ /* Search from the beginning for the last output note
+ section with equal or larger alignments. NB: Don't
+ place orphan note section after non-note sections. */
- for (sec = as;
+ first_orphan_note = NULL;
+ for (sec = link_info.output_bfd->sections;
(sec != NULL
&& !bfd_is_abs_section (sec));
sec = sec->next)
&& elf_section_type (sec) == SHT_NOTE
&& (sec->flags & SEC_LOAD) != 0)
{
- if (!first_note)
- first_note = sec;
+ if (!first_orphan_note)
+ first_orphan_note = sec;
if (sec->alignment_power >= s->alignment_power)
after_sec = sec;
}
+ else if (first_orphan_note)
+ {
+ /* Stop if there is non-note section after the first
+ orphan note section. */
+ break;
+ }
- if (after_sec)
- after_sec_note = TRUE;
- else
+ /* If this will be the first orphan note section, it can
+ be placed at the default location. */
+ after_sec_note = first_orphan_note != NULL;
+ if (after_sec == NULL && after_sec_note)
{
- /* Search backward for the first output note section
- as well as the last output note section with equal
- or larger alignments. */
- after_sec = NULL;
- for (sec = as;
- (sec != NULL
- && !bfd_is_abs_section (sec));
- sec = sec->prev)
- if (sec != snew
- && elf_section_type (sec) == SHT_NOTE
- && (sec->flags & SEC_LOAD) != 0)
- {
- first_note = sec;
- if (!after_sec
- && sec->alignment_power >= s->alignment_power)
- after_sec = sec;
- }
-
- /* If this will be the first note section, it can be
- placed at the default location. */
- after_sec_note = first_note != NULL;
- if (after_sec == NULL && after_sec_note)
- {
- /* If all output note sections have smaller
- alignments, place the section before all
- output note sections. AFTER_SEC will be
- NULL if FIRST_NOTE is the first output
- section. */
- after_sec = first_note->prev;
- }
+ /* If all output note sections have smaller
+ alignments, place the section before all
+ output orphan note sections. */
+ after_sec = first_orphan_note;
+ insert_after = FALSE;
}
}
- else
+ else if (first_orphan_note)
{
- /* Don't place non-note sections in the middle of note
- sections. */
+ /* Don't place non-note sections in the middle of orphan
+ note sections. */
after_sec_note = TRUE;
after_sec = as;
for (sec = as->next;
{
if (after_sec)
{
- /* Insert OS after AFTER_SEC output statement. */
- lang_output_section_statement_type *stmt;
- for (stmt = after;
- stmt != NULL;
- stmt = stmt->next)
- if (stmt->bfd_section == after_sec)
+ /* Search forward to insert OS after AFTER_SEC output
+ statement. */
+ lang_output_section_statement_type *stmt, *next;
+ bfd_boolean found = FALSE;
+ for (stmt = after; stmt != NULL; stmt = next)
+ {
+ next = stmt->next;
+ if (insert_after)
+ {
+ if (stmt->bfd_section == after_sec)
+ {
+ place_after = TRUE;
+ found = TRUE;
+ after = stmt;
+ break;
+ }
+ }
+ else
+ {
+ /* If INSERT_AFTER is FALSE, place OS before
+ AFTER_SEC output statement. */
+ if (next && next->bfd_section == after_sec)
+ {
+ place_after = TRUE;
+ found = TRUE;
+ after = stmt;
+ break;
+ }
+ }
+ }
+
+ /* Search backward to insert OS after AFTER_SEC output
+ statement. */
+ if (!found)
+ for (stmt = after; stmt != NULL; stmt = stmt->prev)
{
- place_after = TRUE;
- after = stmt;
- break;
+ if (insert_after)
+ {
+ if (stmt->bfd_section == after_sec)
+ {
+ place_after = TRUE;
+ after = stmt;
+ break;
+ }
+ }
+ else
+ {
+ /* If INSERT_AFTER is FALSE, place OS before
+ AFTER_SEC output statement. */
+ if (stmt->next->bfd_section == after_sec)
+ {
+ place_after = TRUE;
+ after = stmt;
+ break;
+ }
+ }
}
}
- if (after_sec == NULL || after_sec->next != snew)
+ if (after_sec == NULL
+ || (insert_after && after_sec->next != snew)
+ || (!insert_after && after_sec->prev != snew))
{
/* Unlink the section. */
bfd_section_list_remove (link_info.output_bfd, snew);
/* Place SNEW after AFTER_SEC. If AFTER_SEC is NULL,
prepend SNEW. */
if (after_sec)
- bfd_section_list_insert_after (link_info.output_bfd,
- after_sec, snew);
+ {
+ if (insert_after)
+ bfd_section_list_insert_after (link_info.output_bfd,
+ after_sec, snew);
+ else
+ bfd_section_list_insert_before (link_info.output_bfd,
+ after_sec, snew);
+ }
else
bfd_section_list_prepend (link_info.output_bfd, snew);
}
|| file->flags.just_syms)
continue;
- for (s = file->the_bfd->sections; s != NULL; s = s->next)
- if ((s->output_section == NULL
- || s->output_section->owner != link_info.output_bfd)
- && (s->flags & (SEC_LINKER_CREATED | SEC_KEEP)) == 0)
- {
- if (!dis_header_printed)
- {
- fprintf (config.map_file, _("\nDiscarded input sections\n\n"));
- dis_header_printed = TRUE;
- }
+ if (config.print_map_discarded)
+ for (s = file->the_bfd->sections; s != NULL; s = s->next)
+ if ((s->output_section == NULL
+ || s->output_section->owner != link_info.output_bfd)
+ && (s->flags & (SEC_LINKER_CREATED | SEC_KEEP)) == 0)
+ {
+ if (! dis_header_printed)
+ {
+ fprintf (config.map_file, _("\nDiscarded input sections\n\n"));
+ dis_header_printed = TRUE;
+ }
- print_input_section (s, TRUE);
- }
+ print_input_section (s, TRUE);
+ }
}
minfo (_("\nMemory Configuration\n\n"));
obstack_begin (&map_obstack, 1000);
bfd_link_hash_traverse (link_info.hash, sort_def_symbol, 0);
}
+ expld.phase = lang_fixed_phase_enum;
lang_statement_iteration++;
print_statements ();
{
case normal_section:
case overlay_section:
+ case first_overlay_section:
break;
case noalloc_section:
flags &= ~SEC_ALLOC;
if (entry->flags.missing_file)
return TRUE;
+ if (trace_files || verbose)
+ info_msg ("%pI\n", entry);
+
if (!bfd_check_format (entry->the_bfd, bfd_archive)
&& !bfd_check_format_matches (entry->the_bfd, bfd_object, &matching))
{
case bfd_object:
if (!entry->flags.reload)
ldlang_add_file (entry);
- if (trace_files || verbose)
- info_msg ("%pI\n", entry);
break;
case bfd_archive:
case lang_wild_statement_enum:
for (sec = s->wild_statement.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:
default:
break;
}
- }
break;
case lang_constructors_statement_enum:
break;
case lang_output_section_statement_enum:
- /* Don't sort .init/.fini sections. */
- if (strcmp (s->output_section_statement.name, ".init") != 0
- && strcmp (s->output_section_statement.name, ".fini") != 0)
- update_wild_statements
- (s->output_section_statement.children.head);
+ update_wild_statements
+ (s->output_section_statement.children.head);
break;
case lang_group_statement_enum:
{
case normal_section:
case overlay_section:
+ case first_overlay_section:
break;
case noalloc_section:
flags = SEC_HAS_CONTENTS;
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;
+ tree = assignment->exp;
}
osec = output_section->bfd_section;
h = bfd_link_hash_lookup (link_info.hash, assignment->exp->assign.dst,
FALSE, FALSE, TRUE);
- if (h)
+ if (h != NULL
+ && (h->type == bfd_link_hash_defined
+ || h->type == bfd_link_hash_defweak))
{
value = h->u.def.value;
value += h->u.def.section->output_section->vma;
important, if an orphan section is placed after an
otherwise empty output section that has an explicit lma
set, we want that lma reflected in the orphans lma. */
- if (!IGNORE_SECTION (os->bfd_section)
- && (os->bfd_section->size != 0
- || (r->last_os == NULL
- && os->bfd_section->vma != os->bfd_section->lma)
- || (r->last_os != NULL
- && dot >= (r->last_os->output_section_statement
- .bfd_section->vma)))
+ if (((!IGNORE_SECTION (os->bfd_section)
+ && (os->bfd_section->size != 0
+ || (r->last_os == NULL
+ && os->bfd_section->vma != os->bfd_section->lma)
+ || (r->last_os != NULL
+ && dot >= (r->last_os->output_section_statement
+ .bfd_section->vma))))
+ || os->sectype == first_overlay_section)
&& os->lma_region == NULL
&& !bfd_link_relocatable (&link_info))
r->last_os = s;
break;
case lang_object_symbols_statement_enum:
- link_info.create_object_symbols_section =
- output_section_statement->bfd_section;
+ link_info.create_object_symbols_section
+ = output_section_statement->bfd_section;
+ output_section_statement->bfd_section->flags |= SEC_KEEP;
break;
case lang_output_statement_enum:
warn = TRUE;
/* Force the user to specify a root when generating a relocatable with
- --gc-sections. */
- if (link_info.gc_sections && bfd_link_relocatable (&link_info)
+ --gc-sections, unless --gc-keep-exported was also given. */
+ if (bfd_link_relocatable (&link_info)
+ && link_info.gc_sections
+ && !link_info.gc_keep_exported
&& !(entry_from_cmdline || undef_from_cmdline))
einfo (_("%F%P: gc-sections requires either an entry or "
"an undefined symbol\n"));
if (l->next == 0)
{
l->os->load_base = lma_expr;
- l->os->sectype = normal_section;
+ l->os->sectype = first_overlay_section;
}
if (phdrs != NULL && l->os->phdrs == NULL)
l->os->phdrs = phdrs;