- 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. */
-\f
-/* 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 (_("Linker: cannot init ex9 hash table error \n"));
- 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);