/* Linker command language support.
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of the GNU Binutils.
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
-#include <limits.h>
-
#include "sysdep.h"
#include "bfd.h"
#include "libiberty.h"
static const char *output_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];
/* Forward declarations. */
static void exp_init_os (etree_type *);
list->tail = &list->head;
}
+void
+push_stat_ptr (lang_statement_list_type *new_ptr)
+{
+ if (stat_save_ptr >= stat_save + sizeof (stat_save) / sizeof (stat_save[0]))
+ abort ();
+ *stat_save_ptr++ = stat_ptr;
+ stat_ptr = new_ptr;
+}
+
+void
+pop_stat_ptr (void)
+{
+ if (stat_save_ptr <= stat_save)
+ abort ();
+ stat_ptr = *--stat_save_ptr;
+}
+
/* Build a new statement node for the parse tree. */
static lang_statement_union_type *
In this case it is probably an error to create a region that has
already been created. If we are not inside a MEMORY block it is
dubious to use an undeclared region name (except DEFAULT_MEMORY_REGION)
- and so we issue a warning. */
+ and so we issue a warning.
+
+ Each region has at least one name. The first name is either
+ DEFAULT_MEMORY_REGION or the name given in the MEMORY block. You can add
+ alias names to an existing region within a script with
+ REGION_ALIAS (alias, region_name). Each name corresponds to at most one
+ region. */
static lang_memory_region_type *lang_memory_region_list;
static lang_memory_region_type **lang_memory_region_list_tail
lang_memory_region_type *
lang_memory_region_lookup (const char *const name, bfd_boolean create)
{
- lang_memory_region_type *p;
+ lang_memory_region_name *n;
+ lang_memory_region_type *r;
lang_memory_region_type *new;
/* NAME is NULL for LMA memspecs if no region was specified. */
if (name == NULL)
return NULL;
- for (p = lang_memory_region_list; p != NULL; p = p->next)
- if (strcmp (p->name, name) == 0)
- {
- if (create)
- einfo (_("%P:%S: warning: redeclaration of memory region '%s'\n"),
- name);
- return p;
- }
+ for (r = lang_memory_region_list; r != NULL; r = r->next)
+ for (n = &r->name_list; n != NULL; n = n->next)
+ if (strcmp (n->name, name) == 0)
+ {
+ if (create)
+ einfo (_("%P:%S: warning: redeclaration of memory region `%s'\n"),
+ name);
+ return r;
+ }
if (!create && strcmp (name, DEFAULT_MEMORY_REGION))
- einfo (_("%P:%S: warning: memory region %s not declared\n"), name);
+ einfo (_("%P:%S: warning: memory region `%s' not declared\n"), name);
new = stat_alloc (sizeof (lang_memory_region_type));
- new->name = xstrdup (name);
+ new->name_list.name = xstrdup (name);
+ new->name_list.next = NULL;
new->next = NULL;
new->origin = 0;
new->length = ~(bfd_size_type) 0;
return new;
}
+void
+lang_memory_region_alias (const char * alias, const char * region_name)
+{
+ lang_memory_region_name * n;
+ lang_memory_region_type * r;
+ lang_memory_region_type * region;
+
+ /* The default region must be unique. This ensures that it is not necessary
+ to iterate through the name list if someone wants the check if a region is
+ the default memory region. */
+ if (strcmp (region_name, DEFAULT_MEMORY_REGION) == 0
+ || strcmp (alias, DEFAULT_MEMORY_REGION) == 0)
+ einfo (_("%F%P:%S: error: alias for default memory region\n"));
+
+ /* Look for the target region and check if the alias is not already
+ in use. */
+ region = NULL;
+ for (r = lang_memory_region_list; r != NULL; r = r->next)
+ for (n = &r->name_list; n != NULL; n = n->next)
+ {
+ if (region == NULL && strcmp (n->name, region_name) == 0)
+ region = r;
+ if (strcmp (n->name, alias) == 0)
+ einfo (_("%F%P:%S: error: redefinition of memory region "
+ "alias `%s'\n"),
+ alias);
+ }
+
+ /* Check if the target region exists. */
+ if (region == NULL)
+ einfo (_("%F%P:%S: error: memory region `%s' "
+ "for alias `%s' does not exist\n"),
+ region_name,
+ alias);
+
+ /* Add alias to region name list. */
+ n = stat_alloc (sizeof (lang_memory_region_name));
+ n->name = xstrdup (alias);
+ n->next = region->name_list.next;
+ region->name_list.next = n;
+}
+
static lang_memory_region_type *
-lang_memory_default (asection *section)
+lang_memory_default (asection * section)
{
lang_memory_region_type *p;
etree_type *address,
lang_statement_list_type *add_child)
{
- lang_statement_list_type *old;
lang_statement_list_type add;
const char *ps;
lang_output_section_statement_type *os;
lang_output_section_statement_type **os_tail;
- /* Start building a list of statements for this section.
- First save the current statement pointer. */
- old = stat_ptr;
-
/* If we have found an appropriate place for the output section
statements for this orphan, add them to our own private list,
inserting them later into the global statement list. */
if (after != NULL)
{
- stat_ptr = &add;
- lang_list_init (stat_ptr);
+ lang_list_init (&add);
+ push_stat_ptr (&add);
}
ps = NULL;
{
char *symname;
- /* lang_leave_ouput_section_statement resets stat_ptr.
- Put stat_ptr back where we want it. */
- if (after != NULL)
- stat_ptr = &add;
-
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);
/* Restore the global list pointer. */
if (after != NULL)
- stat_ptr = old;
+ pop_stat_ptr ();
if (after != NULL && os->bfd_section != NULL)
{
/* Fix the global list pointer if we happened to tack our
new list at the tail. */
- if (*old->tail == add.head)
- old->tail = add.tail;
+ if (*stat_ptr->tail == add.head)
+ stat_ptr->tail = add.tail;
/* Save the end of this list. */
place->stmt = add.tail;
char buf[100];
int len;
- fprintf (config.map_file, "%-16s ", m->name);
+ fprintf (config.map_file, "%-16s ", m->name_list.name);
sprintf_vma (buf, m->origin);
minfo ("0x%s ", buf);
&& ! bfd_check_format_matches (entry->the_bfd, bfd_object, &matching))
{
bfd_error_type err;
- lang_statement_list_type *hold;
- bfd_boolean bad_load = TRUE;
bfd_boolean save_ldlang_sysrooted_script;
bfd_boolean save_as_needed, save_add_needed;
else if (err != bfd_error_file_not_recognized
|| place == NULL)
einfo (_("%F%B: file not recognized: %E\n"), entry->the_bfd);
- else
- bad_load = FALSE;
bfd_close (entry->the_bfd);
entry->the_bfd = NULL;
/* Try to interpret the file as a linker script. */
ldfile_open_command_file (entry->filename);
- hold = stat_ptr;
- stat_ptr = place;
+ push_stat_ptr (place);
save_ldlang_sysrooted_script = ldlang_sysrooted_script;
ldlang_sysrooted_script = entry->sysrooted;
save_as_needed = as_needed;
ldlang_sysrooted_script = save_ldlang_sysrooted_script;
as_needed = save_as_needed;
add_needed = save_add_needed;
- stat_ptr = hold;
+ pop_stat_ptr ();
- return ! bad_load;
+ return TRUE;
}
if (ldemul_recognized_file (entry))
case lang_input_statement_enum:
if (s->input_statement.real)
{
+ lang_statement_union_type **os_tail;
lang_statement_list_type add;
s->input_statement.target = current_target;
bfd_archive))
s->input_statement.loaded = FALSE;
+ os_tail = lang_output_section_statement.tail;
lang_list_init (&add);
if (! load_symbols (&s->input_statement, &add))
if (add.head != NULL)
{
- *add.tail = s->header.next;
- s->header.next = add.head;
+ /* If this was a script with output sections then
+ tack any added statements on to the end of the
+ list. This avoids having to reorder the output
+ section statement list. Very likely the user
+ forgot -T, and whatever we do here will not meet
+ naive user expectations. */
+ if (os_tail != lang_output_section_statement.tail)
+ {
+ einfo (_("%P: warning: %s contains output sections;"
+ " did you forget -T?\n"),
+ s->input_statement.filename);
+ *stat_ptr->tail = add.head;
+ stat_ptr->tail = add.tail;
+ }
+ else
+ {
+ *add.tail = s->header.next;
+ s->header.next = add.head;
+ }
}
}
break;
{
/* 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;
+ os = &(*s)->output_section_statement;
+
+ ASSERT (last_os == NULL || last_os->next == os);
+ last_os = os;
/* Set constraint negative so that lang_output_section_find
won't match this output section statement. At this
a bfd_vma quantity in decimal. */
for (m = lang_memory_region_list; m; m = m->next)
if (m->had_full_message)
- einfo (_("%X%P: region %s overflowed by %ld bytes\n"),
- m->name, (long)(m->current - (m->origin + m->length)));
+ einfo (_("%X%P: region `%s' overflowed by %ld bytes\n"),
+ m->name_list.name, (long)(m->current - (m->origin + m->length)));
}
{
if (tree != NULL)
{
- einfo (_("%X%P: address 0x%v of %B section %s"
- " is not within region %s\n"),
+ einfo (_("%X%P: address 0x%v of %B section `%s'"
+ " is not within region `%s'\n"),
region->current,
os->bfd_section->owner,
os->bfd_section->name,
- region->name);
+ region->name_list.name);
}
else if (!region->had_full_message)
{
region->had_full_message = TRUE;
- einfo (_("%X%P: %B section %s will not fit in region %s\n"),
+ einfo (_("%X%P: %B section `%s' will not fit in region `%s'\n"),
os->bfd_section->owner,
os->bfd_section->name,
- region->name);
+ region->name_list.name);
}
}
}
from the region specification. */
if (os->region == NULL
|| ((os->bfd_section->flags & (SEC_ALLOC | SEC_LOAD))
- && os->region->name[0] == '*'
- && strcmp (os->region->name,
+ && os->region->name_list.name[0] == '*'
+ && strcmp (os->region->name_list.name,
DEFAULT_MEMORY_REGION) == 0))
{
os->region = lang_memory_default (os->bfd_section);
&& !IGNORE_SECTION (os->bfd_section)
&& ! link_info.relocatable
&& check_regions
- && strcmp (os->region->name,
+ && strcmp (os->region->name_list.name,
DEFAULT_MEMORY_REGION) == 0
&& lang_memory_region_list != NULL
- && (strcmp (lang_memory_region_list->name,
+ && (strcmp (lang_memory_region_list->name_list.name,
DEFAULT_MEMORY_REGION) != 0
|| lang_memory_region_list->next != NULL)
&& expld.phase != lang_mark_phase_enum)
bfd_boolean warn;
if ((link_info.relocatable && !link_info.gc_sections)
- || link_info.shared)
+ || (link_info.shared && !link_info.executable))
warn = entry_from_cmdline;
else
warn = TRUE;
return TRUE;
section = h->u.c.p->section;
-
- /* Increase the size of the section to align the common sym. */
- section->size += ((bfd_vma) 1 << (power_of_two + opb_shift)) - 1;
- section->size &= (- (bfd_vma) 1 << (power_of_two + opb_shift));
-
- /* Adjust the alignment if necessary. */
- if (power_of_two > section->alignment_power)
- section->alignment_power = power_of_two;
-
- /* Change the symbol from common to defined. */
- h->type = bfd_link_hash_defined;
- h->u.def.section = section;
- h->u.def.value = section->size;
-
- /* Increase the size of the section. */
- section->size += size;
-
- /* Make sure the section is allocated in memory, and make sure that
- it is no longer a common section. */
- section->flags |= SEC_ALLOC;
- section->flags &= ~SEC_IS_COMMON;
+ if (!bfd_define_common_symbol (link_info.output_bfd, &link_info, h))
+ einfo (_("%P%F: Could not define common symbol `%T': %E\n"),
+ h->root.string);
if (config.map_file != NULL)
{
os->block_value = 1;
/* Make next things chain into subchain of this. */
- stat_ptr = &os->children;
+ push_stat_ptr (&os->children);
os->subsection_alignment =
topower (exp_get_value_int (subalign, -1, "subsection alignment"));
ldemul_finish ();
/* Make sure that the section addresses make sense. */
- if (! link_info.relocatable
- && command_line.check_section_addresses)
+ if (command_line.check_section_addresses)
lang_check_section_addresses ();
lang_end ();
memspec, lma_memspec,
current_section->load_base != NULL,
current_section->addr_tree != NULL);
+
+ /* If this section has no load region or base, but has the same
+ region as the previous section, then propagate the previous
+ section's load region. */
+
+ if (!current_section->lma_region && !current_section->load_base
+ && current_section->region == current_section->prev->region)
+ current_section->lma_region = current_section->prev->lma_region;
+
current_section->fill = fill;
current_section->phdrs = phdrs;
- stat_ptr = &statement_list;
+ pop_stat_ptr ();
}
/* Create an absolute symbol with the given name with the value of the
g = new_stat (lang_group_statement, stat_ptr);
lang_list_init (&g->children);
- stat_ptr = &g->children;
+ push_stat_ptr (&g->children);
}
/* Leave a group. This just resets stat_ptr to start writing to the
void
lang_leave_group (void)
{
- stat_ptr = &statement_list;
+ pop_stat_ptr ();
}
/* Add a new program header. This is called for each entry in a PHDRS
|| (os->bfd_section->flags & SEC_ALLOC) == 0)
continue;
+ /* Don't add orphans to PT_INTERP header. */
+ if (l->type == 3)
+ continue;
+
if (last == NULL)
{
lang_output_section_statement_type * tmp_os;
java_sym = sym;
}
- if (head->htab && (prev == NULL || prev->symbol))
+ if (head->htab && (prev == NULL || prev->literal))
{
struct bfd_elf_version_expr e;
case 0:
if (head->mask & BFD_ELF_VERSION_C_TYPE)
{
- e.symbol = sym;
+ e.pattern = sym;
expr = htab_find (head->htab, &e);
- while (expr && strcmp (expr->symbol, sym) == 0)
+ while (expr && strcmp (expr->pattern, sym) == 0)
if (expr->mask == BFD_ELF_VERSION_C_TYPE)
goto out_ret;
else
case BFD_ELF_VERSION_C_TYPE:
if (head->mask & BFD_ELF_VERSION_CXX_TYPE)
{
- e.symbol = cxx_sym;
+ e.pattern = cxx_sym;
expr = htab_find (head->htab, &e);
- while (expr && strcmp (expr->symbol, cxx_sym) == 0)
+ while (expr && strcmp (expr->pattern, cxx_sym) == 0)
if (expr->mask == BFD_ELF_VERSION_CXX_TYPE)
goto out_ret;
else
case BFD_ELF_VERSION_CXX_TYPE:
if (head->mask & BFD_ELF_VERSION_JAVA_TYPE)
{
- e.symbol = java_sym;
+ e.pattern = java_sym;
expr = htab_find (head->htab, &e);
- while (expr && strcmp (expr->symbol, java_sym) == 0)
+ while (expr && strcmp (expr->pattern, java_sym) == 0)
if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
goto out_ret;
else
}
/* Finally, try the wildcards. */
- if (prev == NULL || prev->symbol)
+ if (prev == NULL || prev->literal)
expr = head->remaining;
else
expr = prev->next;
}
/* Return NULL if the PATTERN argument is a glob pattern, otherwise,
- return a string pointing to the symbol name. */
+ return a pointer to the symbol name with any backslash quotes removed. */
static const char *
realsymbol (const char *pattern)
{
/* It is a glob pattern only if there is no preceding
backslash. */
- if (! backslash && (*p == '?' || *p == '*' || *p == '['))
- {
- free (symbol);
- return NULL;
- }
-
if (backslash)
{
/* Remove the preceding backslash. */
*(s - 1) = *p;
+ backslash = FALSE;
changed = TRUE;
}
else
- *s++ = *p;
+ {
+ if (*p == '?' || *p == '*' || *p == '[')
+ {
+ free (symbol);
+ return NULL;
+ }
- backslash = *p == '\\';
+ *s++ = *p;
+ backslash = *p == '\\';
+ }
}
if (changed)
ret = xmalloc (sizeof *ret);
ret->next = orig;
- ret->pattern = literal_p ? NULL : new;
ret->symver = 0;
ret->script = 0;
- ret->symbol = literal_p ? new : realsymbol (new);
+ ret->literal = TRUE;
+ ret->pattern = literal_p ? new : realsymbol (new);
+ if (ret->pattern == NULL)
+ {
+ ret->pattern = new;
+ ret->literal = FALSE;
+ }
if (lang == NULL || strcasecmp (lang, "C") == 0)
ret->mask = BFD_ELF_VERSION_C_TYPE;
{
const struct bfd_elf_version_expr *e = p;
- return htab_hash_string (e->symbol);
+ return htab_hash_string (e->pattern);
}
static int
const struct bfd_elf_version_expr *e1 = p1;
const struct bfd_elf_version_expr *e2 = p2;
- return strcmp (e1->symbol, e2->symbol) == 0;
+ return strcmp (e1->pattern, e2->pattern) == 0;
}
static void
for (e = head->list; e; e = e->next)
{
- if (e->symbol)
+ if (e->literal)
count++;
head->mask |= e->mask;
}
for (e = head->list; e; e = next)
{
next = e->next;
- if (!e->symbol)
+ if (!e->literal)
{
*remaining_loc = e;
remaining_loc = &e->next;
last = e1;
e1 = e1->next;
}
- while (e1 && strcmp (e1->symbol, e->symbol) == 0);
+ while (e1 && strcmp (e1->pattern, e->pattern) == 0);
if (last == NULL)
{
/* This is a duplicate. */
/* FIXME: Memory leak. Sometimes pattern is not
xmalloced alone, but in larger chunk of memory. */
- /* free (e->symbol); */
+ /* free (e->pattern); */
free (e);
}
else
{
struct bfd_elf_version_expr *e2;
- if (t->locals.htab && e1->symbol)
+ if (t->locals.htab && e1->literal)
{
e2 = htab_find (t->locals.htab, e1);
- while (e2 && strcmp (e1->symbol, e2->symbol) == 0)
+ while (e2 && strcmp (e1->pattern, e2->pattern) == 0)
{
if (e1->mask == e2->mask)
einfo (_("%X%P: duplicate expression `%s'"
- " in version information\n"), e1->symbol);
+ " in version information\n"), e1->pattern);
e2 = e2->next;
}
}
- else if (!e1->symbol)
+ else if (!e1->literal)
for (e2 = t->locals.remaining; e2 != NULL; e2 = e2->next)
if (strcmp (e1->pattern, e2->pattern) == 0
&& e1->mask == e2->mask)
{
struct bfd_elf_version_expr *e2;
- if (t->globals.htab && e1->symbol)
+ if (t->globals.htab && e1->literal)
{
e2 = htab_find (t->globals.htab, e1);
- while (e2 && strcmp (e1->symbol, e2->symbol) == 0)
+ while (e2 && strcmp (e1->pattern, e2->pattern) == 0)
{
if (e1->mask == e2->mask)
einfo (_("%X%P: duplicate expression `%s'"
" in version information\n"),
- e1->symbol);
+ e1->pattern);
e2 = e2->next;
}
}
- else if (!e1->symbol)
+ else if (!e1->literal)
for (e2 = t->globals.remaining; e2 != NULL; e2 = e2->next)
if (strcmp (e1->pattern, e2->pattern) == 0
&& e1->mask == e2->mask)