diff options
Diffstat (limited to 'ld/emultempl/xtensaelf.em')
-rw-r--r-- | ld/emultempl/xtensaelf.em | 295 |
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 |