#include "bfd.h"
#include "sysdep.h"
-#ifdef ANSI_PROTOTYPES
#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
#include <strings.h>
#include "bfdlink.h"
/* Local helper functions. */
static bfd_boolean add_extra_plt_sections (bfd *, int);
-static char *build_encoding_error_message (xtensa_opcode, bfd_vma);
+static char *vsprint_msg (const char *, const char *, int, ...) ATTRIBUTE_PRINTF(2,4);
static bfd_reloc_status_type bfd_elf_xtensa_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static bfd_boolean do_fix_for_relocatable_link
for (s = dynobj->sections; s != NULL; s = s->next)
{
const char *name;
- bfd_boolean strip;
if ((s->flags & SEC_LINKER_CREATED) == 0)
continue;
of the dynobj section names depend upon the input files. */
name = bfd_get_section_name (dynobj, s);
- strip = FALSE;
-
if (strncmp (name, ".rela", 5) == 0)
{
- if (strcmp (name, ".rela.plt") == 0)
- relplt = TRUE;
- else if (strcmp (name, ".rela.got") == 0)
- relgot = TRUE;
-
- /* We use the reloc_count field as a counter if we need
- to copy relocs into the output file. */
- s->reloc_count = 0;
- }
- else if (strncmp (name, ".plt.", 5) == 0
- || strncmp (name, ".got.plt.", 9) == 0)
- {
- if (s->size == 0)
+ if (s->size != 0)
{
- /* If we don't need this section, strip it from the output
- file. We must create the ".plt*" and ".got.plt*"
- sections in create_dynamic_sections and/or check_relocs
- based on a conservative estimate of the PLT relocation
- count, because the sections must be created before the
- linker maps input sections to output sections. The
- linker does that before size_dynamic_sections, where we
- compute the exact size of the PLT, so there may be more
- of these sections than are actually needed. */
- strip = TRUE;
+ if (strcmp (name, ".rela.plt") == 0)
+ relplt = TRUE;
+ else if (strcmp (name, ".rela.got") == 0)
+ relgot = TRUE;
+
+ /* We use the reloc_count field as a counter if we need
+ to copy relocs into the output file. */
+ s->reloc_count = 0;
}
}
- else if (strcmp (name, ".got") != 0
+ else if (strncmp (name, ".plt.", 5) != 0
+ && strncmp (name, ".got.plt.", 9) != 0
+ && strcmp (name, ".got") != 0
&& strcmp (name, ".plt") != 0
&& strcmp (name, ".got.plt") != 0
&& strcmp (name, ".xt.lit.plt") != 0
continue;
}
- if (strip)
- s->flags |= SEC_EXCLUDE;
- else
+ if (s->size == 0)
+ {
+ /* If we don't need this section, strip it from the output
+ file. We must create the ".plt*" and ".got.plt*"
+ sections in create_dynamic_sections and/or check_relocs
+ based on a conservative estimate of the PLT relocation
+ count, because the sections must be created before the
+ linker maps input sections to output sections. The
+ linker does that before size_dynamic_sections, where we
+ compute the exact size of the PLT, so there may be more
+ of these sections than are actually needed. */
+ s->flags |= SEC_EXCLUDE;
+ }
+ else if ((s->flags & SEC_HAS_CONTENTS) != 0)
{
/* Allocate memory for the section contents. */
s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
- if (s->contents == NULL && s->size != 0)
+ if (s->contents == NULL)
return FALSE;
}
}
|| xtensa_operand_set_field (isa, opcode, opnd, fmt, slot,
sbuff, newval))
{
- *error_message = build_encoding_error_message (opcode, relocation);
+ const char *opname = xtensa_opcode_name (isa, opcode);
+ const char *msg;
+
+ msg = "cannot encode";
+ if (is_direct_call_opcode (opcode))
+ {
+ if ((relocation & 0x3) != 0)
+ msg = "misaligned call target";
+ else
+ msg = "call target out of range";
+ }
+ else if (opcode == get_l32r_opcode ())
+ {
+ if ((relocation & 0x3) != 0)
+ msg = "misaligned literal target";
+ else if (is_alt_relocation (howto->type))
+ msg = "literal target out of range (too many literals)";
+ else if (self_address > relocation)
+ msg = "literal target out of range (try using text-section-literals)";
+ else
+ msg = "literal placed after use";
+ }
+
+ *error_message = vsprint_msg (opname, ": %s", strlen (msg) + 2, msg);
return bfd_reloc_dangerous;
}
}
-static char *
-build_encoding_error_message (xtensa_opcode opcode, bfd_vma target_address)
-{
- const char *opname = xtensa_opcode_name (xtensa_default_isa, opcode);
- const char *msg;
-
- msg = "cannot encode";
- if (is_direct_call_opcode (opcode))
- {
- if ((target_address & 0x3) != 0)
- msg = "misaligned call target";
- else
- msg = "call target out of range";
- }
- else if (opcode == get_l32r_opcode ())
- {
- if ((target_address & 0x3) != 0)
- msg = "misaligned literal target";
- else
- msg = "literal target out of range";
- }
-
- return vsprint_msg (opname, ": %s", strlen (msg) + 2, msg);
-}
-
-
/* This function is registered as the "special_function" in the
Xtensa howto for handling simplify operations.
bfd_perform_relocation / bfd_install_relocation use it to
*error_message = "";
*error_message = vsprint_msg (*error_message, ": (%s + 0x%lx)",
strlen (symbol->name) + 17,
- symbol->name, reloc_entry->addend);
+ symbol->name,
+ (unsigned long) reloc_entry->addend);
}
return flag;
&& !((input_section->flags & SEC_DEBUGGING) != 0
&& h->def_dynamic))
(*_bfd_error_handler)
- (_("%B(%A+0x%lx): unresolvable relocation against symbol `%s'"),
+ (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
input_bfd,
input_section,
(long) rel->r_offset,
+ howto->name,
h->root.root.string);
/* There's no point in calling bfd_perform_relocation here.
else
error_message = vsprint_msg (error_message, ": (%s+0x%x)",
strlen (name) + 22,
- name, rel->r_addend);
+ name, (int)rel->r_addend);
}
if (!((*info->callbacks->reloc_dangerous)
/* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */
if (strcmp (h->root.root.string, "_DYNAMIC") == 0
- || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+ || h == elf_hash_table (info)->hgot)
sym->st_shndx = SHN_ABS;
return TRUE;
}
+static unsigned
+action_list_count (text_action_list *action_list)
+{
+ text_action *r = action_list->head;
+ unsigned count = 0;
+ for (r = action_list->head; r != NULL; r = r->next)
+ {
+ count++;
+ }
+ return count;
+}
+
+
static bfd_vma
offset_with_removed_text_before_fill (text_action_list *action_list,
bfd_vma offset)
}
+/* The xlate_map is a sorted array of address mappings designed to
+ answer the offset_with_removed_text() query with a binary search instead
+ of a linear search through the section's action_list. */
+
+typedef struct xlate_map_entry xlate_map_entry_t;
+typedef struct xlate_map xlate_map_t;
+
+struct xlate_map_entry
+{
+ unsigned orig_address;
+ unsigned new_address;
+ unsigned size;
+};
+
+struct xlate_map
+{
+ unsigned entry_count;
+ xlate_map_entry_t *entry;
+};
+
+
+static int
+xlate_compare (const void *a_v, const void *b_v)
+{
+ const xlate_map_entry_t *a = (const xlate_map_entry_t *) a_v;
+ const xlate_map_entry_t *b = (const xlate_map_entry_t *) b_v;
+ if (a->orig_address < b->orig_address)
+ return -1;
+ if (a->orig_address > (b->orig_address + b->size - 1))
+ return 1;
+ return 0;
+}
+
+
+static bfd_vma
+xlate_offset_with_removed_text (const xlate_map_t *map,
+ text_action_list *action_list,
+ bfd_vma offset)
+{
+ xlate_map_entry_t tmp;
+ void *r;
+ xlate_map_entry_t *e;
+
+ if (map == NULL)
+ return offset_with_removed_text (action_list, offset);
+
+ if (map->entry_count == 0)
+ return offset;
+
+ tmp.orig_address = offset;
+ tmp.new_address = offset;
+ tmp.size = 1;
+
+ r = bsearch (&offset, map->entry, map->entry_count,
+ sizeof (xlate_map_entry_t), &xlate_compare);
+ e = (xlate_map_entry_t *) r;
+
+ BFD_ASSERT (e != NULL);
+ if (e == NULL)
+ return offset;
+ return e->new_address - e->orig_address + offset;
+}
+
+
+/* Build a binary searchable offset translation map from a section's
+ action list. */
+
+static xlate_map_t *
+build_xlate_map (asection *sec, xtensa_relax_info *relax_info)
+{
+ xlate_map_t *map = (xlate_map_t *) bfd_malloc (sizeof (xlate_map_t));
+ text_action_list *action_list = &relax_info->action_list;
+ unsigned num_actions = 0;
+ text_action *r;
+ int removed;
+ xlate_map_entry_t *current_entry;
+
+ if (map == NULL)
+ return NULL;
+
+ num_actions = action_list_count (action_list);
+ map->entry = (xlate_map_entry_t *)
+ bfd_malloc (sizeof (xlate_map_entry_t) * (num_actions + 1));
+ if (map->entry == NULL)
+ {
+ free (map);
+ return NULL;
+ }
+ map->entry_count = 0;
+
+ removed = 0;
+ current_entry = &map->entry[0];
+
+ current_entry->orig_address = 0;
+ current_entry->new_address = 0;
+ current_entry->size = 0;
+
+ for (r = action_list->head; r != NULL; r = r->next)
+ {
+ unsigned orig_size = 0;
+ switch (r->action)
+ {
+ case ta_none:
+ case ta_remove_insn:
+ case ta_convert_longcall:
+ case ta_remove_literal:
+ case ta_add_literal:
+ break;
+ case ta_remove_longcall:
+ orig_size = 6;
+ break;
+ case ta_narrow_insn:
+ orig_size = 3;
+ break;
+ case ta_widen_insn:
+ orig_size = 2;
+ break;
+ case ta_fill:
+ break;
+ }
+ current_entry->size =
+ r->offset + orig_size - current_entry->orig_address;
+ if (current_entry->size != 0)
+ {
+ current_entry++;
+ map->entry_count++;
+ }
+ current_entry->orig_address = r->offset + orig_size;
+ removed += r->removed_bytes;
+ current_entry->new_address = r->offset + orig_size - removed;
+ current_entry->size = 0;
+ }
+
+ current_entry->size = (bfd_get_section_limit (sec->owner, sec)
+ - current_entry->orig_address);
+ if (current_entry->size != 0)
+ map->entry_count++;
+
+ return map;
+}
+
+
+/* Free an offset translation map. */
+
+static void
+free_xlate_map (xlate_map_t *map)
+{
+ if (map && map->entry)
+ free (map->entry);
+ if (map)
+ free (map);
+}
+
+
/* Use check_section_ebb_pcrels_fit to make sure that all of the
relocations in a section will fit if a proposed set of actions
are performed. */
{
unsigned i, j;
Elf_Internal_Rela *irel;
+ xlate_map_t *xmap = NULL;
+ bfd_boolean ok = TRUE;
xtensa_relax_info *relax_info;
relax_info = get_xtensa_relax_info (sec);
+ if (relax_info && sec->reloc_count > 100)
+ {
+ xmap = build_xlate_map (sec, relax_info);
+ /* NULL indicates out of memory, but the slow version
+ can still be used. */
+ }
+
for (i = 0; i < sec->reloc_count; i++)
{
r_reloc r_rel;
if (relax_info)
{
- self_offset = offset_with_removed_text (&relax_info->action_list,
- orig_self_offset);
- target_offset = offset_with_removed_text (&relax_info->action_list,
- orig_target_offset);
+ self_offset =
+ xlate_offset_with_removed_text (xmap, &relax_info->action_list,
+ orig_self_offset);
+ target_offset =
+ xlate_offset_with_removed_text (xmap, &relax_info->action_list,
+ orig_target_offset);
}
self_removed_bytes = 0;
opcode = get_relocation_opcode (abfd, sec, contents, irel);
if (opcode == XTENSA_UNDEFINED)
- return FALSE;
+ {
+ ok = FALSE;
+ break;
+ }
opnum = get_relocation_opnd (opcode, ELF32_R_TYPE (irel->r_info));
if (opnum == XTENSA_UNDEFINED)
- return FALSE;
+ {
+ ok = FALSE;
+ break;
+ }
if (!pcrel_reloc_fits (opcode, opnum, self_offset, target_offset))
- return FALSE;
+ {
+ ok = FALSE;
+ break;
+ }
}
}
- return TRUE;
+ if (xmap)
+ free_xlate_map (xmap);
+
+ return ok;
}
!= sec->output_section)
return FALSE;
+ /* Absolute literals in the same output section can always be
+ combined. */
+ if (reloc[i].is_abs_literal)
+ continue;
+
/* A literal with no PC-relative relocations can be moved anywhere. */
if (reloc[i].opnd != -1)
{
/* The default literal sections should always be marked as "code" (i.e.,
SHF_EXECINSTR). This is particularly important for the Linux kernel
module loader so that the literals are not placed after the text. */
-static struct bfd_elf_special_section const
- xtensa_special_sections_f[]=
+static const struct bfd_elf_special_section elf_xtensa_special_sections[] =
{
{ ".fini.literal", 13, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
- { NULL, 0, 0, 0, 0 }
-};
-
-static struct bfd_elf_special_section const
- xtensa_special_sections_i[]=
-{
{ ".init.literal", 13, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
- { NULL, 0, 0, 0, 0 }
-};
-static struct bfd_elf_special_section const
- xtensa_special_sections_l[]=
-{
{ ".literal", 8, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
{ NULL, 0, 0, 0, 0 }
};
-
-static struct bfd_elf_special_section const *
- elf_xtensa_special_sections[27] =
-{
- NULL, /* 'a' */
- NULL, /* 'b' */
- NULL, /* 'c' */
- NULL, /* 'd' */
- NULL, /* 'e' */
- xtensa_special_sections_f, /* 'f' */
- NULL, /* 'g' */
- NULL, /* 'h' */
- xtensa_special_sections_i, /* 'i' */
- NULL, /* 'j' */
- NULL, /* 'k' */
- xtensa_special_sections_l, /* 'l' */
- NULL, /* 'm' */
- NULL, /* 'n' */
- NULL, /* 'o' */
- NULL, /* 'p' */
- NULL, /* 'q' */
- NULL, /* 'r' */
- NULL, /* 's' */
- NULL, /* 't' */
- NULL, /* 'u' */
- NULL, /* 'v' */
- NULL, /* 'w' */
- NULL, /* 'x' */
- NULL, /* 'y' */
- NULL, /* 'z' */
- NULL /* other */
-};
-
\f
#ifndef ELF_ARCH
#define TARGET_LITTLE_SYM bfd_elf32_xtensa_le_vec
#define TARGET_BIG_NAME "elf32-xtensa-be"
#define ELF_ARCH bfd_arch_xtensa
-/* The new EM_XTENSA value will be recognized beginning in the Xtensa T1040
- release. However, we still have to generate files with the EM_XTENSA_OLD
- value so that pre-T1040 tools can read the files. As soon as we stop
- caring about pre-T1040 tools, the following two values should be
- swapped. At the same time, any other code that uses EM_XTENSA_OLD
- should be changed to use EM_XTENSA. */
-#define ELF_MACHINE_CODE EM_XTENSA_OLD
-#define ELF_MACHINE_ALT1 EM_XTENSA
+#define ELF_MACHINE_CODE EM_XTENSA
+#define ELF_MACHINE_ALT1 EM_XTENSA_OLD
#if XCHAL_HAVE_MMU
#define ELF_MAXPAGESIZE (1 << XCHAL_MMU_MIN_PTE_PAGE_SIZE)