/* Linker command language support.
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of the GNU Binutils.
case lang_padding_statement_enum:
case lang_address_statement_enum:
case lang_fill_statement_enum:
+ case lang_insert_statement_enum:
break;
default:
FAIL ();
p->is_archive = TRUE;
p->filename = name;
p->real = TRUE;
- p->local_sym_name = concat ("-l", name, NULL);
+ p->local_sym_name = concat ("-l", name, (const char *) NULL);
p->just_syms_flag = FALSE;
p->search_dirs_flag = TRUE;
break;
if (look->bfd_section != NULL)
{
flags = look->bfd_section->flags;
- if (match_type && !match_type (output_bfd, look->bfd_section,
+ if (match_type && !match_type (link_info.output_bfd,
+ look->bfd_section,
sec->owner, sec))
continue;
}
if (look->bfd_section != NULL)
{
flags = look->bfd_section->flags;
- if (match_type && !match_type (output_bfd, look->bfd_section,
+ if (match_type && !match_type (link_info.output_bfd,
+ look->bfd_section,
sec->owner, sec))
continue;
}
if (look->bfd_section != NULL)
{
flags = look->bfd_section->flags;
- if (match_type && !match_type (output_bfd, look->bfd_section,
+ if (match_type && !match_type (link_info.output_bfd,
+ look->bfd_section,
sec->owner, sec))
continue;
}
if (look->bfd_section != NULL)
{
flags = look->bfd_section->flags;
- if (match_type && !match_type (output_bfd, look->bfd_section,
+ if (match_type && !match_type (link_info.output_bfd,
+ look->bfd_section,
sec->owner, sec))
continue;
}
if (look->bfd_section != NULL)
{
flags = look->bfd_section->flags;
- if (match_type && !match_type (output_bfd, look->bfd_section,
+ if (match_type && !match_type (link_info.output_bfd,
+ look->bfd_section,
sec->owner, sec))
continue;
}
if (look->bfd_section != NULL)
{
flags = look->bfd_section->flags;
- if (match_type && !match_type (output_bfd, look->bfd_section,
+ if (match_type && !match_type (link_info.output_bfd,
+ look->bfd_section,
sec->owner, sec))
continue;
}
return NULL;
}
+/* Look for a suitable place for a new output section statement. The
+ idea is to skip over anything that might be inside a SECTIONS {}
+ statement in a script, before we find another output section
+ statement. Assignments to "dot" before an output section statement
+ are assumed to belong to it. An exception to this rule is made for
+ the first assignment to dot, otherwise we might put an orphan
+ before . = . + SIZEOF_HEADERS or similar assignments that set the
+ initial address. */
+
+static lang_statement_union_type **
+insert_os_after (lang_output_section_statement_type *after)
+{
+ lang_statement_union_type **where;
+ lang_statement_union_type **assign = NULL;
+ bfd_boolean ignore_first;
+
+ ignore_first
+ = after == &lang_output_section_statement.head->output_section_statement;
+
+ for (where = &after->header.next;
+ *where != NULL;
+ where = &(*where)->header.next)
+ {
+ switch ((*where)->header.type)
+ {
+ case lang_assignment_statement_enum:
+ if (assign == NULL)
+ {
+ lang_assignment_statement_type *ass;
+
+ ass = &(*where)->assignment_statement;
+ if (ass->exp->type.node_class != etree_assert
+ && ass->exp->assign.dst[0] == '.'
+ && ass->exp->assign.dst[1] == 0
+ && !ignore_first)
+ assign = where;
+ }
+ ignore_first = FALSE;
+ continue;
+ case lang_wild_statement_enum:
+ case lang_input_section_enum:
+ case lang_object_symbols_statement_enum:
+ case lang_fill_statement_enum:
+ case lang_data_statement_enum:
+ case lang_reloc_statement_enum:
+ case lang_padding_statement_enum:
+ case lang_constructors_statement_enum:
+ assign = NULL;
+ continue;
+ case lang_output_section_statement_enum:
+ if (assign != NULL)
+ where = assign;
+ break;
+ case lang_input_statement_enum:
+ case lang_address_statement_enum:
+ case lang_target_statement_enum:
+ case lang_output_statement_enum:
+ case lang_group_statement_enum:
+ case lang_insert_statement_enum:
+ continue;
+ }
+ break;
+ }
+
+ return where;
+}
+
lang_output_section_statement_type *
lang_insert_orphan (asection *s,
const char *secname,
etree_type *e_align;
symname = (char *) xmalloc (ps - secname + sizeof "__start_" + 1);
- symname[0] = bfd_get_symbol_leading_char (output_bfd);
+ symname[0] = bfd_get_symbol_leading_char (link_info.output_bfd);
sprintf (symname + (symname[0] != 0), "__start_%s", secname);
e_align = exp_unop (ALIGN_K,
exp_intop ((bfd_vma) 1 << s->alignment_power));
stat_ptr = &add;
symname = (char *) xmalloc (ps - secname + sizeof "__stop_" + 1);
- symname[0] = bfd_get_symbol_leading_char (output_bfd);
+ 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,
exp_nameop (NAME, "."),
}
if (place->section == NULL)
- place->section = &output_bfd->sections;
+ place->section = &link_info.output_bfd->sections;
as = *place->section;
/* Put the section at the end of the list. */
/* Unlink the section. */
- bfd_section_list_remove (output_bfd, snew);
+ bfd_section_list_remove (link_info.output_bfd, snew);
/* Now tack it back on in the right place. */
- bfd_section_list_append (output_bfd, snew);
+ bfd_section_list_append (link_info.output_bfd, snew);
}
else if (as != snew && as->prev != snew)
{
/* Unlink the section. */
- bfd_section_list_remove (output_bfd, snew);
+ bfd_section_list_remove (link_info.output_bfd, snew);
/* Now tack it back on in the right place. */
- bfd_section_list_insert_before (output_bfd, as, snew);
+ bfd_section_list_insert_before (link_info.output_bfd, as, snew);
}
/* Save the end of this list. Further ophans of this type will
if (place->stmt == NULL)
{
- lang_statement_union_type **where;
- lang_statement_union_type **assign = NULL;
- bfd_boolean ignore_first;
-
- /* Look for a suitable place for the new statement list.
- The idea is to skip over anything that might be inside
- a SECTIONS {} statement in a script, before we find
- another output_section_statement. Assignments to "dot"
- before an output section statement are assumed to
- belong to it. An exception to this rule is made for
- the first assignment to dot, otherwise we might put an
- orphan before . = . + SIZEOF_HEADERS or similar
- assignments that set the initial address. */
-
- ignore_first = after == (&lang_output_section_statement.head
- ->output_section_statement);
- for (where = &after->header.next;
- *where != NULL;
- where = &(*where)->header.next)
- {
- switch ((*where)->header.type)
- {
- case lang_assignment_statement_enum:
- if (assign == NULL)
- {
- lang_assignment_statement_type *ass;
- ass = &(*where)->assignment_statement;
- if (ass->exp->type.node_class != etree_assert
- && ass->exp->assign.dst[0] == '.'
- && ass->exp->assign.dst[1] == 0
- && !ignore_first)
- assign = where;
- }
- ignore_first = FALSE;
- continue;
- case lang_wild_statement_enum:
- case lang_input_section_enum:
- case lang_object_symbols_statement_enum:
- case lang_fill_statement_enum:
- case lang_data_statement_enum:
- case lang_reloc_statement_enum:
- case lang_padding_statement_enum:
- case lang_constructors_statement_enum:
- assign = NULL;
- continue;
- case lang_output_section_statement_enum:
- if (assign != NULL)
- where = assign;
- break;
- case lang_input_statement_enum:
- case lang_address_statement_enum:
- case lang_target_statement_enum:
- case lang_output_statement_enum:
- case lang_group_statement_enum:
- case lang_afile_asection_pair_statement_enum:
- continue;
- }
- break;
- }
+ lang_statement_union_type **where = insert_os_after (after);
*add.tail = *where;
*where = add.head;
for (s = file->the_bfd->sections; s != NULL; s = s->next)
if ((s->output_section == NULL
- || s->output_section->owner != output_bfd)
+ || s->output_section->owner != link_info.output_bfd)
&& (s->flags & (SEC_LINKER_CREATED | SEC_KEEP)) == 0)
{
if (! dis_header_printed)
if (strcmp (s->name, DISCARD_SECTION_NAME) == 0)
einfo (_("%P%F: Illegal use of `%s' section\n"), DISCARD_SECTION_NAME);
- s->bfd_section = bfd_get_section_by_name (output_bfd, s->name);
+ s->bfd_section = bfd_get_section_by_name (link_info.output_bfd, s->name);
if (s->bfd_section == NULL)
- s->bfd_section = bfd_make_section_with_flags (output_bfd, s->name,
- flags);
+ s->bfd_section = bfd_make_section_with_flags (link_info.output_bfd,
+ s->name, flags);
if (s->bfd_section == NULL)
{
einfo (_("%P%F: output format %s cannot represent section called %s\n"),
- output_bfd->xvec->name, s->name);
+ link_info.output_bfd->xvec->name, s->name);
}
s->bfd_section->output_section = s->bfd_section;
s->bfd_section->output_offset = 0;
if (isec)
bfd_init_private_section_data (isec->owner, isec,
- output_bfd, s->bfd_section,
+ link_info.output_bfd, s->bfd_section,
&link_info);
}
/* Open the output file. */
-static bfd *
+static void
open_output (const char *name)
{
- bfd *output;
-
output_target = lang_get_output_target ();
/* Has the user requested a particular endianness on the command
}
}
- output = bfd_openw (name, output_target);
+ link_info.output_bfd = bfd_openw (name, output_target);
- if (output == NULL)
+ if (link_info.output_bfd == NULL)
{
if (bfd_get_error () == bfd_error_invalid_target)
einfo (_("%P%F: target %s not found\n"), output_target);
delete_output_file_on_failure = TRUE;
- if (! bfd_set_format (output, bfd_object))
+ if (! bfd_set_format (link_info.output_bfd, bfd_object))
einfo (_("%P%F:%s: can not make object file: %E\n"), name);
- if (! bfd_set_arch_mach (output,
+ if (! bfd_set_arch_mach (link_info.output_bfd,
ldfile_output_architecture,
ldfile_output_machine))
einfo (_("%P%F:%s: can not set architecture: %E\n"), name);
- link_info.hash = bfd_link_hash_table_create (output);
+ link_info.hash = bfd_link_hash_table_create (link_info.output_bfd);
if (link_info.hash == NULL)
einfo (_("%P%F: can not create hash table: %E\n"));
- bfd_set_gp_size (output, g_switch_value);
- return output;
+ bfd_set_gp_size (link_info.output_bfd, g_switch_value);
}
static void
switch (statement->header.type)
{
case lang_output_statement_enum:
- ASSERT (output_bfd == NULL);
- output_bfd = open_output (statement->output_statement.name);
+ ASSERT (link_info.output_bfd == NULL);
+ open_output (statement->output_statement.name);
ldemul_set_output_arch ();
if (config.magic_demand_paged && !link_info.relocatable)
- output_bfd->flags |= D_PAGED;
+ link_info.output_bfd->flags |= D_PAGED;
else
- output_bfd->flags &= ~D_PAGED;
+ link_info.output_bfd->flags &= ~D_PAGED;
if (config.text_read_only)
- output_bfd->flags |= WP_TEXT;
+ link_info.output_bfd->flags |= WP_TEXT;
else
- output_bfd->flags &= ~WP_TEXT;
+ link_info.output_bfd->flags &= ~WP_TEXT;
if (link_info.traditional_format)
- output_bfd->flags |= BFD_TRADITIONAL_FORMAT;
+ link_info.output_bfd->flags |= BFD_TRADITIONAL_FORMAT;
else
- output_bfd->flags &= ~BFD_TRADITIONAL_FORMAT;
+ link_info.output_bfd->flags &= ~BFD_TRADITIONAL_FORMAT;
break;
case lang_target_statement_enum:
new->name = xstrdup (name);
- if (output_bfd != NULL)
+ if (link_info.output_bfd != NULL)
insert_undefined (new->name);
}
are initialized. */
exp_init_os (s->assignment_statement.exp);
break;
- case lang_afile_asection_pair_statement_enum:
- FAIL ();
- break;
case lang_address_statement_enum:
/* Mark the specified section with the supplied address.
aos->addr_tree = s->address_statement.address;
}
break;
+ case lang_insert_statement_enum:
+ break;
+ }
+ }
+}
+
+/* An insert statement snips out all the linker statements from the
+ start of the list and places them after the output section
+ statement specified by the insert. This operation is complicated
+ by the fact that we keep a doubly linked list of output section
+ statements as well as the singly linked list of all statements. */
+
+static void
+process_insert_statements (void)
+{
+ lang_statement_union_type **s;
+ lang_output_section_statement_type *first_os = NULL;
+ lang_output_section_statement_type *last_os = NULL;
+
+ /* "start of list" is actually the statement immediately after
+ the special abs_section output statement, so that it isn't
+ reordered. */
+ s = &lang_output_section_statement.head;
+ while (*(s = &(*s)->header.next) != NULL)
+ {
+ if ((*s)->header.type == lang_output_section_statement_enum)
+ {
+ /* Keep pointers to the first and last output section
+ statement in the sequence we may be about to move. */
+ last_os = &(*s)->output_section_statement;
+ if (first_os == NULL)
+ first_os = last_os;
+ }
+ else if ((*s)->header.type == lang_insert_statement_enum)
+ {
+ lang_insert_statement_type *i = &(*s)->insert_statement;
+ lang_output_section_statement_type *where;
+ lang_output_section_statement_type *os;
+ lang_statement_union_type **ptr;
+ lang_statement_union_type *first;
+
+ where = lang_output_section_find (i->where);
+ if (where != NULL && i->is_before)
+ {
+ do
+ where = where->prev;
+ while (where != NULL && where->constraint == -1);
+ }
+ if (where == NULL)
+ {
+ einfo (_("%X%P: %s not found for insert\n"), i->where);
+ continue;
+ }
+ /* You can't insert into the list you are moving. */
+ for (os = first_os; os != NULL; os = os->next)
+ if (os == where || os == last_os)
+ break;
+ if (os == where)
+ {
+ einfo (_("%X%P: %s not found for insert\n"), i->where);
+ continue;
+ }
+
+ /* Deal with reordering the output section statement list. */
+ if (last_os != NULL)
+ {
+ asection *first_sec, *last_sec;
+ struct lang_output_section_statement_struct **next;
+
+ /* Snip out the output sections we are moving. */
+ first_os->prev->next = last_os->next;
+ if (last_os->next == NULL)
+ {
+ next = &first_os->prev->next;
+ lang_output_section_statement.tail
+ = (lang_statement_union_type **) next;
+ }
+ else
+ last_os->next->prev = first_os->prev;
+ /* Add them in at the new position. */
+ last_os->next = where->next;
+ if (where->next == NULL)
+ {
+ next = &last_os->next;
+ lang_output_section_statement.tail
+ = (lang_statement_union_type **) next;
+ }
+ else
+ where->next->prev = last_os;
+ first_os->prev = where;
+ where->next = first_os;
+
+ /* Move the bfd sections in the same way. */
+ first_sec = NULL;
+ last_sec = NULL;
+ for (os = first_os; os != NULL; os = os->next)
+ {
+ if (os->bfd_section != NULL
+ && os->bfd_section->owner != NULL)
+ {
+ last_sec = os->bfd_section;
+ if (first_sec == NULL)
+ first_sec = last_sec;
+ }
+ if (os == last_os)
+ break;
+ }
+ if (last_sec != NULL)
+ {
+ asection *sec = where->bfd_section;
+ if (sec == NULL)
+ sec = output_prev_sec_find (where);
+
+ /* The place we want to insert must come after the
+ sections we are moving. So if we find no
+ section or if the section is the same as our
+ last section, then no move is needed. */
+ if (sec != NULL && sec != last_sec)
+ {
+ /* Trim them off. */
+ if (first_sec->prev != NULL)
+ first_sec->prev->next = last_sec->next;
+ else
+ link_info.output_bfd->sections = last_sec->next;
+ if (last_sec->next != NULL)
+ last_sec->next->prev = first_sec->prev;
+ else
+ link_info.output_bfd->section_last = first_sec->prev;
+ /* Add back. */
+ last_sec->next = sec->next;
+ if (sec->next != NULL)
+ sec->next->prev = last_sec;
+ else
+ link_info.output_bfd->section_last = last_sec;
+ first_sec->prev = sec;
+ sec->next = first_sec;
+ }
+ }
+
+ first_os = NULL;
+ last_os = NULL;
+ }
+
+ ptr = insert_os_after (where);
+ /* Snip everything after the abs_section output statement we
+ know is at the start of the list, up to and including
+ the insert statement we are currently processing. */
+ first = lang_output_section_statement.head->header.next;
+ lang_output_section_statement.head->header.next = (*s)->header.next;
+ /* Add them back where they belong. */
+ *s = *ptr;
+ if (*s == NULL)
+ statement_list.tail = s;
+ *ptr = first;
+ s = &lang_output_section_statement.head;
}
}
}
exclude = (output_section->rawsize == 0
&& (output_section->flags & SEC_KEEP) == 0
- && !bfd_section_removed_from_list (output_bfd,
+ && !bfd_section_removed_from_list (link_info.output_bfd,
output_section));
/* Some sections have not yet been sized, notably .gnu.version,
&& !os->update_dot_tree)
os->ignored = TRUE;
output_section->flags |= SEC_EXCLUDE;
- bfd_section_list_remove (output_bfd, output_section);
- output_bfd->section_count--;
+ bfd_section_list_remove (link_info.output_bfd, output_section);
+ link_info.output_bfd->section_count--;
}
}
++len;
}
- if (i->output_section != NULL && i->output_section->owner == output_bfd)
+ if (i->output_section != NULL
+ && i->output_section->owner == link_info.output_bfd)
addr = i->output_section->vma + i->output_offset;
else
{
minfo (_("%W (size before relaxing)\n"), i->rawsize);
}
- if (i->output_section != NULL && i->output_section->owner == output_bfd)
+ if (i->output_section != NULL
+ && i->output_section->owner == link_info.output_bfd)
{
if (link_info.reduce_memory_overheads)
bfd_link_hash_traverse (link_info.hash, print_one_symbol, i);
case lang_group_statement_enum:
print_group (&s->group_statement, os);
break;
- case lang_afile_asection_pair_statement_enum:
- FAIL ();
+ case lang_insert_statement_enum:
+ minfo ("INSERT %s %s\n",
+ s->insert_statement.is_before ? "BEFORE" : "AFTER",
+ s->insert_statement.where);
break;
}
}
bfd_size_type amt;
lang_memory_region_type *m;
- if (bfd_count_sections (output_bfd) <= 1)
+ if (bfd_count_sections (link_info.output_bfd) <= 1)
return;
- amt = bfd_count_sections (output_bfd) * sizeof (asection *);
+ amt = bfd_count_sections (link_info.output_bfd) * sizeof (asection *);
sections = xmalloc (amt);
/* Scan all sections in the output list. */
count = 0;
- for (s = output_bfd->sections; s != NULL; s = s->next)
+ for (s = link_info.output_bfd->sections; s != NULL; s = s->next)
{
/* Only consider loadable sections with real contents. */
if (IGNORE_SECTION (s) || s->size == 0)
spp = sections;
s = *spp++;
- s_start = bfd_section_lma (output_bfd, s);
+ s_start = bfd_section_lma (link_info.output_bfd, s);
s_end = s_start + TO_ADDR (s->size) - 1;
for (count--; count; count--)
{
os_start = s_start;
os_end = s_end;
s = *spp++;
- s_start = bfd_section_lma (output_bfd, s);
+ s_start = bfd_section_lma (link_info.output_bfd, s);
s_end = s_start + TO_ADDR (s->size) - 1;
/* Look for an overlap. */
address from the input section. FIXME: This is COFF
specific; it would be cleaner if there were some other way
to do this, but nothing simple comes to mind. */
- if ((bfd_get_flavour (output_bfd) == bfd_target_ecoff_flavour
- || bfd_get_flavour (output_bfd) == bfd_target_coff_flavour)
+ if (((bfd_get_flavour (link_info.output_bfd)
+ == bfd_target_ecoff_flavour)
+ || (bfd_get_flavour (link_info.output_bfd)
+ == bfd_target_coff_flavour))
&& (os->bfd_section->flags & SEC_COFF_SHARED_LIBRARY) != 0)
{
asection *input;
if (command_line.check_section_addresses)
einfo (_("%P%F: error: no memory region specified"
" for loadable section `%s'\n"),
- bfd_get_section_name (output_bfd,
+ bfd_get_section_name (link_info.output_bfd,
os->bfd_section));
else
einfo (_("%P: warning: no memory region specified"
" for loadable section `%s'\n"),
- bfd_get_section_name (output_bfd,
+ bfd_get_section_name (link_info.output_bfd,
os->bfd_section));
}
bfd_vma lma = exp_get_abs_int (os->load_base, 0, "load base");
os->bfd_section->lma = lma;
}
- else if (os->region != NULL
- && os->lma_region != NULL
- && os->lma_region != os->region)
+ else if (os->lma_region != NULL)
{
bfd_vma lma = os->lma_region->current;
should have space allocated to it, unless the
user has explicitly stated that the section
should never be loaded. */
- if (!(output_section_statement->flags
- & (SEC_NEVER_LOAD | SEC_ALLOC)))
+ if (!(output_section_statement->flags & SEC_NEVER_LOAD))
output_section_statement->bfd_section->flags |= SEC_ALLOC;
}
dot = newdot;
fill, dot, relax, check_regions);
break;
- default:
- FAIL ();
+ case lang_insert_statement_enum:
break;
/* We can only get here when relaxing is turned on. */
case lang_address_statement_enum:
break;
+
+ default:
+ FAIL ();
+ break;
}
prev = &s->header.next;
}
/* Find maximum alignment power of sections between
DATA_SEGMENT_ALIGN and DATA_SEGMENT_RELRO_END. */
- for (sec = output_bfd->sections; sec; sec = sec->next)
+ 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)
current_os, fill, dot);
break;
- default:
- FAIL ();
+ case lang_insert_statement_enum:
break;
case lang_address_statement_enum:
break;
+
+ default:
+ FAIL ();
+ break;
}
}
return dot;
if (link_info.relocatable)
return;
- for (s = output_bfd->sections; s != NULL; s = s->next)
+ for (s = link_info.output_bfd->sections; s != NULL; s = s->next)
{
const char *secname;
char *buf;
struct bfd_link_hash_entry *h;
- secname = bfd_get_section_name (output_bfd, s);
+ secname = bfd_get_section_name (link_info.output_bfd, s);
buf = xmalloc (10 + strlen (secname));
sprintf (buf, ".startof.%s", secname);
if (h != NULL && h->type == bfd_link_hash_undefined)
{
h->type = bfd_link_hash_defined;
- h->u.def.value = bfd_get_section_vma (output_bfd, s);
+ h->u.def.value = bfd_get_section_vma (link_info.output_bfd, s);
h->u.def.section = bfd_abs_section_ptr;
}
struct bfd_link_hash_entry *h;
bfd_boolean warn;
- if (link_info.relocatable || link_info.shared)
- warn = FALSE;
+ if ((link_info.relocatable && !link_info.gc_sections)
+ || link_info.shared)
+ warn = entry_from_cmdline;
else
warn = TRUE;
+ /* Force the user to specify a root when generating a relocatable with
+ --gc-sections. */
+ if (link_info.gc_sections && link_info.relocatable
+ && (entry_symbol.name == NULL
+ && ldlang_undef_chain_list_head == NULL))
+ einfo (_("%P%F: gc-sections requires either an entry or "
+ "an undefined symbol\n"));
+
if (entry_symbol.name == NULL)
{
/* No entry has been specified. Look for the default entry, but
bfd_vma val;
val = (h->u.def.value
- + bfd_get_section_vma (output_bfd,
+ + bfd_get_section_vma (link_info.output_bfd,
h->u.def.section->output_section)
+ h->u.def.section->output_offset);
- if (! bfd_set_start_address (output_bfd, val))
+ if (! bfd_set_start_address (link_info.output_bfd, val))
einfo (_("%P%F:%s: can't set start address\n"), entry_symbol.name);
}
else
val = bfd_scan_vma (entry_symbol.name, &send, 0);
if (*send == '\0')
{
- if (! bfd_set_start_address (output_bfd, val))
+ if (! bfd_set_start_address (link_info.output_bfd, val))
einfo (_("%P%F: can't set start address\n"));
}
else
/* Can't find the entry symbol, and it's not a number. Use
the first address in the text section. */
- ts = bfd_get_section_by_name (output_bfd, entry_section);
+ ts = bfd_get_section_by_name (link_info.output_bfd, entry_section);
if (ts != NULL)
{
if (warn)
einfo (_("%P: warning: cannot find entry symbol %s;"
" defaulting to %V\n"),
entry_symbol.name,
- bfd_get_section_vma (output_bfd, ts));
- if (! bfd_set_start_address (output_bfd,
- bfd_get_section_vma (output_bfd,
- ts)))
+ bfd_get_section_vma (link_info.output_bfd, ts));
+ if (!(bfd_set_start_address
+ (link_info.output_bfd,
+ bfd_get_section_vma (link_info.output_bfd, ts))))
einfo (_("%P%F: can't set start address\n"));
}
else
{
input_bfd = file->input_statement.the_bfd;
compatible
- = bfd_arch_get_compatible (input_bfd, output_bfd,
+ = bfd_arch_get_compatible (input_bfd, link_info.output_bfd,
command_line.accept_unknown_input_arch);
/* In general it is not possible to perform a relocatable
relocs for other link purposes than a final link). */
if ((link_info.relocatable || link_info.emitrelocations)
&& (compatible == NULL
- || bfd_get_flavour (input_bfd) != bfd_get_flavour (output_bfd))
+ || (bfd_get_flavour (input_bfd)
+ != bfd_get_flavour (link_info.output_bfd)))
&& (bfd_get_file_flags (input_bfd) & HAS_RELOC) != 0)
{
einfo (_("%P%F: Relocatable linking with relocations from"
" format %s (%B) to format %s (%B) is not supported\n"),
bfd_get_target (input_bfd), input_bfd,
- bfd_get_target (output_bfd), output_bfd);
+ bfd_get_target (link_info.output_bfd), link_info.output_bfd);
/* einfo with %F exits. */
}
einfo (_("%P%X: %s architecture of input file `%B'"
" is incompatible with %s output\n"),
bfd_printable_name (input_bfd), input_bfd,
- bfd_printable_name (output_bfd));
+ bfd_printable_name (link_info.output_bfd));
}
else if (bfd_count_sections (input_bfd))
{
information which is needed in the output file. */
if (! command_line.warn_mismatch)
pfn = bfd_set_error_handler (ignore_bfd_errors);
- if (! bfd_merge_private_bfd_data (input_bfd, output_bfd))
+ if (! bfd_merge_private_bfd_data (input_bfd, link_info.output_bfd))
{
if (command_line.warn_mismatch)
einfo (_("%P%X: failed to merge target specific data"
header_printed = TRUE;
}
- name = bfd_demangle (output_bfd, h->root.string,
+ name = bfd_demangle (link_info.output_bfd, h->root.string,
DMGL_ANSI | DMGL_PARAMS);
if (name == NULL)
{
/* 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 != output_bfd);
+ 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;
os->processed_lma = FALSE;
}
- for (o = output_bfd->sections; o != NULL; o = o->next)
+ for (o = link_info.output_bfd->sections; o != NULL; o = o->next)
{
/* Save the last size for possible use by bfd_relax_section. */
o->rawsize = o->size;
static void
lang_gc_sections (void)
{
- struct bfd_link_hash_entry *h;
- ldlang_undef_chain_list_type *ulist;
-
/* Keep all sections so marked in the link script. */
lang_gc_sections_1 (statement_list.head);
- /* Keep all sections containing symbols undefined on the command-line,
- and the section containing the entry symbol. */
-
- for (ulist = link_info.gc_sym_list; ulist; ulist = ulist->next)
- {
- h = bfd_link_hash_lookup (link_info.hash, ulist->name,
- FALSE, FALSE, FALSE);
-
- if (h != NULL
- && (h->type == bfd_link_hash_defined
- || h->type == bfd_link_hash_defweak)
- && ! bfd_is_abs_section (h->u.def.section))
- {
- h->u.def.section->flags |= SEC_KEEP;
- }
- }
-
/* 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.gc_sections)
- bfd_gc_sections (output_bfd, &link_info);
+ bfd_gc_sections (link_info.output_bfd, &link_info);
}
/* Worker for lang_find_relro_sections_1. */
/* Discarded, excluded and ignored sections effectively have zero
size. */
if (section->output_section != NULL
- && section->output_section->owner == output_bfd
+ && section->output_section->owner == link_info.output_bfd
&& (section->output_section->flags & SEC_EXCLUDE) == 0
&& !IGNORE_SECTION (section)
&& section->size != 0)
to the correct output sections. */
map_input_to_output_sections (statement_list.head, NULL, NULL);
+ process_insert_statements ();
+
/* Find any sections not attached explicitly and handle them. */
lang_place_orphans ();
sections, so that GCed sections are not merged, but before
assigning dynamic symbols, since removing whole input sections
is hard then. */
- bfd_merge_sections (output_bfd, &link_info);
+ bfd_merge_sections (link_info.output_bfd, &link_info);
/* Look for a text section and set the readonly attribute in it. */
- found = bfd_get_section_by_name (output_bfd, ".text");
+ found = bfd_get_section_by_name (link_info.output_bfd, ".text");
if (found != NULL)
{
h->type = bfd_link_hash_defined;
- sec = bfd_get_section_by_name (output_bfd, secname);
+ sec = bfd_get_section_by_name (link_info.output_bfd, secname);
if (sec == NULL)
h->u.def.value = 0;
else
- h->u.def.value = bfd_get_section_vma (output_bfd, sec);
+ h->u.def.value = bfd_get_section_vma (link_info.output_bfd, sec);
h->u.def.section = bfd_abs_section_ptr;
}
h->type = bfd_link_hash_defined;
- sec = bfd_get_section_by_name (output_bfd, secname);
+ sec = bfd_get_section_by_name (link_info.output_bfd, secname);
if (sec == NULL)
h->u.def.value = 0;
else
- h->u.def.value = (bfd_get_section_vma (output_bfd, sec)
+ h->u.def.value = (bfd_get_section_vma (link_info.output_bfd, sec)
+ TO_ADDR (sec->size));
h->u.def.section = bfd_abs_section_ptr;
}
}
+void
+lang_add_insert (const char *where, int is_before)
+{
+ lang_insert_statement_type *new;
+
+ new = new_stat (lang_insert_statement, stat_ptr);
+ new->where = where;
+ new->is_before = is_before;
+ saved_script_handle = previous_script_handle;
+}
+
/* Enter a group. This creates a new lang_group_statement, and sets
stat_ptr to build new statements within the group. */
else
at = exp_get_vma (l->at, 0, "phdr load address");
- if (! bfd_record_phdr (output_bfd, l->type,
+ if (! bfd_record_phdr (link_info.output_bfd, l->type,
l->flags != NULL, flags, l->at != NULL,
at, l->filehdr, l->phdrs, c, secs))
einfo (_("%F%P: bfd_record_phdr failed: %E\n"));