(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,
/* 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[] =
#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
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. */
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)
/* Target dependnet option. */
struct elf_nds32_link_hash_table *table;
int load_store_relax;
- int relax_round;
relax_blank_list = NULL;
/* 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. */
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,
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;
}
}
- nds32_elf_pick_relax (FALSE, sec, again, table, link_info);
-
if (!*again)
{
if (!nds32_relax_adjust_label (abfd, sec, internal_relocs, contents,
return NULL;
}
\f
-/* 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. */
-\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 (_("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 */
-\f
#define ELF_ARCH bfd_arch_nds32
#define ELF_MACHINE_CODE EM_NDS32