diff options
-rw-r--r-- | bfd/ChangeLog | 16 | ||||
-rw-r--r-- | bfd/elf32-nds32.c | 2785 | ||||
-rw-r--r-- | ld/ChangeLog | 5 | ||||
-rw-r--r-- | ld/emultempl/nds32elf.em | 8 |
4 files changed, 22 insertions, 2792 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index fac9b62..d06541a 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,19 @@ +2018-03-15 Kuan-Lin Chen <kuanlinchentw@gmail.com> + + * elf32-nds32.c (nds32_elf_ex9_build_hash_table): Removed. + Not support the target feature. + (nds32_elf_ex9_itb_base): Likewise. + (nds32_elf_ex9_import_table): Likewise. + (nds32_elf_ex9_finish): Likewise. + (nds32_elf_ex9_reloc_jmp): Likewise. + (nds32_elf_get_insn_with_reg): Likewise. + (nds32_get_local_syms): Likewise. + (nds32_elf_ex9_replace_instruction): Likewise. + (nds32_elf_ifc_calc): Likewise. + (nds32_elf_ifc_finish): Likewise. + (nds32_elf_ifc_replace): Likewise. + (nds32_elf_ifc_reloc): Likewise. + 2018-03-14 Alan Modra <amodra@gmail.com> * elf64-ppc.c (sfpr_define): Adjust for stub_sec size having diff --git a/bfd/elf32-nds32.c b/bfd/elf32-nds32.c index e240d31..449e834 100644 --- a/bfd/elf32-nds32.c +++ b/bfd/elf32-nds32.c @@ -62,23 +62,8 @@ static bfd_vma calculate_memory_address (bfd *, Elf_Internal_Rela *, Elf_Internal_Sym *, Elf_Internal_Shdr *); static int nds32_get_section_contents (bfd *, asection *, bfd_byte **, bfd_boolean); -static bfd_boolean nds32_elf_ex9_build_hash_table -(bfd *, asection *, struct bfd_link_info *); -static bfd_boolean nds32_elf_ex9_itb_base (struct bfd_link_info *); -static void nds32_elf_ex9_import_table (struct bfd_link_info *); -static void nds32_elf_ex9_finish (struct bfd_link_info *); -static void nds32_elf_ex9_reloc_jmp (struct bfd_link_info *); -static void nds32_elf_get_insn_with_reg - (Elf_Internal_Rela *, uint32_t, uint32_t *); static int nds32_get_local_syms (bfd *, asection *ATTRIBUTE_UNUSED, Elf_Internal_Sym **); -static bfd_boolean nds32_elf_ex9_replace_instruction - (struct bfd_link_info *, bfd *, asection *); -static bfd_boolean nds32_elf_ifc_calc (struct bfd_link_info *, bfd *, - asection *); -static bfd_boolean nds32_elf_ifc_finish (struct bfd_link_info *); -static bfd_boolean nds32_elf_ifc_replace (struct bfd_link_info *); -static bfd_boolean nds32_elf_ifc_reloc (void); static bfd_boolean nds32_relax_fp_as_gp (struct bfd_link_info *link_info, bfd *abfd, asection *sec, Elf_Internal_Rela *internal_relocs, Elf_Internal_Rela *irelend, @@ -163,7 +148,6 @@ enum /* Size of small data/bss sections, used to calculate SDA_BASE. */ static long got_size = 0; static int is_SDA_BASE_set = 0; -static int is_ITB_BASE_set = 0; /* Convert ELF-VER in eflags to string for debugging purpose. */ static const char *const nds32_elfver_strtab[] = @@ -212,7 +196,6 @@ struct elf_nds32_link_hash_entry #define FP_BASE_NAME "_FP_BASE_" static int check_start_export_sym = 0; -static size_t ex9_relax_size = 0; /* Save ex9 predicted reducing size. */ /* The offset for executable tls relaxation. */ #define TP_OFFSET 0x0 @@ -4415,26 +4398,6 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, return FALSE; } - if (is_ITB_BASE_set == 0) - { - /* Set the _ITB_BASE_. */ - if (!nds32_elf_ex9_itb_base (info)) - { - _bfd_error_handler (_("%pB: error: cannot set %s"), - output_bfd, "_ITB_BASE_"); - bfd_set_error (bfd_error_bad_value); - } - } - - if (table->target_optimize & NDS32_RELAX_JUMP_IFC_ON) - if (!nds32_elf_ifc_reloc ()) - _bfd_error_handler (_("error: IFC relocation error")); - - /* Relocation for .ex9.itable. */ - if (table->target_optimize & NDS32_RELAX_EX9_ON - || (table->ex9_import_file && table->update_ex9_table)) - nds32_elf_ex9_reloc_jmp (info); - /* Use gp as fp to prevent truncated fit. Because in relaxation time the fp value is set as gp, and it has be reverted for instruction setting fp. */ @@ -11583,118 +11546,6 @@ nds32_relax_adjust_label (bfd *abfd, asection *sec, return TRUE; } -/* Pick relaxation round. */ - -static int -nds32_elf_pick_relax (bfd_boolean init, asection *sec, bfd_boolean *again, - struct elf_nds32_link_hash_table *table, - struct bfd_link_info *link_info) -{ - static asection *final_sec, *first_sec = NULL; - static bfd_boolean normal_again = FALSE; - static bfd_boolean set = FALSE; - static bfd_boolean first = TRUE; - int round_table[] = { - NDS32_RELAX_NORMAL_ROUND, - NDS32_RELAX_JUMP_IFC_ROUND, - NDS32_RELAX_EX9_BUILD_ROUND, - NDS32_RELAX_EX9_REPLACE_ROUND, - }; - static int pass = 0; - static int relax_round; - - /* The new round. */ - if (init && first_sec == sec) - { - set = TRUE; - normal_again = FALSE; - } - - if (first) - { - /* Run an empty run to get the final section. */ - relax_round = NDS32_RELAX_EMPTY_ROUND; - - /* It has to enter relax again because we can - not make sure what the final turn is. */ - *again = TRUE; - - first = FALSE; - first_sec = sec; - } - - if (!set) - { - /* Not reenter yet. */ - final_sec = sec; - return relax_round; - } - - relax_round = round_table[pass]; - - if (!init && relax_round == NDS32_RELAX_NORMAL_ROUND && *again) - normal_again = TRUE; - - if (!init && final_sec == sec) - { - switch (relax_round) - { - case NDS32_RELAX_NORMAL_ROUND: - if (!normal_again) - { - /* Normal relaxation done. */ - if (table->target_optimize & NDS32_RELAX_JUMP_IFC_ON) - { - pass++; - *again = TRUE; - } - else if (table->target_optimize & NDS32_RELAX_EX9_ON) - { - pass += 2; /* NDS32_RELAX_EX9_BUILD_ROUND */ - *again = TRUE; - } - else if (table->ex9_import_file) - { - /* Import ex9 table. */ - if (table->update_ex9_table) - pass += 2; /* NDS32_RELAX_EX9_BUILD_ROUND */ - else - pass += 3; /* NDS32_RELAX_EX9_REPLACE_ROUND */ - nds32_elf_ex9_import_table (link_info); - *again = TRUE; - } - } - break; - case NDS32_RELAX_JUMP_IFC_ROUND: - if (!nds32_elf_ifc_finish (link_info)) - _bfd_error_handler (_("error: jump IFC fail")); - if (table->target_optimize & NDS32_RELAX_EX9_ON) - { - pass++; - *again = TRUE; - } - break; - case NDS32_RELAX_EX9_BUILD_ROUND: - nds32_elf_ex9_finish (link_info); - pass++; - *again = TRUE; - break; - case NDS32_RELAX_EX9_REPLACE_ROUND: - if (table->target_optimize & NDS32_RELAX_JUMP_IFC_ON) - { - /* Do jump IFC optimization again. */ - if (!nds32_elf_ifc_finish (link_info)) - _bfd_error_handler (_("error: jump IFC fail")); - } - break; - default: - break; - } - } - - return relax_round; -} - static bfd_boolean nds32_elf_relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info, bfd_boolean *again) @@ -11715,7 +11566,6 @@ nds32_elf_relax_section (bfd *abfd, asection *sec, /* Target dependnet option. */ struct elf_nds32_link_hash_table *table; int load_store_relax; - int relax_round; relax_blank_list = NULL; @@ -11743,41 +11593,6 @@ nds32_elf_relax_section (bfd *abfd, asection *sec, /* The optimization type to do. */ table = nds32_elf_hash_table (link_info); - relax_round = nds32_elf_pick_relax (TRUE, sec, again, table, link_info); - switch (relax_round) - { - case NDS32_RELAX_JUMP_IFC_ROUND: - /* Here is the entrance of ifc jump relaxation. */ - if (!nds32_elf_ifc_calc (link_info, abfd, sec)) - return FALSE; - nds32_elf_pick_relax (FALSE, sec, again, table, link_info); - return TRUE; - - case NDS32_RELAX_EX9_BUILD_ROUND: - /* Here is the entrance of ex9 relaxation. There are two pass of - ex9 relaxation. The one is to traverse all instructions and build - the hash table. The other one is to compare instructions and replace - it by ex9.it. */ - if (!nds32_elf_ex9_build_hash_table (abfd, sec, link_info)) - return FALSE; - nds32_elf_pick_relax (FALSE, sec, again, table, link_info); - return TRUE; - - case NDS32_RELAX_EX9_REPLACE_ROUND: - if (!nds32_elf_ex9_replace_instruction (link_info, abfd, sec)) - return FALSE; - return TRUE; - - case NDS32_RELAX_EMPTY_ROUND: - nds32_elf_pick_relax (FALSE, sec, again, table, link_info); - return TRUE; - - case NDS32_RELAX_NORMAL_ROUND: - default: - if (sec->reloc_count == 0) - return TRUE; - break; - } /* The begining of general relaxation. */ @@ -11790,17 +11605,6 @@ nds32_elf_relax_section (bfd *abfd, asection *sec, relax_range_measurement (abfd); } - if (is_ITB_BASE_set == 0) - { - /* Set the _ITB_BASE_. */ - if (!nds32_elf_ex9_itb_base (link_info)) - { - _bfd_error_handler (_("%pB: error: cannot set %s"), - abfd, "_ITB_BASE_"); - bfd_set_error (bfd_error_bad_value); - } - } - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; /* Relocations MUST be kept in memory, because relaxation adjust them. */ internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, @@ -11818,10 +11622,7 @@ nds32_elf_relax_section (bfd *abfd, asection *sec, if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY) { if (irel->r_addend & R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG) - { - nds32_elf_pick_relax (FALSE, sec, again, table, link_info); - return TRUE; - } + return TRUE; if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FLAG) optimize = 1; @@ -12075,8 +11876,6 @@ nds32_elf_relax_section (bfd *abfd, asection *sec, } } - nds32_elf_pick_relax (FALSE, sec, again, table, link_info); - if (!*again) { if (!nds32_relax_adjust_label (abfd, sec, internal_relocs, contents, @@ -12865,2588 +12664,6 @@ error_return: return NULL; } -/* Link-time IFC relaxation. - In this optimization, we chains jump instructions - of the same destination with ifcall. */ - - -/* List to save jal and j relocation. */ -struct elf_nds32_ifc_symbol_entry -{ - asection *sec; - struct elf_link_hash_entry *h; - struct elf_nds32_ifc_irel_list *irel_head; - unsigned long insn; - int times; - int enable; /* Apply ifc. */ - int ex9_enable; /* Apply ifc after ex9. */ - struct elf_nds32_ifc_symbol_entry *next; -}; - -struct elf_nds32_ifc_irel_list -{ - Elf_Internal_Rela *irel; - asection *sec; - bfd_vma addr; - /* If this is set, then it is the last instruction for - ifc-chain, so it must be keep for the actual branching. */ - int keep; - struct elf_nds32_ifc_irel_list *next; -}; - -static struct elf_nds32_ifc_symbol_entry *ifc_symbol_head = NULL; - -/* Insert symbol of jal and j for ifc. */ - -static void -nds32_elf_ifc_insert_symbol (asection *sec, - struct elf_link_hash_entry *h, - Elf_Internal_Rela *irel, - unsigned long insn) -{ - struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head; - - /* Check there is target of existing entry the same as the new one. */ - while (ptr != NULL) - { - if (((h == NULL && ptr->sec == sec - && ELF32_R_SYM (ptr->irel_head->irel->r_info) == ELF32_R_SYM (irel->r_info) - && ptr->irel_head->irel->r_addend == irel->r_addend) - || h != NULL) - && ptr->h == h - && ptr->insn == insn) - { - /* The same target exist, so insert into list. */ - struct elf_nds32_ifc_irel_list *irel_list = ptr->irel_head; - - while (irel_list->next != NULL) - irel_list = irel_list->next; - irel_list->next = bfd_malloc (sizeof (struct elf_nds32_ifc_irel_list)); - irel_list = irel_list->next; - irel_list->irel = irel; - irel_list->keep = 1; - - if (h == NULL) - irel_list->sec = NULL; - else - irel_list->sec = sec; - irel_list->next = NULL; - return; - } - if (ptr->next == NULL) - break; - ptr = ptr->next; - } - - /* There is no same target entry, so build a new one. */ - if (ifc_symbol_head == NULL) - { - ifc_symbol_head = bfd_malloc (sizeof (struct elf_nds32_ifc_symbol_entry)); - ptr = ifc_symbol_head; - } - else - { - ptr->next = bfd_malloc (sizeof (struct elf_nds32_ifc_symbol_entry)); - ptr = ptr->next; - } - - ptr->h = h; - ptr->irel_head = bfd_malloc (sizeof (struct elf_nds32_ifc_irel_list)); - ptr->irel_head->irel = irel; - ptr->insn = insn; - ptr->irel_head->keep = 1; - - if (h == NULL) - { - /* Local symbols. */ - ptr->sec = sec; - ptr->irel_head->sec = NULL; - } - else - { - /* Global symbol. */ - ptr->sec = NULL; - ptr->irel_head->sec = sec; - } - - ptr->irel_head->next = NULL; - ptr->times = 0; - ptr->enable = 0; - ptr->ex9_enable = 0; - ptr->next = NULL; -} - -/* Gather all jal and j instructions. */ - -static bfd_boolean -nds32_elf_ifc_calc (struct bfd_link_info *info, - bfd *abfd, asection *sec) -{ - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irelend; - Elf_Internal_Rela *irel; - Elf_Internal_Shdr *symtab_hdr; - bfd_byte *contents = NULL; - uint32_t insn, insn_with_reg; - unsigned long r_symndx; - struct elf_link_hash_entry *h; - struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (abfd); - struct elf_nds32_link_hash_table *table; - bfd_boolean ifc_loop_aware; - - internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, - TRUE /* keep_memory */); - irelend = internal_relocs + sec->reloc_count; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* Check if the object enable ifc. */ - irel = find_relocs_at_address (internal_relocs, internal_relocs, irelend, - R_NDS32_RELAX_ENTRY); - - if (irel == NULL - || irel >= irelend - || ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_ENTRY - || (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY - && !(irel->r_addend & R_NDS32_RELAX_ENTRY_IFC_FLAG))) - return TRUE; - - if (!nds32_get_section_contents (abfd, sec, &contents, TRUE)) - return FALSE; - - table = nds32_elf_hash_table (info); - ifc_loop_aware = table->ifc_loop_aware; - while (irel != NULL && irel < irelend) - { - /* Traverse all relocation and gather all of them to build the list. */ - - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN) - { - if (ifc_loop_aware == 1 - && (irel->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG) != 0) - { - /* Check the region if loop or not. If it is true and - ifc-loop-aware is true, ignore the region till region end. */ - while (irel != NULL - && irel < irelend - && (ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_REGION_END - || (irel->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG) != 0)) - irel++; - } - } - - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_25_PCREL_RELA) - { - insn = bfd_getb32 (contents + irel->r_offset); - nds32_elf_get_insn_with_reg (irel, insn, &insn_with_reg); - r_symndx = ELF32_R_SYM (irel->r_info); - if (r_symndx < symtab_hdr->sh_info) - { - /* Local symbol. */ - nds32_elf_ifc_insert_symbol (sec, NULL, irel, insn_with_reg); - } - else - { - /* External symbol. */ - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - nds32_elf_ifc_insert_symbol (sec, h, irel, insn_with_reg); - } - } - irel++; - } - return TRUE; -} - -/* Determine whether j and jal should be substituted. */ - -static void -nds32_elf_ifc_filter (struct bfd_link_info *info) -{ - struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head; - struct elf_nds32_ifc_irel_list *irel_ptr = NULL; - struct elf_nds32_ifc_irel_list *irel_keeper = NULL; - struct elf_nds32_link_hash_table *table; - int target_optimize; - bfd_vma address; - - table = nds32_elf_hash_table (info); - target_optimize = table->target_optimize; - while (ptr) - { - irel_ptr = ptr->irel_head; - if (ptr->h == NULL) - { - /* Local symbol. */ - irel_keeper = irel_ptr; - while (irel_ptr && irel_ptr->next) - { - /* Check there is jump target can be used. */ - if ((irel_ptr->next->irel->r_offset - - irel_keeper->irel->r_offset) > 1022) - irel_keeper = irel_ptr->next; - else - { - ptr->enable = 1; - irel_ptr->keep = 0; - } - irel_ptr = irel_ptr->next; - } - } - else - { - /* Global symbol. */ - /* We have to get the absolute address and decide - whether to keep it or not. */ - while (irel_ptr) - { - address = (irel_ptr->irel->r_offset - + irel_ptr->sec->output_section->vma - + irel_ptr->sec->output_offset); - irel_ptr->addr = address; - irel_ptr = irel_ptr->next; - } - - irel_ptr = ptr->irel_head; - while (irel_ptr) - { - /* Sort by address. */ - struct elf_nds32_ifc_irel_list *irel_dest = irel_ptr; - struct elf_nds32_ifc_irel_list *irel_temp = irel_ptr; - struct elf_nds32_ifc_irel_list *irel_ptr_prev = NULL; - struct elf_nds32_ifc_irel_list *irel_dest_prev = NULL; - - /* Get the smallest one. */ - while (irel_temp->next) - { - if (irel_temp->next->addr < irel_dest->addr) - { - irel_dest_prev = irel_temp; - irel_dest = irel_temp->next; - } - irel_temp = irel_temp->next; - } - - if (irel_dest != irel_ptr) - { - if (irel_ptr_prev) - irel_ptr_prev->next = irel_dest; - if (irel_dest_prev) - irel_dest_prev->next = irel_ptr; - irel_temp = irel_ptr->next; - irel_ptr->next = irel_dest->next; - irel_dest->next = irel_temp; - } - irel_ptr_prev = irel_ptr; - irel_ptr = irel_ptr->next; - } - - irel_ptr = ptr->irel_head; - irel_keeper = irel_ptr; - while (irel_ptr && irel_ptr->next) - { - if ((irel_ptr->next->addr - irel_keeper->addr) > 1022) - irel_keeper = irel_ptr->next; - else - { - ptr->enable = 1; - irel_ptr->keep = 0; - } - irel_ptr = irel_ptr->next; - } - } - - /* Ex9 enable. Reserve it for ex9. */ - if ((target_optimize & NDS32_RELAX_EX9_ON) - && ptr->irel_head != irel_keeper) - ptr->enable = 0; - ptr = ptr->next; - } -} - -/* Determine whether j and jal should be substituted after ex9 done. */ - -static void -nds32_elf_ifc_filter_after_ex9 (void) -{ - struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head; - struct elf_nds32_ifc_irel_list *irel_ptr = NULL; - - while (ptr) - { - if (ptr->enable == 0) - { - /* Check whether ifc is applied or not. */ - irel_ptr = ptr->irel_head; - ptr->ex9_enable = 1; - while (irel_ptr) - { - if (ELF32_R_TYPE (irel_ptr->irel->r_info) == R_NDS32_TRAN) - { - /* Ex9 already. */ - ptr->ex9_enable = 0; - break; - } - irel_ptr = irel_ptr->next; - } - } - ptr = ptr->next; - } -} - -/* Wrapper to do ifc relaxation. */ - -bfd_boolean -nds32_elf_ifc_finish (struct bfd_link_info *info) -{ - int relax_status; - struct elf_nds32_link_hash_table *table; - - table = nds32_elf_hash_table (info); - relax_status = table->relax_status; - - if (!(relax_status & NDS32_RELAX_JUMP_IFC_DONE)) - nds32_elf_ifc_filter (info); - else - nds32_elf_ifc_filter_after_ex9 (); - - if (!nds32_elf_ifc_replace (info)) - return FALSE; - - if (table) - table->relax_status |= NDS32_RELAX_JUMP_IFC_DONE; - return TRUE; -} - -/* Traverse the result of ifc filter and replace it with ifcall9. */ - -static bfd_boolean -nds32_elf_ifc_replace (struct bfd_link_info *info) -{ - struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head; - struct elf_nds32_ifc_irel_list *irel_ptr = NULL; - nds32_elf_blank_t *relax_blank_list = NULL; - bfd_byte *contents = NULL; - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irel; - Elf_Internal_Rela *irelend; - unsigned short insn16 = INSN_IFCALL9; - struct elf_nds32_link_hash_table *table; - int relax_status; - - table = nds32_elf_hash_table (info); - relax_status = table->relax_status; - - while (ptr) - { - /* Traverse the ifc gather list, and replace the - filter entries by ifcall9. */ - if ((!(relax_status & NDS32_RELAX_JUMP_IFC_DONE) && ptr->enable == 1) - || ((relax_status & NDS32_RELAX_JUMP_IFC_DONE) - && ptr->ex9_enable == 1)) - { - irel_ptr = ptr->irel_head; - if (ptr->h == NULL) - { - /* Local symbol. */ - internal_relocs = _bfd_elf_link_read_relocs - (ptr->sec->owner, ptr->sec, NULL, NULL, TRUE /* keep_memory */); - irelend = internal_relocs + ptr->sec->reloc_count; - - if (!nds32_get_section_contents (ptr->sec->owner, ptr->sec, - &contents, TRUE)) - return FALSE; - - while (irel_ptr) - { - if (irel_ptr->keep == 0 && irel_ptr->next) - { - /* The one can be replaced. We have to check whether - there is any alignment point in the region. */ - irel = irel_ptr->irel; - while (((irel_ptr->next->keep == 0 - && irel < irel_ptr->next->irel) - || (irel_ptr->next->keep == 1 && irel < irelend)) - && !(ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL - && (irel->r_addend & 0x1f) == 2)) - irel++; - if (irel >= irelend - || !(ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL - && (irel->r_addend & 0x1f) == 2 - && ((irel->r_offset - get_nds32_elf_blank_total - (&relax_blank_list, irel->r_offset, 1)) - & 0x02) == 0)) - { - /* Replace by ifcall9. */ - bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset); - if (!insert_nds32_elf_blank_recalc_total - (&relax_blank_list, irel_ptr->irel->r_offset + 2, 2)) - return FALSE; - irel_ptr->irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), - R_NDS32_10IFCU_PCREL_RELA); - } - } - irel_ptr = irel_ptr->next; - } - - /* Delete the redundant code. */ - if (relax_blank_list) - { - nds32_elf_relax_delete_blanks (ptr->sec->owner, ptr->sec, - relax_blank_list); - relax_blank_list = NULL; - } - } - else - { - /* Global symbol. */ - while (irel_ptr) - { - if (irel_ptr->keep == 0 && irel_ptr->next) - { - /* The one can be replaced, and we have to check - whether there is any alignment point in the region. */ - internal_relocs = _bfd_elf_link_read_relocs - (irel_ptr->sec->owner, irel_ptr->sec, NULL, NULL, - TRUE /* keep_memory */); - irelend = internal_relocs + irel_ptr->sec->reloc_count; - if (!nds32_get_section_contents (irel_ptr->sec->owner, - irel_ptr->sec, &contents, - TRUE)) - return FALSE; - - irel = irel_ptr->irel; - while (((irel_ptr->sec == irel_ptr->next->sec - && irel_ptr->next->keep == 0 - && irel < irel_ptr->next->irel) - || ((irel_ptr->sec != irel_ptr->next->sec - || irel_ptr->next->keep == 1) - && irel < irelend)) - && !(ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL - && (irel->r_addend & 0x1f) == 2)) - irel++; - if (irel >= irelend - || !(ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL - && (irel->r_addend & 0x1f) == 2 - && ((irel->r_offset - - get_nds32_elf_blank_total (&relax_blank_list, - irel->r_offset, 1)) & 0x02) == 0)) - { - /* Replace by ifcall9. */ - bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset); - if (!insert_nds32_elf_blank_recalc_total - (&relax_blank_list, irel_ptr->irel->r_offset + 2, 2)) - return FALSE; - - /* Delete the redundant code, and clear the relocation. */ - nds32_elf_relax_delete_blanks (irel_ptr->sec->owner, - irel_ptr->sec, - relax_blank_list); - irel_ptr->irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), - R_NDS32_10IFCU_PCREL_RELA); - relax_blank_list = NULL; - } - } - - irel_ptr = irel_ptr->next; - } - } - } - ptr = ptr->next; - } - - return TRUE; -} - -/* Relocate ifcall. */ - -static bfd_boolean -nds32_elf_ifc_reloc (void) -{ - struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head; - struct elf_nds32_ifc_irel_list *irel_ptr = NULL; - struct elf_nds32_ifc_irel_list *irel_keeper = NULL; - bfd_vma relocation, address; - unsigned short insn16; - bfd_byte *contents = NULL; - static bfd_boolean done = FALSE; - - if (done) - return TRUE; - - done = TRUE; - - while (ptr) - { - /* Check the entry is enable ifcall. */ - if (ptr->enable == 1 || ptr->ex9_enable == 1) - { - /* Get the reserve jump. */ - irel_ptr = ptr->irel_head; - while (irel_ptr) - { - if (irel_ptr->keep == 1) - { - irel_keeper = irel_ptr; - break; - } - irel_ptr = irel_ptr->next; - } - - irel_ptr = ptr->irel_head; - if (ptr->h == NULL) - { - /* Local symbol. */ - if (!nds32_get_section_contents (ptr->sec->owner, ptr->sec, - &contents, TRUE)) - return FALSE; - - while (irel_ptr) - { - if (irel_ptr->keep == 0 - && ELF32_R_TYPE (irel_ptr->irel->r_info) == R_NDS32_10IFCU_PCREL_RELA) - { - relocation = irel_keeper->irel->r_offset; - relocation = relocation - irel_ptr->irel->r_offset; - while (irel_keeper && relocation > 1022) - { - irel_keeper = irel_keeper->next; - if (irel_keeper && irel_keeper->keep == 1) - { - relocation = irel_keeper->irel->r_offset; - relocation = relocation - irel_ptr->irel->r_offset; - } - } - if (relocation > 1022) - { - /* Double check. */ - irel_keeper = ptr->irel_head; - while (irel_keeper) - { - if (irel_keeper->keep == 1) - { - relocation = irel_keeper->irel->r_offset; - relocation = relocation - irel_ptr->irel->r_offset; - } - if (relocation <= 1022) - break; - irel_keeper = irel_keeper->next; - } - if (!irel_keeper) - return FALSE; - } - irel_ptr->irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), - R_NDS32_NONE); - insn16 = INSN_IFCALL9 | (relocation >> 1); - bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset); - } - irel_ptr = irel_ptr->next; - } - } - else - { - /* Global symbol. */ - while (irel_ptr) - { - if (irel_ptr->keep == 0 - && ELF32_R_TYPE (irel_ptr->irel->r_info) == R_NDS32_10IFCU_PCREL_RELA) - { - /* Get the distance between ifcall and jump. */ - relocation = (irel_keeper->irel->r_offset - + irel_keeper->sec->output_section->vma - + irel_keeper->sec->output_offset); - address = (irel_ptr->irel->r_offset - + irel_ptr->sec->output_section->vma - + irel_ptr->sec->output_offset); - relocation = relocation - address; - - /* The distance is over ragne, find callee again. */ - while (irel_keeper && relocation > 1022) - { - irel_keeper = irel_keeper->next; - if (irel_keeper && irel_keeper->keep ==1) - { - relocation = (irel_keeper->irel->r_offset - + irel_keeper->sec->output_section->vma - + irel_keeper->sec->output_offset); - relocation = relocation - address; - } - } - - if (relocation > 1022) - { - /* Double check. */ - irel_keeper = ptr->irel_head; - while (irel_keeper) - { - if (irel_keeper->keep == 1) - { - - relocation = (irel_keeper->irel->r_offset - + irel_keeper->sec->output_section->vma - + irel_keeper->sec->output_offset); - relocation = relocation - address; - } - if (relocation <= 1022) - break; - irel_keeper = irel_keeper->next; - } - if (!irel_keeper) - return FALSE; - } - if (!nds32_get_section_contents - (irel_ptr->sec->owner, irel_ptr->sec, &contents, TRUE)) - return FALSE; - insn16 = INSN_IFCALL9 | (relocation >> 1); - bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset); - irel_ptr->irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), - R_NDS32_NONE); - } - irel_ptr =irel_ptr->next; - } - } - } - ptr = ptr->next; - } - - return TRUE; -} - -/* End of IFC relaxation. */ - -/* EX9 Instruction Table Relaxation. */ - -/* Global hash list. */ -struct elf_link_hash_entry_list -{ - struct elf_link_hash_entry *h; - struct elf_link_hash_entry_list *next; -}; - -/* Save different destination but same insn. */ -struct elf_link_hash_entry_mul_list -{ - /* Global symbol times. */ - int times; - /* Save relocation for each global symbol but useful?? */ - Elf_Internal_Rela *irel; - /* For sethi, two sethi may have the same high-part but different low-parts. */ - Elf_Internal_Rela rel_backup; - struct elf_link_hash_entry_list *h_list; - struct elf_link_hash_entry_mul_list *next; -}; - -/* Instruction hash table. */ -struct elf_nds32_code_hash_entry -{ - struct bfd_hash_entry root; - int times; - /* For insn that can use relocation or constant ex: sethi. */ - int const_insn; - asection *sec; - struct elf_link_hash_entry_mul_list *m_list; - /* Using r_addend. */ - Elf_Internal_Rela *irel; - /* Using r_info. */ - Elf_Internal_Rela rel_backup; -}; - -/* Instruction count list. */ -struct elf_nds32_insn_times_entry -{ - const char *string; - int times; - int order; - asection *sec; - struct elf_link_hash_entry_mul_list *m_list; - Elf_Internal_Rela *irel; - Elf_Internal_Rela rel_backup; - struct elf_nds32_insn_times_entry *next; -}; - -/* J and JAL symbol list. */ -struct elf_nds32_symbol_entry -{ - char *string; - unsigned long insn; - struct elf_nds32_symbol_entry *next; -}; - -/* Relocation list. */ -struct elf_nds32_irel_entry -{ - Elf_Internal_Rela *irel; - struct elf_nds32_irel_entry *next; -}; - -/* ex9.it insn need to be fixed. */ -struct elf_nds32_ex9_refix -{ - Elf_Internal_Rela *irel; - asection *sec; - struct elf_link_hash_entry *h; - int order; - struct elf_nds32_ex9_refix *next; -}; - -static struct bfd_hash_table ex9_code_table; -static struct elf_nds32_insn_times_entry *ex9_insn_head = NULL; -static struct elf_nds32_ex9_refix *ex9_refix_head = NULL; - -/* EX9 hash function. */ - -static struct bfd_hash_entry * -nds32_elf_code_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct elf_nds32_code_hash_entry *ret; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (entry == NULL) - { - entry = (struct bfd_hash_entry *) - bfd_hash_allocate (table, sizeof (*ret)); - if (entry == NULL) - return entry; - } - - /* Call the allocation method of the superclass. */ - entry = bfd_hash_newfunc (entry, table, string); - if (entry == NULL) - return entry; - - ret = (struct elf_nds32_code_hash_entry*) entry; - ret->times = 0; - ret->const_insn = 0; - ret->m_list = NULL; - ret->sec = NULL; - ret->irel = NULL; - return &ret->root; -} - -/* Insert ex9 entry - this insert must be stable sorted by times. */ - -static void -nds32_elf_ex9_insert_entry (struct elf_nds32_insn_times_entry *ptr) -{ - struct elf_nds32_insn_times_entry *temp; - struct elf_nds32_insn_times_entry *temp2; - - if (ex9_insn_head == NULL) - { - ex9_insn_head = ptr; - ptr->next = NULL; - } - else - { - temp = ex9_insn_head; - temp2 = ex9_insn_head; - while (temp->next && - (temp->next->times >= ptr->times - || temp->times == -1)) - { - if (temp->times == -1) - temp2 = temp; - temp = temp->next; - } - if (ptr->times > temp->times && temp->times != -1) - { - ptr->next = temp; - if (temp2->times == -1) - temp2->next = ptr; - else - ex9_insn_head = ptr; - } - else if (temp->next == NULL) - { - temp->next = ptr; - ptr->next = NULL; - } - else - { - ptr->next = temp->next; - temp->next = ptr; - } - } -} - -/* Examine each insn times in hash table. - Handle multi-link hash entry. - - TODO: This function doesn't assign so much info since it is fake. */ - -static int -nds32_elf_examine_insn_times (struct elf_nds32_code_hash_entry *h) -{ - struct elf_nds32_insn_times_entry *ptr; - int times; - - if (h->m_list == NULL) - { - /* Local symbol insn or insn without relocation. */ - if (h->times < 3) - return TRUE; - - ptr = (struct elf_nds32_insn_times_entry *) - bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); - ptr->times = h->times; - ptr->string = h->root.string; - ptr->m_list = NULL; - ptr->sec = h->sec; - ptr->irel = h->irel; - ptr->rel_backup = h->rel_backup; - nds32_elf_ex9_insert_entry (ptr); - } - else - { - /* Global symbol insn. */ - /* Only sethi insn has multiple m_list. */ - struct elf_link_hash_entry_mul_list *m_list = h->m_list; - - times = 0; - while (m_list) - { - times += m_list->times; - m_list = m_list->next; - } - if (times >= 3) - { - m_list = h->m_list; - ptr = (struct elf_nds32_insn_times_entry *) - bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); - ptr->times = times; /* Use the total times. */ - ptr->string = h->root.string; - ptr->m_list = m_list; - ptr->sec = h->sec; - ptr->irel = m_list->irel; - ptr->rel_backup = m_list->rel_backup; - nds32_elf_ex9_insert_entry (ptr); - } - if (h->const_insn == 1) - { - /* sethi with constant value. */ - if (h->times < 3) - return TRUE; - - ptr = (struct elf_nds32_insn_times_entry *) - bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); - ptr->times = h->times; - ptr->string = h->root.string; - ptr->m_list = NULL; - ptr->sec = NULL; - ptr->irel = NULL; - ptr->rel_backup = h->rel_backup; - nds32_elf_ex9_insert_entry (ptr); - } - } - return TRUE; -} - -/* Count each insn times in hash table. - Handle multi-link hash entry. */ - -static int -nds32_elf_count_insn_times (struct elf_nds32_code_hash_entry *h) -{ - int reservation, times; - unsigned long relocation, min_relocation; - struct elf_nds32_insn_times_entry *ptr; - - if (h->m_list == NULL) - { - /* Local symbol insn or insn without relocation. */ - if (h->times < 3) - return TRUE; - ptr = (struct elf_nds32_insn_times_entry *) - bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); - ptr->times = h->times; - ptr->string = h->root.string; - ptr->m_list = NULL; - ptr->sec = h->sec; - ptr->irel = h->irel; - ptr->rel_backup = h->rel_backup; - nds32_elf_ex9_insert_entry (ptr); - } - else - { - /* Global symbol insn. */ - /* Only sethi insn has multiple m_list. */ - struct elf_link_hash_entry_mul_list *m_list = h->m_list; - - if (ELF32_R_TYPE (m_list->rel_backup.r_info) == R_NDS32_HI20_RELA - && m_list->next != NULL) - { - /* Sethi insn has different symbol or addend but has same hi20. */ - times = 0; - reservation = 1; - relocation = 0; - min_relocation = 0xffffffff; - while (m_list) - { - /* Get the minimum sethi address - and calculate how many entry the sethi-list have to use. */ - if ((m_list->h_list->h->root.type == bfd_link_hash_defined - || m_list->h_list->h->root.type == bfd_link_hash_defweak) - && (m_list->h_list->h->root.u.def.section != NULL - && m_list->h_list->h->root.u.def.section->output_section != NULL)) - { - relocation = (m_list->h_list->h->root.u.def.value + - m_list->h_list->h->root.u.def.section->output_section->vma + - m_list->h_list->h->root.u.def.section->output_offset); - relocation += m_list->irel->r_addend; - } - else - relocation = 0; - if (relocation < min_relocation) - min_relocation = relocation; - times += m_list->times; - m_list = m_list->next; - } - if (min_relocation < ex9_relax_size) - reservation = (min_relocation >> 12) + 1; - else - reservation = (min_relocation >> 12) - - ((min_relocation - ex9_relax_size) >> 12) + 1; - if (reservation < (times / 3)) - { - /* Efficient enough to use ex9. */ - int i; - - for (i = reservation ; i > 0; i--) - { - /* Allocate number of reservation ex9 entry. */ - ptr = (struct elf_nds32_insn_times_entry *) - bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); - ptr->times = h->m_list->times / reservation; - ptr->string = h->root.string; - ptr->m_list = h->m_list; - ptr->sec = h->sec; - ptr->irel = h->m_list->irel; - ptr->rel_backup = h->m_list->rel_backup; - nds32_elf_ex9_insert_entry (ptr); - } - } - } - else - { - /* Normal global symbol that means no different address symbol - using same ex9 entry. */ - if (m_list->times >= 3) - { - ptr = (struct elf_nds32_insn_times_entry *) - bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); - ptr->times = m_list->times; - ptr->string = h->root.string; - ptr->m_list = h->m_list; - ptr->sec = h->sec; - ptr->irel = h->m_list->irel; - ptr->rel_backup = h->m_list->rel_backup; - nds32_elf_ex9_insert_entry (ptr); - } - } - - if (h->const_insn == 1) - { - /* sethi with constant value. */ - if (h->times < 3) - return TRUE; - - ptr = (struct elf_nds32_insn_times_entry *) - bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); - ptr->times = h->times; - ptr->string = h->root.string; - ptr->m_list = NULL; - ptr->sec = NULL; - ptr->irel = NULL; - ptr->rel_backup = h->rel_backup; - nds32_elf_ex9_insert_entry (ptr); - } - } - - return TRUE; -} - -/* Hash table traverse function. */ - -static void -nds32_elf_code_hash_traverse (int (*func) (struct elf_nds32_code_hash_entry*)) -{ - unsigned int i; - - ex9_code_table.frozen = 1; - for (i = 0; i < ex9_code_table.size; i++) - { - struct bfd_hash_entry *p; - - for (p = ex9_code_table.table[i]; p != NULL; p = p->next) - if (!func ((struct elf_nds32_code_hash_entry *) p)) - goto out; - } -out: - ex9_code_table.frozen = 0; -} - - -/* Give order number to insn list. */ - -static void -nds32_elf_order_insn_times (struct bfd_link_info *info) -{ - struct elf_nds32_insn_times_entry *ex9_insn; - struct elf_nds32_insn_times_entry *temp = NULL; - struct elf_nds32_link_hash_table *table; - int ex9_limit; - int number = 0; - - if (ex9_insn_head == NULL) - return; - -/* The max number of entries is 512. */ - ex9_insn = ex9_insn_head; - table = nds32_elf_hash_table (info); - ex9_limit = table->ex9_limit; - - ex9_insn = ex9_insn_head; - - while (ex9_insn != NULL && number < ex9_limit) - { - ex9_insn->order = number; - number++; - temp = ex9_insn; - ex9_insn = ex9_insn->next; - } - - if (ex9_insn && temp) - temp->next = NULL; - - while (ex9_insn != NULL) - { - /* Free useless entry. */ - temp = ex9_insn; - ex9_insn = ex9_insn->next; - free (temp); - } -} - -/* Build .ex9.itable section. */ - -static void -nds32_elf_ex9_build_itable (struct bfd_link_info *link_info) -{ - asection *table_sec; - struct elf_nds32_insn_times_entry *ptr; - bfd *it_abfd; - int number = 0; - bfd_byte *contents = NULL; - - for (it_abfd = link_info->input_bfds; it_abfd != NULL; - it_abfd = it_abfd->link.next) - { - /* Find the section .ex9.itable, and put all entries into it. */ - table_sec = bfd_get_section_by_name (it_abfd, ".ex9.itable"); - if (table_sec != NULL) - { - if (!nds32_get_section_contents (it_abfd, table_sec, &contents, TRUE)) - return; - - for (ptr = ex9_insn_head; ptr !=NULL ; ptr = ptr->next) - number++; - - table_sec->size = number * 4; - - if (number == 0) - return; - - elf_elfheader (link_info->output_bfd)->e_flags |= E_NDS32_HAS_EX9_INST; - number = 0; - for (ptr = ex9_insn_head; ptr !=NULL ; ptr = ptr->next) - { - long val; - - val = strtol (ptr->string, NULL, 16); - bfd_putb32 ((bfd_vma) val, (char *) contents + (number * 4)); - number++; - } - break; - } - } -} - -/* Get insn with regs according to relocation type. */ - -static void -nds32_elf_get_insn_with_reg (Elf_Internal_Rela *irel, - uint32_t insn, uint32_t *insn_with_reg) -{ - reloc_howto_type *howto = NULL; - - if (irel == NULL - || (ELF32_R_TYPE (irel->r_info) >= (int) ARRAY_SIZE (nds32_elf_howto_table) - && (ELF32_R_TYPE (irel->r_info) - R_NDS32_RELAX_ENTRY) - >= (int) ARRAY_SIZE (nds32_elf_relax_howto_table))) - { - *insn_with_reg = insn; - return; - } - - howto = bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE (irel->r_info)); - *insn_with_reg = insn & (0xffffffff ^ howto->dst_mask); -} - -/* Mask number of address bits according to relocation. */ - -static unsigned long -nds32_elf_irel_mask (Elf_Internal_Rela *irel) -{ - reloc_howto_type *howto = NULL; - - if (irel == NULL - || (ELF32_R_TYPE (irel->r_info) >= (int) ARRAY_SIZE (nds32_elf_howto_table) - && (ELF32_R_TYPE (irel->r_info) - R_NDS32_RELAX_ENTRY) - >= (int) ARRAY_SIZE (nds32_elf_relax_howto_table))) - return 0; - - howto = bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE (irel->r_info)); - return howto->dst_mask; -} - -static void -nds32_elf_insert_irel_entry (struct elf_nds32_irel_entry **irel_list, - struct elf_nds32_irel_entry *irel_ptr) -{ - if (*irel_list == NULL) - { - *irel_list = irel_ptr; - irel_ptr->next = NULL; - } - else - { - irel_ptr->next = *irel_list; - *irel_list = irel_ptr; - } -} - -static void -nds32_elf_ex9_insert_fix (asection * sec, Elf_Internal_Rela * irel, - struct elf_link_hash_entry *h, int order) -{ - struct elf_nds32_ex9_refix *ptr; - - ptr = bfd_malloc (sizeof (struct elf_nds32_ex9_refix)); - ptr->sec = sec; - ptr->irel = irel; - ptr->h = h; - ptr->order = order; - ptr->next = NULL; - - if (ex9_refix_head == NULL) - ex9_refix_head = ptr; - else - { - struct elf_nds32_ex9_refix *temp = ex9_refix_head; - - while (temp->next != NULL) - temp = temp->next; - temp->next = ptr; - } -} - -enum -{ - DATA_EXIST = 1, - CLEAN_PRE = 1 << 1, - PUSH_PRE = 1 << 2 -}; - -/* Check relocation type if supporting for ex9. */ - -static int -nds32_elf_ex9_relocation_check (struct bfd_link_info *info, - Elf_Internal_Rela **irel, - Elf_Internal_Rela *irelend, - nds32_elf_blank_t *relax_blank_list, - asection *sec,bfd_vma *off, - bfd_byte *contents) -{ - /* Suppress ex9 if `.no_relax ex9' or inner loop. */ - bfd_boolean nested_ex9, nested_loop; - bfd_boolean ex9_loop_aware; - /* We use the highest 1 byte of result to record - how many bytes location counter has to move. */ - int result = 0; - Elf_Internal_Rela *irel_save = NULL; - struct elf_nds32_link_hash_table *table; - - table = nds32_elf_hash_table (info); - ex9_loop_aware = table->ex9_loop_aware; - - while ((*irel) != NULL && (*irel) < irelend && *off == (*irel)->r_offset) - { - switch (ELF32_R_TYPE ((*irel)->r_info)) - { - case R_NDS32_RELAX_REGION_BEGIN: - /* Ignore code block. */ - nested_ex9 = FALSE; - nested_loop = FALSE; - if (((*irel)->r_addend & R_NDS32_RELAX_REGION_NO_EX9_FLAG) - || (ex9_loop_aware - && ((*irel)->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG))) - { - /* Check the region if loop or not. If it is true and - ex9-loop-aware is true, ignore the region till region end. */ - /* To save the status for in .no_relax ex9 region and - loop region to conform the block can do ex9 relaxation. */ - nested_ex9 = ((*irel)->r_addend & R_NDS32_RELAX_REGION_NO_EX9_FLAG); - nested_loop = (ex9_loop_aware - && ((*irel)->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG)); - while ((*irel) && (*irel) < irelend && (nested_ex9 || nested_loop)) - { - (*irel)++; - if (ELF32_R_TYPE ((*irel)->r_info) == R_NDS32_RELAX_REGION_BEGIN) - { - /* There may be nested region. */ - if (((*irel)->r_addend & R_NDS32_RELAX_REGION_NO_EX9_FLAG) != 0) - nested_ex9 = TRUE; - else if (ex9_loop_aware - && ((*irel)->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG)) - nested_loop = TRUE; - } - else if (ELF32_R_TYPE ((*irel)->r_info) == R_NDS32_RELAX_REGION_END) - { - /* The end of region. */ - if (((*irel)->r_addend & R_NDS32_RELAX_REGION_NO_EX9_FLAG) != 0) - nested_ex9 = FALSE; - else if (ex9_loop_aware - && ((*irel)->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG)) - nested_loop = FALSE; - } - else if (ELF32_R_TYPE ((*irel)->r_info) == R_NDS32_LABEL - && ((*irel)->r_addend & 0x1f) == 2) - { - /* Alignment exist in the region. */ - result |= CLEAN_PRE; - if (((*irel)->r_offset - - get_nds32_elf_blank_total (&relax_blank_list, - (*irel)->r_offset, 0)) & 0x02) - result |= PUSH_PRE; - } - } - if ((*irel) >= irelend) - *off = sec->size; - else - *off = (*irel)->r_offset; - - /* The final instruction in the region, regard this one as data to ignore it. */ - result |= DATA_EXIST; - return result; - } - break; - - case R_NDS32_LABEL: - if (((*irel)->r_addend & 0x1f) == 2) - { - /* Check this point is align and decide to do ex9 or not. */ - result |= CLEAN_PRE; - if (((*irel)->r_offset - - get_nds32_elf_blank_total (&relax_blank_list, - (*irel)->r_offset, 0)) & 0x02) - result |= PUSH_PRE; - } - break; - case R_NDS32_32_RELA: - /* Data. */ - result |= (4 << 24); - result |= DATA_EXIST; - break; - case R_NDS32_16_RELA: - /* Data. */ - result |= (2 << 24); - result |= DATA_EXIST; - break; - case R_NDS32_DATA: - /* Data. */ - /* The least code alignment is 2. If the data is only one byte, - we have to shift one more byte. */ - if ((*irel)->r_addend == 1) - result |= ((*irel)->r_addend << 25) ; - else - result |= ((*irel)->r_addend << 24) ; - - result |= DATA_EXIST; - break; - - case R_NDS32_25_PCREL_RELA: - case R_NDS32_SDA16S3_RELA: - case R_NDS32_SDA15S3_RELA: - case R_NDS32_SDA15S3: - case R_NDS32_SDA17S2_RELA: - case R_NDS32_SDA15S2_RELA: - case R_NDS32_SDA12S2_SP_RELA: - case R_NDS32_SDA12S2_DP_RELA: - case R_NDS32_SDA15S2: - case R_NDS32_SDA18S1_RELA: - case R_NDS32_SDA15S1_RELA: - case R_NDS32_SDA15S1: - case R_NDS32_SDA19S0_RELA: - case R_NDS32_SDA15S0_RELA: - case R_NDS32_SDA15S0: - case R_NDS32_HI20_RELA: - case R_NDS32_LO12S0_ORI_RELA: - case R_NDS32_LO12S0_RELA: - case R_NDS32_LO12S1_RELA: - case R_NDS32_LO12S2_RELA: - /* These relocation is supported ex9 relaxation currently. */ - /* We have to save the relocation for using later, since we have - to check there is any alignment in the same address. */ - irel_save = *irel; - break; - default: - /* Not support relocations. */ - if (ELF32_R_TYPE ((*irel)->r_info) < ARRAY_SIZE (nds32_elf_howto_table) - && ELF32_R_TYPE ((*irel)->r_info) != R_NDS32_NONE - && ELF32_R_TYPE ((*irel)->r_info) != R_NDS32_INSN16) - { - /* Note: To optimize aggressively, it maybe can ignore R_NDS32_INSN16 here. - But we have to consider if there is any side-effect. */ - if (!(result & DATA_EXIST)) - { - /* We have to confirm there is no data relocation in the - same address. In general case, this won't happen. */ - /* We have to do ex9 conservative, for those relocation not - considerd we ignore instruction. */ - result |= DATA_EXIST; - if (*(contents + *off) & 0x80) - result |= (2 << 24); - else - result |= (4 << 24); - break; - } - } - } - if ((*irel) < irelend - && ((*irel) + 1) < irelend - && (*irel)->r_offset == ((*irel) + 1)->r_offset) - /* There are relocations pointing to the same address, we have to - check all of them. */ - (*irel)++; - else - { - if (irel_save) - *irel = irel_save; - return result; - } - } - return result; -} - -/* Replace with ex9 instruction. */ - -static bfd_boolean -nds32_elf_ex9_push_insn (uint16_t insn16, bfd_byte *contents, bfd_vma pre_off, - nds32_elf_blank_t **relax_blank_list, - struct elf_nds32_irel_entry *pre_irel_ptr, - struct elf_nds32_irel_entry **irel_list) -{ - if (insn16 != 0) - { - /* Implement the ex9 relaxation. */ - bfd_putb16 (insn16, contents + pre_off); - if (!insert_nds32_elf_blank_recalc_total (relax_blank_list, - pre_off + 2, 2)) - return FALSE; - if (pre_irel_ptr != NULL) - nds32_elf_insert_irel_entry (irel_list, pre_irel_ptr); - } - return TRUE; -} - -/* Replace input file instruction which is in ex9 itable. */ - -static bfd_boolean -nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asection *sec) -{ - struct elf_nds32_insn_times_entry *ex9_insn = ex9_insn_head; - bfd_byte *contents = NULL; - bfd_vma off; - uint16_t insn16, insn_ex9; - /* `pre_*' are used to track previous instruction that can use ex9.it. */ - bfd_vma pre_off = -1; - uint16_t pre_insn16 = 0; - struct elf_nds32_irel_entry *pre_irel_ptr = NULL; - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irel; - Elf_Internal_Rela *irelend; - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym *isym = NULL; - nds32_elf_blank_t *relax_blank_list = NULL; - uint32_t insn = 0; - uint32_t insn_with_reg = 0; - uint32_t it_insn; - uint32_t it_insn_with_reg; - unsigned long r_symndx; - asection *isec; - struct elf_nds32_irel_entry *irel_list = NULL; - struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (abfd); - int data_flag, do_replace, save_irel; - struct elf_link_hash_entry_list *h_list; - - - /* Load section instructions, relocations, and symbol table. */ - if (!nds32_get_section_contents (abfd, sec, &contents, TRUE) - || !nds32_get_local_syms (abfd, sec, &isym)) - return FALSE; - internal_relocs = - _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, TRUE /* keep_memory */); - irelend = internal_relocs + sec->reloc_count; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - off = 0; - - /* Check if the object enable ex9. */ - irel = find_relocs_at_address (internal_relocs, internal_relocs, - irelend, R_NDS32_RELAX_ENTRY); - - /* Check this section trigger ex9 relaxation. */ - if (irel == NULL - || irel >= irelend - || ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_ENTRY - || (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY - && !(irel->r_addend & R_NDS32_RELAX_ENTRY_EX9_FLAG))) - return TRUE; - - irel = internal_relocs; - - /* Check alignment and fetch proper relocation. */ - while (off < sec->size) - { - struct elf_link_hash_entry *h = NULL; - struct elf_nds32_irel_entry *irel_ptr = NULL; - - /* Syn the instruction and the relocation. */ - while (irel != NULL && irel < irelend && irel->r_offset < off) - irel++; - - data_flag = nds32_elf_ex9_relocation_check (info, &irel, irelend, - relax_blank_list, sec, - &off, contents); - if (data_flag & PUSH_PRE) - if (!nds32_elf_ex9_push_insn (pre_insn16, contents, pre_off, - &relax_blank_list, pre_irel_ptr, - &irel_list)) - return FALSE; - - if (data_flag & CLEAN_PRE) - { - pre_off = 0; - pre_insn16 = 0; - pre_irel_ptr = NULL; - } - if (data_flag & DATA_EXIST) - { - /* We save the move offset in the highest byte. */ - off += (data_flag >> 24); - continue; - } - - if (*(contents + off) & 0x80) - { - /* 2-byte instruction. */ - off += 2; - continue; - } - - /* Load the instruction and its opcode with register for comparing. */ - ex9_insn = ex9_insn_head; - insn = bfd_getb32 (contents + off); - insn_with_reg = 0; - while (ex9_insn) - { - it_insn = strtol (ex9_insn->string, NULL, 16); - it_insn_with_reg = 0; - do_replace = 0; - save_irel = 0; - - if (irel != NULL && irel < irelend && irel->r_offset == off) - { - /* Insn with relocation. */ - nds32_elf_get_insn_with_reg (irel, insn, &insn_with_reg); - - if (ex9_insn->irel != NULL) - nds32_elf_get_insn_with_reg (ex9_insn->irel, it_insn, - &it_insn_with_reg); - - if (ex9_insn->irel != NULL - && (ELF32_R_TYPE (irel->r_info) == - ELF32_R_TYPE (ex9_insn->irel->r_info)) - && (insn_with_reg == it_insn_with_reg)) - { - /* Insn relocation and format is the same as table entry. */ - - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_25_PCREL_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S0_ORI_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S0_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S1_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_RELA - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3 - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0) - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3_RELA - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0_RELA) - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA12S2_DP_RELA - && ELF32_R_TYPE (irel->r_info) <= - R_NDS32_SDA12S2_SP_RELA) - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA16S3_RELA - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA19S0_RELA)) - { - r_symndx = ELF32_R_SYM (irel->r_info); - if (r_symndx < symtab_hdr->sh_info) - { - /* Local symbol. */ - int shndx = isym[r_symndx].st_shndx; - - isec = elf_elfsections (abfd)[shndx]->bfd_section; - if (ex9_insn->sec == isec - && ex9_insn->irel->r_addend == irel->r_addend - && ex9_insn->irel->r_info == irel->r_info) - { - do_replace = 1; - save_irel = 1; - } - } - else - { - /* External symbol. */ - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - if (ex9_insn->m_list) - { - h_list = ex9_insn->m_list->h_list; - while (h_list) - { - if (h == h_list->h - && (ex9_insn->m_list->irel->r_addend == - irel->r_addend)) - { - do_replace = 1; - save_irel = 1; - break; - } - h_list = h_list->next; - } - } - } - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_HI20_RELA) - { - r_symndx = ELF32_R_SYM (irel->r_info); - if (r_symndx < symtab_hdr->sh_info) - { - /* Local symbols. Compare its base symbol and offset. */ - int shndx = isym[r_symndx].st_shndx; - - isec = elf_elfsections (abfd)[shndx]->bfd_section; - if (ex9_insn->sec == isec - && ex9_insn->irel->r_addend == irel->r_addend - && ex9_insn->irel->r_info == irel->r_info) - { - do_replace = 1; - save_irel = 1; - } - } - else - { - /* External symbol. */ - struct elf_link_hash_entry_mul_list *m_list; - - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - m_list = ex9_insn->m_list; - - while (m_list) - { - h_list = m_list->h_list; - - while (h_list) - { - if (h == h_list->h - && (m_list->irel->r_addend - == irel->r_addend)) - { - do_replace = 1; - save_irel = 1; - if (ex9_insn->next - && ex9_insn->m_list - && ex9_insn->m_list == ex9_insn->next->m_list) - { - /* sethi multiple entry must be fixed */ - nds32_elf_ex9_insert_fix (sec, irel, - h, ex9_insn->order); - } - break; - } - h_list = h_list->next; - } - m_list = m_list->next; - } - } - } - } - - /* Import table: Check the symbol hash table and the - jump target. Only R_NDS32_25_PCREL_RELA now. */ - else if (ex9_insn->times == -1 - && ELF32_R_TYPE (irel->r_info) == R_NDS32_25_PCREL_RELA) - { - nds32_elf_get_insn_with_reg (irel, it_insn, &it_insn_with_reg); - if (insn_with_reg == it_insn_with_reg) - { - char code[10]; - bfd_vma relocation; - - r_symndx = ELF32_R_SYM (irel->r_info); - if (r_symndx >= symtab_hdr->sh_info) - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - if ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->root.u.def.section != NULL - && h->root.u.def.section->output_section != NULL - && h->root.u.def.section->gc_mark == 1 - && bfd_is_abs_section (h->root.u.def.section) - && h->root.u.def.value > sec->size) - { - relocation = h->root.u.def.value + - h->root.u.def.section->output_section->vma + - h->root.u.def.section->output_offset; - relocation += irel->r_addend; - insn = insn_with_reg - | ((relocation >> 1) & 0xffffff); - snprintf (code, sizeof (code), "%08x", insn); - if (strcmp (code, ex9_insn->string) == 0) - { - do_replace = 1; - save_irel = 1; - } - } - } - } - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN - || ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END - || ELF32_R_TYPE (irel->r_info) == R_NDS32_NONE) - { - /* These relocations do not have to relocate contens, so it can - be regard as instruction without relocation. */ - if (insn == it_insn && ex9_insn->irel == NULL) - do_replace = 1; - } - } - else - { - /* Instruction without relocation, we only - have to compare their byte code. */ - if (insn == it_insn && ex9_insn->irel == NULL) - do_replace = 1; - } - - /* Insntruction match so replacing the code here. */ - if (do_replace == 1) - { - /* There are two formats of ex9 instruction. */ - if (ex9_insn->order < 32) - insn_ex9 = INSN_EX9_IT_2; - else - insn_ex9 = INSN_EX9_IT_1; - insn16 = insn_ex9 | ex9_insn->order; - - /* Insert ex9 instruction. */ - nds32_elf_ex9_push_insn (pre_insn16, contents, pre_off, - &relax_blank_list, pre_irel_ptr, - &irel_list); - pre_off = off; - pre_insn16 = insn16; - - if (save_irel) - { - /* For instuction with relocation do relax. */ - irel_ptr = (struct elf_nds32_irel_entry *) - bfd_malloc (sizeof (struct elf_nds32_irel_entry)); - irel_ptr->irel = irel; - irel_ptr->next = NULL; - pre_irel_ptr = irel_ptr; - } - else - pre_irel_ptr = NULL; - break; - } - ex9_insn = ex9_insn->next; - } - off += 4; - } - - /* Insert ex9 instruction. */ - nds32_elf_ex9_push_insn (pre_insn16, contents, pre_off, - &relax_blank_list, pre_irel_ptr, - &irel_list); - - /* Delete the redundant code. */ - if (relax_blank_list) - { - nds32_elf_relax_delete_blanks (abfd, sec, relax_blank_list); - relax_blank_list = NULL; - } - - /* Clear the relocation that is replaced by ex9. */ - while (irel_list) - { - struct elf_nds32_irel_entry *irel_ptr; - - irel_ptr = irel_list; - irel_list = irel_ptr->next; - irel_ptr->irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), R_NDS32_TRAN); - free (irel_ptr); - } - return TRUE; -} - -/* Initialize ex9 hash table. */ - -int -nds32_elf_ex9_init (void) -{ - if (!bfd_hash_table_init_n (&ex9_code_table, nds32_elf_code_hash_newfunc, - sizeof (struct elf_nds32_code_hash_entry), - 1023)) - { - _bfd_error_handler (_("cannot init ex9 hash table error")); - return FALSE; - } - return TRUE; -} - -/* Predict how many bytes will be relaxed with ex9 and ifc. */ - -static void -nds32_elf_ex9_total_relax (struct bfd_link_info *info) -{ - struct elf_nds32_insn_times_entry *ex9_insn; - struct elf_nds32_insn_times_entry *temp; - int target_optimize; - struct elf_nds32_link_hash_table *table; - - if (ex9_insn_head == NULL) - return; - - table = nds32_elf_hash_table (info); - target_optimize = table->target_optimize; - ex9_insn = ex9_insn_head; - while (ex9_insn) - { - ex9_relax_size = ex9_insn->times * 2 + ex9_relax_size; - temp = ex9_insn; - ex9_insn = ex9_insn->next; - free (temp); - } - ex9_insn_head = NULL; - - if ((target_optimize & NDS32_RELAX_JUMP_IFC_ON)) - { - /* Examine ifc reduce size. */ - struct elf_nds32_ifc_symbol_entry *ifc_ent = ifc_symbol_head; - struct elf_nds32_ifc_irel_list *irel_ptr = NULL; - int size = 0; - - while (ifc_ent) - { - if (ifc_ent->enable == 0) - { - /* Not ifc yet. */ - irel_ptr = ifc_ent->irel_head; - while (irel_ptr) - { - size += 2; - irel_ptr = irel_ptr->next; - } - } - size -= 2; - ifc_ent = ifc_ent->next; - } - ex9_relax_size += size; - } -} - -/* Finish ex9 table. */ - -void -nds32_elf_ex9_finish (struct bfd_link_info *link_info) -{ - nds32_elf_code_hash_traverse (nds32_elf_examine_insn_times); - nds32_elf_order_insn_times (link_info); - nds32_elf_ex9_total_relax (link_info); - /* Traverse the hash table and count its times. */ - nds32_elf_code_hash_traverse (nds32_elf_count_insn_times); - nds32_elf_order_insn_times (link_info); - nds32_elf_ex9_build_itable (link_info); -} - -/* Relocate the entries in ex9 table. */ - -static bfd_vma -nds32_elf_ex9_reloc_insn (struct elf_nds32_insn_times_entry *ptr, - struct bfd_link_info *link_info) -{ - Elf_Internal_Sym *isym = NULL; - bfd_vma relocation = -1; - struct elf_link_hash_entry *h; - - if (ptr->m_list != NULL) - { - /* Global symbol. */ - h = ptr->m_list->h_list->h; - if ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->root.u.def.section != NULL - && h->root.u.def.section->output_section != NULL) - { - - relocation = h->root.u.def.value + - h->root.u.def.section->output_section->vma + - h->root.u.def.section->output_offset; - relocation += ptr->m_list->irel->r_addend; - } - else - relocation = 0; - } - else if (ptr->sec !=NULL) - { - /* Local symbol. */ - Elf_Internal_Sym sym; - asection *sec = NULL; - asection isec; - asection *isec_ptr = &isec; - Elf_Internal_Rela irel_backup = *(ptr->irel); - asection *sec_backup = ptr->sec; - bfd *abfd = ptr->sec->owner; - - if (!nds32_get_local_syms (abfd, sec, &isym)) - return FALSE; - isym = isym + ELF32_R_SYM (ptr->irel->r_info); - - sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (sec != NULL) - *isec_ptr = *sec; - sym = *isym; - - /* The purpose is same as elf_link_input_bfd. */ - if (isec_ptr != NULL - && isec_ptr->sec_info_type == SEC_INFO_TYPE_MERGE - && ELF_ST_TYPE (isym->st_info) != STT_SECTION) - { - sym.st_value = - _bfd_merged_section_offset (ptr->sec->output_section->owner, &isec_ptr, - elf_section_data (isec_ptr)->sec_info, - isym->st_value); - } - relocation = _bfd_elf_rela_local_sym (link_info->output_bfd, &sym, - &ptr->sec, ptr->irel); - if (ptr->irel != NULL) - relocation += ptr->irel->r_addend; - - /* Restore origin value since there may be some insntructions that - could not be replaced with ex9.it. */ - *(ptr->irel) = irel_backup; - ptr->sec = sec_backup; - } - - return relocation; -} - -/* Import ex9 table and build list. */ - -void -nds32_elf_ex9_import_table (struct bfd_link_info *info) -{ - int num = 0; - bfd_byte *contents; - FILE *ex9_import_file; - int update_ex9_table; - struct elf_nds32_link_hash_table *table; - - table = nds32_elf_hash_table (info); - ex9_import_file = table->ex9_import_file; - rewind (table->ex9_import_file); - - contents = bfd_malloc (sizeof (bfd_byte) * 4); - - /* Read instructions from the input file and build the list. */ - while (!feof (ex9_import_file)) - { - unsigned long insn; - char *code; - struct elf_nds32_insn_times_entry *ptr; - size_t nread; - - nread = fread (contents, sizeof (bfd_byte) * 4, 1, ex9_import_file); - /* Ignore the final byte 0x0a. */ - if (nread < 1) - break; - insn = bfd_getb32 (contents); - code = bfd_malloc (sizeof (char) * 9); - snprintf (code, 9, "%08lx", (insn & 0xffffffff)); - ptr = bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); - ptr->string = code; - ptr->order = num; - ptr->times = -1; - ptr->sec = NULL; - ptr->m_list = NULL; - ptr->rel_backup.r_offset = 0; - ptr->rel_backup.r_info = 0; - ptr->rel_backup.r_addend = 0; - ptr->irel = NULL; - ptr->next = NULL; - nds32_elf_ex9_insert_entry (ptr); - num++; - } - - update_ex9_table = table->update_ex9_table; - if (update_ex9_table == 1) - { - /* It has to consider of sethi need to use multiple page - but it not be done yet. */ - nds32_elf_code_hash_traverse (nds32_elf_examine_insn_times); - nds32_elf_order_insn_times (info); - } -} - -/* Export ex9 table. */ - -static void -nds32_elf_ex9_export (struct bfd_link_info *info, - bfd_byte *contents, int size) -{ - FILE *ex9_export_file; - struct elf_nds32_link_hash_table *table; - - table = nds32_elf_hash_table (info); - ex9_export_file = table->ex9_export_file; - fwrite (contents, sizeof (bfd_byte), size, ex9_export_file); - fclose (ex9_export_file); -} - -/* Adjust relocations of J and JAL in ex9.itable. - Export ex9 table. */ - -static void -nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info) -{ - asection *table_sec = NULL; - struct elf_nds32_insn_times_entry *ex9_insn = ex9_insn_head; - struct elf_nds32_insn_times_entry *temp_ptr, *temp_ptr2; - bfd *it_abfd; - uint32_t insn, insn_with_reg, source_insn; - bfd_byte *contents = NULL, *source_contents = NULL; - int size = 0; - bfd_vma gp; - int shift, update_ex9_table, offset = 0; - reloc_howto_type *howto = NULL; - Elf_Internal_Rela rel_backup; - unsigned short insn_ex9; - struct elf_nds32_link_hash_table *table; - FILE *ex9_export_file; - static bfd_boolean done = FALSE; - - if (done) - return; - - done = TRUE; - - table = nds32_elf_hash_table (link_info); - if (table) - table->relax_status |= NDS32_RELAX_EX9_DONE; - - - update_ex9_table = table->update_ex9_table; - /* Generated ex9.itable exactly. */ - if (update_ex9_table == 0) - { - for (it_abfd = link_info->input_bfds; it_abfd != NULL; - it_abfd = it_abfd->link.next) - { - table_sec = bfd_get_section_by_name (it_abfd, ".ex9.itable"); - if (table_sec != NULL) - break; - } - - if (table_sec != NULL) - { - bfd *output_bfd; - - output_bfd = table_sec->output_section->owner; - nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE); - if (table_sec->size == 0) - return; - - if (!nds32_get_section_contents (it_abfd, table_sec, &contents, TRUE)) - return; - } - } - else - { - /* Set gp. */ - bfd *output_bfd; - - output_bfd = link_info->input_bfds->sections->output_section->owner; - nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE); - contents = bfd_malloc (sizeof (bfd_byte) * 2048); - } - - /* Relocate instruction. */ - while (ex9_insn) - { - bfd_vma relocation, min_relocation = 0xffffffff; - - insn = strtol (ex9_insn->string, NULL, 16); - insn_with_reg = 0; - if (ex9_insn->m_list != NULL || ex9_insn->sec != NULL) - { - if (ex9_insn->m_list) - rel_backup = ex9_insn->m_list->rel_backup; - else - rel_backup = ex9_insn->rel_backup; - - nds32_elf_get_insn_with_reg (&rel_backup, insn, &insn_with_reg); - howto = - bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE - (rel_backup.r_info)); - shift = howto->rightshift; - if (ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_25_PCREL_RELA - || ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_LO12S0_ORI_RELA - || ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_LO12S0_RELA - || ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_LO12S1_RELA - || ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_LO12S2_RELA) - { - relocation = nds32_elf_ex9_reloc_insn (ex9_insn, link_info); - insn = - insn_with_reg | ((relocation >> shift) & - nds32_elf_irel_mask (&rel_backup)); - bfd_putb32 (insn, contents + (ex9_insn->order) * 4); - } - else if ((ELF32_R_TYPE (rel_backup.r_info) >= R_NDS32_SDA15S3 - && ELF32_R_TYPE (rel_backup.r_info) <= R_NDS32_SDA15S0) - || (ELF32_R_TYPE (rel_backup.r_info) >= R_NDS32_SDA15S3_RELA - && ELF32_R_TYPE (rel_backup.r_info) <= R_NDS32_SDA15S0_RELA) - || (ELF32_R_TYPE (rel_backup.r_info) >= R_NDS32_SDA12S2_DP_RELA - && ELF32_R_TYPE (rel_backup.r_info) <= R_NDS32_SDA12S2_SP_RELA) - || (ELF32_R_TYPE (rel_backup.r_info) >= R_NDS32_SDA16S3_RELA - && ELF32_R_TYPE (rel_backup.r_info) <= R_NDS32_SDA19S0_RELA)) - { - relocation = nds32_elf_ex9_reloc_insn (ex9_insn, link_info); - insn = - insn_with_reg | (((relocation - gp) >> shift) & - nds32_elf_irel_mask (&rel_backup)); - bfd_putb32 (insn, contents + (ex9_insn->order) * 4); - } - else if (ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_HI20_RELA) - { - /* Sethi may be multiple entry for one insn. */ - if (ex9_insn->next && ex9_insn->m_list - && ex9_insn->m_list == ex9_insn->next->m_list) - { - struct elf_link_hash_entry_mul_list *m_list; - struct elf_nds32_ex9_refix *fix_ptr; - struct elf_link_hash_entry *h; - - temp_ptr = ex9_insn; - temp_ptr2 = ex9_insn; - m_list = ex9_insn->m_list; - while (m_list) - { - h = m_list->h_list->h; - relocation = h->root.u.def.value + - h->root.u.def.section->output_section->vma + - h->root.u.def.section->output_offset; - relocation += m_list->irel->r_addend; - - if (relocation < min_relocation) - min_relocation = relocation; - m_list = m_list->next; - } - relocation = min_relocation; - - /* Put insntruction into ex9 table. */ - insn = insn_with_reg - | ((relocation >> shift) & nds32_elf_irel_mask (&rel_backup)); - bfd_putb32 (insn, contents + (ex9_insn->order) * 4); - relocation = relocation + 0x1000; /* hi20 */ - - while (ex9_insn->next && ex9_insn->m_list - && ex9_insn->m_list == ex9_insn->next->m_list) - { - /* Multiple sethi. */ - ex9_insn = ex9_insn->next; - size += 4; - insn = - insn_with_reg | ((relocation >> shift) & - nds32_elf_irel_mask (&rel_backup)); - bfd_putb32 (insn, contents + (ex9_insn->order) * 4); - relocation = relocation + 0x1000; /* hi20 */ - } - - fix_ptr = ex9_refix_head; - while (fix_ptr) - { - /* Fix ex9 insn. */ - /* temp_ptr2 points to the head of multiple sethi. */ - temp_ptr = temp_ptr2; - while (fix_ptr->order != temp_ptr->order && fix_ptr->next) - { - fix_ptr = fix_ptr->next; - } - if (fix_ptr->order != temp_ptr->order) - break; - - /* Set source insn. */ - relocation = - fix_ptr->h->root.u.def.value + - fix_ptr->h->root.u.def.section->output_section->vma + - fix_ptr->h->root.u.def.section->output_offset; - relocation += fix_ptr->irel->r_addend; - /* sethi imm is imm20s. */ - source_insn = insn_with_reg | ((relocation >> shift) & 0xfffff); - - while (temp_ptr) - { - /* Match entry and source code. */ - insn = bfd_getb32 (contents + (temp_ptr->order) * 4 + offset); - if (insn == source_insn) - { - /* Fix the ex9 insn. */ - if (temp_ptr->order != fix_ptr->order) - { - if (!nds32_get_section_contents - (fix_ptr->sec->owner, fix_ptr->sec, - &source_contents, TRUE)) - _bfd_error_handler - (_("error: cannot fix ex9 relocation")); - if (temp_ptr->order < 32) - insn_ex9 = INSN_EX9_IT_2; - else - insn_ex9 = INSN_EX9_IT_1; - insn_ex9 = insn_ex9 | temp_ptr->order; - bfd_putb16 (insn_ex9, source_contents + fix_ptr->irel->r_offset); - } - break; - } - else - { - if (!temp_ptr->next || temp_ptr->m_list != temp_ptr->next->m_list) - _bfd_error_handler - (_("Linker: error cannot fixed ex9 relocation \n")); - else - temp_ptr = temp_ptr->next; - } - } - fix_ptr = fix_ptr->next; - } - } - else - { - relocation = nds32_elf_ex9_reloc_insn (ex9_insn, link_info); - insn = insn_with_reg - | ((relocation >> shift) & nds32_elf_irel_mask (&rel_backup)); - bfd_putb32 (insn, contents + (ex9_insn->order) * 4); - } - } - } - else - { - /* Insn without relocation does not have to be fixed - if need to update export table. */ - if (update_ex9_table == 1) - bfd_putb32 (insn, contents + (ex9_insn->order) * 4); - } - ex9_insn = ex9_insn->next; - size += 4; - } - - ex9_export_file = table->ex9_export_file; - if (ex9_export_file != NULL) - nds32_elf_ex9_export (link_info, contents, table_sec->size); - else if (update_ex9_table == 1) - { - table->ex9_export_file = table->ex9_import_file; - rewind (table->ex9_export_file); - nds32_elf_ex9_export (link_info, contents, size); - } -} - -/* Generate ex9 hash table. */ - -static bfd_boolean -nds32_elf_ex9_build_hash_table (bfd *abfd, asection *sec, - struct bfd_link_info *link_info) -{ - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irelend; - Elf_Internal_Rela *irel; - Elf_Internal_Rela *jrel; - Elf_Internal_Rela rel_backup; - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym *isym = NULL; - asection *isec; - struct elf_link_hash_entry **sym_hashes; - bfd_byte *contents = NULL; - bfd_vma off = 0; - unsigned long r_symndx; - uint32_t insn, insn_with_reg; - struct elf_link_hash_entry *h; - int data_flag, shift, align; - bfd_vma relocation; - /* Suppress ex9 if `.no_relax ex9' or inner loop. */ - reloc_howto_type *howto = NULL; - - sym_hashes = elf_sym_hashes (abfd); - /* Load section instructions, relocations, and symbol table. */ - if (!nds32_get_section_contents (abfd, sec, &contents, TRUE)) - return FALSE; - - internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, - TRUE /* keep_memory */); - irelend = internal_relocs + sec->reloc_count; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - if (!nds32_get_local_syms (abfd, sec, &isym)) - return FALSE; - - /* Check the object if enable ex9. */ - irel = find_relocs_at_address (internal_relocs, internal_relocs, irelend, - R_NDS32_RELAX_ENTRY); - - /* Check this section trigger ex9 relaxation. */ - if (irel == NULL - || irel >= irelend - || ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_ENTRY - || (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY - && !(irel->r_addend & R_NDS32_RELAX_ENTRY_EX9_FLAG))) - return TRUE; - - irel = internal_relocs; - - /* Push each insn into hash table. */ - while (off < sec->size) - { - char code[10]; - struct elf_nds32_code_hash_entry *entry; - - while (irel != NULL && irel < irelend && irel->r_offset < off) - irel++; - - data_flag = nds32_elf_ex9_relocation_check (link_info, &irel, irelend, - NULL, sec, &off, contents); - if (data_flag & DATA_EXIST) - { - /* We save the move offset in the highest byte. */ - off += (data_flag >> 24); - continue; - } - - if (*(contents + off) & 0x80) - { - off += 2; - } - else - { - h = NULL; - isec = NULL; - jrel = NULL; - rel_backup.r_info = 0; - rel_backup.r_offset = 0; - rel_backup.r_addend = 0; - /* Load the instruction and its opcode with register for comparing. */ - insn = bfd_getb32 (contents + off); - insn_with_reg = 0; - if (irel != NULL && irel < irelend && irel->r_offset == off) - { - nds32_elf_get_insn_with_reg (irel, insn, &insn_with_reg); - howto = bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE (irel->r_info)); - shift = howto->rightshift; - align = (1 << shift) - 1; - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_25_PCREL_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_HI20_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S0_ORI_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S0_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S1_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_RELA - ||(ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3 - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0) - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3_RELA - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0_RELA) - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA12S2_DP_RELA - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA12S2_SP_RELA) - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA16S3_RELA - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA19S0_RELA)) - { - r_symndx = ELF32_R_SYM (irel->r_info); - jrel = irel; - rel_backup = *irel; - if (r_symndx < symtab_hdr->sh_info) - { - /* Local symbol. */ - int shndx = isym[r_symndx].st_shndx; - - bfd_vma st_value = (isym + r_symndx)->st_value; - isec = elf_elfsections (abfd)[shndx]->bfd_section; - relocation = (isec->output_section->vma + isec->output_offset - + st_value + irel->r_addend); - } - else - { - /* External symbol. */ - bfd_boolean warned ATTRIBUTE_UNUSED; - bfd_boolean ignored ATTRIBUTE_UNUSED; - bfd_boolean unresolved_reloc ATTRIBUTE_UNUSED; - asection *sym_sec; - - /* Maybe there is a better way to get h and relocation */ - RELOC_FOR_GLOBAL_SYMBOL (link_info, abfd, sec, irel, - r_symndx, symtab_hdr, sym_hashes, - h, sym_sec, relocation, - unresolved_reloc, warned, ignored); - relocation += irel->r_addend; - if ((h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - || strcmp (h->root.root.string, "_FP_BASE_") == 0) - { - off += 4; - continue; - } - } - - /* Check for gp relative instruction alignment. */ - if ((ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3 - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0) - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3_RELA - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0_RELA) - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA12S2_DP_RELA - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA12S2_SP_RELA) - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA16S3_RELA - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA19S0_RELA)) - { - bfd_vma gp; - bfd *output_bfd = sec->output_section->owner; - bfd_reloc_status_type r; - - /* If the symbol is in the abs section, the out_bfd will be null. - This happens when the relocation has a symbol@GOTOFF. */ - r = nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE); - if (r != bfd_reloc_ok) - { - off += 4; - continue; - } - - relocation -= gp; - - /* Make sure alignment is correct. */ - if (relocation & align) - { - /* Incorrect alignment. */ - _bfd_error_handler - /* xgettext:c-format */ - (_("%pB: warning: unaligned small data access " - "for entry: {%" PRId64 ", %" PRId64 ", %" PRId64 - "}, addr = %#" PRIx64 ", align = %#x"), - abfd, (int64_t) irel->r_offset, - (int64_t) irel->r_info, (int64_t) irel->r_addend, - (uint64_t) relocation, align); - off += 4; - continue; - } - } - - insn = insn_with_reg - | ((relocation >> shift) & nds32_elf_irel_mask (irel)); - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN - || ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END - || ELF32_R_TYPE (irel->r_info) == R_NDS32_NONE) - { - /* These relocations do not have to relocate contens, so it can - be regard as instruction without relocation. */ - } - else - { - off += 4; - continue; - } - } - - snprintf (code, sizeof (code), "%08x", insn); - /* Copy "code". */ - entry = (struct elf_nds32_code_hash_entry*) - bfd_hash_lookup (&ex9_code_table, code, TRUE, TRUE); - if (entry == NULL) - { - _bfd_error_handler - (_("failed creating ex9.it %s hash table entry"), code); - return FALSE; - } - if (h) - { - if (h->root.type == bfd_link_hash_undefined) - return TRUE; - /* Global symbol. */ - /* In order to do sethi with different symbol but same value. */ - if (entry->m_list == NULL) - { - struct elf_link_hash_entry_mul_list *m_list_new; - struct elf_link_hash_entry_list *h_list_new; - - m_list_new = (struct elf_link_hash_entry_mul_list *) - bfd_malloc (sizeof (struct elf_link_hash_entry_mul_list)); - h_list_new = (struct elf_link_hash_entry_list *) - bfd_malloc (sizeof (struct elf_link_hash_entry_list)); - entry->m_list = m_list_new; - m_list_new->h_list = h_list_new; - m_list_new->rel_backup = rel_backup; - m_list_new->times = 1; - m_list_new->irel = jrel; - m_list_new->next = NULL; - h_list_new->h = h; - h_list_new->next = NULL; - } - else - { - struct elf_link_hash_entry_mul_list *m_list = entry->m_list; - struct elf_link_hash_entry_list *h_list; - - while (m_list) - { - /* Build the different symbols that point to the same address. */ - h_list = m_list->h_list; - if (h_list->h->root.u.def.value == h->root.u.def.value - && h_list->h->root.u.def.section->output_section->vma - == h->root.u.def.section->output_section->vma - && h_list->h->root.u.def.section->output_offset - == h->root.u.def.section->output_offset - && m_list->rel_backup.r_addend == rel_backup.r_addend) - { - m_list->times++; - m_list->irel = jrel; - while (h_list->h != h && h_list->next) - h_list = h_list->next; - if (h_list->h != h) - { - struct elf_link_hash_entry_list *h_list_new; - - h_list_new = (struct elf_link_hash_entry_list *) - bfd_malloc (sizeof (struct elf_link_hash_entry_list)); - h_list->next = h_list_new; - h_list_new->h = h; - h_list_new->next = NULL; - } - break; - } - /* The sethi case may have different address but the - hi20 is the same. */ - else if (ELF32_R_TYPE (jrel->r_info) == R_NDS32_HI20_RELA - && m_list->next == NULL) - { - struct elf_link_hash_entry_mul_list *m_list_new; - struct elf_link_hash_entry_list *h_list_new; - - m_list_new = (struct elf_link_hash_entry_mul_list *) - bfd_malloc (sizeof (struct elf_link_hash_entry_mul_list)); - h_list_new = (struct elf_link_hash_entry_list *) - bfd_malloc (sizeof (struct elf_link_hash_entry_list)); - m_list->next = m_list_new; - m_list_new->h_list = h_list_new; - m_list_new->rel_backup = rel_backup; - m_list_new->times = 1; - m_list_new->irel = jrel; - m_list_new->next = NULL; - h_list_new->h = h; - h_list_new->next = NULL; - break; - } - m_list = m_list->next; - } - if (!m_list) - { - off += 4; - continue; - } - } - } - else - { - /* Local symbol and insn without relocation*/ - entry->times++; - entry->rel_backup = rel_backup; - } - - /* Use in sethi insn with constant and global symbol in same format. */ - if (!jrel) - entry->const_insn = 1; - else - entry->irel = jrel; - entry->sec = isec; - off += 4; - } - } - return TRUE; -} - -/* Set the _ITB_BASE, and point it to ex9 table. */ - -bfd_boolean -nds32_elf_ex9_itb_base (struct bfd_link_info *link_info) -{ - bfd *abfd; - asection *sec; - bfd *output_bfd = NULL; - struct bfd_link_hash_entry *bh = NULL; - - if (is_ITB_BASE_set == 1) - return TRUE; - - is_ITB_BASE_set = 1; - - bh = bfd_link_hash_lookup (link_info->hash, "_ITB_BASE_", FALSE, FALSE, TRUE); - - if (bh && (bh->type == bfd_link_hash_defined - || bh->type == bfd_link_hash_defweak)) - return TRUE; - - for (abfd = link_info->input_bfds; abfd != NULL; - abfd = abfd->link.next) - { - sec = bfd_get_section_by_name (abfd, ".ex9.itable"); - if (sec != NULL) - { - output_bfd = sec->output_section->owner; - break; - } - } - if (output_bfd == NULL) - { - output_bfd = link_info->output_bfd; - if (output_bfd->sections == NULL) - return TRUE; - else - sec = bfd_abs_section_ptr; - } - bh = bfd_link_hash_lookup (link_info->hash, "_ITB_BASE_", - FALSE, FALSE, TRUE); - return (_bfd_generic_link_add_one_symbol - (link_info, output_bfd, "_ITB_BASE_", - BSF_GLOBAL | BSF_WEAK, sec, 0, - (const char *) NULL, FALSE, get_elf_backend_data - (output_bfd)->collect, &bh)); -} /* End EX9.IT */ - #define ELF_ARCH bfd_arch_nds32 #define ELF_MACHINE_CODE EM_NDS32 diff --git a/ld/ChangeLog b/ld/ChangeLog index e74f722..ab27208 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,8 @@ +2018-03-15 Kuan-Lin Chen <kuanlinchentw@gmail.com> + + * emultempl/nds32elf.em (nds32_elf_after_allocation): Remove + unsupported target feature. + 2018-03-14 H.J. Lu <hongjiu.lu@intel.com> PR ld/20882 diff --git a/ld/emultempl/nds32elf.em b/ld/emultempl/nds32elf.em index 3ea0ea2..eb29d04 100644 --- a/ld/emultempl/nds32elf.em +++ b/ld/emultempl/nds32elf.em @@ -191,14 +191,6 @@ nds32_elf_after_open (void) static void nds32_elf_after_allocation (void) { - if (target_optimize & NDS32_RELAX_EX9_ON - || (ex9_import_file != NULL && update_ex9_table == 1)) - { - /* Initialize ex9 hash table. */ - if (!nds32_elf_ex9_init ()) - return; - } - /* Call default after allocation callback. 1. This is where relaxation is done. 2. It calls gld${EMULATION_NAME}_map_segments to build ELF segment table. |