/* Linker command language support.
- Copyright 1991-2013 Free Software Foundation, Inc.
+ Copyright (C) 1991-2014 Free Software Foundation, Inc.
This file is part of the GNU Binutils.
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
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:
p->local_sym_name = name;
break;
case lang_input_file_is_l_enum:
- p->filename = name;
+ 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;
p->flags.real = TRUE;
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 ();
}
lang_match_sec_type_func match_type)
{
lang_output_section_statement_type *first, *look, *found;
- flagword flags;
+ flagword look_flags, sec_flags, differ;
/* We know the first statement on this list is *ABS*. May as well
skip it. */
first = first->next;
/* First try for an exact match. */
+ sec_flags = sec->flags;
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
- | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
+ 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;
}
if (found != NULL)
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
- | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
+ 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
- | SEC_READONLY | SEC_SMALL_DATA))
- || (!(flags & (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))))
+ differ = look_flags ^ sec_flags;
+ if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+ | SEC_READONLY | SEC_SMALL_DATA))
+ || (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+ | SEC_READONLY))
+ && !(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
- | SEC_THREAD_LOCAL))
- || ((look->flags & SEC_SMALL_DATA)
- && !(sec->flags & SEC_HAS_CONTENTS)))
+ 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)))
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
- | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
+ 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;
}
}
/* 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;
}
lang_statement_iteration++;
print_statements ();
+
+ ldemul_extra_map_file_text (link_info.output_bfd, &link_info, config.map_file);
}
static bfd_boolean
return default_target;
}
+/* Stashed function to free link_info.hash; see open_output. */
+void (*output_bfd_hash_table_free_fn) (struct bfd_link_hash_table *);
+
/* Open the output file. */
static void
if (link_info.hash == NULL)
einfo (_("%P%F: can not create hash table: %E\n"));
+ /* We want to please memory leak checkers by deleting link_info.hash.
+ We can't do it in lang_finish, as a bfd target may hold references to
+ symbols in this table and use them when their _bfd_write_contents
+ function is invoked, as part of bfd_close on the output_bfd. But,
+ output_bfd is deallocated at bfd_close, so we can't refer to
+ output_bfd after that time, and dereferencing it is needed to call
+ "bfd_link_hash_table_free". Smash this dependency deadlock and grab
+ the function pointer; arrange to call it on link_info.hash in
+ ld_cleanup. */
+ output_bfd_hash_table_free_fn
+ = link_info.output_bfd->xvec->_bfd_link_hash_table_free;
+
bfd_set_gp_size (link_info.output_bfd, g_switch_value);
}
{
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
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;
}
/* 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. */
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;
}
{
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;
}
newdot = dot;
+ dotdelta = 0;
if (bfd_is_abs_section (os->bfd_section))
{
/* No matter what happens, an abs section starts at zero. */
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);
{
bfd_vma lma = os->lma_region->current;
- /* 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)
- section_alignment = os->section_alignment;
- if (section_alignment > 0)
- lma = align_power (lma, section_alignment);
+ 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. */
+ 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
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);
+ 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);
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,
*relax = TRUE;
}
dot = size_input_section (prev, output_section_statement,
- output_section_statement->fill, dot);
+ fill, dot);
}
break;