aboutsummaryrefslogtreecommitdiff
path: root/ld/emultempl/xtensaelf.em
diff options
context:
space:
mode:
Diffstat (limited to 'ld/emultempl/xtensaelf.em')
-rw-r--r--ld/emultempl/xtensaelf.em295
1 files changed, 291 insertions, 4 deletions
diff --git a/ld/emultempl/xtensaelf.em b/ld/emultempl/xtensaelf.em
index ffd4add..386bf8a 100644
--- a/ld/emultempl/xtensaelf.em
+++ b/ld/emultempl/xtensaelf.em
@@ -25,9 +25,17 @@
cat >>e${EMULATION_NAME}.c <<EOF
#include <xtensa-config.h>
+#include "../bfd/elf-bfd.h"
+#include "../bfd/libbfd.h"
+#include "elf/xtensa.h"
+#include "bfd.h"
static void xtensa_wild_group_interleave (lang_statement_union_type *);
static void xtensa_colocate_output_literals (lang_statement_union_type *);
+static void remove_section (bfd *, asection *);
+static bfd_boolean replace_insn_sec_with_prop_sec (bfd *, const char *,
+ const char *, char **);
+static void replace_instruction_table_sections (bfd *, asection *);
/* Flag for the emulation-specific "--no-relax" option. */
@@ -37,7 +45,7 @@ static bfd_boolean disable_relaxation = FALSE;
static bfd_vma xtensa_page_power = 12; /* 4K pages. */
/* To force a page break between literals and text, change
- xtensa_use_literal_pages to "true". */
+ xtensa_use_literal_pages to "TRUE". */
static bfd_boolean xtensa_use_literal_pages = FALSE;
#define EXTRA_VALIDATION 0
@@ -74,6 +82,266 @@ elf_xtensa_before_parse (void)
}
+void
+remove_section (abfd, os)
+ bfd *abfd;
+ asection *os;
+{
+ asection **spp;
+ for (spp = &abfd->sections; *spp; spp = &(*spp)->next)
+ if (*spp == os)
+ {
+ *spp = os->next;
+ os->owner->section_count--;
+ break;
+ }
+}
+
+
+bfd_boolean
+replace_insn_sec_with_prop_sec (abfd, insn_sec_name, prop_sec_name,
+ error_message)
+ bfd *abfd;
+ const char *insn_sec_name;
+ const char *prop_sec_name;
+ char **error_message;
+{
+ asection *insn_sec;
+ asection *prop_sec;
+ bfd_byte *prop_contents = NULL;
+ bfd_byte *insn_contents = NULL;
+ unsigned entry_count;
+ unsigned entry;
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Rela *internal_relocs = NULL;
+ unsigned reloc_count;
+
+ *error_message = "";
+ insn_sec = bfd_get_section_by_name (abfd, insn_sec_name);
+ if (insn_sec == NULL)
+ return TRUE;
+ entry_count = insn_sec->size / 8;
+
+ prop_sec = bfd_get_section_by_name (abfd, prop_sec_name);
+ if (prop_sec != NULL && insn_sec != NULL)
+ {
+ *error_message = _("file already has property tables");
+ return FALSE;
+ }
+
+ if (insn_sec->size != 0)
+ {
+ insn_contents = (bfd_byte *) bfd_malloc (insn_sec->size);
+ if (insn_contents == NULL)
+ {
+ *error_message = _("out of memory");
+ goto cleanup;
+ }
+ if (! bfd_get_section_contents (abfd, insn_sec, insn_contents,
+ (file_ptr) 0, insn_sec->size))
+ {
+ *error_message = _("failed to read section contents");
+ goto cleanup;
+ }
+ }
+
+ /* Create a Property table section and relocation section for it. */
+ prop_sec_name = strdup (prop_sec_name);
+ prop_sec = bfd_make_section (abfd, prop_sec_name);
+ if (prop_sec == NULL
+ || ! bfd_set_section_flags (abfd, prop_sec,
+ bfd_get_section_flags (abfd, insn_sec))
+ || ! bfd_set_section_alignment (abfd, prop_sec, 2))
+ {
+ *error_message = _("could not create new section");
+ goto cleanup;
+ }
+
+ if (! bfd_set_section_flags (abfd, prop_sec,
+ bfd_get_section_flags (abfd, insn_sec))
+ || ! bfd_set_section_alignment (abfd, prop_sec, 2))
+ {
+ *error_message = _("could not set new section properties");
+ goto cleanup;
+ }
+ prop_sec->size = entry_count * 12;
+ prop_contents = (bfd_byte *) bfd_zalloc (abfd, prop_sec->size);
+ elf_section_data (prop_sec)->this_hdr.contents = prop_contents;
+
+ /* The entry size and size must be set to allow the linker to compute
+ the number of relocations since it does not use reloc_count. */
+ elf_section_data (prop_sec)->rel_hdr.sh_entsize =
+ sizeof (Elf32_External_Rela);
+ elf_section_data (prop_sec)->rel_hdr.sh_size =
+ elf_section_data (insn_sec)->rel_hdr.sh_size;
+
+ if (prop_contents == NULL && prop_sec->size != 0)
+ {
+ *error_message = _("could not allocate section contents");
+ goto cleanup;
+ }
+
+ /* Read the relocations. */
+ reloc_count = insn_sec->reloc_count;
+ if (reloc_count != 0)
+ {
+ /* If there is already an internal_reloc, then save it so that the
+ read_relocs function freshly allocates a copy. */
+ Elf_Internal_Rela *saved_relocs = elf_section_data (insn_sec)->relocs;
+
+ elf_section_data (insn_sec)->relocs = NULL;
+ internal_relocs =
+ _bfd_elf_link_read_relocs (abfd, insn_sec, NULL, NULL, FALSE);
+ elf_section_data (insn_sec)->relocs = saved_relocs;
+
+ if (internal_relocs == NULL)
+ {
+ *error_message = _("out of memory");
+ goto cleanup;
+ }
+ }
+
+ /* Create a relocation section for the property section. */
+ if (internal_relocs != NULL)
+ {
+ elf_section_data (prop_sec)->relocs = internal_relocs;
+ prop_sec->reloc_count = reloc_count;
+ }
+
+ /* Now copy each insn table entry to the prop table entry with
+ appropriate flags. */
+ for (entry = 0; entry < entry_count; ++entry)
+ {
+ unsigned value;
+ unsigned flags = (XTENSA_PROP_INSN | XTENSA_PROP_INSN_NO_TRANSFORM
+ | XTENSA_PROP_INSN_NO_REORDER);
+ value = bfd_get_32 (abfd, insn_contents + entry * 8 + 0);
+ bfd_put_32 (abfd, value, prop_contents + entry * 12 + 0);
+ value = bfd_get_32 (abfd, insn_contents + entry * 8 + 4);
+ bfd_put_32 (abfd, value, prop_contents + entry * 12 + 4);
+ bfd_put_32 (abfd, flags, prop_contents + entry * 12 + 8);
+ }
+
+ /* Now copy all of the relocations. Change offsets for the
+ instruction table section to offsets in the property table
+ section. */
+ if (internal_relocs)
+ {
+ unsigned i;
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+
+ for (i = 0; i < reloc_count; i++)
+ {
+ Elf_Internal_Rela *rela;
+ unsigned r_offset;
+
+ rela = &internal_relocs[i];
+
+ /* If this relocation is to the .xt.insn section,
+ change the section number and the offset. */
+ r_offset = rela->r_offset;
+ r_offset += 4 * (r_offset / 8);
+ rela->r_offset = r_offset;
+ }
+ }
+
+ remove_section (abfd, insn_sec);
+
+ if (insn_contents)
+ free (insn_contents);
+
+ return TRUE;
+
+ cleanup:
+ if (prop_sec && prop_sec->owner)
+ remove_section (abfd, prop_sec);
+ if (insn_contents)
+ free (insn_contents);
+ if (internal_relocs)
+ free (internal_relocs);
+
+ return FALSE;
+}
+
+
+#define PROP_SEC_BASE_NAME ".xt.prop"
+#define INSN_SEC_BASE_NAME ".xt.insn"
+#define LINKONCE_SEC_OLD_TEXT_BASE_NAME ".gnu.linkonce.x."
+
+
+void
+replace_instruction_table_sections (abfd, sec)
+ bfd *abfd;
+ asection *sec;
+{
+ char *message = "";
+ const char *insn_sec_name = NULL;
+ char *prop_sec_name = NULL;
+ char *owned_prop_sec_name = NULL;
+ const char *sec_name;
+
+ sec_name = bfd_get_section_name (abfd, sec);
+ if (strcmp (sec_name, INSN_SEC_BASE_NAME) == 0)
+ {
+ insn_sec_name = INSN_SEC_BASE_NAME;
+ prop_sec_name = PROP_SEC_BASE_NAME;
+ }
+ else if (strncmp (sec_name, LINKONCE_SEC_OLD_TEXT_BASE_NAME,
+ strlen (LINKONCE_SEC_OLD_TEXT_BASE_NAME)) == 0)
+ {
+ insn_sec_name = sec_name;
+ owned_prop_sec_name = (char *) xmalloc (strlen (sec_name) + 20);
+ prop_sec_name = owned_prop_sec_name;
+ strcpy (prop_sec_name, ".gnu.linkonce.prop.t.");
+ strcat (prop_sec_name,
+ sec_name + strlen (LINKONCE_SEC_OLD_TEXT_BASE_NAME));
+ }
+ if (insn_sec_name != NULL)
+ {
+ if (! replace_insn_sec_with_prop_sec (abfd, insn_sec_name, prop_sec_name,
+ &message))
+ {
+ einfo (_("%P: warning: failed to convert %s table in %B (%s); subsequent disassembly may be incomplete\n"),
+ insn_sec_name, abfd, message);
+ }
+ }
+ if (owned_prop_sec_name)
+ free (owned_prop_sec_name);
+}
+
+
+/* This is called after all input sections have been opened to convert
+ instruction tables (.xt.insn, gnu.linkonce.x.*) tables into property
+ tables (.xt.prop) before any section placement. */
+
+static void
+elf_xtensa_after_open (void)
+{
+ bfd *abfd;
+
+ /* First call the ELF version. */
+ gld${EMULATION_NAME}_after_open ();
+
+ /* Now search the input files looking for instruction table sections. */
+ for (abfd = link_info.input_bfds;
+ abfd != NULL;
+ abfd = abfd->link_next)
+ {
+ asection *sec = abfd->sections;
+ asection *next_sec;
+
+ /* Do not use bfd_map_over_sections here since we are removing
+ sections as we iterate. */
+ while (sec != NULL)
+ {
+ next_sec = sec->next;
+ replace_instruction_table_sections (abfd, sec);
+ sec = next_sec;
+ }
+ }
+}
+
+
/* This is called after the sections have been attached to output
sections, but before any sizes or addresses have been set. */
@@ -443,7 +711,7 @@ ld_xtensa_move_section_after (xtensa_ld_iter *to, xtensa_ld_iter *current)
/* Can only be called with lang_statements that have lists. Returns
- false if the list is empty. */
+ FALSE if the list is empty. */
static bfd_boolean
iter_stack_empty (xtensa_ld_iter_stack **stack_p)
@@ -1443,30 +1711,49 @@ ld_xtensa_insert_page_offsets (bfd_vma dot,
EOF
-# Define some shell vars to insert bits of code into the standard elf
+# Define some shell vars to insert bits of code into the standard ELF
# parse_args and list_options functions.
#
PARSE_AND_LIST_PROLOGUE='
-#define OPTION_NO_RELAX 301
+#define OPTION_OPT_SIZEOPT (300)
+#define OPTION_NO_RELAX (OPTION_OPT_SIZEOPT + 1)
+#define OPTION_LITERAL_MOVEMENT (OPTION_NO_RELAX + 1)
+#define OPTION_NO_LITERAL_MOVEMENT (OPTION_LITERAL_MOVEMENT + 1)
+extern int elf32xtensa_size_opt;
+extern int elf32xtensa_no_literal_movement;
'
PARSE_AND_LIST_LONGOPTS='
+ { "size-opt", no_argument, NULL, OPTION_OPT_SIZEOPT},
{ "no-relax", no_argument, NULL, OPTION_NO_RELAX},
+ { "literal-movement", no_argument, NULL, OPTION_LITERAL_MOVEMENT},
+ { "no-literal-movement", no_argument, NULL, OPTION_NO_LITERAL_MOVEMENT},
'
PARSE_AND_LIST_OPTIONS='
+ fprintf (file, _(" --size-opt\t\tWhen relaxing longcalls, prefer size optimization\n\t\t\t over branch target alignment\n"));
fprintf (file, _(" --no-relax\t\tDo not relax branches or coalesce literals\n"));
'
PARSE_AND_LIST_ARGS_CASES='
+ case OPTION_OPT_SIZEOPT:
+ elf32xtensa_size_opt = 1;
+ break;
case OPTION_NO_RELAX:
disable_relaxation = TRUE;
break;
+ case OPTION_LITERAL_MOVEMENT:
+ elf32xtensa_no_literal_movement = 0;
+ break;
+ case OPTION_NO_LITERAL_MOVEMENT:
+ elf32xtensa_no_literal_movement = 1;
+ break;
'
# Replace some of the standard ELF functions with our own versions.
#
LDEMUL_BEFORE_PARSE=elf_xtensa_before_parse
+LDEMUL_AFTER_OPEN=elf_xtensa_after_open
LDEMUL_CHOOSE_TARGET=elf_xtensa_choose_target
LDEMUL_PLACE_ORPHAN=elf_xtensa_place_orphan
LDEMUL_BEFORE_ALLOCATION=elf_xtensa_before_allocation