From 1c8f6a4d1fcca9e56ac705a224778bf690122a07 Mon Sep 17 00:00:00 2001 From: Kuan-Lin Chen Date: Thu, 11 Sep 2014 14:25:05 +0800 Subject: [PATCH] NDS32: Code refactoring of relaxation. Refactor each relaxation pattern to raise the maintainability. In origin, all patterns is analysed in nds32_elf_relax_section, so it is hard to debug and maintain. Therefore, we classify all patterns into different functions in this patch. Moreover, we adjust all optimizations into nds32_elf_relax_section to take these optimizations in turn. This can promise all relaxation being done after calling gld${EMULATION_NAME}_after_allocation. --- bfd/ChangeLog | 32 + bfd/bfd-in2.h | 27 + bfd/elf32-nds32.c | 6868 +++++++++++++++++++++++--------------- bfd/elf32-nds32.h | 40 +- bfd/libbfd.h | 21 + bfd/reloc.c | 52 +- gas/ChangeLog | 17 + gas/config/tc-nds32.c | 3228 +++++++++++------- gas/config/tc-nds32.h | 51 +- include/elf/ChangeLog | 4 + include/elf/nds32.h | 31 +- ld/ChangeLog | 7 + ld/emultempl/nds32elf.em | 132 +- 13 files changed, 6375 insertions(+), 4135 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 3fea46ed4eb..fcfdeadee1f 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,35 @@ +2014-09-16 Kuan-Lin Chen + + * bfd-in2.h: Regenerate. + * elf32-nds32.c (nds32_elf_mkobject): Hook bfd_elf32_mkobject. + (nds32_elf_relax_section): Code refactoring. + (nds32_elf_relax_longcall1, nds32_elf_relax_longcall2, + nds32_elf_relax_longcall3, nds32_elf_relax_longcall4, + nds32_elf_relax_longcall5, nds32_elf_relax_longcall6): Relax call + pattern. The first three is moved from nds32_elf_relax_section, + and the last three is new function. + (nds32_elf_relax_longjump1, nds32_elf_relax_longjump2, + nds32_elf_relax_longjump3, nds32_elf_relax_longjump4, + nds32_elf_relax_longjump5, nds32_elf_relax_longjump6, + nds32_elf_relax_longjump7): Relax condition branch pattern. The first + three is moved from nds32_elf_relax_section, and the last four + is new function. + (nds32_elf_relax_loadstore, nds32_elf_relax_lo12): Relax load-store + pattern and address setting pattern. + (nds32_elf_relax_piclo12, nds32_elf_relax_ptr, + nds32_elf_relax_pltgot_suff, nds32_elf_relax_got_suff, + nds32_elf_relax_gotoff_suff): Relax pic pattern. + (nds32_elf_relax_letlslo12, nds32_elf_relax_letlsadd, + nds32_elf_relax_letlsls): Relax TLS pattern. + (nds32_relax_adjust_label): Adjust alignment and nop. + (nds32_elf_pick_relax): Choose relaxation optimization. + (nds32_elf_get_relocated_section_contents): New hook. + (nds32_elf_order_insn_times, nds32_elf_ex9_build_itable): Release ex9 + table 234th entry. + * elf32-nds32.h: Declare. + * libbfd.h: Regenerate. + * reloc.c: Add nds32 new relocations. + 2014-09-15 Chen Gang * dwarf2.c (find_abstract_instance_name): Use 'form' instead of diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 1f1aed521a8..a40a14a1526 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -3956,6 +3956,13 @@ and shift left by 0 for use in lbi.gp, sbi.gp... */ BFD_RELOC_NDS32_15_FIXED, BFD_RELOC_NDS32_17_FIXED, BFD_RELOC_NDS32_25_FIXED, + BFD_RELOC_NDS32_LONGCALL4, + BFD_RELOC_NDS32_LONGCALL5, + BFD_RELOC_NDS32_LONGCALL6, + BFD_RELOC_NDS32_LONGJUMP4, + BFD_RELOC_NDS32_LONGJUMP5, + BFD_RELOC_NDS32_LONGJUMP6, + BFD_RELOC_NDS32_LONGJUMP7, /* for PIC */ BFD_RELOC_NDS32_PLTREL_HI20, @@ -4016,12 +4023,32 @@ This is a 5 bit absolute address. */ BFD_RELOC_NDS32_DIFF16, BFD_RELOC_NDS32_DIFF32, BFD_RELOC_NDS32_DIFF_ULEB128, + BFD_RELOC_NDS32_EMPTY, + +/* This is a 25 bit absolute address. */ BFD_RELOC_NDS32_25_ABS, + +/* For ex9 and ifc using. */ BFD_RELOC_NDS32_DATA, BFD_RELOC_NDS32_TRAN, BFD_RELOC_NDS32_17IFC_PCREL, BFD_RELOC_NDS32_10IFCU_PCREL, +/* For TLS. */ + BFD_RELOC_NDS32_TPOFF, + BFD_RELOC_NDS32_TLS_LE_HI20, + BFD_RELOC_NDS32_TLS_LE_LO12, + BFD_RELOC_NDS32_TLS_LE_ADD, + BFD_RELOC_NDS32_TLS_LE_LS, + BFD_RELOC_NDS32_GOTTPOFF, + BFD_RELOC_NDS32_TLS_IE_HI20, + BFD_RELOC_NDS32_TLS_IE_LO12S2, + BFD_RELOC_NDS32_TLS_TPOFF, + BFD_RELOC_NDS32_TLS_LE_20, + BFD_RELOC_NDS32_TLS_LE_15S0, + BFD_RELOC_NDS32_TLS_LE_15S1, + BFD_RELOC_NDS32_TLS_LE_15S2, + /* This is a 9-bit reloc */ BFD_RELOC_V850_9_PCREL, diff --git a/bfd/elf32-nds32.c b/bfd/elf32-nds32.c index d1a2c3035cd..4a0fad2d13f 100644 --- a/bfd/elf32-nds32.c +++ b/bfd/elf32-nds32.c @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA.*/ + 02110-1301, USA. */ #include "sysdep.h" @@ -97,6 +97,7 @@ static bfd_boolean nds32_elf_finish_dynamic_sections static bfd_boolean nds32_elf_finish_dynamic_symbol (bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, Elf_Internal_Sym *); +static bfd_boolean nds32_elf_mkobject (bfd *); /* Nds32 helper functions. */ static bfd_reloc_status_type nds32_elf_final_sda_base @@ -111,15 +112,21 @@ static bfd_vma calculate_memory_address static int nds32_get_section_contents (bfd *, asection *, bfd_byte **); 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 *, unsigned long, unsigned long *); + (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, @@ -127,6 +134,13 @@ static bfd_boolean nds32_relax_fp_as_gp static bfd_boolean nds32_fag_remove_unused_fpbase (bfd *abfd, asection *sec, Elf_Internal_Rela *internal_relocs, Elf_Internal_Rela *irelend); +static bfd_byte * +nds32_elf_get_relocated_section_contents (bfd *abfd, + struct bfd_link_info *link_info, + struct bfd_link_order *link_order, + bfd_byte *data, + bfd_boolean relocatable, + asymbol **symbols); enum { @@ -181,13 +195,31 @@ enum #define PLT_PIC_ENTRY_WORD4 0x45000000 /* movi r16, sizeof(RELA) * n */ #define PLT_PIC_ENTRY_WORD5 0x48000000 /* j .plt0 */ +/* These are macros used to get the relocation accurate value. */ +#define ACCURATE_8BIT_S1 (0x100) +#define ACCURATE_U9BIT_S1 (0x400) +#define ACCURATE_12BIT_S1 (0x2000) +#define ACCURATE_14BIT_S1 (0x4000) +#define ACCURATE_19BIT (0x40000) + +/* These are macros used to get the relocation conservative value. */ +#define CONSERVATIVE_8BIT_S1 (0x100 - 4) +#define CONSERVATIVE_14BIT_S1 (0x4000 - 4) +#define CONSERVATIVE_16BIT_S1 (0x10000 - 4) +#define CONSERVATIVE_24BIT_S1 (0x1000000 - 4) +/* These must be more conservative because the address may be in + different segment. */ +#define CONSERVATIVE_15BIT (0x4000 - 0x1000) +#define CONSERVATIVE_15BIT_S1 (0x8000 - 0x1000) +#define CONSERVATIVE_15BIT_S2 (0x10000 - 0x1000) +#define CONSERVATIVE_19BIT (0x40000 - 0x1000) +#define CONSERVATIVE_20BIT (0x80000 - 0x1000) + /* 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; -static int relax_active = 0; - /* Convert ELF-VER in eflags to string for debugging purpose. */ static const char *const nds32_elfver_strtab[] = { @@ -243,6 +275,12 @@ struct elf_nds32_link_hash_entry /* Track dynamic relocs copied for this symbol. */ struct elf_nds32_dyn_relocs *dyn_relocs; + + /* For checking relocation type. */ +#define GOT_UNKNOWN 0 +#define GOT_NORMAL 1 +#define GOT_TLS_IE 2 + unsigned int tls_type; }; /* Get the nds32 ELF linker hash table from a link_info structure. */ @@ -251,6 +289,32 @@ struct elf_nds32_link_hash_entry 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 + +struct elf_nds32_obj_tdata +{ + struct elf_obj_tdata root; + + /* tls_type for each local got entry. */ + char *local_got_tls_type; +}; + +#define elf_nds32_tdata(bfd) \ + ((struct elf_nds32_obj_tdata *) (bfd)->tdata.any) + +#define elf32_nds32_local_got_tls_type(bfd) \ + (elf_nds32_tdata (bfd)->local_got_tls_type) + +#define elf32_nds32_hash_entry(ent) ((struct elf_nds32_link_hash_entry *)(ent)) + +static bfd_boolean +nds32_elf_mkobject (bfd *abfd) +{ + return bfd_elf_allocate_object (abfd, sizeof (struct elf_nds32_obj_tdata), + NDS32_ELF_DATA); +} + /* Relocations used for relocation. */ static reloc_howto_type nds32_elf_howto_table[] = { @@ -1704,6 +1768,234 @@ static reloc_howto_type nds32_elf_howto_table[] = 0x1ff, /* src_mask */ 0x1ff, /* dst_mask */ TRUE), /* pcrel_offset */ + + /* Like R_NDS32_HI20, but referring to the TLS entry for the symbol. */ + HOWTO (R_NDS32_TLS_LE_HI20, /* type */ + 12, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_TLS_LE_HI20", /* name */ + FALSE, /* partial_inplace */ + 0x000fffff, /* src_mask */ + 0x000fffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_TLS_LE_LO12, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_TLS_LE_LO12", /* name */ + FALSE, /* partial_inplace */ + 0x00000fff, /* src_mask */ + 0x00000fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Like R_NDS32_HI20, but referring to the TLS entry for the symbol. */ + HOWTO (R_NDS32_TLS_IE_HI20, /* type */ + 12, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_TLS_IE_HI20", /* name */ + FALSE, /* partial_inplace */ + 0x000fffff, /* src_mask */ + 0x000fffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_TLS_IE_LO12S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 10, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_TLS_IE_LO12S2", /* name */ + FALSE, /* partial_inplace */ + 0x000003ff, /* src_mask */ + 0x000003ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* Mark a TLS IE entry in GOT. */ + HOWTO (R_NDS32_TLS_TPOFF, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_TLS_TPOFF", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* A 20 bit address. */ + HOWTO (R_NDS32_TLS_LE_20, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_TLS_LE_20", /* name */ + FALSE, /* partial_inplace */ + 0xfffff, /* src_mask */ + 0xfffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_TLS_LE_15S0, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_TLS_LE_15S0", /* name */ + FALSE, /* partial_inplace */ + 0x7fff, /* src_mask */ + 0x7fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_TLS_LE_15S1, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_TLS_LE_15S1", /* name */ + FALSE, /* partial_inplace */ + 0x7fff, /* src_mask */ + 0x7fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_TLS_LE_15S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_NDS32_TLS_LE_15S2", /* name */ + FALSE, /* partial_inplace */ + 0x7fff, /* src_mask */ + 0x7fff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for unconditional call sequence */ + HOWTO (R_NDS32_LONGCALL4, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_LONGCALL4", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for conditional call sequence. */ + HOWTO (R_NDS32_LONGCALL5, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_LONGCALL5", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for conditional call sequence. */ + HOWTO (R_NDS32_LONGCALL6, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_LONGCALL6", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for unconditional branch sequence. */ + HOWTO (R_NDS32_LONGJUMP4, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_LONGJUMP4", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for conditional branch sequence. */ + HOWTO (R_NDS32_LONGJUMP5, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_LONGJUMP5", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for conditional branch sequence. */ + HOWTO (R_NDS32_LONGJUMP6, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_LONGJUMP6", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Relax hint for conditional branch sequence. */ + HOWTO (R_NDS32_LONGJUMP7, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_LONGJUMP7", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ }; /* Relocations used for relaxation. */ @@ -1956,6 +2248,45 @@ static reloc_howto_type nds32_elf_relax_howto_table[] = 0xffffffff, /* src_mask */ 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_TLS_LE_ADD, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_TLS_LE_ADD", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_TLS_LE_LS, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_TLS_LE_LS", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_NDS32_EMPTY, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + nds32_elf_ignore_reloc, /* special_function */ + "R_NDS32_EMPTY", /* name */ + FALSE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ }; @@ -1967,7 +2298,7 @@ nds32_insertion_sort (void *base, size_t nmemb, size_t size, int (*compar) (const void *lhs, const void *rhs)) { char *ptr = (char *) base; - unsigned int i, j; + int i, j; char *tmp = alloca (size); /* If i is less than j, i is inserted before j. @@ -1977,14 +2308,16 @@ nds32_insertion_sort (void *base, size_t nmemb, size_t size, sorted unsorted */ - for (i = 1; i < nmemb; i++) + for (i = 1; i < (int) nmemb; i++) { - for (j = 0; j < i; j++) - if (compar (ptr + i * size, ptr + j * size) < 0) + for (j = (i - 1); j >= 0; j--) + if (compar (ptr + i * size, ptr + j * size) >= 0) break; + j++; + if (i == j) - continue; /* j is in order. */ + continue; /* i is in order. */ memcpy (tmp, ptr + i * size, size); memmove (ptr + (j + 1) * size, ptr + j * size, (i - j) * size); @@ -2065,7 +2398,8 @@ nds32_elf_9_pcrel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, static bfd_reloc_status_type nds32_elf_do_9_pcrel_reloc (bfd *abfd, reloc_howto_type *howto, asection *input_section, bfd_byte *data, - bfd_vma offset, asection *symbol_section ATTRIBUTE_UNUSED, + bfd_vma offset, + asection *symbol_section ATTRIBUTE_UNUSED, bfd_vma symbol_value, bfd_vma addend) { bfd_signed_vma relocation; @@ -2084,7 +2418,7 @@ nds32_elf_do_9_pcrel_reloc (bfd *abfd, reloc_howto_type *howto, before doing pcrel calculations. */ relocation -= (offset & -(bfd_vma) 2); - if (relocation < -0x100 || relocation > 0xff) + if (relocation < -ACCURATE_8BIT_S1 || relocation >= ACCURATE_8BIT_S1) status = bfd_reloc_overflow; else status = bfd_reloc_ok; @@ -2495,9 +2829,16 @@ static const struct nds32_reloc_map_entry nds32_reloc_map[] = {BFD_RELOC_NDS32_LONGCALL1, R_NDS32_LONGCALL1}, {BFD_RELOC_NDS32_LONGCALL2, R_NDS32_LONGCALL2}, {BFD_RELOC_NDS32_LONGCALL3, R_NDS32_LONGCALL3}, + {BFD_RELOC_NDS32_LONGCALL4, R_NDS32_LONGCALL4}, + {BFD_RELOC_NDS32_LONGCALL5, R_NDS32_LONGCALL5}, + {BFD_RELOC_NDS32_LONGCALL6, R_NDS32_LONGCALL6}, {BFD_RELOC_NDS32_LONGJUMP1, R_NDS32_LONGJUMP1}, {BFD_RELOC_NDS32_LONGJUMP2, R_NDS32_LONGJUMP2}, {BFD_RELOC_NDS32_LONGJUMP3, R_NDS32_LONGJUMP3}, + {BFD_RELOC_NDS32_LONGJUMP4, R_NDS32_LONGJUMP4}, + {BFD_RELOC_NDS32_LONGJUMP5, R_NDS32_LONGJUMP5}, + {BFD_RELOC_NDS32_LONGJUMP6, R_NDS32_LONGJUMP6}, + {BFD_RELOC_NDS32_LONGJUMP7, R_NDS32_LONGJUMP7}, {BFD_RELOC_NDS32_LOADSTORE, R_NDS32_LOADSTORE}, {BFD_RELOC_NDS32_9_FIXED, R_NDS32_9_FIXED_RELA}, {BFD_RELOC_NDS32_15_FIXED, R_NDS32_15_FIXED_RELA}, @@ -2538,6 +2879,7 @@ static const struct nds32_reloc_map_entry nds32_reloc_map[] = {BFD_RELOC_NDS32_RELAX_REGION_END, R_NDS32_RELAX_REGION_END}, {BFD_RELOC_NDS32_MINUEND, R_NDS32_MINUEND}, {BFD_RELOC_NDS32_SUBTRAHEND, R_NDS32_SUBTRAHEND}, + {BFD_RELOC_NDS32_EMPTY, R_NDS32_EMPTY}, {BFD_RELOC_NDS32_DIFF8, R_NDS32_DIFF8}, {BFD_RELOC_NDS32_DIFF16, R_NDS32_DIFF16}, @@ -2548,6 +2890,17 @@ static const struct nds32_reloc_map_entry nds32_reloc_map[] = {BFD_RELOC_NDS32_TRAN, R_NDS32_TRAN}, {BFD_RELOC_NDS32_17IFC_PCREL, R_NDS32_17IFC_PCREL_RELA}, {BFD_RELOC_NDS32_10IFCU_PCREL, R_NDS32_10IFCU_PCREL_RELA}, + {BFD_RELOC_NDS32_TLS_LE_HI20, R_NDS32_TLS_LE_HI20}, + {BFD_RELOC_NDS32_TLS_LE_LO12, R_NDS32_TLS_LE_LO12}, + {BFD_RELOC_NDS32_TLS_LE_ADD, R_NDS32_TLS_LE_ADD}, + {BFD_RELOC_NDS32_TLS_LE_LS, R_NDS32_TLS_LE_LS}, + {BFD_RELOC_NDS32_TLS_IE_HI20, R_NDS32_TLS_IE_HI20}, + {BFD_RELOC_NDS32_TLS_IE_LO12S2, R_NDS32_TLS_IE_LO12S2}, + {BFD_RELOC_NDS32_TLS_TPOFF, R_NDS32_TLS_TPOFF}, + {BFD_RELOC_NDS32_TLS_LE_20, R_NDS32_TLS_LE_20}, + {BFD_RELOC_NDS32_TLS_LE_15S0, R_NDS32_TLS_LE_15S0}, + {BFD_RELOC_NDS32_TLS_LE_15S1, R_NDS32_TLS_LE_15S1}, + {BFD_RELOC_NDS32_TLS_LE_15S2, R_NDS32_TLS_LE_15S2}, }; /* Patch tag. */ @@ -2802,7 +3155,7 @@ nds32_elf_add_symbol_hook (bfd *abfd, static asection *sda_rela_sec = NULL; -#define SDA_SECTION_NUM 11 +#define SDA_SECTION_NUM 10 static bfd_reloc_status_type nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info, @@ -2811,6 +3164,7 @@ nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info, int relax_fp_as_gp; struct elf_nds32_link_hash_table *table; struct bfd_link_hash_entry *h, *h2; + long unsigned int total = 0; h = bfd_link_hash_lookup (info->hash, "_SDA_BASE_", FALSE, FALSE, TRUE); if (!h || (h->type != bfd_link_hash_defined && h->type != bfd_link_hash_defweak)) @@ -2823,7 +3177,7 @@ nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info, static const char sec_name[SDA_SECTION_NUM][10] = { ".data", ".got", ".sdata_d", ".sdata_w", ".sdata_h", ".sdata_b", - ".sbss_b", ".sbss_h", ".sbss_w", ".sbss_d", ".bss" + ".sbss_b", ".sbss_h", ".sbss_w", ".sbss_d" }; size_t i = 0; @@ -2834,24 +3188,49 @@ nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info, } /* Get the first and final section. */ - while (i < sizeof (sec_name) / 10) + while (i < sizeof (sec_name) / sizeof (sec_name [0])) { temp = bfd_get_section_by_name (output_bfd, sec_name[i]); if (temp && !first && (temp->size != 0 || temp->rawsize != 0)) first = temp; if (temp && (temp->size != 0 || temp->rawsize != 0)) final = temp; + + /* Summarize the sections in order to check if joining .bss. */ + if (temp && temp->size != 0) + total += temp->size; + else if (temp && temp->rawsize != 0) + total += temp->rawsize; + i++; } + /* Check .bss size. */ + temp = bfd_get_section_by_name (output_bfd, ".bss"); + if (temp) + { + if (temp->size != 0) + total += temp->size; + else if (temp->rawsize != 0) + total += temp->rawsize; + + if (total < 0x80000) + { + if (!first && (temp->size != 0 || temp->rawsize != 0)) + first = temp; + if ((temp->size != 0 || temp->rawsize != 0)) + final = temp; + } + } + if (first && final) { /* The middle of data region. */ - sda_base = (final->vma + final->rawsize + first->vma) / 2; + sda_base = final->vma / 2 + final->rawsize / 2 + first->vma / 2; /* Find the section sda_base located. */ i = 0; - while (i < sizeof (sec_name) / 10) + while (i < sizeof (sec_name) / sizeof (sec_name [0])) { final = bfd_get_section_by_name (output_bfd, sec_name[i]); if (final && (final->size != 0 || final->rawsize != 0) @@ -2876,7 +3255,7 @@ nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info, *psb = elf_gp (output_bfd); return bfd_reloc_ok; } - sda_base = first->vma; + sda_base = first->vma + first->rawsize; } sda_base -= first->vma; @@ -2963,6 +3342,7 @@ nds32_elf_link_hash_newfunc (struct bfd_hash_entry *entry, eh = (struct elf_nds32_link_hash_entry *) ret; eh->dyn_relocs = NULL; + eh->tls_type = GOT_UNKNOWN; } return (struct bfd_hash_entry *) ret; @@ -3453,6 +3833,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) { asection *s; bfd_boolean dyn; + int tls_type = elf32_nds32_hash_entry (h)->tls_type; /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic. */ @@ -3463,9 +3844,15 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) } s = htab->sgot; - h->got.offset = s->size; - s->size += 4; + + if (tls_type == GOT_UNKNOWN) + abort (); + else if (tls_type == GOT_NORMAL + || tls_type == GOT_TLS_IE) + /* Need a GOT slot. */ + s->size += 4; + dyn = htab->root.dynamic_sections_created; if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)) htab->srelgot->size += sizeof (Elf32_External_Rela); @@ -4060,6 +4447,15 @@ nds32_elf_output_symbol_hook (struct bfd_link_info *info, section, which means that the addend must be adjusted accordingly. */ +static bfd_vma +dtpoff_base (struct bfd_link_info *info) +{ + /* If tls_sec is NULL, we should have signalled an error already. */ + if (elf_hash_table (info)->tls_sec == NULL) + return 0; + return elf_hash_table (info)->tls_sec->vma; +} + static bfd_boolean nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, struct bfd_link_info * info, @@ -4113,6 +4509,15 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, return FALSE; } + 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. */ @@ -4153,7 +4558,8 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, || r_type == R_NDS32_RELA_GNU_VTINHERIT || (r_type >= R_NDS32_INSN16 && r_type <= R_NDS32_25_FIXED_RELA) || r_type == R_NDS32_DATA - || r_type == R_NDS32_TRAN) + || r_type == R_NDS32_TRAN + || (r_type >= R_NDS32_LONGCALL4 && r_type <= R_NDS32_LONGJUMP6)) continue; /* If we enter the fp-as-gp region. Resolve the address of best fp-base. */ @@ -4581,8 +4987,8 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, if (info->shared) { (*_bfd_error_handler) - (_("%s: warning: cannot deal R_NDS32_25_ABS_RELA in shared mode."), - bfd_get_filename (input_bfd)); + (_("%s: warning: cannot deal R_NDS32_25_ABS_RELA in shared " + "mode."), bfd_get_filename (input_bfd)); return FALSE; } break; @@ -4616,7 +5022,8 @@ nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, } else r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, offset, relocation, addend); + contents, offset, relocation, + addend); } goto check_reloc; @@ -4789,6 +5196,101 @@ handle_sda: /* do nothing */ break; + case R_NDS32_TLS_LE_HI20: + case R_NDS32_TLS_LE_LO12: + case R_NDS32_TLS_LE_20: + case R_NDS32_TLS_LE_15S0: + case R_NDS32_TLS_LE_15S1: + case R_NDS32_TLS_LE_15S2: + if (elf_hash_table (info)->tls_sec != NULL) + relocation -= (elf_hash_table (info)->tls_sec->vma + TP_OFFSET); + break; + case R_NDS32_TLS_IE_HI20: + case R_NDS32_TLS_IE_LO12S2: + { + /* Relocation is to the entry for this symbol in the global + offset table. */ + unsigned int tls_type; + asection *srelgot; + Elf_Internal_Rela outrel; + bfd_vma off; + bfd_byte *loc; + int indx = 0; + + BFD_ASSERT (sgot != NULL); + if (h != NULL) + { + bfd_boolean dyn; + + off = h->got.offset; + BFD_ASSERT (off != (bfd_vma) - 1); + dyn = htab->root.dynamic_sections_created; + tls_type = ((struct elf_nds32_link_hash_entry *) h)->tls_type; + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) + && (!info->shared + || !SYMBOL_REFERENCES_LOCAL (info, h))) + indx = h->dynindx; + } + else + { + /* Never happen currently. */ + BFD_ASSERT (local_got_offsets != NULL + && local_got_offsets[r_symndx] != (bfd_vma) - 1); + + off = local_got_offsets[r_symndx]; + + tls_type = elf32_nds32_local_got_tls_type (input_bfd)[r_symndx]; + } + relocation = sgot->output_section->vma + sgot->output_offset + off; + + if (r_type == R_NDS32_TLS_IE_LO12S2) + break; + + /* The offset must always be a multiple of 4. We use + the least significant bit to record whether we have + already processed this entry. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_boolean need_relocs = FALSE; + srelgot = htab->srelgot; + if ((info->shared || indx != 0) + && (h == NULL + || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak)) + { + need_relocs = TRUE; + BFD_ASSERT (srelgot != NULL); + } + if (tls_type & GOT_TLS_IE) + { + if (need_relocs) + { + if (h->dynindx == 0) + outrel.r_addend = relocation - dtpoff_base (info); + else + outrel.r_addend = 0; + outrel.r_offset = (sgot->output_section->vma + + sgot->output_offset + + off); + outrel.r_info = + ELF32_R_INFO (h->dynindx, R_NDS32_TLS_TPOFF); + + loc = srelgot->contents; + loc += + srelgot->reloc_count * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); + ++srelgot->reloc_count; + } + else + bfd_put_32 (output_bfd, h->root.u.def.value - TP_OFFSET, + sgot->contents + off); + } + } + } + break; + /* DON'T fall through. */ default: @@ -4855,8 +5357,16 @@ handle_sda: case R_NDS32_PLT_GOTREL_LO20: case R_NDS32_17IFC_PCREL_RELA: case R_NDS32_10IFCU_PCREL_RELA: + case R_NDS32_TLS_LE_HI20: + case R_NDS32_TLS_LE_LO12: + case R_NDS32_TLS_IE_HI20: + case R_NDS32_TLS_IE_LO12S2: + case R_NDS32_TLS_LE_20: + case R_NDS32_TLS_LE_15S0: + case R_NDS32_TLS_LE_15S1: + case R_NDS32_TLS_LE_15S2: /* Instruction related relocs must handle endian properly. */ - /* NOTE: PIC IS NOT HANDLE YET; DO IT LATER */ + /* NOTE: PIC IS NOT HANDLE YET; DO IT LATER. */ r = nds32_elf_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_offset, relocation, @@ -5845,6 +6355,7 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, enum elf_nds32_reloc_type r_type; struct elf_link_hash_entry *h; unsigned long r_symndx; + int tls_type, old_tls_type; r_symndx = ELF32_R_SYM (rel->r_info); r_type = ELF32_R_TYPE (rel->r_info); @@ -5858,7 +6369,9 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, h = (struct elf_link_hash_entry *) h->root.u.i.link; } - /* Some relocs require a global offset table. */ + /* Some relocs require a global offset table. We create + got section here, since these relocation need got section + and it is not created yet. */ if (htab->sgot == NULL) { switch (r_type) @@ -5878,6 +6391,8 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_NDS32_GOTPC_HI20: case R_NDS32_GOTPC_LO12: case R_NDS32_GOT20: + case R_NDS32_TLS_IE_HI20: + case R_NDS32_TLS_IE_LO12S2: if (dynobj == NULL) htab->root.dynobj = dynobj = abfd; if (!create_got_section (dynobj, info)) @@ -5896,8 +6411,23 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_NDS32_GOT_LO15: case R_NDS32_GOT_LO19: case R_NDS32_GOT20: + case R_NDS32_TLS_IE_HI20: + case R_NDS32_TLS_IE_LO12S2: + switch (r_type) + { + case R_NDS32_TLS_IE_HI20: + case R_NDS32_TLS_IE_LO12S2: + tls_type = GOT_TLS_IE; + break; + default: + tls_type = GOT_NORMAL; + break; + } if (h != NULL) - h->got.refcount += 1; + { + old_tls_type = elf32_nds32_hash_entry (h)->tls_type; + h->got.refcount += 1; + } else { bfd_signed_vma *local_got_refcounts; @@ -5917,10 +6447,25 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, elf_local_got_refcounts (abfd) = local_got_refcounts; } local_got_refcounts[r_symndx] += 1; + old_tls_type = elf32_nds32_local_got_tls_type (abfd)[r_symndx]; } - break; - case R_NDS32_9_PLTREL: + /* We will already have issued an error message if there + is a TLS/non-TLS mismatch, based on the symbol + type. So just combine any TLS types needed. */ + if (old_tls_type != GOT_UNKNOWN && old_tls_type != GOT_NORMAL + && tls_type != GOT_NORMAL) + tls_type |= old_tls_type; + + if (old_tls_type != tls_type) + { + if (h != NULL) + elf32_nds32_hash_entry (h)->tls_type = tls_type; + else + elf32_nds32_local_got_tls_type (abfd)[r_symndx] = tls_type; + } + break; + case R_NDS32_9_PLTREL: case R_NDS32_25_PLTREL: case R_NDS32_PLTREL_HI20: case R_NDS32_PLTREL_LO12: @@ -5944,6 +6489,7 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, if (h->forced_local) break; + elf32_nds32_hash_entry (h)->tls_type = GOT_NORMAL; h->needs_plt = 1; h->plt.refcount += 1; break; @@ -6602,7 +7148,8 @@ nds32_convert_32_to_16 (bfd *abfd, uint32_t insn, uint16_t *pinsn16, else if (N32_IS_RT4 (insn) && N32_RT5 (insn) == N32_RA5 (insn) && N32_IMM15S (insn) > -32) { - insn16 = N16_TYPE45 (SUBI45, N32_RT54 (insn), 0 - N32_IMM15S (insn)); + insn16 = N16_TYPE45 (SUBI45, N32_RT54 (insn), + 0 - N32_IMM15S (insn)); insn_type = NDS32_INSN_SUBI45; } else if (mach >= MACH_V2 && N32_RT5 (insn) == REG_SP @@ -6727,7 +7274,8 @@ nds32_convert_32_to_16 (bfd *abfd, uint32_t insn, uint16_t *pinsn16, else if (mach >= MACH_V2 && N32_IS_RT4 (insn) && N32_RA5 (insn) == REG_R8 && -32 <= N32_IMM15S (insn) && N32_IMM15S (insn) < 0) { - insn16 = N16_TYPE45 (LWI45_FE, N32_RT54 (insn), N32_IMM15S (insn) + 32); + insn16 = N16_TYPE45 (LWI45_FE, N32_RT54 (insn), + N32_IMM15S (insn) + 32); insn_type = NDS32_INSN_LWI45_FE; } break; @@ -6741,7 +7289,8 @@ nds32_convert_32_to_16 (bfd *abfd, uint32_t insn, uint16_t *pinsn16, else if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) && IS_WITHIN_U (N32_IMM15S (insn), 3)) { - insn16 = N16_TYPE333 (SWI333, N32_RT5 (insn), N32_RA5 (insn), N32_IMM15S (insn)); + insn16 = N16_TYPE333 (SWI333, N32_RT5 (insn), N32_RA5 (insn), + N32_IMM15S (insn)); insn_type = NDS32_INSN_SWI333; } else if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_FP @@ -6863,7 +7412,8 @@ nds32_convert_32_to_16 (bfd *abfd, uint32_t insn, uint16_t *pinsn16, insn16 = N16_TYPE38 (BEQZ38, N32_RT5 (insn), N32_IMM16S (insn)); insn_type = NDS32_INSN_BEQZ38; } - else if (N32_RT5 (insn) == REG_R15 && IS_WITHIN_S (N32_IMM16S (insn), 8)) + else if (N32_RT5 (insn) == REG_R15 + && IS_WITHIN_S (N32_IMM16S (insn), 8)) { insn16 = N16_TYPE8 (BEQZS8, N32_IMM16S (insn)); insn_type = NDS32_INSN_BEQZS8; @@ -6876,7 +7426,8 @@ nds32_convert_32_to_16 (bfd *abfd, uint32_t insn, uint16_t *pinsn16, insn16 = N16_TYPE38 (BNEZ38, N32_RT5 (insn), N32_IMM16S (insn)); insn_type = NDS32_INSN_BNEZ38; } - else if (N32_RT5 (insn) == REG_R15 && IS_WITHIN_S (N32_IMM16S (insn), 8)) + else if (N32_RT5 (insn) == REG_R15 + && IS_WITHIN_S (N32_IMM16S (insn), 8)) { insn16 = N16_TYPE8 (BNEZS8, N32_IMM16S (insn)); insn_type = NDS32_INSN_BNEZS8; @@ -7026,71 +7577,88 @@ nds32_convert_16_to_32 (bfd *abfd, uint16_t insn16, uint32_t *pinsn) switch (__GF (insn16, 9, 6)) { case 0x4: /* add45 */ - insn = N32_ALU1 (ADD, N16_RT4 (insn16), N16_RT4 (insn16), N16_RA5 (insn16)); + insn = N32_ALU1 (ADD, N16_RT4 (insn16), N16_RT4 (insn16), + N16_RA5 (insn16)); goto done; case 0x5: /* sub45 */ - insn = N32_ALU1 (SUB, N16_RT4 (insn16), N16_RT4 (insn16), N16_RA5 (insn16)); + insn = N32_ALU1 (SUB, N16_RT4 (insn16), N16_RT4 (insn16), + N16_RA5 (insn16)); goto done; case 0x6: /* addi45 */ - insn = N32_TYPE2 (ADDI, N16_RT4 (insn16), N16_RT4 (insn16), N16_IMM5U (insn16)); + insn = N32_TYPE2 (ADDI, N16_RT4 (insn16), N16_RT4 (insn16), + N16_IMM5U (insn16)); goto done; case 0x7: /* subi45 */ - insn = N32_TYPE2 (ADDI, N16_RT4 (insn16), N16_RT4 (insn16), -N16_IMM5U (insn16)); + insn = N32_TYPE2 (ADDI, N16_RT4 (insn16), N16_RT4 (insn16), + -N16_IMM5U (insn16)); goto done; case 0x8: /* srai45 */ - insn = N32_ALU1 (SRAI, N16_RT4 (insn16), N16_RT4 (insn16), N16_IMM5U (insn16)); + insn = N32_ALU1 (SRAI, N16_RT4 (insn16), N16_RT4 (insn16), + N16_IMM5U (insn16)); goto done; case 0x9: /* srli45 */ - insn = N32_ALU1 (SRLI, N16_RT4 (insn16), N16_RT4 (insn16), N16_IMM5U (insn16)); + insn = N32_ALU1 (SRLI, N16_RT4 (insn16), N16_RT4 (insn16), + N16_IMM5U (insn16)); goto done; - case 0xa: /* slli333 */ - insn = N32_ALU1 (SLLI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16)); + insn = N32_ALU1 (SLLI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); goto done; case 0xc: /* add333 */ - insn = N32_ALU1 (ADD, N16_RT3 (insn16), N16_RA3 (insn16), N16_RB3 (insn16)); + insn = N32_ALU1 (ADD, N16_RT3 (insn16), N16_RA3 (insn16), + N16_RB3 (insn16)); goto done; case 0xd: /* sub333 */ - insn = N32_ALU1 (SUB, N16_RT3 (insn16), N16_RA3 (insn16), N16_RB3 (insn16)); + insn = N32_ALU1 (SUB, N16_RT3 (insn16), N16_RA3 (insn16), + N16_RB3 (insn16)); goto done; case 0xe: /* addi333 */ - insn = N32_TYPE2 (ADDI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16)); + insn = N32_TYPE2 (ADDI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); goto done; case 0xf: /* subi333 */ - insn = N32_TYPE2 (ADDI, N16_RT3 (insn16), N16_RA3 (insn16), -N16_IMM3U (insn16)); + insn = N32_TYPE2 (ADDI, N16_RT3 (insn16), N16_RA3 (insn16), + -N16_IMM3U (insn16)); goto done; - case 0x10: /* lwi333 */ - insn = N32_TYPE2 (LWI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16)); + insn = N32_TYPE2 (LWI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); goto done; case 0x12: /* lhi333 */ - insn = N32_TYPE2 (LHI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16)); + insn = N32_TYPE2 (LHI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); goto done; case 0x13: /* lbi333 */ - insn = N32_TYPE2 (LBI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16)); + insn = N32_TYPE2 (LBI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); goto done; case 0x11: /* lwi333.bi */ - insn = N32_TYPE2 (LWI_BI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16)); + insn = N32_TYPE2 (LWI_BI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); goto done; case 0x14: /* swi333 */ - insn = N32_TYPE2 (SWI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16)); + insn = N32_TYPE2 (SWI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); goto done; case 0x16: /* shi333 */ - insn = N32_TYPE2 (SHI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16)); + insn = N32_TYPE2 (SHI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); goto done; case 0x17: /* sbi333 */ - insn = N32_TYPE2 (SBI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16)); + insn = N32_TYPE2 (SBI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); goto done; case 0x15: /* swi333.bi */ - insn = N32_TYPE2 (SWI_BI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16)); + insn = N32_TYPE2 (SWI_BI, N16_RT3 (insn16), N16_RA3 (insn16), + N16_IMM3U (insn16)); goto done; - case 0x18: /* addri36.sp */ - insn = N32_TYPE2 (ADDI, REG_SP, N16_RT3 (insn16), N16_IMM6U (insn16) << 2); + insn = N32_TYPE2 (ADDI, N16_RT3 (insn16), REG_SP, + N16_IMM6U (insn16) << 2); goto done; - case 0x19: /* lwi45.fe */ - insn = N32_TYPE2 (LWI, N16_RT4 (insn16), REG_R8, (32 - N16_IMM5U (insn16)) << 2); + insn = N32_TYPE2 (LWI, N16_RT4 (insn16), REG_R8, + (N16_IMM5U (insn16) - 32)); goto done; case 0x1a: /* lwi450 */ insn = N32_TYPE2 (LWI, N16_RT4 (insn16), N16_RA5 (insn16), 0); @@ -7099,7 +7667,7 @@ nds32_convert_16_to_32 (bfd *abfd, uint16_t insn16, uint32_t *pinsn) insn = N32_TYPE2 (SWI, N16_RT4 (insn16), N16_RA5 (insn16), 0); goto done; - /* These are r15 implied instructions. */ + /* These are r15 implied instructions. */ case 0x30: /* slts45 */ insn = N32_ALU1 (SLTS, REG_TA, N16_RT4 (insn16), N16_RA5 (insn16)); goto done; @@ -7132,30 +7700,35 @@ nds32_convert_16_to_32 (bfd *abfd, uint16_t insn16, uint32_t *pinsn) goto done; case 0x3f: /* MISC33 */ - switch (insn & 0x7) + switch (insn16 & 0x7) { case 2: /* neg33 */ insn = N32_TYPE2 (SUBRI, N16_RT3 (insn16), N16_RA3 (insn16), 0); break; case 3: /* not33 */ - insn = N32_ALU1 (NOR, N16_RT3 (insn16), N16_RA3 (insn16), N16_RA3 (insn16)); + insn = N32_ALU1 (NOR, N16_RT3 (insn16), N16_RA3 (insn16), + N16_RA3 (insn16)); break; case 4: /* mul33 */ - insn = N32_ALU2 (MUL, N16_RT3 (insn16), N16_RT3 (insn16), N16_RA3 (insn16)); + insn = N32_ALU2 (MUL, N16_RT3 (insn16), N16_RT3 (insn16), + N16_RA3 (insn16)); break; case 5: /* xor33 */ - insn = N32_ALU1 (XOR, N16_RT3 (insn16), N16_RT3 (insn16), N16_RA3 (insn16)); + insn = N32_ALU1 (XOR, N16_RT3 (insn16), N16_RT3 (insn16), + N16_RA3 (insn16)); break; case 6: /* and33 */ - insn = N32_ALU1 (AND, N16_RT3 (insn16), N16_RT3 (insn16), N16_RA3 (insn16)); + insn = N32_ALU1 (AND, N16_RT3 (insn16), N16_RT3 (insn16), + N16_RA3 (insn16)); break; case 7: /* or33 */ - insn = N32_ALU1 (OR, N16_RT3 (insn16), N16_RT3 (insn16), N16_RA3 (insn16)); + insn = N32_ALU1 (OR, N16_RT3 (insn16), N16_RT3 (insn16), + N16_RA3 (insn16)); break; } goto done; - case 0xb: /* ... */ + case 0xb: switch (insn16 & 0x7) { case 0: /* zeb33 */ @@ -7178,11 +7751,11 @@ nds32_convert_16_to_32 (bfd *abfd, uint16_t insn16, uint32_t *pinsn) break; case 6: /* bmski33 */ insn = N32_TYPE2 (ANDI, N16_RT3 (insn16), N16_RT3 (insn16), - 1 << N16_IMM3U (insn16)); + 1 << __GF (insn16, 3, 3)); break; case 7: /* fexti33 */ insn = N32_TYPE2 (ANDI, N16_RT3 (insn16), N16_RT3 (insn16), - (1 << (N16_IMM3U (insn16) + 1)) - 1); + (1 << (__GF (insn16, 3, 3) + 1)) - 1); break; } goto done; @@ -7193,9 +7766,9 @@ nds32_convert_16_to_32 (bfd *abfd, uint16_t insn16, uint32_t *pinsn) case 0x0: /* mov55 or ifret16 */ if (mach >= MACH_V3 && N16_RT5 (insn16) == REG_SP && N16_RT5 (insn16) == N16_RA5 (insn16)) - insn = N32_JREG (JR, 0, 0, 0, 3); + insn = N32_JREG (JR, 0, 0, 0, 3); else - insn = N32_TYPE2 (ADDI, N16_RT5 (insn16), N16_RA5 (insn16), 0); + insn = N32_TYPE2 (ADDI, N16_RT5 (insn16), N16_RA5 (insn16), 0); goto done; case 0x1: /* movi55 */ insn = N32_TYPE1 (MOVI, N16_RT5 (insn16), N16_IMM5S (insn16)); @@ -7582,7 +8155,7 @@ is_convert_32_to_16 (bfd *abfd, asection *sec, /* Find the first relocation of the same relocation-type, so we iteratie them forward. */ pc_rel = reloc; - while ((pc_rel - 1) > internal_relocs && pc_rel[-1].r_offset == offset) + while ((pc_rel - 1) >= internal_relocs && pc_rel[-1].r_offset == offset) pc_rel--; for (; pc_rel < irelend && pc_rel->r_offset == offset; pc_rel++) @@ -7594,19 +8167,29 @@ is_convert_32_to_16 (bfd *abfd, asection *sec, { off = calculate_offset (abfd, sec, pc_rel, isymbuf, symtab_hdr, &pic_ext_target); - if (off > 0xff || off < -0x100 || off == 0) + if (off >= ACCURATE_8BIT_S1 || off < -ACCURATE_8BIT_S1 + || off == 0) return FALSE; break; } else if (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_20_RELA) { /* movi => movi55 */ - mem_addr = calculate_memory_address (abfd, pc_rel, isymbuf, symtab_hdr); - /* mem_addr is unsigned, but the value should be between [-16, 15]. */ + mem_addr = calculate_memory_address (abfd, pc_rel, isymbuf, + symtab_hdr); + /* mem_addr is unsigned, but the value should + be between [-16, 15]. */ if ((mem_addr + 0x10) >> 5) return FALSE; break; } + else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_TLS_LE_20) + || (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_TLS_LE_LO12)) + { + /* It never happen movi to movi55 for R_NDS32_TLS_LE_20, + because it can be relaxed to addi for TLS_LE_ADD. */ + return FALSE; + } else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_SDA15S2_RELA || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_SDA17S2_RELA) && (reloc->r_addend & R_NDS32_INSN16_FP7U2_FLAG) @@ -7624,9 +8207,18 @@ is_convert_32_to_16 (bfd *abfd, asection *sec, || ((ELF32_R_TYPE (pc_rel->r_info) > R_NDS32_LOADSTORE) && (ELF32_R_TYPE (pc_rel->r_info) < R_NDS32_DWARF2_OP1_RELA))) { - /* Prevent unresolved addi instruction translate to addi45 or addi333. */ + /* Prevent unresolved addi instruction translate + to addi45 or addi333. */ return FALSE; } + else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_17IFC_PCREL_RELA)) + { + off = calculate_offset (abfd, sec, pc_rel, isymbuf, symtab_hdr, + &pic_ext_target); + if (off >= ACCURATE_U9BIT_S1 || off <= 0) + return FALSE; + break; + } } return TRUE; @@ -7669,6 +8261,9 @@ nds32_elf_write_16 (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *contents, || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_SDA17S2_RELA) pc_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (pc_rel->r_info), R_NDS32_SDA_FP7U2_RELA); + else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_17IFC_PCREL_RELA)) + pc_rel->r_info = + ELF32_R_INFO (ELF32_R_SYM (pc_rel->r_info), R_NDS32_10IFCU_PCREL_RELA); } } @@ -7695,7 +8290,7 @@ find_relocs_at_address (Elf_Internal_Rela *reloc, if (ELF32_R_TYPE (rel_t->r_info) == reloc_type) return rel_t; - /* We didn't find it backward. Try find it forward. */ + /* We didn't find it backward. Try find it forward. */ for (rel_t = reloc; rel_t < irelend && rel_t->r_offset == reloc->r_offset; rel_t++) @@ -7985,7 +8580,7 @@ nds32_elf_relax_delete_blanks (bfd *abfd, asection *sec, nds32_elf_blank_t *blank_p) { Elf_Internal_Shdr *symtab_hdr; /* Symbol table header of this bfd. */ - Elf_Internal_Sym *isym = NULL; /* Symbol table of this bfd. */ + Elf_Internal_Sym *isym = NULL; /* Symbol table of this bfd. */ Elf_Internal_Sym *isymend; /* Symbol entry iterator. */ unsigned int sec_shndx; /* The section the be relaxed. */ bfd_byte *contents; /* Contents data of iterating section. */ @@ -8066,18 +8661,28 @@ nds32_elf_relax_delete_blanks (bfd *abfd, asection *sec, && isym[ELF32_R_SYM (irel->r_info)].st_shndx == sec_shndx) { unsigned long val = 0; - unsigned long before, between; + unsigned long mask; + long before, between; + long offset; switch (ELF32_R_TYPE (irel->r_info)) { case R_NDS32_DIFF8: - val = bfd_get_8 (abfd, contents + irel->r_offset); + offset = bfd_get_8 (abfd, contents + irel->r_offset); break; case R_NDS32_DIFF16: - val = bfd_get_16 (abfd, contents + irel->r_offset); + offset = bfd_get_16 (abfd, contents + irel->r_offset); break; case R_NDS32_DIFF32: val = bfd_get_32 (abfd, contents + irel->r_offset); + /* Get the signed bit and mask for the high part. The + gcc will alarm when right shift 32-bit since the + type size of long may be 32-bit. */ + mask = 0 - (val >> 31); + if (mask) + offset = (val | (mask - 0xffffffff)); + else + offset = val; break; default: BFD_ASSERT (0); @@ -8090,23 +8695,28 @@ nds32_elf_relax_delete_blanks (bfd *abfd, asection *sec, -- before ---| ***************** --------------------- between ---| - We only care how much data are relax between DIFF, marked as ***. */ + We only care how much data are relax between DIFF, + marked as ***. */ before = get_nds32_elf_blank_total (&blank_t, irel->r_addend, 0); - between = get_nds32_elf_blank_total (&blank_t, irel->r_addend + val, 0); + between = get_nds32_elf_blank_total (&blank_t, + irel->r_addend + offset, 0); if (between == before) goto done_adjust_diff; switch (ELF32_R_TYPE (irel->r_info)) { case R_NDS32_DIFF8: - bfd_put_8 (abfd, val - (between - before), contents + irel->r_offset); + bfd_put_8 (abfd, offset - (between - before), + contents + irel->r_offset); break; case R_NDS32_DIFF16: - bfd_put_16 (abfd, val - (between - before), contents + irel->r_offset); + bfd_put_16 (abfd, offset - (between - before), + contents + irel->r_offset); break; case R_NDS32_DIFF32: - bfd_put_32 (abfd, val - (between - before), contents + irel->r_offset); + bfd_put_32 (abfd, offset - (between - before), + contents + irel->r_offset); break; } } @@ -8118,10 +8728,12 @@ nds32_elf_relax_delete_blanks (bfd *abfd, asection *sec, unsigned long before, between; bfd_byte *endp, *p; - val = read_unsigned_leb128 (abfd, contents + irel->r_offset, &len); + val = read_unsigned_leb128 (abfd, contents + irel->r_offset, + &len); before = get_nds32_elf_blank_total (&blank_t, irel->r_addend, 0); - between = get_nds32_elf_blank_total (&blank_t, irel->r_addend + val, 0); + between = get_nds32_elf_blank_total (&blank_t, + irel->r_addend + val, 0); if (between == before) goto done_adjust_diff; @@ -8138,14 +8750,17 @@ done_adjust_diff: if (sec == sect) { raddr = irel->r_offset; - irel->r_offset -= get_nds32_elf_blank_total (&blank_t2, irel->r_offset, 1); + irel->r_offset -= get_nds32_elf_blank_total (&blank_t2, + irel->r_offset, 1); if (ELF32_R_TYPE (irel->r_info) == R_NDS32_NONE) continue; if (blank_t2 && blank_t2->next - && (blank_t2->offset > raddr || blank_t2->next->offset <= raddr)) - (*_bfd_error_handler) (_("%B: %s\n"), abfd, - "Error: search_nds32_elf_blank reports wrong node"); + && (blank_t2->offset > raddr + || blank_t2->next->offset <= raddr)) + (*_bfd_error_handler) + (_("%B: %s\n"), abfd, + "Error: search_nds32_elf_blank reports wrong node"); /* Mark reloc in deleted portion as NONE. For some relocs like R_NDS32_LABEL that doesn't modify the @@ -8197,9 +8812,11 @@ done_adjust_diff: isym->st_value -= ahead; /* Adjust function size. */ - if (ELF32_ST_TYPE (isym->st_info) == STT_FUNC && isym->st_size > 0) - isym->st_size -= get_nds32_elf_blank_total - (&blank_t, orig_addr + isym->st_size, 0) - ahead; + if (ELF32_ST_TYPE (isym->st_info) == STT_FUNC + && isym->st_size > 0) + isym->st_size -= + get_nds32_elf_blank_total + (&blank_t, orig_addr + isym->st_size, 0) - ahead; } } } @@ -8228,8 +8845,9 @@ done_adjust_diff: /* Adjust function size. */ if (sym_hash->type == STT_FUNC) - sym_hash->size -= get_nds32_elf_blank_total - (&blank_t, orig_addr + sym_hash->size, 0) - ahead; + sym_hash->size -= + get_nds32_elf_blank_total + (&blank_t, orig_addr + sym_hash->size, 0) - ahead; } } @@ -8323,8 +8941,9 @@ nds32_get_local_syms (bfd *abfd, asection *sec ATTRIBUTE_UNUSED, } /* Range of small data. */ -static bfd_vma sdata_range[5][2]; -static bfd_vma const sdata_init_range[5] = { 0x2000, 0x4000, 0x8000, 0x10000, 0x40000 }; +static bfd_vma sdata_range[2][2]; +static bfd_vma const sdata_init_range[2] = +{ ACCURATE_12BIT_S1, ACCURATE_19BIT }; static int nds32_elf_insn_size (bfd *abfd ATTRIBUTE_UNUSED, @@ -8348,9 +8967,9 @@ relax_range_measurement (bfd *abfd) /* For upper bound. */ bfd_vma maxpgsz = get_elf_backend_data (abfd)->maxpagesize; bfd_vma align; - bfd_vma init_range; static int decide_relax_range = 0; int i; + int range_number = sizeof (sdata_init_range) / sizeof (sdata_init_range[0]); if (decide_relax_range) return; @@ -8359,7 +8978,7 @@ relax_range_measurement (bfd *abfd) if (sda_rela_sec == NULL) { /* Since there is no data sections, we assume the range is page size. */ - for (i = 0; i < 5; i++) + for (i = 0; i < range_number; i++) { sdata_range[i][0] = sdata_init_range[i] - 0x1000; sdata_range[i][1] = sdata_init_range[i] - 0x1000; @@ -8380,12 +8999,11 @@ relax_range_measurement (bfd *abfd) /* I guess we can not determine the section before gp located section, so we assume the align is max page size. */ - for (i = 0; i < 5; i++) + for (i = 0; i < range_number; i++) { - init_range = sdata_init_range[i]; - sdata_range[i][1] = init_range - align; + sdata_range[i][1] = sdata_init_range[i] - align; BFD_ASSERT (sdata_range[i][1] <= sdata_init_range[i]); - sdata_range[i][0] = init_range - maxpgsz; + sdata_range[i][0] = sdata_init_range[i] - maxpgsz; BFD_ASSERT (sdata_range[i][0] <= sdata_init_range[i]); } } @@ -8397,2561 +9015,3284 @@ relax_range_measurement (bfd *abfd) #define IS_OPTIMIZE(addend) ((addend) & 0x40000000) #define IS_16BIT_ON(addend) ((addend) & 0x20000000) +/* Relax LONGCALL1 relocation for nds32_elf_relax_section. */ + static bfd_boolean -nds32_elf_relax_section (bfd *abfd, asection *sec, - struct bfd_link_info *link_info, bfd_boolean *again) -{ - nds32_elf_blank_t *relax_blank_list = NULL; - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irel; - Elf_Internal_Rela *irelend; - Elf_Internal_Sym *isymbuf = NULL; - bfd_byte *contents = NULL; - bfd_boolean result = TRUE; - int optimize = 0; - int optimize_for_space ATTRIBUTE_UNUSED = 0; - int optimize_for_space_no_align ATTRIBUTE_UNUSED = 0; - int insn_opt = 0; - int i; +nds32_elf_relax_longcall1 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* There are 3 variations for LONGCALL1 + case 4-4-2; 16-bit on, optimize off or optimize for space + sethi ta, hi20(symbol) ; LONGCALL1/HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jral5 ta ; + + case 4-4-4; 16-bit off, optimize don't care + sethi ta, hi20(symbol) ; LONGCALL1/HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jral ta ; + + case 4-4-4; 16-bit on, optimize for speed + sethi ta, hi20(symbol) ; LONGCALL1/HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jral ta ; + Check code for -mlong-calls output. */ + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + + bfd_vma laddr; + int seq_len; /* Original length of instruction sequence. */ uint32_t insn; + Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *irelend; + int pic_ext_target = 0; + bfd_signed_vma foff; uint16_t insn16; - bfd_vma local_sda; - - /* Target dependnet option. */ - struct elf_nds32_link_hash_table *table; - int load_store_relax; - int relax_round; - relax_blank_list = NULL; - - *again = FALSE; + irelend = internal_relocs + sec->reloc_count; + seq_len = GET_SEQ_LEN (irel->r_addend); + laddr = irel->r_offset; + *insn_len = seq_len; - /* Nothing to do for - * relocatable link or - * non-relocatable section or - * non-code section or - * empty content or - * no reloc entry. */ - if (link_info->relocatable - || (sec->flags & SEC_RELOC) == 0 - || (sec->flags & SEC_EXCLUDE) == 1 - || (sec->flags & SEC_CODE) == 0 - || sec->size == 0) - return TRUE; + hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_HI20_RELA, laddr); + lo_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_LO12S0_ORI_RELA, + laddr + 4); - /* 09.12.11 Workaround. */ - /* We have to adjust align for R_NDS32_LABEL if needed. - The adjust approach only can fix 2-byte align once. */ - if (sec->alignment_power > 2) + if (hi_irelfn == irelend || lo_irelfn == irelend) { (*_bfd_error_handler) - (_("%B(%A): warning: relax is suppressed for sections " - "of alignment %d-bytes > 4-byte."), - abfd, sec, sec->alignment_power); - return TRUE; + ("%B: warning: R_NDS32_LONGCALL1 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; } - /* The optimization type to do. */ + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, + &pic_ext_target); - table = nds32_elf_hash_table (link_info); - relax_round = table->relax_round; - 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; - return TRUE; + /* This condition only happened when symbol is undefined. */ + if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 + || foff >= CONSERVATIVE_24BIT_S1) + return FALSE; - 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; - return TRUE; + /* Relax to: jal symbol; 25_PCREL */ + /* For simplicity of coding, we are going to modify the section + contents, the section relocs, and the BFD symbol table. We + must tell the rest of the code not to free up this + information. It would be possible to instead create a table + of changes which have to be made, as is done in coff-mips.c; + that would be more work, but would require less memory when + the linker is run. */ + + /* Replace the long call with a jal. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), + R_NDS32_25_PCREL_RELA); + irel->r_addend = hi_irelfn->r_addend; + + /* We don't resolve this here but resolve it in relocate_section. */ + insn = INSN_JAL; + bfd_putb32 (insn, contents + irel->r_offset); + + hi_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE); + lo_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); + *insn_len = 4; + + if (seq_len & 0x2) + { + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + irel->r_offset + *insn_len); + lo_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_INSN16); + lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; + *insn_len += 2; + } + return TRUE; +} - case NDS32_RELAX_EX9_REPLACE_ROUND: - if (!nds32_elf_ex9_replace_instruction (link_info, abfd, sec)) - return FALSE; - return TRUE; +#define CONVERT_CONDITION_CALL(insn) (((insn) & 0xffff0000) ^ 0x90000) +/* Relax LONGCALL2 relocation for nds32_elf_relax_section. */ - default: - if (sec->reloc_count == 0) - return TRUE; - break; - } +static bfd_boolean +nds32_elf_relax_longcall2 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* bltz rt, .L1 ; LONGCALL2 + jal symbol ; 25_PCREL + .L1: */ - /* The begining of general relaxation. */ + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ - if (is_SDA_BASE_set == 0) - { - bfd_vma gp; - is_SDA_BASE_set = 1; - nds32_elf_final_sda_base (sec->output_section->owner, link_info, &gp, FALSE); - relax_range_measurement (abfd); - } + bfd_vma laddr; + uint32_t insn; + Elf_Internal_Rela *i1_irelfn, *cond_irelfn, *irelend; + int pic_ext_target = 0; + bfd_signed_vma foff; - if (is_ITB_BASE_set == 0) + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + i1_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_25_PCREL_RELA, laddr + 4); + + if (i1_irelfn == irelend) { - /* Set the _ITB_BASE_. */ - if (!nds32_elf_ex9_itb_base (link_info)) - { - (*_bfd_error_handler) (_("%B: error: Cannot set _ITB_BASE_"), abfd); - bfd_set_error (bfd_error_bad_value); - } + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGCALL2 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; } - 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, - TRUE /* keep_memory */); - if (internal_relocs == NULL) - goto error_return; + insn = bfd_getb32 (contents + laddr); - irelend = internal_relocs + sec->reloc_count; - irel = - find_relocs_at_address (internal_relocs, internal_relocs, irelend, - R_NDS32_RELAX_ENTRY); - /* If 31th bit of addend of R_NDS32_RELAX_ENTRY is set, - this section is already relaxed. */ - if (irel == irelend) - return TRUE; + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, i1_irelfn, isymbuf, symtab_hdr, + &pic_ext_target); - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY) - { - if (irel->r_addend & R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG) - return TRUE; + if (foff == 0 || foff < -CONSERVATIVE_16BIT_S1 + || foff >= CONSERVATIVE_16BIT_S1) + return FALSE; - if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FLAG) - optimize = 1; + /* Relax to bgezal rt, label ; 17_PCREL + or bltzal rt, label ; 17_PCREL */ + + /* Convert to complimentary conditional call. */ + insn = CONVERT_CONDITION_CALL (insn); + + /* For simplicity of coding, we are going to modify the section + contents, the section relocs, and the BFD symbol table. We + must tell the rest of the code not to free up this + information. It would be possible to instead create a table + of changes which have to be made, as is done in coff-mips.c; + that would be more work, but would require less memory when + the linker is run. */ + + /* Clean unnessary relocations. */ + i1_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), R_NDS32_NONE); + cond_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_17_PCREL_RELA, laddr); + if (cond_irelfn != irelend) + cond_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info), R_NDS32_NONE); + + /* Replace the long call with a bgezal. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), + R_NDS32_17_PCREL_RELA); + irel->r_addend = i1_irelfn->r_addend; + + bfd_putb32 (insn, contents + irel->r_offset); + + *insn_len = 4; + return TRUE; +} - if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FOR_SPACE_FLAG) - optimize_for_space = 1; +/* Relax LONGCALL3 relocation for nds32_elf_relax_section. */ + +static bfd_boolean +nds32_elf_relax_longcall3 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* There are 3 variations for LONGCALL3 + case 4-4-4-2; 16-bit on, optimize off or optimize for space + bltz rt, $1 ; LONGCALL3 + sethi ta, hi20(symbol) ; HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jral5 ta ; + $1 + + case 4-4-4-4; 16-bit off, optimize don't care + bltz rt, $1 ; LONGCALL3 + sethi ta, hi20(symbol) ; HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jral ta ; + $1 + + case 4-4-4-4; 16-bit on, optimize for speed + bltz rt, $1 ; LONGCALL3 + sethi ta, hi20(symbol) ; HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jral ta ; + $1 */ + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + + bfd_vma laddr; + int seq_len; /* Original length of instruction sequence. */ + uint32_t insn; + Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *cond_irelfn, *irelend; + int pic_ext_target = 0; + bfd_signed_vma foff; + uint16_t insn16; + + irelend = internal_relocs + sec->reloc_count; + seq_len = GET_SEQ_LEN (irel->r_addend); + laddr = irel->r_offset; + *insn_len = seq_len; + + hi_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_HI20_RELA, laddr + 4); + lo_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_LO12S0_ORI_RELA, laddr + 8); + + if (hi_irelfn == irelend || lo_irelfn == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGCALL3 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; } - relax_active = 1; - load_store_relax = table->load_store_relax; + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, + &pic_ext_target); - /* Get symbol table and section content. */ - if (!nds32_get_section_contents (abfd, sec, &contents) - || !nds32_get_local_syms (abfd, sec, &isymbuf)) - goto error_return; + if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 + || foff >= CONSERVATIVE_24BIT_S1) + return FALSE; - /* Do relax loop only when finalize is not done. - Take care of relaxable relocs except INSN16. */ - for (irel = internal_relocs; irel < irelend; irel++) + insn = bfd_getb32 (contents + laddr); + if (foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1) { - bfd_vma laddr; - unsigned long comp_insn = 0; - unsigned short comp_insn16 = 0; - unsigned long i_mask = 0xffffffff; - int seq_len; /* Original length of instruction sequence. */ - int insn_len = 0; /* Final length of instruction sequence. */ - int convertible; /* 1st insn convertible. */ - int insn16_on; /* 16-bit on/off. */ - Elf_Internal_Rela *hi_irelfn = NULL; - Elf_Internal_Rela *lo_irelfn = NULL; - Elf_Internal_Rela *i1_irelfn = NULL; - Elf_Internal_Rela *i2_irelfn = NULL; - Elf_Internal_Rela *cond_irelfn = NULL; - int i1_offset = 0; - int i2_offset = 0; - bfd_signed_vma foff; - unsigned long reloc = R_NDS32_NONE; - int hi_off; - int insn_off; - int pic_ext_target = 0; - bfd_vma access_addr = 0; - bfd_vma range_l = 0, range_h = 0; /* Upper/lower bound. */ + /* Relax to bgezal rt, label ; 17_PCREL + or bltzal rt, label ; 17_PCREL */ - insn = 0; - insn16 = 0; - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL - && (irel->r_addend & 0x1f) >= 2) - optimize = 1; + /* Convert to complimentary conditional call. */ + insn = CONVERT_CONDITION_CALL (insn); + bfd_putb32 (insn, contents + irel->r_offset); - /* Relocation Types - R_NDS32_LONGCALL1 53 - R_NDS32_LONGCALL2 54 - R_NDS32_LONGCALL3 55 - R_NDS32_LONGJUMP1 56 - R_NDS32_LONGJUMP2 57 - R_NDS32_LONGJUMP3 58 - R_NDS32_LOADSTORE 59 */ - if (ELF32_R_TYPE (irel->r_info) >= R_NDS32_LONGCALL1 - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_LOADSTORE) + *insn_len = 4; + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE); + hi_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE); + lo_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); + + cond_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_17_PCREL_RELA, laddr); + if (cond_irelfn != irelend) { - seq_len = GET_SEQ_LEN (irel->r_addend); - insn_opt = IS_OPTIMIZE (irel->r_addend); - convertible = IS_1ST_CONVERT (irel->r_addend); - insn16_on = IS_16BIT_ON (irel->r_addend); - laddr = irel->r_offset; + cond_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), + R_NDS32_17_PCREL_RELA); + cond_irelfn->r_addend = hi_irelfn->r_addend; } - /* Relocation Types - R_NDS32_LO12S0_RELA 30 - R_NDS32_LO12S1_RELA 29 - R_NDS32_LO12S2_RELA 28 - R_NDS32_LO12S2_SP_RELA 71 - R_NDS32_LO12S2_DP_RELA 70 - R_NDS32_GOT_LO12 46 - R_NDS32_GOTOFF_LO12 50 - R_NDS32_PLTREL_LO12 65 - R_NDS32_PLT_GOTREL_LO12 67 - R_NDS32_GOT_SUFF 193 - R_NDS32_GOTOFF_SUFF 194 - R_NDS32_PLT_GOT_SUFF 195 - R_NDS32_MULCALL_SUFF 196 - R_NDS32_PTR 197 */ - else if ((ELF32_R_TYPE (irel->r_info) <= R_NDS32_LO12S0_RELA - && ELF32_R_TYPE (irel->r_info) >= R_NDS32_LO12S2_RELA) - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_SP_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_DP_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_LO12 - || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_LO12 - || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLTREL_LO12 - || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOTREL_LO12 - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_GOT_SUFF - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_PTR) - || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLTBLOCK - || ELF32_R_TYPE (irel->r_info) == R_NDS32_17IFC_PCREL_RELA) + + if (seq_len & 0x2) { - seq_len = 0; - insn_opt = IS_OPTIMIZE (irel->r_addend) > 0; - convertible = 0; - insn16_on = 0; - laddr = irel->r_offset; + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + irel->r_offset + *insn_len); + hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), + R_NDS32_INSN16); + hi_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; + insn_len += 2; } - else - continue; + } + else if (foff >= -CONSERVATIVE_24BIT_S1 && foff < CONSERVATIVE_24BIT_S1) + { + /* Relax to the following instruction sequence + bltz rt, $1 ; LONGCALL2 + jal symbol ; 25_PCREL + $1 */ + *insn_len = 8; + insn = INSN_JAL; + bfd_putb32 (insn, contents + hi_irelfn->r_offset); - insn_len = seq_len; + hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), + R_NDS32_25_PCREL_RELA); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_LONGCALL2); + + lo_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); - if (laddr + seq_len > (bfd_vma) sec->size) + if (seq_len & 0x2) { - char *s = NULL; - int pass_check = 0; + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + irel->r_offset + *insn_len); + lo_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_INSN16); + lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; + insn_len += 2; + } + } + return TRUE; +} - if (ELF32_R_TYPE (irel->r_info) >= R_NDS32_LONGCALL1 - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_LONGJUMP3) - { - for (i1_irelfn = irel; - i1_irelfn < irelend && i1_irelfn->r_offset < (laddr + seq_len - 4); - i1_irelfn++) - ; - - for (; - i1_irelfn < irelend && i1_irelfn->r_offset == (laddr + seq_len - 4); - i1_irelfn++) - if (ELF32_R_TYPE (i1_irelfn->r_info) == R_NDS32_INSN16) - { - pass_check = 1; - break; - } - i1_irelfn = NULL; - } +/* Relax LONGJUMP1 relocation for nds32_elf_relax_section. */ - if (pass_check == 0) - { - reloc_howto_type *howto = - bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE - (irel->r_info)); - s = howto->name; +static bfd_boolean +nds32_elf_relax_longjump1 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* There are 3 variations for LONGJUMP1 + case 4-4-2; 16-bit bit on, optimize off or optimize for space + sethi ta, hi20(symbol) ; LONGJUMP1/HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jr5 ta ; + + case 4-4-4; 16-bit off, optimize don't care + sethi ta, hi20(symbol) ; LONGJUMP1/HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jr ta ; + + case 4-4-4; 16-bit on, optimize for speed + sethi ta, hi20(symbol) ; LONGJUMP1/HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jr ta ; */ + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + + bfd_vma laddr; + int seq_len; /* Original length of instruction sequence. */ + int insn16_on; /* 16-bit on/off. */ + uint32_t insn; + Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *irelend; + int pic_ext_target = 0; + bfd_signed_vma foff; + uint16_t insn16; + unsigned long reloc; - (*_bfd_error_handler) - ("%B: warning: %s points to unrecognized insns at 0x%lx.", - abfd, s, (long) irel->r_offset); + irelend = internal_relocs + sec->reloc_count; + seq_len = GET_SEQ_LEN (irel->r_addend); + laddr = irel->r_offset; + *insn_len = seq_len; + insn16_on = IS_16BIT_ON (irel->r_addend); + + hi_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_HI20_RELA, laddr); + lo_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_LO12S0_ORI_RELA, laddr + 4); + if (hi_irelfn == irelend || lo_irelfn == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGJUMP1 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } - continue; - } - } + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, + &pic_ext_target); - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LONGCALL1) - { - /* There are 3 variations for LONGCALL1 - case 4-4-2; 16-bit on, optimize off or optimize for space - sethi ta, hi20(symbol) ; LONGCALL1/HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jral5 ta ; - - case 4-4-4; 16-bit off, optimize don't care - sethi ta, hi20(symbol) ; LONGCALL1/HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jral ta ; - - case 4-4-4; 16-bit on, optimize for speed - sethi ta, hi20(symbol) ; LONGCALL1/HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jral ta ; (INSN16) - Check code for -mlong-calls output. */ - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_HI20_RELA, laddr); - lo_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_LO12S0_ORI_RELA, - laddr + 4); - i1_offset = 8; - - if (hi_irelfn == irelend || lo_irelfn == irelend) - { - hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_20_RELA, laddr); - i1_offset = 4; - if (hi_irelfn == irelend) - { - (*_bfd_error_handler) - ("%B: warning: R_NDS32_LONGCALL1 points to unrecognized reloc at 0x%lx.", - abfd, (long) irel->r_offset); - continue; - } - } + if (pic_ext_target || foff == 0 || foff >= CONSERVATIVE_24BIT_S1 + || foff < -CONSERVATIVE_24BIT_S1) + return FALSE; - i1_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_INSN16, - laddr + i1_offset); + if (insn16_on && foff >= -ACCURATE_8BIT_S1 + && foff < ACCURATE_8BIT_S1 && (seq_len & 0x2)) + { + /* j8 label */ + /* 16-bit on, but not optimized for speed. */ + reloc = R_NDS32_9_PCREL_RELA; + insn16 = INSN_J8; + bfd_putb16 (insn16, contents + irel->r_offset); + *insn_len = 2; + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + } + else + { + /* j label */ + reloc = R_NDS32_25_PCREL_RELA; + insn = INSN_J; + bfd_putb32 (insn, contents + irel->r_offset); + *insn_len = 4; + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_INSN16); + irel->r_addend = 0; + } - /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, - &pic_ext_target); + hi_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), reloc); + lo_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); - /* This condition only happened when symbol is undefined. */ - if (pic_ext_target || foff == 0) - continue; - if (foff < -0x1000000 || foff >= 0x1000000) + if ((seq_len & 0x2) && ((*insn_len & 2) == 0)) + { + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + irel->r_offset + *insn_len); + lo_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), + R_NDS32_INSN16); + lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; + *insn_len += 2; + } + return TRUE; +} + +/* Revert condition branch. This function does not check if the input + instruction is condition branch or not. */ + +static void +nds32_elf_convert_branch (uint16_t insn16, uint32_t insn, + uint16_t *re_insn16, uint32_t *re_insn) +{ + uint32_t comp_insn = 0; + uint16_t comp_insn16 = 0; + + if (insn) + { + if (N32_OP6 (insn) == N32_OP6_BR1) + { + /* beqs label. */ + comp_insn = (insn ^ 0x4000) & 0xffffc000; + if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_R5) { - continue; + /* Insn can be contracted to 16-bit implied r5. */ + comp_insn16 = + (comp_insn & 0x4000) ? INSN_BNES38 : INSN_BEQS38; + comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8; } - - /* Relax to - jal symbol ; 25_PCREL */ - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - - /* Replace the long call with a jal. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), - R_NDS32_25_PCREL_RELA); - irel->r_addend = hi_irelfn->r_addend; - - /* We don't resolve this here but resolve it in relocate_section. */ - insn = INSN_JAL; - - bfd_putb32 (insn, contents + irel->r_offset); - hi_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); - insn_len = 4; - if (i1_irelfn != irelend) + } + else if (N32_OP6 (insn) == N32_OP6_BR3) + { + /* bnec $ta, imm11, label. */ + comp_insn = (insn ^ 0x80000) & 0xffffff00; + } + else + { + comp_insn = (insn ^ 0x10000) & 0xffffc000; + if (N32_BR2_SUB (insn) == N32_BR2_BEQZ + || N32_BR2_SUB (insn) == N32_BR2_BNEZ) { - if (!insn_opt - && (i1_irelfn->r_addend & R_NDS32_INSN16_CONVERT_FLAG)) + if (N32_IS_RT3 (insn)) { - /* The instruction pointed by R_NDS32_INSN16 is already - turned into 16-bit instruction, so the total length of - this sequence is decreased by 2. */ - seq_len = seq_len - 2; + /* Insn can be contracted to 16-bit. */ + comp_insn16 = + (comp_insn & 0x10000) ? INSN_BNEZ38 : INSN_BEQZ38; + comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8; + } + else if (N32_RT5 (insn) == REG_R15) + { + /* Insn can be contracted to 16-bit. */ + comp_insn16 = + (comp_insn & 0x10000) ? INSN_BNES38 : INSN_BEQS38; } - i1_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), R_NDS32_NONE); - } - if (seq_len & 0x2) - { - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + irel->r_offset + insn_len); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), - R_NDS32_INSN16); - lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - insn_len += 2; } } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LONGCALL2) + } + else + { + switch ((insn16 & 0xf000) >> 12) { - /* bltz rt, $1 ; LONGCALL2 - jal symbol ; 25_FIXED - $1: */ - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - i1_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_25_PCREL_RELA, laddr + 4); + case 0xc: + /* beqz38 or bnez38 */ + comp_insn16 = (insn16 ^ 0x0800) & 0xff00; + comp_insn = (comp_insn16 & 0x0800) ? INSN_BNEZ : INSN_BEQZ; + comp_insn |= ((comp_insn16 & 0x0700) >> 8) << 20; + break; - if (i1_irelfn == irelend) - { - (*_bfd_error_handler) - ("%B: warning: R_NDS32_LONGCALL2 points to unrecognized reloc at 0x%lx.", - abfd, (long) irel->r_offset); + case 0xd: + /* beqs38 or bnes38 */ + comp_insn16 = (insn16 ^ 0x0800) & 0xff00; + comp_insn = (comp_insn16 & 0x0800) ? INSN_BNE : INSN_BEQ; + comp_insn |= (((comp_insn16 & 0x0700) >> 8) << 20) + | (REG_R5 << 15); + break; - continue; - } + case 0xe: + /* beqzS8 or bnezS8 */ + comp_insn16 = (insn16 ^ 0x0100) & 0xff00; + comp_insn = (comp_insn16 & 0x0100) ? INSN_BNEZ : INSN_BEQZ; + comp_insn |= REG_R15 << 20; + break; - insn = bfd_getb32 (contents + laddr); + default: + break; + } + } + if (comp_insn && re_insn) + *re_insn = comp_insn; + if (comp_insn16 && re_insn16) + *re_insn16 = comp_insn16; +} - /* Get the value of the symbol referred to by the reloc. */ - foff = - calculate_offset (abfd, sec, i1_irelfn, isymbuf, symtab_hdr, - &pic_ext_target); - if (foff == 0) - continue; - if (foff < -0x10000 - 4 || foff >= 0x10000 - 4) - /* After all that work, we can't shorten this function call. */ - continue; +/* Relax LONGJUMP2 relocation for nds32_elf_relax_section. */ - /* Relax to bgezal rt, label ; 17_PCREL - or bltzal rt, label ; 17_PCREL */ +static bfd_boolean +nds32_elf_relax_longjump2 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* There are 3 variations for LONGJUMP2 + case 2-4; 1st insn convertible, 16-bit on, + optimize off or optimize for space + bnes38 rt, ra, $1 ; LONGJUMP2 + j label ; 25_PCREL + $1: + + case 4-4; 1st insn not convertible + bne rt, ra, $1 ; LONGJUMP2 + j label ; 25_PCREL + $1: + + case 4-4; 1st insn convertible, 16-bit on, optimize for speed + bne rt, ra, $1 ; LONGJUMP2 + j label ; 25_PCREL + $1: */ + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + + bfd_vma laddr; + int seq_len; /* Original length of instruction sequence. */ + Elf_Internal_Rela *i2_irelfn, *cond_irelfn, *irelend; + int pic_ext_target = 0, first_size; + unsigned int i; + bfd_signed_vma foff; + uint32_t insn, re_insn = 0; + uint16_t insn16, re_insn16 = 0; + unsigned long reloc, cond_reloc; - /* Convert to complimentary conditional call. */ - insn &= 0xffff0000; - insn ^= 0x90000; + enum elf_nds32_reloc_type checked_types[] = + { R_NDS32_15_PCREL_RELA, R_NDS32_9_PCREL_RELA }; - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ + irelend = internal_relocs + sec->reloc_count; + seq_len = GET_SEQ_LEN (irel->r_addend); + laddr = irel->r_offset; + *insn_len = seq_len; + first_size = (seq_len == 6) ? 2 : 4; + + i2_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, + irelend, R_NDS32_25_PCREL_RELA, + laddr + first_size); + + for (i = 0; i < sizeof (checked_types) / sizeof(checked_types[0]); i++) + { + cond_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + checked_types[i], laddr); + if (cond_irelfn != irelend) + break; + } - /* Replace the long call with a bgezal. */ - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), - R_NDS32_17_PCREL_RELA); + if (i2_irelfn == irelend || cond_irelfn == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGJUMP2 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } - bfd_putb32 (insn, contents + irel->r_offset); + /* Get the value of the symbol referred to by the reloc. */ + foff = + calculate_offset (abfd, sec, i2_irelfn, isymbuf, symtab_hdr, + &pic_ext_target); + if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_16BIT_S1 + || foff >= CONSERVATIVE_16BIT_S1) + return FALSE; - i1_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), R_NDS32_NONE); - cond_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_17_PCREL_RELA, laddr); - if (cond_irelfn != irelend) - { - cond_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), - R_NDS32_17_PCREL_RELA); - cond_irelfn->r_addend = i1_irelfn->r_addend; - } - insn_len = 4; - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LONGCALL3) - { - /* There are 3 variations for LONGCALL3 - case 4-4-4-2; 16-bit on, optimize off or optimize for space - bltz rt, $1 ; LONGCALL3 - sethi ta, hi20(symbol) ; HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jral5 ta ; - $1 - - case 4-4-4-4; 16-bit off, optimize don't care - bltz rt, $1 ; LONGCALL3 - sethi ta, hi20(symbol) ; HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jral ta ; - $1 - - case 4-4-4-4; 16-bit on, optimize for speed - bltz rt, $1 ; LONGCALL3 - sethi ta, hi20(symbol) ; HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jral ta ; (INSN16) - $1 */ - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - hi_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_HI20_RELA, laddr + 4); - lo_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_LO12S0_ORI_RELA, laddr + 8); - i2_offset = 12; + /* Get the all corresponding instructions. */ + if (first_size == 4) + { + insn = bfd_getb32 (contents + laddr); + nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn); + } + else + { + insn16 = bfd_getb16 (contents + laddr); + nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn); + } - if (hi_irelfn == irelend || lo_irelfn == irelend) - { - i2_offset = 8; - hi_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_20_RELA, laddr + 4); + if (re_insn16 && foff >= -(ACCURATE_8BIT_S1 - first_size) + && foff < ACCURATE_8BIT_S1 - first_size) + { + if (first_size == 4) + { + /* Don't convert it to 16-bit now, keep this as relaxable for + ``label reloc; INSN16''. */ - if (hi_irelfn == irelend) - { - (*_bfd_error_handler) - ("%B: warning: R_NDS32_LONGCALL3 points to unrecognized reloc at 0x%lx.", - abfd, (long) irel->r_offset); - continue; - } - } + /* Save comp_insn32 to buffer. */ + bfd_putb32 (re_insn, contents + irel->r_offset); + *insn_len = 4; + reloc = (N32_OP6 (re_insn) == N32_OP6_BR1) ? + R_NDS32_15_PCREL_RELA : R_NDS32_17_PCREL_RELA; + cond_reloc = R_NDS32_INSN16; + } + else + { + bfd_putb16 (re_insn16, contents + irel->r_offset); + *insn_len = 2; + reloc = R_NDS32_9_PCREL_RELA; + cond_reloc = R_NDS32_NONE; + } + } + else if (N32_OP6 (re_insn) == N32_OP6_BR1 + && (foff >= -(ACCURATE_14BIT_S1 - first_size) + && foff < ACCURATE_14BIT_S1 - first_size)) + { + /* beqs label ; 15_PCREL */ + bfd_putb32 (re_insn, contents + irel->r_offset); + *insn_len = 4; + reloc = R_NDS32_15_PCREL_RELA; + cond_reloc = R_NDS32_NONE; + } + else if (N32_OP6 (re_insn) == N32_OP6_BR2 + && foff >= -CONSERVATIVE_16BIT_S1 + && foff < CONSERVATIVE_16BIT_S1) + { + /* beqz label ; 17_PCREL */ + bfd_putb32 (re_insn, contents + irel->r_offset); + *insn_len = 4; + reloc = R_NDS32_17_PCREL_RELA; + cond_reloc = R_NDS32_NONE; + } + else + return FALSE; - i2_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_INSN16, laddr + i2_offset); + /* Set all relocations. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), reloc); + irel->r_addend = i2_irelfn->r_addend; - /* Get the value of the symbol referred to by the reloc. */ - foff = - calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, - &pic_ext_target); - if (pic_ext_target || foff == 0) - continue; - if (foff < -0x1000000 || foff >= 0x1000000) - continue; + cond_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info), + cond_reloc); + cond_irelfn->r_addend = 0; - insn = bfd_getb32 (contents + laddr); - if (foff >= -0x10000 - 4 && foff < 0x10000 - 4) - { - /* Relax to bgezal rt, label ; 17_PCREL - or bltzal rt, label ; 17_PCREL */ + if ((seq_len ^ *insn_len ) & 0x2) + { + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + irel->r_offset + 4); + i2_irelfn->r_offset = 4; + i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), + R_NDS32_INSN16); + i2_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; + *insn_len += 2; + } + else + i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), + R_NDS32_NONE); + return TRUE; +} - /* Convert to complimentary conditional call. */ - insn &= 0xffff0000; - insn ^= 0x90000; - bfd_putb32 (insn, contents + irel->r_offset); +/* Relax LONGJUMP3 relocation for nds32_elf_relax_section. */ - insn_len = 4; - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), - R_NDS32_NONE); - hi_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); - if (i2_irelfn != irelend) - { - if (!insn_opt - && (i2_irelfn->r_addend & R_NDS32_INSN16_CONVERT_FLAG)) - { - /* The instruction pointed by R_NDS32_INSN16 is already - turned into 16-bit instruction, so the total length - of this sequence is decreased by 2. */ - seq_len = seq_len - 2; - } - i2_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), - R_NDS32_NONE); - } - cond_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_17_PCREL_RELA, laddr); - if (cond_irelfn != irelend) - { - cond_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), - R_NDS32_17_PCREL_RELA); - cond_irelfn->r_addend = hi_irelfn->r_addend; - } +static bfd_boolean +nds32_elf_relax_longjump3 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* There are 5 variations for LONGJUMP3 + case 1: 2-4-4-2; 1st insn convertible, 16-bit on, + optimize off or optimize for space + bnes38 rt, ra, $1 ; LONGJUMP3 + sethi ta, hi20(symbol) ; HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jr5 ta ; + $1: ; + + case 2: 2-4-4-2; 1st insn convertible, 16-bit on, optimize for speed + bnes38 rt, ra, $1 ; LONGJUMP3 + sethi ta, hi20(symbol) ; HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jr5 ta ; + $1: ; LABEL + + case 3: 4-4-4-2; 1st insn not convertible, 16-bit on, + optimize off or optimize for space + bne rt, ra, $1 ; LONGJUMP3 + sethi ta, hi20(symbol) ; HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jr5 ta ; + $1: ; + + case 4: 4-4-4-4; 1st insn don't care, 16-bit off, optimize don't care + 16-bit off if no INSN16 + bne rt, ra, $1 ; LONGJUMP3 + sethi ta, hi20(symbol) ; HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jr ta ; + $1: ; + + case 5: 4-4-4-4; 1st insn not convertible, 16-bit on, optimize for speed + 16-bit off if no INSN16 + bne rt, ra, $1 ; LONGJUMP3 + sethi ta, hi20(symbol) ; HI20 + ori ta, ta, lo12(symbol) ; LO12S0 + jr ta ; + $1: ; LABEL */ + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + enum elf_nds32_reloc_type checked_types[] = + { R_NDS32_15_PCREL_RELA, R_NDS32_9_PCREL_RELA }; + + int reloc_off = 0, cond_removed = 0, convertible; + bfd_vma laddr; + int seq_len; /* Original length of instruction sequence. */ + Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *cond_irelfn, *irelend; + int pic_ext_target = 0, first_size; + unsigned int i; + bfd_signed_vma foff; + uint32_t insn, re_insn = 0; + uint16_t insn16, re_insn16 = 0; + unsigned long reloc, cond_reloc; - if (seq_len & 0x2) - { - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + irel->r_offset + insn_len); - hi_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), - R_NDS32_INSN16); - hi_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - insn_len += 2; - } - } - else - { - /* Relax to the following instruction sequence - bltz rt, $1 ; LONGCALL2 - jal symbol ; 25_PCREL - $1 - */ - insn = (insn & 0xffff0000) | 4; - bfd_putb32 (insn, contents + irel->r_offset); - /* This relax is incorrect. Review, fix and test it. - Check 6a726f0f for the oringnal code. */ - BFD_ASSERT (0); - - bfd_putb32 (insn, contents + irel->r_offset + 4); - insn_len = 8; - hi_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), - R_NDS32_25_PCREL_RELA); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_LONGCALL2); + irelend = internal_relocs + sec->reloc_count; + seq_len = GET_SEQ_LEN (irel->r_addend); + laddr = irel->r_offset; + *insn_len = seq_len; - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); - if (i2_irelfn != irelend) - { - i2_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), - R_NDS32_NONE); - } - if (seq_len & 0x2) - { - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + irel->r_offset + insn_len); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), - R_NDS32_INSN16); - lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - insn_len += 2; - } - } - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LONGJUMP1) - { - /* There are 3 variations for LONGJUMP1 - case 4-4-2; 16-bit bit on, optimize off or optimize for space - sethi ta, hi20(symbol) ; LONGJUMP1/HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jr5 ta ; + convertible = IS_1ST_CONVERT (irel->r_addend); - case 4-4-4; 16-bit off, optimize don't care - sethi ta, hi20(symbol) ; LONGJUMP1/HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jr ta ; + if (convertible) + first_size = 2; + else + first_size = 4; + + /* Get all needed relocations. */ + hi_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_HI20_RELA, laddr + first_size); + lo_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_LO12S0_ORI_RELA, + laddr + first_size + 4); + + for (i = 0; i < sizeof (checked_types) / sizeof (checked_types[0]); i++) + { + cond_irelfn = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + checked_types[i], laddr); + if (cond_irelfn != irelend) + break; + } - case 4-4-4; 16-bit on, optimize for speed - sethi ta, hi20(symbol) ; LONGJUMP1/HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jr ta ; INSN16 */ + if (hi_irelfn == irelend || lo_irelfn == irelend || cond_irelfn == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGJUMP3 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - hi_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_HI20_RELA, laddr); - lo_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_LO12S0_ORI_RELA, laddr + 4); - i1_offset = 8; + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, + &pic_ext_target); - if (hi_irelfn == irelend || lo_irelfn == irelend) - { - hi_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_20_RELA, laddr); - i1_offset = 4; + if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 + || foff >= CONSERVATIVE_24BIT_S1) + return FALSE; - if (hi_irelfn == irelend) - { - (*_bfd_error_handler) - ("%B: warning: R_NDS32_LONGJUMP1 points to unrecognized reloc at 0x%lx.", - abfd, (long) irel->r_offset); + /* Get the all corresponding instructions. */ + if (first_size == 4) + { + insn = bfd_getb32 (contents + laddr); + nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn); + } + else + { + insn16 = bfd_getb16 (contents + laddr); + nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn); + } - continue; - } - } + /* For simplicity of coding, we are going to modify the section + contents, the section relocs, and the BFD symbol table. We + must tell the rest of the code not to free up this + information. It would be possible to instead create a table + of changes which have to be made, as is done in coff-mips.c; + that would be more work, but would require less memory when + the linker is run. */ - i1_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_INSN16, laddr + i1_offset); + if (re_insn16 && foff >= -ACCURATE_8BIT_S1 - first_size + && foff < ACCURATE_8BIT_S1 - first_size) + { + if (!(seq_len & 0x2)) + { + /* Don't convert it to 16-bit now, keep this as relaxable + for ``label reloc; INSN1a''6. */ + /* Save comp_insn32 to buffer. */ + bfd_putb32 (re_insn, contents + irel->r_offset); + *insn_len = 4; + reloc = (N32_OP6 (re_insn) == N32_OP6_BR1) ? + R_NDS32_15_PCREL_RELA : R_NDS32_17_PCREL_RELA; + cond_reloc = R_NDS32_INSN16; + } + else + { + /* Not optimize for speed; convert sequence to 16-bit. */ + /* Save comp_insn16 to buffer. */ + bfd_putb16 (re_insn16, contents + irel->r_offset); + *insn_len = 2; + reloc = R_NDS32_9_PCREL_RELA; + cond_reloc = R_NDS32_NONE; + } + cond_removed = 1; + } + else if (N32_OP6 (re_insn) == N32_OP6_BR1 + && (foff >= -(ACCURATE_14BIT_S1 - first_size) + && foff < ACCURATE_14BIT_S1 - first_size)) + { + /* beqs label ; 15_PCREL */ + bfd_putb32 (re_insn, contents + irel->r_offset); + *insn_len = 4; + reloc = R_NDS32_15_PCREL_RELA; + cond_reloc = R_NDS32_NONE; + cond_removed = 1; + } + else if (N32_OP6 (re_insn) == N32_OP6_BR2 + && foff >= -CONSERVATIVE_16BIT_S1 + && foff < CONSERVATIVE_16BIT_S1) + { + /* beqz label ; 17_PCREL */ + bfd_putb32 (re_insn, contents + irel->r_offset); + *insn_len = 4; + reloc = R_NDS32_17_PCREL_RELA; + cond_reloc = R_NDS32_NONE; + cond_removed = 1; + } + else if (foff >= -CONSERVATIVE_24BIT_S1 - reloc_off + && foff < CONSERVATIVE_24BIT_S1 - reloc_off) + { + /* Relax to one of the following 3 variations + + case 2-4; 1st insn convertible, 16-bit on, optimize off or optimize + for space + bnes38 rt, $1 ; LONGJUMP2 + j label ; 25_PCREL + $1 + + case 4-4; 1st insn not convertible, others don't care + bne rt, ra, $1 ; LONGJUMP2 + j label ; 25_PCREL + $1 + + case 4-4; 1st insn convertible, 16-bit on, optimize for speed + bne rt, ra, $1 ; LONGJUMP2 + j label ; 25_PCREL + $1 */ + + /* Offset for first instruction. */ + + /* Use j label as second instruction. */ + *insn_len = 4 + first_size; + insn = INSN_J; + bfd_putb32 (insn, contents + hi_irelfn->r_offset); + reloc = R_NDS32_LONGJUMP2; + cond_reloc = R_NDS32_25_PLTREL; + } + else + return FALSE; - /* Get the value of the symbol referred to by the reloc. */ - foff = - calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, - &pic_ext_target); - if (pic_ext_target || foff == 0) - continue; + if (cond_removed == 1) + { + /* Set all relocations. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), reloc); + irel->r_addend = hi_irelfn->r_addend; + + cond_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info), + cond_reloc); + cond_irelfn->r_addend = 0; + hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), + R_NDS32_NONE); + } + else + { + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); + irel->r_addend = irel->r_addend; + hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), + cond_reloc); + } - if (foff >= -0x1000000 && foff < 0x1000000) - { - /* j label */ - if (!insn_opt && insn16_on && foff >= -0x100 && foff < 0x100 - && (seq_len & 0x2)) - { - /* 16-bit on, but not optimized for speed. */ - reloc = R_NDS32_9_PCREL_RELA; - insn16 = INSN_J8; - bfd_putb16 (insn16, contents + irel->r_offset); - insn_len = 2; - } - else - { - reloc = R_NDS32_25_PCREL_RELA; - insn = INSN_J; - bfd_putb32 (insn, contents + irel->r_offset); - insn_len = 4; - } - } - else - { - continue; - } + if ((seq_len ^ *insn_len ) & 0x2) + { + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + irel->r_offset + *insn_len); + lo_irelfn->r_offset = *insn_len; + lo_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), + R_NDS32_INSN16); + lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; + *insn_len += 2; + } + else + lo_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), + R_NDS32_NONE); + return TRUE; +} - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ +/* Relax LONGCALL4 relocation for nds32_elf_relax_section. */ - if (insn == 4) - { - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_INSN16); - irel->r_addend = 0; - } - else - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); +static bfd_boolean +nds32_elf_relax_longcall4 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* The pattern for LONGCALL4. Support for function cse. + sethi ta, hi20(symbol) ; LONGCALL4/HI20 + ori ta, ta, lo12(symbol) ; LO12S0_ORI/PTR + jral ta ; PTR_RES/EMPTY/INSN16 */ - hi_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), reloc); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); - if (i1_irelfn != irelend) - { - if (!insn_opt - && (i1_irelfn->r_addend & R_NDS32_INSN16_CONVERT_FLAG)) - { - /* The instruction pointed by R_NDS32_INSN16 is already - turned into 16-bit instruction, so the total length - of this sequence is decreased by 2. */ - seq_len = seq_len - 2; - i1_irelfn->r_addend = 0; - } - i1_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), R_NDS32_NONE); - } + bfd_vma laddr; + uint32_t insn; + Elf_Internal_Rela *hi_irel, *ptr_irel, *insn_irel, *em_irel, *call_irel; + Elf_Internal_Rela *irelend; + int pic_ext_target = 0; + bfd_signed_vma foff; - if ((seq_len & 0x2) && ((insn_len & 2) == 0)) - { - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + irel->r_offset + insn_len); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), - R_NDS32_INSN16); - lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - insn_len += 2; - } - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LONGJUMP2) - { - /* There are 3 variations for LONGJUMP2 - case 2-4; 1st insn convertible, 16-bit on, optimize off or optimize for space - bnes38 rt, ra, $1 ; LONGJUMP2 - j label ; 25_PCREL - $1: - - case 4-4; 1st insn not convertible - bne rt, ra, $1 ; LONGJUMP2 - j label ; 25_PCREL - $1: - - case 4-4; 1st insn convertible, 16-bit on, optimize for speed - bne rt, ra, $1 ; LONGJUMP2/INSN16 - j label ; 25_PCREL - $1: */ - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - enum elf_nds32_reloc_type checked_types[] = - { R_NDS32_15_PCREL_RELA, R_NDS32_9_PCREL_RELA }; - hi_off = (seq_len == 6) ? 2 : 4; - i2_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_25_PCREL_RELA, - laddr + hi_off); + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; - for (i = 0; i < 2; i++) - { - cond_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - checked_types[i], laddr); - if (cond_irelfn != irelend) - break; - } - if (i2_irelfn == irelend) - { - (*_bfd_error_handler) - ("%B: warning: R_NDS32_LONGJUMP2 points to unrecognized reloc at 0x%lx.", - abfd, (long) irel->r_offset); + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + hi_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_HI20_RELA, laddr); - continue; - } + if (hi_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGCALL4 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } - i1_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_INSN16, laddr); + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, hi_irel, isymbuf, symtab_hdr, + &pic_ext_target); - if (i1_irelfn != irelend && !insn_opt - && (i1_irelfn->r_addend & R_NDS32_INSN16_CONVERT_FLAG)) - { - /* The instruction pointed by R_NDS32_INSN16 is already turned - into 16-bit instruction, so the total length of this sequence - is decreased by 2. */ - seq_len = seq_len - 2; - } + /* This condition only happened when symbol is undefined. */ + if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 + || foff >= CONSERVATIVE_24BIT_S1) + return FALSE; - if (seq_len == 8) - { - /* possible cases - 1. range is outside of +/-256 bytes - 2. optimize is on with INSN16 - 3. optimize is off */ - insn_off = 4; - insn = bfd_getb32 (contents + laddr); - if (!insn16_on) - { - /* 16-bit is off, can't convert to 16-bit. */ - comp_insn16 = 0; - } - else if (N32_OP6 (insn) == N32_OP6_BR1) - { - /* beqs label ; 15_PCREL (INSN16) */ - comp_insn = (insn ^ 0x4000) & 0xffffc000; - i_mask = 0xffffc000; - if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_R5) - { - /* Insn can be contracted to 16-bit. */ - comp_insn16 = - (insn & 0x4000) ? INSN_BNES38 : INSN_BEQS38; - comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8; - } - else - { - /* No conversion. */ - comp_insn16 = 0; - } - } - else - { - comp_insn = (insn ^ 0x10000) & 0xffffc000; - i_mask = 0xffff0000; - if (N32_BR2_SUB (insn) == N32_BR2_BEQZ - || N32_BR2_SUB (insn) == N32_BR2_BNEZ) - { - if (N32_IS_RT3 (insn)) - { - /* Insn can be contracted to 16-bit. */ - comp_insn16 = - (insn & 0x10000) ? INSN_BNEZ38 : INSN_BEQZ38; - comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8; - } - else if (N32_RT5 (insn) == REG_R15) - { - /* Insn can be contracted to 16-bit. */ - comp_insn16 = - (insn & 0x10000) ? INSN_BNES38 : INSN_BEQS38; - } - else - { - /* No conversion. */ - comp_insn16 = 0; - } - } - else - { - /* No conversion. */ - comp_insn16 = 0; - } - } - } - else - { - /* First instruction is 16-bit. */ - insn_off = 2; - insn16 = bfd_getb16 (contents + laddr); - switch ((insn16 & 0xf000) >> 12) - { - case 0xc: - /* beqz38 or bnez38 */ - comp_insn = (insn16 & 0x0800) ? INSN_BNEZ : INSN_BEQZ; - comp_insn |= ((insn16 & 0x0700) >> 8) << 20; - comp_insn16 = (insn16 ^ 0x0800) & 0xff00; - insn = (insn16 & 0x0800) ? INSN_BEQZ : INSN_BNEZ; - insn |= ((insn16 & 0x0700) >> 8) << 20; - i_mask = 0xffff0000; - break; + /* Relax to: jal symbol; 25_PCREL */ + /* For simplicity of coding, we are going to modify the section + contents, the section relocs, and the BFD symbol table. We + must tell the rest of the code not to free up this + information. It would be possible to instead create a table + of changes which have to be made, as is done in coff-mips.c; + that would be more work, but would require less memory when + the linker is run. */ - case 0xd: - /* beqs38 or bnes38 */ - comp_insn = (insn16 & 0x0800) ? INSN_BNE : INSN_BEQ; - comp_insn |= (((insn16 & 0x0700) >> 8) << 20) - | (REG_R5 << 15); - comp_insn16 = (insn16 ^ 0x0800) & 0xff00; - insn = (insn16 & 0x0800) ? INSN_BEQ : INSN_BNE; - insn |= (((insn16 & 0x0700) >> 8) << 20) | (REG_R5 << 15); - i_mask = 0xffffc000; - break; + ptr_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED, irel->r_addend); + em_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_EMPTY, irel->r_addend); - case 0xe: - /* beqzS8 or bnezS8 */ - comp_insn = (insn16 & 0x0100) ? INSN_BNEZ : INSN_BEQZ; - comp_insn |= REG_R15 << 20; - comp_insn16 = (insn16 ^ 0x0100) & 0xff00; - insn = (insn16 & 0x0100) ? INSN_BEQZ : INSN_BNEZ; - insn |= REG_R15 << 20; - i_mask = 0xffff0000; - break; + if (ptr_irel == irelend || em_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGCALL4 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + /* Check these is enough space to insert jal in R_NDS32_EMPTY. */ + insn = bfd_getb32 (contents + irel->r_addend); + if (insn & 0x80000000) + return FALSE; - default: - comp_insn16 = 0; - insn = 0; - break; - } - } + /* Replace the long call with a jal. */ + em_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), + R_NDS32_25_PCREL_RELA); + ptr_irel->r_addend = 1; - /* Get the value of the symbol referred to by the reloc. */ - foff = - calculate_offset (abfd, sec, i2_irelfn, isymbuf, symtab_hdr, - &pic_ext_target); - if (pic_ext_target || foff == 0) - continue; + /* We don't resolve this here but resolve it in relocate_section. */ + insn = INSN_JAL; + bfd_putb32 (insn, contents + em_irel->r_offset); - if (comp_insn16 - && foff >= -0x100 - insn_off && foff < 0x100 - insn_off) - { - if (insn_opt || seq_len == 8) - { - /* Don't convert it to 16-bit now, keep this as relaxable for - ``label reloc; INSN16''. */ + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - /* Save comp_insn32 to buffer. */ - insn = comp_insn; - bfd_putb32 (insn, contents + irel->r_offset); - insn_len = 4; - reloc = (N32_OP6 (comp_insn) == N32_OP6_BR1) ? - R_NDS32_15_PCREL_RELA : R_NDS32_17_PCREL_RELA; + /* If there is function cse, HI20 can not remove now. */ + call_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_LONGCALL4, laddr); + if (call_irel == irelend) + { + *insn_len = 0; + hi_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (hi_irel->r_info), R_NDS32_NONE); + } - if (cond_irelfn != irelend) - { - cond_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info), - R_NDS32_INSN16); - cond_irelfn->r_addend = 0; - } - } - else - { - /* Not optimize for speed; convert sequence to 16-bit. */ + insn_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_INSN16, irel->r_addend); + if (insn_irel != irelend) + insn_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - /* Save comp_insn16 to buffer. */ - insn16 = comp_insn16; - bfd_putb16 (insn16, contents + irel->r_offset); - insn_len = 2; - reloc = R_NDS32_9_PCREL_RELA; - } + return TRUE; +} - /* Change relocs. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), reloc); - irel->r_addend = i2_irelfn->r_addend; +/* Relax LONGCALL5 relocation for nds32_elf_relax_section. */ - i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), - R_NDS32_NONE); - } - else if (N32_OP6 (insn) == N32_OP6_BR1 - && (foff >= -0x4000 - insn_off && foff < 0x4000 - insn_off)) - { - /* beqs label ; 15_PCREL */ - insn = comp_insn; - bfd_putb32 (insn, contents + irel->r_offset); - insn_len = 4; - - /* Change relocs. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), - R_NDS32_15_PCREL_RELA); - irel->r_addend = i2_irelfn->r_addend; - if (i1_irelfn != irelend) - i1_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), - R_NDS32_NONE); - - if (seq_len & 0x2) - { - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + irel->r_offset + insn_len); - i2_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), - R_NDS32_INSN16); - i2_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - insn_len += 2; - } - } - else if (N32_OP6 (insn) == N32_OP6_BR2 && foff >= -0x10000 && foff < 0x10000) - { - /* beqz label ; 17_PCREL */ - insn = comp_insn; - bfd_putb32 (insn, contents + irel->r_offset); - insn_len = 4; - - /* Change relocs. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), - R_NDS32_17_PCREL_RELA); - irel->r_addend = i2_irelfn->r_addend; - if (i1_irelfn != irelend) - i1_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), - R_NDS32_NONE); - if (seq_len & 0x2) - { - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + irel->r_offset + insn_len); - i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), - R_NDS32_INSN16); - i2_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - insn_len += 2; - } - } - else - continue; +static bfd_boolean +nds32_elf_relax_longcall5 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* The pattern for LONGCALL5. + bltz rt, .L1 ; LONGCALL5/17_PCREL + jal symbol ; 25_PCREL + .L1: */ - if (cond_irelfn != irelend) - cond_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info), - R_NDS32_NONE); - - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LONGJUMP3) - { - int reloc_off = 0, cond_removed = 0; - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - enum elf_nds32_reloc_type checked_types[] = - { R_NDS32_15_PCREL_RELA, R_NDS32_9_PCREL_RELA }; - - /* There are 5 variations for LONGJUMP3 - case 1: 2-4-4-2; 1st insn convertible, 16-bit on, - optimize off or optimize for space - bnes38 rt, ra, $1 ; LONGJUMP3 - sethi ta, hi20(symbol) ; HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jr5 ta ; - $1: ; - - case 2: 2-4-4-2; 1st insn convertible, 16-bit on, optimize for speed - bnes38 rt, ra, $1 ; LONGJUMP3 - sethi ta, hi20(symbol) ; HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jr5 ta ; - $1: ; LABEL - - case 3: 4-4-4-2; 1st insn not convertible, 16-bit on, - optimize off or optimize for space - bne rt, ra, $1 ; LONGJUMP3 - sethi ta, hi20(symbol) ; HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jr5 ta ; - $1: ; - - case 4: 4-4-4-4; 1st insn don't care, 16-bit off, optimize don't care - 16-bit off if no INSN16 - bne rt, ra, $1 ; LONGJUMP3 - sethi ta, hi20(symbol) ; HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jr ta ; - $1: ; - - case 5: 4-4-4-4; 1st insn not convertible, 16-bit on, optimize for speed - 16-bit off if no INSN16 - bne rt, ra, $1 ; LONGJUMP3 - sethi ta, hi20(symbol) ; HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jr ta ; INSN16 - $1: ; LABEL - */ - - if (convertible) - { - hi_off = 2; - if (insn_opt) - reloc_off = 2; - } - else - { - hi_off = 4; - } + bfd_vma laddr; + uint32_t insn; + Elf_Internal_Rela *cond_irel, *irelend; + int pic_ext_target = 0; + bfd_signed_vma foff; - hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_HI20_RELA, - laddr + hi_off); - lo_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_LO12S0_ORI_RELA, - laddr + hi_off + 4); - i2_offset = 8; + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + insn = bfd_getb32 (contents + laddr); - if (hi_irelfn == irelend || lo_irelfn == irelend) - { - hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_20_RELA, - laddr + hi_off); - i2_offset = 4; + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_25_PCREL_RELA, irel->r_addend); + if (cond_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGCALL5 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } - if (hi_irelfn == irelend) - { - (*_bfd_error_handler) - ("%B: warning: R_NDS32_LONGJUMP3 points to unrecognized reloc at 0x%lx.", - abfd, (long) irel->r_offset); - continue; - } - } + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr, + &pic_ext_target); - i2_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_INSN16, - laddr + hi_off + i2_offset); - - /* Get the value of the symbol referred to by the reloc. */ - foff = - calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, - &pic_ext_target); - if (pic_ext_target || foff == 0) - continue; + if (foff == 0 || foff < -CONSERVATIVE_16BIT_S1 + || foff >= CONSERVATIVE_16BIT_S1) + return FALSE; - /* Set offset adjustment value. */ - /* Check instruction type and set complimentary instruction. */ - if (hi_off == 2) - { - /* First instruction is 16-bit. */ - insn_off = 2; - insn16 = bfd_getb16 (contents + laddr); - switch ((insn16 & 0xf000) >> 12) - { - case 0xc: - /* beqz38 or bnez38 */ - comp_insn = (insn16 & 0x0800) ? INSN_BNEZ : INSN_BEQZ; - comp_insn |= ((insn16 & 0x0700) >> 8) << 20; - comp_insn16 = (insn16 ^ 0x0800) & 0xff00; - insn = (insn16 & 0x0800) ? INSN_BEQZ : INSN_BNEZ; - insn |= ((insn16 & 0x0700) >> 8) << 20; - i_mask = 0xffff0000; - break; + /* Relax to bgezal rt, label ; 17_PCREL + or bltzal rt, label ; 17_PCREL */ - case 0xd: - /* beqs38 or bnes38 */ - comp_insn = (insn16 & 0x0800) ? INSN_BNE : INSN_BEQ; - comp_insn |= (((insn16 & 0x0700) >> 8) << 20) - | (REG_R5 << 15); - comp_insn16 = (insn16 ^ 0x0800) & 0xff00; - insn = (insn16 & 0x0800) ? INSN_BEQ : INSN_BNE; - insn |= (((insn16 & 0x0700) >> 8) << 20) | (REG_R5 << 15); - i_mask = 0xffffc000; - break; + /* Convert to complimentary conditional call. */ + insn = CONVERT_CONDITION_CALL (insn); - case 0xe: - /* beqzS8 or bnezS8 */ - comp_insn = (insn16 & 0x0100) ? INSN_BNEZ : INSN_BEQZ; - comp_insn |= REG_R15 << 20; - comp_insn16 = (insn16 ^ 0x0100) & 0xff00; - insn = (insn16 & 0x0100) ? INSN_BEQZ : INSN_BNEZ; - insn |= REG_R15 << 20; - i_mask = 0xffff0000; - break; - } - } - else - { - /* First instruction is 32-bit. */ - insn_off = 4; - insn = bfd_getb32 (contents + laddr); - if (!insn16_on) - { - /* 16-bit is off */ - comp_insn16 = 0; - } - else if (N32_OP6 (insn) == N32_OP6_BR1) - { - /* +/-16K range */ - comp_insn = insn ^ 0x4000; - i_mask = 0xffffc000; - if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_R5) - { - /* This instruction can turn to 16-bit. */ - comp_insn16 = - (insn & 0x4000) ? INSN_BNES38 : INSN_BEQS38; - comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8; - } - else - { - /* no conversion */ - comp_insn16 = 0; - } - } - else - { - /* +/-64K range */ - comp_insn = insn ^ 0x10000; - i_mask = 0xffff0000; - if (N32_BR2_SUB (insn) == N32_BR2_BEQZ - || N32_BR2_SUB (insn) == N32_BR2_BNEZ) - { - if (N32_IS_RT3 (insn)) - { - /* This instruction can turn to 16-bit. */ - comp_insn16 = - (insn & 0x10000) ? INSN_BNEZ38 : INSN_BEQZ38; - comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8; - } - else if (N32_RT5 (insn) == REG_R15) - { - /* This instruction can turn to 16-bit. */ - comp_insn16 = - (insn & 0x10000) ? INSN_BNEZS8 : INSN_BEQZS8; - } - else - { - /* No conversion. */ - comp_insn16 = 0; - } - } - else - { - /* No conversion. */ - comp_insn16 = 0; - } - } - } + /* For simplicity of coding, we are going to modify the section + contents, the section relocs, and the BFD symbol table. We + must tell the rest of the code not to free up this + information. It would be possible to instead create a table + of changes which have to be made, as is done in coff-mips.c; + that would be more work, but would require less memory when + the linker is run. */ - if (foff < -0x1000000 && foff >= 0x1000000) - continue; + /* Modify relocation and contents. */ + cond_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_17_PCREL_RELA); - if (i2_irelfn != irelend) - { - if (insn_opt == 0 - && (i2_irelfn->r_addend & R_NDS32_INSN16_CONVERT_FLAG)) - { - /* The instruction pointed by R_NDS32_INSN16 is already - turned into 16-bit instruction, so the total length - of this sequence is decreased by 2. */ - seq_len = seq_len - 2; - i2_irelfn->r_addend = 0; - } - } + /* Replace the long call with a bgezal. */ + bfd_putb32 (insn, contents + cond_irel->r_offset); + *insn_len = 0; - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ + /* Clean unnessary relocations. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - if (comp_insn16 - && foff >= -0x100 - insn_off && foff < 0x100 - insn_off) - { - if (insn_opt || (seq_len & 0x2) == 0) - { - /* Don't convert it to 16-bit now, keep this as relaxable - for ``label reloc; INSN1a''6. */ - /* Save comp_insn32 to buffer. */ - insn = comp_insn; - bfd_putb32 (insn, contents + irel->r_offset); - insn_len = 4; - reloc = (N32_OP6 (comp_insn) == N32_OP6_BR1) ? - R_NDS32_15_PCREL_RELA : R_NDS32_17_PCREL_RELA; - - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), - R_NDS32_INSN16); - } - else - { - /* Not optimize for speed; convert sequence to 16-bit. */ - /* Save comp_insn16 to buffer. */ - insn16 = comp_insn16; - bfd_putb16 (insn16, contents + irel->r_offset); - insn_len = 2; - reloc = R_NDS32_9_PCREL_RELA; - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), - R_NDS32_NONE); - } + cond_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_17_PCREL_RELA, laddr); + cond_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE); - /* Change relocs. */ - for (i = 0; i < 2; i++) - { - cond_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, - irelend, checked_types[i], - laddr); + return TRUE; +} - if (cond_irelfn != irelend) - { - cond_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), reloc); - cond_irelfn->r_addend = hi_irelfn->r_addend; - } - } - hi_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); - cond_removed = 1; - } - else if (N32_OP6 (insn) == N32_OP6_BR1 - && foff >= -0x4000 - insn_off && foff < 0x4000 - insn_off) - { - /* Relax to `beq label ; 15_PCREL'. */ +/* Relax LONGCALL6 relocation for nds32_elf_relax_section. */ - /* Save comp_insn to buffer. */ - insn = comp_insn; - bfd_putb32 (insn, contents + irel->r_offset); - insn_len = 4; - reloc = R_NDS32_15_PCREL_RELA; +static bfd_boolean +nds32_elf_relax_longcall6 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* The pattern for LONGCALL6. + bltz rt, .L1 ; LONGCALL6/17_PCREL + sethi ta, hi20(symbol) ; HI20/PTR + ori ta, ta, lo12(symbol) ; LO12S0_ORI/PTR + jral ta ; PTR_RES/EMPTY/INSN16 + .L1 */ + + bfd_vma laddr; + uint32_t insn; + Elf_Internal_Rela *em_irel, *cond_irel, *irelend; + int pic_ext_target = 0; + bfd_signed_vma foff; - /* Change relocs. */ - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - hi_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); - if (seq_len & 0x2) - { - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + irel->r_offset + insn_len); - hi_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), - R_NDS32_INSN16); - hi_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - if (hi_off == 2) - hi_irelfn->r_offset += 2; - insn_len += 2; - } - cond_removed = 1; - } - else if (N32_OP6 (insn) == N32_OP6_BR2 - && foff >= -0x10000 - insn_off - && foff < 0x10000 - insn_off) - { - /* Relax to `beqz label ; 17_PCREL'. */ + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; - /* Save comp_insn to buffer. */ - insn = comp_insn; - bfd_putb32 (insn, contents + irel->r_offset); - insn_len = 4; - reloc = R_NDS32_17_PCREL_RELA; + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + em_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_EMPTY, irel->r_addend); - /* Change relocs. */ - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - hi_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); - if (seq_len & 0x2) - { - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + irel->r_offset + insn_len); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), - R_NDS32_INSN16); - lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - if (hi_off == 2) - hi_irelfn->r_offset += 2; - insn_len += 2; - } - cond_removed = 1; - } - else if (foff >= -0x1000000 - reloc_off - && foff < 0x1000000 - reloc_off) - { - /* Relax to one of the following 3 variations - - case 2-4; 1st insn convertible, 16-bit on, optimize off or optimize for space - bnes38 rt, $1 ; LONGJUMP2 - j label ; 25_PCREL - $1 - - case 4-4; 1st insn not convertible, others don't care - bne rt, ra, $1 ; LONGJUMP2 - j label ; 25_PCREL - $1 - - case 4-4; 1st insn convertible, 16-bit on, optimize for speed - bne rt, ra, $1 ; LONGJUMP2/INSN16 - j label ; 25_PCREL - $1 - */ + if (em_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGCALL6 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } - /* Offset for first instruction. */ + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, em_irel, isymbuf, symtab_hdr, + &pic_ext_target); - if (hi_off == 2) - { - /* First instruction is 16-bit. */ - if (hi_irelfn != irelend) - { - /* INSN16 exists so this is optimized for speed. */ - /* Convert this instruction to 32-bit for label alignment. */ - insn = (insn & i_mask) | 4; - bfd_putb32 (insn, contents + irel->r_offset); - insn_len = 8; - hi_irelfn->r_offset += 2; - } - else - { - /* Not optimized for speed. */ - insn16 = (insn16 & 0xff00) | 3; - bfd_putb16 (insn16, contents + irel->r_offset); - insn_len = 6; - } - } - else - { - /* First instruction is 32-bit. */ - insn = (insn & i_mask) | 4; - bfd_putb32 (insn, contents + irel->r_offset); - insn_len = 8; - } + if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 + || foff >= CONSERVATIVE_24BIT_S1) + return FALSE; - /* Use j label as second instruction. */ - insn = INSN_J; - bfd_putb32 (insn, contents + irel->r_offset); - - /* Change relocs. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_LONGJUMP2); - hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), - R_NDS32_25_PCREL_RELA); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); - if (((seq_len ^ insn_len) & 0x2) != 0x2) - { - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + irel->r_offset + insn_len); - lo_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), - R_NDS32_INSN16); - lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - lo_irelfn->r_offset = hi_irelfn->r_offset + 4; - insn_len += 2; - } - } + /* Check these is enough space to insert jal in R_NDS32_EMPTY. */ + insn = bfd_getb32 (contents + irel->r_addend); + if (insn & 0x80000000) + return FALSE; - if (cond_removed) - { - for (i = 0; i < 2; i++) - { - cond_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, - irelend, checked_types[i], - laddr); + insn = bfd_getb32 (contents + laddr); + if (foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1) + { + /* Relax to bgezal rt, label ; 17_PCREL + or bltzal rt, label ; 17_PCREL */ - if (cond_irelfn != irelend) - break; - } - if (cond_irelfn != irelend) - { - cond_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), reloc); - cond_irelfn->r_addend = hi_irelfn->r_addend; - } - } - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LOADSTORE) + /* Convert to complimentary conditional call. */ + *insn_len = 0; + insn = CONVERT_CONDITION_CALL (insn); + bfd_putb32 (insn, contents + em_irel->r_offset); + + em_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), R_NDS32_17_PCREL_RELA); + + /* Set resolved relocation. */ + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED, irel->r_addend); + if (cond_irel == irelend) { - int eliminate_sethi = 0, ls_range_type; - enum elf_nds32_reloc_type checked_types[] = - { R_NDS32_HI20_RELA, R_NDS32_GOT_HI20, - R_NDS32_GOTPC_HI20, R_NDS32_GOTOFF_HI20, - R_NDS32_PLTREL_HI20, R_NDS32_PLT_GOTREL_HI20 - }; + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGCALL6 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + cond_irel->r_addend = 1; - insn_len = seq_len; + /* Clear relocations. */ - for (i = 0; i < 6; i++) - { - hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, - checked_types[i], laddr); - if (hi_irelfn != irelend) - break; - } + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - if (hi_irelfn == irelend) - { - (*_bfd_error_handler) - ("%B: warning: R_NDS32_LOADSTORE points to unrecognized reloc at 0x%lx.", - abfd, (long) irel->r_offset); - continue; - } + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_17_PCREL_RELA, laddr); + if (cond_irel != irelend) + cond_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE); - ls_range_type = (irel->r_addend >> 8) & 0x3f; + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_INSN16, irel->r_addend); + if (cond_irel != irelend) + cond_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE); - nds32_elf_final_sda_base (sec->output_section->owner, link_info, - &local_sda, FALSE); - switch (ELF32_R_TYPE (hi_irelfn->r_info)) - { - case R_NDS32_HI20_RELA: - insn = bfd_getb32 (contents + laddr); - access_addr = - calculate_memory_address (abfd, hi_irelfn, isymbuf, - symtab_hdr); + } + else if (foff >= -CONSERVATIVE_24BIT_S1 && foff < CONSERVATIVE_24BIT_S1) + { + /* Relax to the following instruction sequence + bltz rt, .L1 ; LONGCALL2/17_PCREL + jal symbol ; 25_PCREL/PTR_RES + .L1 */ + *insn_len = 4; + /* Convert instruction. */ + insn = INSN_JAL; + bfd_putb32 (insn, contents + em_irel->r_offset); - if ((ls_range_type & 0x3f) == 0x20) - { - if ((access_addr < 0x7f000)) - { - eliminate_sethi = 1; - break; - } - else - { - /* This is avoid to relax symbol address which is fixed - relocations. Ex: _stack. */ - struct elf_link_hash_entry *h; - int indx; - indx = ELF32_R_SYM (hi_irelfn->r_info) - symtab_hdr->sh_info; - if (indx >= 0) - { - h = elf_sym_hashes (abfd)[indx]; - if (h && bfd_is_abs_section (h->root.u.def.section)) - break; - } - } - } + /* Convert relocations. */ + em_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), + R_NDS32_25_PCREL_RELA); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_LONGCALL5); - if (!load_store_relax) - continue; + /* Set resolved relocation. */ + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED, irel->r_addend); + if (cond_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGCALL6 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } + cond_irel->r_addend = 1; - if (((insn >> 20) & 0x1f) == REG_GP) - break; + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_INSN16, irel->r_addend); + if (cond_irel != irelend) + cond_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE); + } + return TRUE; +} - if (ls_range_type & 0x8 || ls_range_type & 0x10) - { - range_l = sdata_range[0][0]; - range_h = sdata_range[0][1]; - } - else - { - range_l = sdata_range[4][0]; - range_h = sdata_range[4][1]; - } - break; +/* Relax LONGJUMP4 relocation for nds32_elf_relax_section. */ - case R_NDS32_GOT_HI20: - access_addr = - calculate_got_memory_address (abfd, link_info, hi_irelfn, - symtab_hdr); - - /* If this symbol is not in .got, the return value will be -1. - Since the gp value is set to SDA_BASE but not GLOBAL_OFFSET_TABLE, - a negative offset is allowed. */ - if ((bfd_signed_vma) (access_addr - local_sda) < 0x7f000 - && (bfd_signed_vma) (access_addr - local_sda) >= -0x7f000) - eliminate_sethi = 1; - break; +static bfd_boolean +nds32_elf_relax_longjump4 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* The pattern for LONGJUMP4. + sethi ta, hi20(symbol) ; LONGJUMP4/HI20 + ori ta, ta, lo12(symbol) ; LO12S0_ORI/PTR + jr ta ; PTR_RES/INSN16/EMPTY */ + + bfd_vma laddr; + int seq_len; /* Original length of instruction sequence. */ + uint32_t insn; + Elf_Internal_Rela *hi_irel, *ptr_irel, *em_irel, *call_irel, *irelend; + int pic_ext_target = 0; + bfd_signed_vma foff; - case R_NDS32_PLT_GOTREL_HI20: - access_addr = - calculate_plt_memory_address (abfd, link_info, isymbuf, - hi_irelfn, symtab_hdr); + irelend = internal_relocs + sec->reloc_count; + seq_len = GET_SEQ_LEN (irel->r_addend); + laddr = irel->r_offset; + *insn_len = seq_len; - if ((bfd_signed_vma) (access_addr - local_sda) < 0x7f000 - && (bfd_signed_vma) (access_addr - local_sda) >= -0x7f000) - eliminate_sethi = 1; - break; + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ - case R_NDS32_GOTOFF_HI20: - access_addr = - calculate_memory_address (abfd, hi_irelfn, isymbuf, - symtab_hdr); + hi_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_HI20_RELA, laddr); - if ((bfd_signed_vma) (access_addr - local_sda) < 0x7f000 - && (bfd_signed_vma) (access_addr - local_sda) >= -0x7f000) - eliminate_sethi = 1; - break; + if (hi_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGJUMP4 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } - case R_NDS32_GOTPC_HI20: - for (i1_irelfn = irel; - i1_irelfn->r_offset <= irel->r_offset + 4 - && i1_irelfn < irelend; i1_irelfn++) - if (ELF32_R_TYPE (i1_irelfn->r_info) == R_NDS32_GOTPC_LO12) - break; - if (i1_irelfn == irelend - || i1_irelfn->r_offset != irel->r_offset + 4) - continue; + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, hi_irel, isymbuf, symtab_hdr, + &pic_ext_target); - access_addr = sec->output_section->vma + sec->output_offset - + irel->r_offset; - if ((bfd_signed_vma) (local_sda - access_addr) < 0x7f000 - && (bfd_signed_vma) (local_sda - access_addr) >= -0x7f000) - { - /* Turn into MOVI. */ - insn = bfd_getb32 (contents + laddr + 4); - if (((insn & 0x1f00000) >> 20) != REG_GP) - continue; - - hi_irelfn->r_addend = ((int) hi_irelfn->r_addend) < -4 - ? (hi_irelfn->r_addend + 4) : (hi_irelfn->r_addend); - hi_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), - R_NDS32_GOTPC20); - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - i1_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), - R_NDS32_NONE); - insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0); - bfd_putb32 (insn, contents + laddr); - insn_len = 4; - seq_len = 8; - } - break; + if (pic_ext_target || foff == 0 || foff >= CONSERVATIVE_24BIT_S1 + || foff < -CONSERVATIVE_24BIT_S1) + return FALSE; - default: - continue; - } - if (eliminate_sethi == 1 - || (local_sda <= access_addr && (access_addr - local_sda) < range_h) - || (local_sda > access_addr && (local_sda - access_addr) <= range_l)) - { - hi_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - insn_len = 0; - } - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_17IFC_PCREL_RELA) - { - foff = calculate_offset (abfd, sec, irel, isymbuf, symtab_hdr, - &pic_ext_target); - if (pic_ext_target || foff == 0) - continue; - if (foff < 1022 && foff >= 0) - { - reloc = R_NDS32_10IFCU_PCREL_RELA; - insn16 = INSN_IFCALL9; - bfd_putb16 (insn16, contents + irel->r_offset); - insn_len = 2; - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_10IFCU_PCREL_RELA); - *again = TRUE; + /* Convert it to "j label", it may be converted to j8 in the final + pass of relaxation. Therefore, we do not consider this currently. */ + ptr_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED, irel->r_addend); + em_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_EMPTY, irel->r_addend); - i2_irelfn = find_relocs_at_address (irel, internal_relocs, - irelend, R_NDS32_INSN16); - if (i2_irelfn < irelend) - { - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + irel->r_offset + 2); - i2_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - i2_irelfn->r_offset += 2; - insn_len += 2; - } - else - { - ((*_bfd_error_handler) - ("%s: 0x%lx: warning: R_NDS32_17IFC points to unrecognized reloc at 0x%lx", - bfd_get_filename (abfd), (long) irel->r_offset)); - } - } - } - else if (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_DP_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_SP_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_RELA) - { - nds32_elf_final_sda_base (sec->output_section->owner, link_info, - &local_sda, FALSE); + if (ptr_irel == irelend || em_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGJUMP4 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } - insn = bfd_getb32 (contents + laddr); + em_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), R_NDS32_25_PCREL_RELA); + ptr_irel->r_addend = 1; - if (!is_sda_access_insn (insn) - && N32_OP6 (insn) != N32_OP6_ORI) - continue; + /* Write instruction. */ + insn = INSN_J; + bfd_putb32 (insn, contents + em_irel->r_offset); - access_addr = - calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); - insn_len = seq_len = 4; + /* Clear relocations. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - /* This is avoid to relax symbol address which is fixed - relocations. Ex: _stack. */ - if (N32_OP6 (insn) == N32_OP6_ORI && access_addr >= 0x7f000) - { - struct elf_link_hash_entry *h; - int indx; - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - if (indx >= 0) - { - h = elf_sym_hashes (abfd)[indx]; - if (h && bfd_is_abs_section (h->root.u.def.section)) - continue; - } - } + /* If there is function cse, HI20 can not remove now. */ + call_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_LONGJUMP4, laddr); + if (call_irel == irelend) + { + *insn_len = 0; + hi_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (hi_irel->r_info), R_NDS32_NONE); + } - if (N32_OP6 (insn) == N32_OP6_ORI && access_addr < 0x7f000) - { - reloc = R_NDS32_20_RELA; - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); - insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0); - bfd_putb32 (insn, contents + laddr); - } - else if (load_store_relax) - { - range_l = sdata_range[4][0]; - range_h = sdata_range[4][1]; - switch (ELF32_R_TYPE (irel->r_info)) - { - case R_NDS32_LO12S0_RELA: - reloc = R_NDS32_SDA19S0_RELA; - break; - case R_NDS32_LO12S1_RELA: - reloc = R_NDS32_SDA18S1_RELA; - break; - case R_NDS32_LO12S2_RELA: - reloc = R_NDS32_SDA17S2_RELA; - break; - case R_NDS32_LO12S2_DP_RELA: - range_l = sdata_range[0][0]; - range_h = sdata_range[0][1]; - reloc = R_NDS32_SDA12S2_DP_RELA; - break; - case R_NDS32_LO12S2_SP_RELA: - range_l = sdata_range[0][0]; - range_h = sdata_range[0][1]; - reloc = R_NDS32_SDA12S2_SP_RELA; - break; - default: - break; - } - - /* There are range_h and range_l because linker has to promise - all sections move cross one page together. */ - if ((local_sda <= access_addr && (access_addr - local_sda) < range_h) - || (local_sda > access_addr && (local_sda - access_addr) <= range_l)) - { - if (N32_OP6 (insn) == N32_OP6_ORI && N32_RT5 (insn) == REG_GP) - { - /* Maybe we should add R_NDS32_INSN16 reloc type here - or manually do some optimization. sethi can't be - eliminated when updating $gp so the relative ori - needs to be preserved. */ - continue; - } - if (!turn_insn_to_sda_access (insn, ELF32_R_TYPE (irel->r_info), - &insn)) - continue; - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); - bfd_putb32 (insn, contents + laddr); - } - } - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_LO12 - || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_LO12 - || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLTREL_LO12 - || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOTREL_LO12) - { - nds32_elf_final_sda_base (sec->output_section->owner, link_info, - &local_sda, FALSE); - - insn = bfd_getb32 (contents + laddr); - - if (N32_OP6 (insn) != N32_OP6_ORI) - continue; + return TRUE; +} - insn_len = seq_len = 4; - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_LO12) - { - foff = calculate_got_memory_address (abfd, link_info, irel, - symtab_hdr) - local_sda; - reloc = R_NDS32_GOT20; - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOTREL_LO12) - { - foff = calculate_plt_memory_address (abfd, link_info, isymbuf, irel, - symtab_hdr) - local_sda; - reloc = R_NDS32_PLT_GOTREL_LO20; - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_LO12) - { - foff = calculate_memory_address (abfd, irel, isymbuf, - symtab_hdr) - local_sda; - reloc = R_NDS32_GOTOFF; - } - else - continue; +/* Relax LONGJUMP5 relocation for nds32_elf_relax_section. */ - if ((foff < 0x7f000) && (foff >= -0x7f000)) - { - /* Turn into MOVI. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); - insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0); - bfd_putb32 (insn, contents + laddr); - } - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_PTR) - { - i1_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_PTR_RESOLVED, irel->r_addend); +static bfd_boolean +nds32_elf_relax_longjump5 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + int *seq_len, bfd_byte *contents, + Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* There are 2 variations for LONGJUMP5 + case 2-4; 1st insn convertible, 16-bit on. + bnes38 rt, ra, .L1 ; LONGJUMP5/9_PCREL/INSN16 + j label ; 25_PCREL/INSN16 + $1: + + case 4-4; 1st insn not convertible + bne rt, ra, .L1 ; LONGJUMP5/15_PCREL/INSN16 + j label ; 25_PCREL/INSN16 + .L1: */ + + bfd_vma laddr; + Elf_Internal_Rela *cond_irel, *irelend; + int pic_ext_target = 0; + unsigned int i; + bfd_signed_vma foff; + uint32_t insn, re_insn = 0; + uint16_t insn16, re_insn16 = 0; + unsigned long reloc; - if (i1_irelfn == irelend) - { - (*_bfd_error_handler) - ("%B: warning: R_NDS32_PTR points to unrecognized reloc at 0x%lx.", - abfd, (long) irel->r_offset); - continue; - } + enum elf_nds32_reloc_type checked_types[] = + { R_NDS32_17_PCREL_RELA, R_NDS32_15_PCREL_RELA, + R_NDS32_9_PCREL_RELA, R_NDS32_INSN16 }; - if (i1_irelfn->r_addend & 1) - { - /* Pointed target is relaxed and no longer needs this void *, - change the type to NONE. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; - i1_irelfn = - find_relocs_at_address (irel, internal_relocs, irelend, - R_NDS32_PTR_COUNT); + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ - if (i1_irelfn == irelend) - { - (*_bfd_error_handler) - ("%B: warning: no R_NDS32_PTR_COUNT coexist with R_NDS32_PTR at 0x%lx.", - abfd, (long) irel->r_offset); - continue; - } + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_25_PCREL_RELA, irel->r_addend); + if (cond_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGJUMP5 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } - if (--i1_irelfn->r_addend > 0) - continue; + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr, + &pic_ext_target); - /* If the PTR_COUNT is already 0, remove current instruction. */ - seq_len = nds32_elf_insn_size (abfd, contents, irel->r_offset); - insn_len = 0; - } - else - continue; - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOT_SUFF) - { - /* FIXME: It's a little trouble to turn JRAL5 to JAL since - we need additional space. It might be help if we could - borrow some space from instructions to be eliminated - such as sethi, ori, add. */ + if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_16BIT_S1 + || foff >= CONSERVATIVE_16BIT_S1) + return FALSE; - insn = bfd_getb32 (contents + laddr); - if (insn & 0x80000000) - continue; + /* Get the all corresponding instructions. */ + insn = bfd_getb32 (contents + laddr); + /* Check instruction size. */ + if (insn & 0x80000000) + { + *seq_len = 0; + insn16 = insn >> 16; + nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn); + } + else + nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn); - if (nds32_elf_check_dup_relocs - (irel, internal_relocs, irelend, R_NDS32_PLT_GOT_SUFF)) - continue; + if (N32_OP6 (re_insn) == N32_OP6_BR1 + && (foff >= -CONSERVATIVE_14BIT_S1 && foff < CONSERVATIVE_14BIT_S1)) + { + /* beqs label ; 15_PCREL. */ + bfd_putb32 (re_insn, contents + cond_irel->r_offset); + reloc = R_NDS32_15_PCREL_RELA; + } + else if (N32_OP6 (re_insn) == N32_OP6_BR2 + && foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1) + { + /* beqz label ; 17_PCREL. */ + bfd_putb32 (re_insn, contents + cond_irel->r_offset); + reloc = R_NDS32_17_PCREL_RELA; + } + else if ( N32_OP6 (re_insn) == N32_OP6_BR3 + && foff >= -CONSERVATIVE_8BIT_S1 && foff < CONSERVATIVE_8BIT_S1) + { + /* beqc label ; 9_PCREL. */ + bfd_putb32 (re_insn, contents + cond_irel->r_offset); + reloc = R_NDS32_WORD_9_PCREL_RELA; + } + else + return FALSE; - seq_len = insn_len = 4; - i1_irelfn = - find_relocs_at_address (irel, internal_relocs, irelend, - R_NDS32_PTR_RESOLVED); - - /* FIXIT 090606 - The boundary should be reduced since the .plt section hasn't - been created and the address of specific entry is still unknown - Maybe the range between the function call and the begin of the - .text section can be used to decide if the .plt is in the range - of function call. */ - - if (N32_OP6 (insn) == N32_OP6_ALU1 - && N32_SUB5 (insn) == N32_ALU1_ADD_SLLI - && N32_SH5 (insn) == 0) - { - /* Get the value of the symbol referred to by the reloc. */ - nds32_elf_final_sda_base (sec->output_section->owner, link_info, - &local_sda, FALSE); - foff = (bfd_signed_vma) (calculate_plt_memory_address - (abfd, link_info, isymbuf, irel, - symtab_hdr) - local_sda); - /* This condition only happened when symbol is undefined. */ - if (foff == 0) - continue; + /* Set all relocations. */ + cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), reloc); - if (foff < -0x3f000 || foff >= 0x3f000) - continue; - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_NDS32_PLT_GOTREL_LO19); - /* addi.gp */ - insn = N32_TYPE1 (SBGP, N32_RT5 (insn), __BIT (19)); - } - else if (N32_OP6 (insn) == N32_OP6_JREG - && N32_SUB5 (insn) == N32_JREG_JRAL) + /* Clean relocations. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + for (i = 0; i < sizeof (checked_types) / sizeof (checked_types[0]); i++) + { + cond_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + checked_types[i], laddr); + if (cond_irel != irelend) + { + if (*seq_len == 0 + && (ELF32_R_TYPE (cond_irel->r_info) == R_NDS32_INSN16)) { - /* Get the value of the symbol referred to by the reloc. */ - foff = - calculate_plt_offset (abfd, sec, link_info, isymbuf, irel, - symtab_hdr); - /* This condition only happened when symbol is undefined. */ - if (foff == 0) - continue; - if (foff < -0x1000000 || foff >= 0x1000000) - continue; - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_25_PLTREL); - insn = INSN_JAL; + /* If the branch instruction is 2 byte, it cannot remove + directly. Only convert it to nop16 and remove it after + checking alignment issue. */ + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + laddr); + cond_irel->r_addend = R_NDS32_INSN16_CONVERT_FLAG; } else - continue; - - bfd_putb32 (insn, contents + laddr); - if (i1_irelfn != irelend) - { - i1_irelfn->r_addend |= 1; - *again = TRUE; - } + cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), + R_NDS32_NONE); } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_SUFF) - { + } + *insn_len = 0; - insn = bfd_getb32 (contents + laddr); - if (insn & 0x80000000) - continue; + return TRUE; +} - if (nds32_elf_check_dup_relocs - (irel, internal_relocs, irelend, R_NDS32_GOT_SUFF)) - continue; +/* Relax LONGJUMP6 relocation for nds32_elf_relax_section. */ - seq_len = insn_len = 4; - i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, - R_NDS32_PTR_RESOLVED); +static bfd_boolean +nds32_elf_relax_longjump6 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + int *seq_len, bfd_byte *contents, + Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* There are 5 variations for LONGJUMP6 + case : 2-4-4-4; 1st insn convertible, 16-bit on. + bnes38 rt, ra, .L1 ; LONGJUMP6/15_PCREL/INSN16 + sethi ta, hi20(symbol) ; HI20/PTR + ori ta, ta, lo12(symbol) ; LO12S0_ORI/PTR + jr ta ; PTR_RES/INSN16/EMPTY + .L1: + + case : 4-4-4-4; 1st insn not convertible, 16-bit on. + bne rt, ra, .L1 ; LONGJUMP6/15_PCREL/INSN16 + sethi ta, hi20(symbol) ; HI20/PTR + ori ta, ta, lo12(symbol) ; LO12S0_ORI/PTR + jr ta ; PTR_RES/INSN16/EMPTY + .L1: */ + + enum elf_nds32_reloc_type checked_types[] = + { R_NDS32_17_PCREL_RELA, R_NDS32_15_PCREL_RELA, + R_NDS32_9_PCREL_RELA, R_NDS32_INSN16 }; + + int reloc_off = 0, cond_removed = 0; + bfd_vma laddr; + Elf_Internal_Rela *cond_irel, *em_irel, *irelend, *insn_irel; + int pic_ext_target = 0; + unsigned int i; + bfd_signed_vma foff; + uint32_t insn, re_insn = 0; + uint16_t insn16, re_insn16 = 0; + unsigned long reloc; - foff = calculate_got_memory_address (abfd, link_info, irel, - symtab_hdr) - local_sda; + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; - if (foff < 0x3f000 && foff >= -0x3f000) - { - /* Turn LW to LWI.GP. Change relocation type to R_NDS32_GOT_REL. */ - insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (6, 17, 3)); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_GOT17S2_RELA); - } - else - continue; + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + em_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_EMPTY, irel->r_addend); - bfd_putb32 (insn, contents + laddr); - if (i1_irelfn != irelend) - { - i1_irelfn->r_addend |= 1; - *again = TRUE; - } - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_SUFF) - { - int opc_insn_gotoff; + if (em_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGJUMP6 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } - insn = bfd_getb32 (contents + laddr); - if (insn & 0x80000000) - continue; + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, em_irel, isymbuf, symtab_hdr, + &pic_ext_target); - if (nds32_elf_check_dup_relocs - (irel, internal_relocs, irelend, R_NDS32_GOTOFF_SUFF)) - continue; + if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 + || foff >= CONSERVATIVE_24BIT_S1) + return FALSE; - seq_len = insn_len = 4; + insn = bfd_getb32 (contents + laddr); + /* Check instruction size. */ + if (insn & 0x80000000) + { + *seq_len = 0; + insn16 = insn >> 16; + nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn); + } + else + nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn); - i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, - R_NDS32_PTR_RESOLVED); - nds32_elf_final_sda_base (sec->output_section->owner, link_info, - &local_sda, FALSE); - access_addr = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); - foff = access_addr - local_sda; + /* For simplicity of coding, we are going to modify the section + contents, the section relocs, and the BFD symbol table. We + must tell the rest of the code not to free up this + information. It would be possible to instead create a table + of changes which have to be made, as is done in coff-mips.c; + that would be more work, but would require less memory when + the linker is run. */ - if (foff >= 0x3f000 || foff < -0x3f000) - continue; + if (N32_OP6 (re_insn) == N32_OP6_BR1 + && (foff >= -CONSERVATIVE_14BIT_S1 && foff < CONSERVATIVE_14BIT_S1)) + { + /* beqs label ; 15_PCREL */ + bfd_putb32 (re_insn, contents + em_irel->r_offset); + reloc = R_NDS32_15_PCREL_RELA; + cond_removed = 1; + } + else if (N32_OP6 (re_insn) == N32_OP6_BR2 + && foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1) + { + /* beqz label ; 17_PCREL */ + bfd_putb32 (re_insn, contents + em_irel->r_offset); + reloc = R_NDS32_17_PCREL_RELA; + cond_removed = 1; + } + else if (foff >= -CONSERVATIVE_24BIT_S1 - reloc_off + && foff < CONSERVATIVE_24BIT_S1 - reloc_off) + { + /* Relax to one of the following 2 variations - /* Concatenate opcode and sub-opcode for switch case. - It may be MEM or ALU1. */ - opc_insn_gotoff = (N32_OP6 (insn) << 8) | (insn & 0xff); - switch (opc_insn_gotoff) - { - case (N32_OP6_MEM << 8) | N32_MEM_LW: - /* 4-byte aligned. */ - insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (6, 17, 3)); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA17S2_RELA); - break; - case (N32_OP6_MEM << 8) | N32_MEM_SW: - insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (7, 17, 3)); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA17S2_RELA); - break; - case (N32_OP6_MEM << 8) | N32_MEM_LH: - /* 2-byte aligned. */ - insn = N32_TYPE1 (HWGP, N32_RT5 (insn), 0); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA18S1_RELA); - break; - case (N32_OP6_MEM << 8) | N32_MEM_LHS: - insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __BIT (18)); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA18S1_RELA); - break; - case (N32_OP6_MEM << 8) | N32_MEM_SH: - insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __BIT (19)); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA18S1_RELA); - break; - case (N32_OP6_MEM << 8) | N32_MEM_LB: - /* 1-byte aligned. */ - insn = N32_TYPE1 (LBGP, N32_RT5 (insn), 0); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA); - break; - case (N32_OP6_MEM << 8) | N32_MEM_LBS: - insn = N32_TYPE1 (LBGP, N32_RT5 (insn), __BIT (19)); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA); - break; - case (N32_OP6_MEM << 8) | N32_MEM_SB: - insn = N32_TYPE1 (SBGP, N32_RT5 (insn), 0); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA); - break; - case (N32_OP6_ALU1 << 8) | N32_ALU1_ADD_SLLI: - if (N32_SH5 (insn) != 0) - continue; - insn = N32_TYPE1 (SBGP, N32_RT5 (insn), __BIT (19)); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA); - break; - default: - continue; - } + case 2-4; 1st insn convertible, 16-bit on. + bnes38 rt, ra, .L1 ; LONGJUMP5/9_PCREL/INSN16 + j label ; 25_PCREL/INSN16 + $1: - bfd_putb32 (insn, contents + laddr); - if (i1_irelfn != irelend) - { - i1_irelfn->r_addend |= 1; - *again = TRUE; - } - if ((i2_irelfn = - find_relocs_at_address (irel, internal_relocs, irelend, - R_NDS32_INSN16)) != irelend) - i2_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_MULCALL_SUFF) - { - /* The last bit of r_addend indicates its a two instruction block. */ - i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, - R_NDS32_PTR_RESOLVED); - if ((i1_irelfn != irelend && (i1_irelfn->r_addend & 1)) - || (nds32_elf_insn_size (abfd, contents, irel->r_offset) != 4 - && !(i1_irelfn != irelend && (i1_irelfn->r_addend & 2)))) - continue; + case 4-4; 1st insn not convertible + bne rt, ra, .L1 ; LONGJUMP5/15_PCREL/INSN16 + j label ; 25_PCREL/INSN16 + .L1: */ - /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, irel, isymbuf, symtab_hdr, - &pic_ext_target); + /* Use j label as second instruction. */ + insn = INSN_J; + reloc = R_NDS32_25_PCREL_RELA; + bfd_putb32 (insn, contents + em_irel->r_offset); + } + else + return FALSE; - /* This condition only happened when symbol is undefined. */ - if (pic_ext_target || foff == 0) - continue; - if (foff < -0x1000000 || foff >= 0x1000000) - continue; + /* Set all relocations. */ + em_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), reloc); - if (i1_irelfn != irelend && (i1_irelfn->r_addend & 2)) - { - seq_len = nds32_elf_insn_size (abfd, contents, irel->r_offset); - seq_len += nds32_elf_insn_size (abfd, contents, - irel->r_offset + seq_len); - } - else - seq_len = 4; - insn_len = 4; + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED, em_irel->r_offset); + cond_irel->r_addend = 1; - insn = INSN_JAL; - bfd_putb32 (insn, contents + laddr); - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_25_PCREL_RELA); + /* Use INSN16 of first branch instruction to distinguish if keeping + INSN16 of final instruction or not. */ + insn_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_INSN16, irel->r_offset); + if (insn_irel == irelend) + { + /* Clean the final INSN16. */ + insn_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_INSN16, em_irel->r_offset); + insn_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), + R_NDS32_NONE); + } + + if (cond_removed == 1) + { + *insn_len = 0; + + /* Clear relocations. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - if (i1_irelfn != irelend) + for (i = 0; i < sizeof (checked_types) / sizeof (checked_types[0]); i++) + { + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + checked_types[i], laddr); + if (cond_irel != irelend) { - i1_irelfn->r_addend |= 1; - *again = TRUE; + if (*seq_len == 0 + && (ELF32_R_TYPE (cond_irel->r_info) == R_NDS32_INSN16)) + { + /* If the branch instruction is 2 byte, it cannot remove + directly. Only convert it to nop16 and remove it after + checking alignment issue. */ + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + laddr); + cond_irel->r_addend = R_NDS32_INSN16_CONVERT_FLAG; + } + else + cond_irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE); } - while (i1_irelfn != irelend - && irel->r_offset == i1_irelfn->r_offset) - i1_irelfn++; - for (; - i1_irelfn != irelend - && i1_irelfn->r_offset < irel->r_offset + 4; i1_irelfn++) - i1_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), R_NDS32_NONE); } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_PLTBLOCK) - { - i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, - R_NDS32_PLT_GOTREL_HI20); + } + else + { + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + R_NDS32_LONGJUMP5); + } - if (i1_irelfn == irelend) - { - (*_bfd_error_handler) - ("%B: warning: R_NDS32_PLTBLOCK points to unrecognized reloc at 0x%lx.", - abfd, (long) irel->r_offset); - continue; - } + return TRUE; +} - nds32_elf_final_sda_base (sec->output_section->owner, link_info, - &local_sda, FALSE); - foff = - calculate_plt_offset (abfd, sec, link_info, isymbuf, hi_irelfn, - symtab_hdr); +/* Relax LONGJUMP7 relocation for nds32_elf_relax_section. */ - if (foff < -0x1000000 || foff >= 0x1000000) - { - foff = (bfd_signed_vma) (calculate_plt_memory_address - (abfd, link_info, isymbuf, hi_irelfn, - symtab_hdr) - local_sda); - if (foff >= -0x4000 && foff < 0x4000) - { - /* addi $rt, $gp, lo15(Sym - SDA_BASE) - jral $rt */ +static bfd_boolean +nds32_elf_relax_longjump7 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + int *seq_len, bfd_byte *contents, + Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + /* There are 2 variations for LONGJUMP5 + case 2-4; 1st insn convertible, 16-bit on. + movi55 ta, imm11 ; LONGJUMP7/INSN16 + beq rt, ta, label ; 15_PCREL + + case 4-4; 1st insn not convertible + movi55 ta, imm11 ; LONGJUMP7/INSN16 + beq rt, ta, label ; 15_PCREL */ + + bfd_vma laddr; + Elf_Internal_Rela *cond_irel, *irelend, *insn_irel; + int pic_ext_target = 0; + bfd_signed_vma foff; + uint32_t insn, re_insn = 0; + uint16_t insn16; + uint32_t imm11; - /* TODO: We can use add.gp here, once ISA V1 is obsolete. */ - insn = N32_TYPE2 (ADDI, N32_RT5 (insn), REG_GP, 0); - bfd_putb32 (insn, contents + irel->r_offset + 8); + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; - i1_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), - R_NDS32_PLT_GOTREL_LO15); - i1_irelfn->r_addend = hi_irelfn->r_addend; + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ - seq_len = 8; - } - else if (foff >= -0x80000 && foff < 0x80000) - { - /* movi $rt, lo20(Sym - SDA_BASE) PLT_GOTREL_LO20 - add $rt, $gp, $rt INSN16 - jral $rt INSN16 */ - - for (i1_irelfn = irel; - i1_irelfn->r_offset < irel->r_offset + 4; i1_irelfn++) - ; - for (; i1_irelfn->r_offset < irel->r_offset + 8; i1_irelfn++) - if (ELF32_R_TYPE (i1_irelfn->r_info) != R_NDS32_PLT_GOTREL_LO12) - i2_irelfn = i1_irelfn; - else if (ELF32_R_TYPE (i1_irelfn->r_info) != R_NDS32_LABEL) - i1_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), - R_NDS32_NONE); - if (i2_irelfn) - { - insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0); - bfd_putb32 (insn, contents + irel->r_offset + 4); - i2_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), - R_NDS32_PLT_GOTREL_LO20); - } - seq_len = 4; - } - else - continue; + cond_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_15_PCREL_RELA, irel->r_addend); + if (cond_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LONGJUMP7 points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } - } - else - { - /* jal Sym INSN16/25_PLTREL */ - for (i1_irelfn = irel; - i1_irelfn->r_offset < irel->r_offset + 12; i1_irelfn++) - ; - - i2_irelfn = i1_irelfn - 1; - i2_irelfn->r_offset = i1_irelfn->r_offset; - i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), - R_NDS32_25_PLTREL); - i2_irelfn->r_addend = hi_irelfn->r_addend; - insn = INSN_JAL; - bfd_putb32 (insn, contents + irel->r_offset + 12); - seq_len = 12; - } + /* Get the value of the symbol referred to by the reloc. */ + foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr, + &pic_ext_target); - insn_len = 0; - } - else - continue; + if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_8BIT_S1 + || foff >= CONSERVATIVE_8BIT_S1) + return FALSE; - if (seq_len - insn_len > 0) - { - if (!insert_nds32_elf_blank - (&relax_blank_list, irel->r_offset + insn_len, - seq_len - insn_len)) - goto error_return; - *again = TRUE; - } + /* Get the first instruction for its size. */ + insn = bfd_getb32 (contents + laddr); + if (insn & 0x80000000) + { + *seq_len = 0; + /* Get the immediate from movi55. */ + imm11 = N16_IMM5S (insn >> 16); + } + else + { + /* Get the immediate from movi. */ + imm11 = N32_IMM20S (insn); } - calc_nds32_blank_total (relax_blank_list); + /* Get the branch instruction. */ + insn = bfd_getb32 (contents + irel->r_addend); + /* Convert instruction to BR3. */ + if ((insn >> 14) & 0x1) + re_insn = N32_BR3 (BNEC, N32_RT5 (insn), imm11, 0); + else + re_insn = N32_BR3 (BEQC, N32_RT5 (insn), imm11, 0); - if (table->relax_fp_as_gp) - { - if (!nds32_relax_fp_as_gp (link_info, abfd, sec, internal_relocs, - irelend, isymbuf)) - goto error_return; + bfd_putb32 (re_insn, contents + cond_irel->r_offset); - if (*again == FALSE) + /* Set all relocations. */ + cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), + R_NDS32_WORD_9_PCREL_RELA); + + /* Clean relocations. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + insn_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_INSN16, irel->r_offset); + if (insn_irel != irelend) + { + if (*seq_len == 0) { - if (!nds32_fag_remove_unused_fpbase (abfd, sec, internal_relocs, - irelend)) - goto error_return; + /* If the first insntruction is 16bit, convert it to nop16. */ + insn16 = NDS32_NOP16; + bfd_putb16 (insn16, contents + laddr); + insn_irel->r_addend = R_NDS32_INSN16_CONVERT_FLAG; } + else + cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), + R_NDS32_NONE); } + *insn_len = 0; - if (*again == FALSE) - { - /* This code block is used to adjust 4-byte alignment by relax a pair - of instruction a time. + return TRUE; +} - It recognizes three types of relocations. - 1. R_NDS32_LABEL - a aligment. - 2. R_NDS32_INSN16 - relax a 32-bit instruction to 16-bit. - 3. is_16bit_NOP () - remove a 16-bit instruction. +#define GET_LOADSTORE_RANGE(addend) (((addend) >> 8) & 0x3f) - FIXME: It seems currently implementation only support 4-byte aligment. - We should handle any-aligment. */ +/* Relax LOADSTORE relocation for nds32_elf_relax_section. */ - Elf_Internal_Rela *insn_rel = NULL; - Elf_Internal_Rela *label_rel = NULL; - Elf_Internal_Rela *tmp_rel, tmp2_rel, *tmp3_rel = NULL; +static bfd_boolean +nds32_elf_relax_loadstore (struct bfd_link_info *link_info, bfd *abfd, + asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr, int load_store_relax) +{ + int eliminate_sethi = 0, range_type, i; + bfd_vma local_sda, laddr; + int seq_len; /* Original length of instruction sequence. */ + uint32_t insn; + Elf_Internal_Rela *hi_irelfn = NULL, *irelend; + bfd_vma access_addr = 0; + bfd_vma range_l = 0, range_h = 0; /* Upper/lower bound. */ + enum elf_nds32_reloc_type checked_types[] = + { R_NDS32_HI20_RELA, R_NDS32_GOT_HI20, + R_NDS32_GOTPC_HI20, R_NDS32_GOTOFF_HI20, + R_NDS32_PLTREL_HI20, R_NDS32_PLT_GOTREL_HI20, + R_NDS32_TLS_LE_HI20 + }; - /* Checking for branch relaxation relies on the relocations to - be sorted on 'r_offset'. This is not guaranteed so we must sort. */ - nds32_insertion_sort (internal_relocs, sec->reloc_count, - sizeof (Elf_Internal_Rela), compar_reloc); + irelend = internal_relocs + sec->reloc_count; + seq_len = GET_SEQ_LEN (irel->r_addend); + laddr = irel->r_offset; + *insn_len = seq_len; - nds32_elf_final_sda_base (sec->output_section->owner, link_info, - &local_sda, FALSE); + /* Get the high part relocation. */ + for (i = 0; (unsigned) i < sizeof (checked_types); i++) + { + hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, + checked_types[i], laddr); + if (hi_irelfn != irelend) + break; + } - /* Force R_NDS32_LABEL before R_NDS32_INSN16. */ - /* FIXME: Can we generate the right order in assembler? - So we don't have to swapping them here. */ - for (label_rel = internal_relocs, insn_rel = internal_relocs; - label_rel < irelend; label_rel++) - { - if (ELF32_R_TYPE (label_rel->r_info) != R_NDS32_LABEL) - continue; + if (hi_irelfn == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_LOADSTORE points to unrecognized" + "reloc at 0x%lx.", abfd, (long) irel->r_offset); + return FALSE; + } - /* Find the first reloc has the same offset with label_rel. */ - while (insn_rel < irelend && insn_rel->r_offset < label_rel->r_offset) - insn_rel++; + range_type = GET_LOADSTORE_RANGE (irel->r_addend); + nds32_elf_final_sda_base (sec->output_section->owner, + link_info, &local_sda, FALSE); - for (; - insn_rel < irelend && insn_rel->r_offset == label_rel->r_offset; - insn_rel++) - /* Check if there were R_NDS32_INSN16 and R_NDS32_LABEL at the same - address. */ - if (ELF32_R_TYPE (insn_rel->r_info) == R_NDS32_INSN16) - break; + switch (ELF32_R_TYPE (hi_irelfn->r_info)) + { + case R_NDS32_HI20_RELA: + insn = bfd_getb32 (contents + laddr); + access_addr = + calculate_memory_address (abfd, hi_irelfn, isymbuf, symtab_hdr); + + if (range_type == NDS32_LOADSTORE_IMM) + { + struct elf_link_hash_entry *h = NULL; + int indx; - if (insn_rel < irelend && insn_rel->r_offset == label_rel->r_offset - && insn_rel < label_rel) + if (ELF32_R_SYM (hi_irelfn->r_info) >= symtab_hdr->sh_info) { - /* Swap the two reloc if the R_NDS32_INSN16 is before R_NDS32_LABEL. */ - memcpy (&tmp2_rel, insn_rel, sizeof (Elf_Internal_Rela)); - memcpy (insn_rel, label_rel, sizeof (Elf_Internal_Rela)); - memcpy (label_rel, &tmp2_rel, sizeof (Elf_Internal_Rela)); + indx = ELF32_R_SYM (hi_irelfn->r_info) - symtab_hdr->sh_info; + h = elf_sym_hashes (abfd)[indx]; } - } - label_rel = NULL; - insn_rel = NULL; - /* If there were a sequence of R_NDS32_LABEL end up with .align 2 or higher, - remove other R_NDS32_LABEL with lower alignment. - If an R_NDS32_INSN16 in between R_NDS32_LABELs must be converted, - then the R_NDS32_LABEL sequence is broke. */ - for (tmp_rel = internal_relocs; tmp_rel < irelend; tmp_rel++) - { - if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_LABEL) + if ((access_addr < CONSERVATIVE_20BIT) + && (!h || (h && strcmp (h->root.root.string, FP_BASE_NAME) != 0))) { - if (label_rel == NULL) - { - if (tmp_rel->r_addend < 2) - label_rel = tmp_rel; - continue; - } - else if (tmp_rel->r_addend > 1) - { - for (tmp3_rel = label_rel; tmp3_rel < tmp_rel; tmp3_rel++) - { - if (ELF32_R_TYPE (tmp3_rel->r_info) == R_NDS32_LABEL - && tmp3_rel->r_addend < 2) - tmp3_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (tmp3_rel->r_info), R_NDS32_NONE); - } - label_rel = NULL; - } + eliminate_sethi = 1; + break; } - else if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_INSN16) + + /* This is avoid to relax symbol address which is fixed + relocations. Ex: _stack. */ + if (h && bfd_is_abs_section (h->root.u.def.section)) + return FALSE; + } + + if (!load_store_relax) + return FALSE; + + /* Case for set gp register. */ + if (N32_RT5 (insn) == REG_GP) + break; + + if (range_type == NDS32_LOADSTORE_FLOAT_S + || range_type == NDS32_LOADSTORE_FLOAT_S) + { + range_l = sdata_range[0][0]; + range_h = sdata_range[0][1]; + } + else + { + range_l = sdata_range[1][0]; + range_h = sdata_range[1][1]; + } + break; + + case R_NDS32_GOT_HI20: + access_addr = + calculate_got_memory_address (abfd, link_info, hi_irelfn, symtab_hdr); + + /* If this symbol is not in .got, the return value will be -1. + Since the gp value is set to SDA_BASE but not GLOBAL_OFFSET_TABLE, + a negative offset is allowed. */ + if ((bfd_signed_vma) (access_addr - local_sda) < CONSERVATIVE_20BIT + && (bfd_signed_vma) (access_addr - local_sda) >= -CONSERVATIVE_20BIT) + eliminate_sethi = 1; + break; + + case R_NDS32_PLT_GOTREL_HI20: + access_addr = calculate_plt_memory_address (abfd, link_info, isymbuf, + hi_irelfn, symtab_hdr); + + if ((bfd_signed_vma) (access_addr - local_sda) < CONSERVATIVE_20BIT + && (bfd_signed_vma) (access_addr - local_sda) >= -CONSERVATIVE_20BIT) + eliminate_sethi = 1; + break; + + case R_NDS32_GOTOFF_HI20: + access_addr = + calculate_memory_address (abfd, hi_irelfn, isymbuf, symtab_hdr); + + if ((bfd_signed_vma) (access_addr - local_sda) < CONSERVATIVE_20BIT + && (bfd_signed_vma) (access_addr - local_sda) >= -CONSERVATIVE_20BIT) + eliminate_sethi = 1; + break; + + case R_NDS32_GOTPC_HI20: + /* The access_addr must consider r_addend of hi_irel. */ + access_addr = sec->output_section->vma + sec->output_offset + + irel->r_offset + hi_irelfn->r_addend; + + if ((bfd_signed_vma) (local_sda - access_addr) < CONSERVATIVE_20BIT + && (bfd_signed_vma) (local_sda - access_addr) >= -CONSERVATIVE_20BIT) + eliminate_sethi = 1; + break; + + case R_NDS32_TLS_LE_HI20: + access_addr = + calculate_memory_address (abfd, hi_irelfn, isymbuf, symtab_hdr); + BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL); + access_addr -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET); + if ((range_type == NDS32_LOADSTORE_IMM) + && (bfd_signed_vma) (access_addr) < CONSERVATIVE_20BIT + && (bfd_signed_vma) (access_addr) >= -CONSERVATIVE_20BIT) + eliminate_sethi = 1; + break; + + default: + return FALSE; + } + + /* Delete sethi instruction. */ + if (eliminate_sethi == 1 + || (local_sda <= access_addr && (access_addr - local_sda) < range_h) + || (local_sda > access_addr && (local_sda - access_addr) <= range_l)) + { + hi_irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + *insn_len = 0; + } + return TRUE; +} + +/* Relax LO12 relocation for nds32_elf_relax_section. */ + +static void +nds32_elf_relax_lo12 (struct bfd_link_info *link_info, bfd *abfd, + asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, bfd_byte *contents, + Elf_Internal_Sym *isymbuf, Elf_Internal_Shdr *symtab_hdr) +{ + uint32_t insn; + bfd_vma local_sda, laddr; + unsigned long reloc; + bfd_vma access_addr; + bfd_vma range_l = 0, range_h = 0; /* Upper/lower bound. */ + Elf_Internal_Rela *irelfn = NULL, *irelend; + struct elf_link_hash_entry *h = NULL; + int indx; + + /* For SDA base relative relaxation. */ + nds32_elf_final_sda_base (sec->output_section->owner, link_info, + &local_sda, FALSE); + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + insn = bfd_getb32 (contents + laddr); + + if (!is_sda_access_insn (insn) && N32_OP6 (insn) != N32_OP6_ORI) + return; + + access_addr = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); + + if (ELF32_R_SYM (irel->r_info) >= symtab_hdr->sh_info) + { + indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; + h = elf_sym_hashes (abfd)[indx]; + } + + if (N32_OP6 (insn) == N32_OP6_ORI && access_addr < CONSERVATIVE_20BIT + && (!h || (h && strcmp (h->root.root.string, FP_BASE_NAME) != 0))) + { + reloc = R_NDS32_20_RELA; + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); + insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0); + bfd_putb32 (insn, contents + laddr); + } + /* This is avoid to relax symbol address which is fixed + relocations. Ex: _stack. */ + else if (N32_OP6 (insn) == N32_OP6_ORI + && h && bfd_is_abs_section (h->root.u.def.section)) + return; + else + { + range_l = sdata_range[1][0]; + range_h = sdata_range[1][1]; + switch (ELF32_R_TYPE (irel->r_info)) + { + case R_NDS32_LO12S0_RELA: + reloc = R_NDS32_SDA19S0_RELA; + break; + case R_NDS32_LO12S1_RELA: + reloc = R_NDS32_SDA18S1_RELA; + break; + case R_NDS32_LO12S2_RELA: + reloc = R_NDS32_SDA17S2_RELA; + break; + case R_NDS32_LO12S2_DP_RELA: + range_l = sdata_range[0][0]; + range_h = sdata_range[0][1]; + reloc = R_NDS32_SDA12S2_DP_RELA; + break; + case R_NDS32_LO12S2_SP_RELA: + range_l = sdata_range[0][0]; + range_h = sdata_range[0][1]; + reloc = R_NDS32_SDA12S2_SP_RELA; + break; + default: + return; + } + + /* There are range_h and range_l because linker has to promise + all sections move cross one page together. */ + if ((local_sda <= access_addr && (access_addr - local_sda) < range_h) + || (local_sda > access_addr && (local_sda - access_addr) <= range_l)) + { + if (N32_OP6 (insn) == N32_OP6_ORI && N32_RT5 (insn) == REG_GP) { - if (label_rel - && label_rel->r_offset != tmp_rel->r_offset - && (is_convert_32_to_16 (abfd, sec, tmp_rel, internal_relocs, - irelend, &insn16) - || is_16bit_NOP (abfd, sec, tmp_rel))) - { - label_rel = NULL; - } + /* Maybe we should add R_NDS32_INSN16 reloc type here + or manually do some optimization. sethi can't be + eliminated when updating $gp so the relative ori + needs to be preserved. */ + return; } + if (!turn_insn_to_sda_access (insn, ELF32_R_TYPE (irel->r_info), + &insn)) + return; + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); + bfd_putb32 (insn, contents + laddr); + + irelfn = find_relocs_at_address (irel, internal_relocs, irelend, + R_NDS32_INSN16); + /* SDA17 must keep INSN16 for converting fp_as_gp. */ + if (irelfn != irelend && reloc != R_NDS32_SDA17S2_RELA) + irelfn->r_info = + ELF32_R_INFO (ELF32_R_SYM (irelfn->r_info), R_NDS32_NONE); + } - label_rel = NULL; - insn_rel = NULL; + } + return; +} - /* Optimized for speed and nothing has not been relaxed. - It's time to align labels. - We may convert a 16-bit instruction right before a label to - 32-bit, in order to align the label if necessary - all reloc entries has been sorted by r_offset. */ - for (irel = internal_relocs; irel < irelend; irel++) +/* Relax low part of PIC instruction pattern. */ + +static void +nds32_elf_relax_piclo12 (struct bfd_link_info *link_info, bfd *abfd, + asection *sec, Elf_Internal_Rela *irel, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + uint32_t insn; + bfd_vma local_sda, laddr; + bfd_signed_vma foff; + unsigned long reloc; + + nds32_elf_final_sda_base (sec->output_section->owner, link_info, + &local_sda, FALSE); + laddr = irel->r_offset; + insn = bfd_getb32 (contents + laddr); + + if (N32_OP6 (insn) != N32_OP6_ORI) + return; + + if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_LO12) + { + foff = calculate_got_memory_address (abfd, link_info, irel, + symtab_hdr) - local_sda; + reloc = R_NDS32_GOT20; + } + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOTREL_LO12) + { + foff = calculate_plt_memory_address (abfd, link_info, isymbuf, irel, + symtab_hdr) - local_sda; + reloc = R_NDS32_PLT_GOTREL_LO20; + } + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_LO12) + { + foff = calculate_memory_address (abfd, irel, isymbuf, + symtab_hdr) - local_sda; + reloc = R_NDS32_GOTOFF; + } + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTPC_LO12) + { + foff = local_sda - sec->output_section->vma + sec->output_offset + + irel->r_offset + irel->r_addend; + reloc = R_NDS32_GOTPC20; + } + else + return; + + if ((foff < CONSERVATIVE_20BIT) && (foff >= -CONSERVATIVE_20BIT)) + { + /* Turn into MOVI. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); + insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0); + bfd_putb32 (insn, contents + laddr); + } +} + +/* Relax low part of LE TLS instruction pattern. */ + +static void +nds32_elf_relax_letlslo12 (struct bfd_link_info *link_info, bfd *abfd, + Elf_Internal_Rela *irel, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr) +{ + uint32_t insn; + bfd_vma laddr; + bfd_signed_vma foff; + unsigned long reloc; + + laddr = irel->r_offset; + foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); + BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL); + foff -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET); + insn = bfd_getb32 (contents + laddr); + + if ( (bfd_signed_vma) (foff) < CONSERVATIVE_20BIT + && (bfd_signed_vma) (foff) >= -CONSERVATIVE_20BIT) + { + /* Pattern sethi-ori transform to movi. */ + reloc = R_NDS32_TLS_LE_20; + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); + insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0); + bfd_putb32 (insn, contents + laddr); + } +} + +/* Relax LE TLS calculate address instruction pattern. */ + +static void +nds32_elf_relax_letlsadd (struct bfd_link_info *link_info, bfd *abfd, + asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again) +{ + /* Local TLS non-pic + sethi ta, hi20(symbol@tpoff) ; TLS_LE_HI20 + ori ta, ta, lo12(symbol@tpoff) ; TLS_LE_LO12 + add ra, ta, tp ; TLS_LE_ADD */ + + uint32_t insn; + bfd_vma laddr; + bfd_signed_vma foff; + Elf_Internal_Rela *i1_irelfn, *irelend; + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + insn = bfd_getb32 (contents + laddr); + i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED); + foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); + BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL); + foff -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET); + + /* The range is +/-16k. */ + if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT + && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT) + { + /* Transform add to addi. */ + insn = N32_TYPE2 (ADDI, N32_RT5 (insn), N32_RB5 (insn), 0); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S0); + + bfd_putb32 (insn, contents + laddr); + if (i1_irelfn != irelend) + { + i1_irelfn->r_addend |= 1; + *again = TRUE; + } + } +} + +/* Relax LE TLS load store instruction pattern. */ + +static void +nds32_elf_relax_letlsls (struct bfd_link_info *link_info, bfd *abfd, + asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again) +{ + + uint32_t insn; + bfd_vma laddr; + bfd_signed_vma foff; + Elf_Internal_Rela *i1_irelfn, *irelend; + int success = 0; + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + insn = bfd_getb32 (contents + laddr); + i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED); + foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); + BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL); + foff -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET); + + switch ((N32_OP6 (insn) << 8) | (insn & 0xff)) + { + case (N32_OP6_MEM << 8) | N32_MEM_LB: + case (N32_OP6_MEM << 8) | N32_MEM_SB: + case (N32_OP6_MEM << 8) | N32_MEM_LBS: + /* The range is +/-16k. */ + if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT + && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT) + { + insn = + ((insn & 0xff) << 25) | (insn & 0x1f00000) | ((insn & 0x7c00) << 5); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S0); + success = 1; + break; + } + case (N32_OP6_MEM << 8) | N32_MEM_LH: + case (N32_OP6_MEM << 8) | N32_MEM_SH: + case (N32_OP6_MEM << 8) | N32_MEM_LHS: + /* The range is +/-32k. */ + if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT_S1 + && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT_S1) { - if (ELF32_R_TYPE (irel->r_info) != R_NDS32_INSN16 - && ELF32_R_TYPE (irel->r_info) != R_NDS32_LABEL) - continue; + insn = + ((insn & 0xff) << 25) | (insn & 0x1f00000) | ((insn & 0x7c00) << 5); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S1); + success = 1; + break; + } + case (N32_OP6_MEM << 8) | N32_MEM_LW: + case (N32_OP6_MEM << 8) | N32_MEM_SW: + /* The range is +/-64k. */ + if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT_S2 + && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT_S2) + { + insn = + ((insn & 0xff) << 25) | (insn & 0x1f00000) | ((insn & 0x7c00) << 5); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S2); + success = 1; + break; + } + default: + break; + } - /* Search for INSN16 reloc. */ - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_INSN16) - { - if (label_rel) - { - /* Previous LABEL reloc exists. Try to resolve it. */ - if (label_rel->r_offset == irel->r_offset) - { - /* LABEL and INSN are at the same addr. */ - if ((irel->r_offset - - get_nds32_elf_blank_total (&relax_blank_list, - irel->r_offset, - 1)) & 0x02) - { - if (irel->r_addend > 1) - { - /* Force to relax. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_NDS32_NONE); - if (is_convert_32_to_16 - (abfd, sec, irel, internal_relocs, irelend, - &insn16)) - { - nds32_elf_write_16 (abfd, contents, irel, - internal_relocs, irelend, - insn16); - - if (!insert_nds32_elf_blank_recalc_total - (&relax_blank_list, irel->r_offset + 2, - 2)) - goto error_return; - } - else if (is_16bit_NOP (abfd, sec, irel)) - { - if (!insert_nds32_elf_blank_recalc_total - (&relax_blank_list, irel->r_offset, 2)) - goto error_return; - } - } - else - { - if (is_convert_32_to_16 - (abfd, sec, irel, internal_relocs, irelend, - &insn16) - || is_16bit_NOP (abfd, sec, irel)) - insn_rel = irel; - } - label_rel = NULL; - continue; - } - else - { - /* Already aligned, reset LABEL and keep INSN16. */ - } - } - else - { - /* No INSN16 to relax, we don't want to insert 16-bit. */ - /* Nop here, just signal the algorithm is wrong. */ - } - label_rel = NULL; - } - /* A new INSN16 found, resize the old one. */ - else if (insn_rel) - { - if (!is_convert_32_to_16 - (abfd, sec, irel, internal_relocs, irelend, - &insn16) - && !is_16bit_NOP (abfd, sec, irel)) - { - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_NDS32_NONE); - continue; - } - /* Previous INSN16 reloc exists, reduce its size to 16-bit. */ - if (is_convert_32_to_16 - (abfd, sec, insn_rel, internal_relocs, irelend, - &insn16)) - { - nds32_elf_write_16 (abfd, contents, insn_rel, - internal_relocs, irelend, insn16); + if (success) + { + bfd_putb32 (insn, contents + laddr); + if (i1_irelfn != irelend) + { + i1_irelfn->r_addend |= 1; + *again = TRUE; + } + } +} - if (!insert_nds32_elf_blank_recalc_total - (&relax_blank_list, insn_rel->r_offset + 2, 2)) - goto error_return; - } - else if (is_16bit_NOP (abfd, sec, insn_rel)) - { - if (!insert_nds32_elf_blank_recalc_total - (&relax_blank_list, insn_rel->r_offset, 2)) - goto error_return; - } - insn_rel->r_info = - ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info), - R_NDS32_NONE); - insn_rel = NULL; - } +/* Relax PTR relocation for nds32_elf_relax_section. */ - if (is_convert_32_to_16 - (abfd, sec, irel, internal_relocs, irelend, &insn16) - || is_16bit_NOP (abfd, sec, irel)) - { - insn_rel = irel; - } - /* Save the new one for later use. */ - } - /* Search for label. */ - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL) - { - /* Label on 16-bit instruction, just reset this reloc. */ - insn16 = bfd_getb16 (contents + irel->r_offset); - if ((irel->r_addend & 0x1f) < 2 && (insn16 & 0x8000)) - { - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - continue; - } +static bfd_boolean +nds32_elf_relax_ptr (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, int *insn_len, + int *seq_len, bfd_byte *contents) +{ + Elf_Internal_Rela *ptr_irel, *irelend, *count_irel, *re_irel; - if (!optimize && (irel->r_addend & 0x1f) < 2) - { - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - continue; - } + irelend = internal_relocs + sec->reloc_count; - /* Try to align this label. */ - if (insn_rel) - { - int force_relax = 0; + re_irel = + find_relocs_at_address_addr (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED, irel->r_addend); - /* If current location is .align 2, we can't relax previous 32-bit inst. */ - /* Or the alignment constraint is broke. */ - if ((irel->r_addend & 0x1f) < 2) - { - /* Label_rel always seats before insn_rel after our sort. */ + if (re_irel == irelend) + { + (*_bfd_error_handler) + ("%B: warning: R_NDS32_PTR points to unrecognized reloc at 0x%lx.", + abfd, (long) irel->r_offset); + return FALSE; + } - /* INSN16 and LABEL at different location. */ - /* Search for INSN16 at LABEL location. */ - for (tmp_rel = irel; - tmp_rel < irelend && tmp_rel->r_offset == irel->r_offset; - tmp_rel++) - { - if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_INSN16) - break; - } + if (re_irel->r_addend != 1) + return FALSE; - if (tmp_rel < irelend - && tmp_rel->r_offset == irel->r_offset) - { - if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_INSN16) - { - if (is_convert_32_to_16 - (abfd, sec, tmp_rel, internal_relocs, - irelend, &insn16) - || is_16bit_NOP (abfd, sec, tmp_rel)) - force_relax = 1; - } - } - } + /* Pointed target is relaxed and no longer needs this void *, + change the type to NONE. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - if ((irel->r_offset - - get_nds32_elf_blank_total (&relax_blank_list, - irel->r_offset, 1)) & 0x01) - { - /* Can't align on byte, BIG ERROR. */ - } - else + /* Find PTR_COUNT to decide remove it or not. If PTR_COUNT does + not exist, it means only count 1 and remove it directly. */ + /* TODO: I hope we can obsolate R_NDS32_COUNT in the future. */ + count_irel = find_relocs_at_address (irel, internal_relocs, irelend, + R_NDS32_PTR_COUNT); + ptr_irel = find_relocs_at_address (irel, internal_relocs, irelend, + R_NDS32_PTR); + if (count_irel != irelend) + { + if (--count_irel->r_addend > 0) + return FALSE; + } + + if (ptr_irel != irelend) + return FALSE; + + /* If the PTR_COUNT is already 0, remove current instruction. */ + *seq_len = nds32_elf_insn_size (abfd, contents, irel->r_offset); + *insn_len = 0; + return TRUE; +} + +/* Relax PLT_GOT_SUFF relocation for nds32_elf_relax_section. */ + +static void +nds32_elf_relax_pltgot_suff (struct bfd_link_info *link_info, bfd *abfd, + asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again) +{ + uint32_t insn; + bfd_signed_vma foff; + Elf_Internal_Rela *i1_irelfn, *irelend; + bfd_vma local_sda, laddr; + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + insn = bfd_getb32 (contents + laddr); + + /* FIXME: It's a little trouble to turn JRAL5 to JAL since + we need additional space. It might be help if we could + borrow some space from instructions to be eliminated + such as sethi, ori, add. */ + if (insn & 0x80000000) + return; + + if (nds32_elf_check_dup_relocs + (irel, internal_relocs, irelend, R_NDS32_PLT_GOT_SUFF)) + return; + + i1_irelfn = + find_relocs_at_address (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED); + + /* FIXIT 090606 + The boundary should be reduced since the .plt section hasn't + been created and the address of specific entry is still unknown + Maybe the range between the function call and the begin of the + .text section can be used to decide if the .plt is in the range + of function call. */ + + if (N32_OP6 (insn) == N32_OP6_ALU1 + && N32_SUB5 (insn) == N32_ALU1_ADD) + { + /* Get the value of the symbol referred to by the reloc. */ + nds32_elf_final_sda_base (sec->output_section->owner, link_info, + &local_sda, FALSE); + foff = (bfd_signed_vma) (calculate_plt_memory_address + (abfd, link_info, isymbuf, irel, + symtab_hdr) - local_sda); + /* This condition only happened when symbol is undefined. */ + if (foff == 0) + return; + + if (foff < -CONSERVATIVE_19BIT || foff >= CONSERVATIVE_19BIT) + return; + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + R_NDS32_PLT_GOTREL_LO19); + /* addi.gp */ + insn = N32_TYPE1 (SBGP, N32_RT5 (insn), __BIT (19)); + } + else if (N32_OP6 (insn) == N32_OP6_JREG + && N32_SUB5 (insn) == N32_JREG_JRAL) + { + /* Get the value of the symbol referred to by the reloc. */ + foff = + calculate_plt_offset (abfd, sec, link_info, isymbuf, irel, symtab_hdr); + /* This condition only happened when symbol is undefined. */ + if (foff == 0) + return; + if (foff < -CONSERVATIVE_24BIT_S1 || foff >= CONSERVATIVE_24BIT_S1) + return; + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_25_PLTREL); + insn = INSN_JAL; + } + else + return; + + bfd_putb32 (insn, contents + laddr); + if (i1_irelfn != irelend) + { + i1_irelfn->r_addend |= 1; + *again = TRUE; + } +} + +/* Relax GOT_SUFF relocation for nds32_elf_relax_section. */ + +static void +nds32_elf_relax_got_suff (struct bfd_link_info *link_info, bfd *abfd, + asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, + bfd_byte *contents, Elf_Internal_Shdr *symtab_hdr, + bfd_boolean *again) +{ + uint32_t insn; + bfd_signed_vma foff; + Elf_Internal_Rela *i1_irelfn, *irelend; + bfd_vma local_sda, laddr; + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + insn = bfd_getb32 (contents + laddr); + if (insn & 0x80000000) + return; + + if (nds32_elf_check_dup_relocs + (irel, internal_relocs, irelend, R_NDS32_GOT_SUFF)) + return; + + i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED); + + nds32_elf_final_sda_base (sec->output_section->owner, link_info, + &local_sda, FALSE); + foff = calculate_got_memory_address (abfd, link_info, irel, + symtab_hdr) - local_sda; + + if (foff < CONSERVATIVE_19BIT && foff >= -CONSERVATIVE_19BIT) + { + /* Turn LW to LWI.GP. Change relocation type to R_NDS32_GOT_REL. */ + insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (6, 17, 3)); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_GOT17S2_RELA); + bfd_putb32 (insn, contents + laddr); + if (i1_irelfn != irelend) + { + i1_irelfn->r_addend |= 1; + *again = TRUE; + } + } +} + +/* Relax PLT_GOT_SUFF relocation for nds32_elf_relax_section. */ + +static void +nds32_elf_relax_gotoff_suff (struct bfd_link_info *link_info, bfd *abfd, + asection *sec, Elf_Internal_Rela *irel, + Elf_Internal_Rela *internal_relocs, + bfd_byte *contents, Elf_Internal_Sym *isymbuf, + Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again) +{ + int opc_insn_gotoff; + uint32_t insn; + bfd_signed_vma foff; + Elf_Internal_Rela *i1_irelfn, *i2_irelfn, *irelend; + bfd_vma local_sda, laddr; + + irelend = internal_relocs + sec->reloc_count; + laddr = irel->r_offset; + insn = bfd_getb32 (contents + laddr); + + if (insn & 0x80000000) + return; + + if (nds32_elf_check_dup_relocs + (irel, internal_relocs, irelend, R_NDS32_GOTOFF_SUFF)) + return; + + i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, + R_NDS32_PTR_RESOLVED); + nds32_elf_final_sda_base (sec->output_section->owner, link_info, + &local_sda, FALSE); + foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); + foff = foff - local_sda; + + if (foff >= CONSERVATIVE_19BIT || foff < -CONSERVATIVE_19BIT) + return; + + /* Concatenate opcode and sub-opcode for switch case. + It may be MEM or ALU1. */ + opc_insn_gotoff = (N32_OP6 (insn) << 8) | (insn & 0xff); + switch (opc_insn_gotoff) + { + case (N32_OP6_MEM << 8) | N32_MEM_LW: + /* 4-byte aligned. */ + insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (6, 17, 3)); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA17S2_RELA); + break; + case (N32_OP6_MEM << 8) | N32_MEM_SW: + insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (7, 17, 3)); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA17S2_RELA); + break; + case (N32_OP6_MEM << 8) | N32_MEM_LH: + /* 2-byte aligned. */ + insn = N32_TYPE1 (HWGP, N32_RT5 (insn), 0); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA18S1_RELA); + break; + case (N32_OP6_MEM << 8) | N32_MEM_LHS: + insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __BIT (18)); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA18S1_RELA); + break; + case (N32_OP6_MEM << 8) | N32_MEM_SH: + insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __BIT (19)); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA18S1_RELA); + break; + case (N32_OP6_MEM << 8) | N32_MEM_LB: + /* 1-byte aligned. */ + insn = N32_TYPE1 (LBGP, N32_RT5 (insn), 0); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA); + break; + case (N32_OP6_MEM << 8) | N32_MEM_LBS: + insn = N32_TYPE1 (LBGP, N32_RT5 (insn), __BIT (19)); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA); + break; + case (N32_OP6_MEM << 8) | N32_MEM_SB: + insn = N32_TYPE1 (SBGP, N32_RT5 (insn), 0); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA); + break; + case (N32_OP6_ALU1 << 8) | N32_ALU1_ADD: + insn = N32_TYPE1 (SBGP, N32_RT5 (insn), __BIT (19)); + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA); + break; + default: + return; + } + + bfd_putb32 (insn, contents + laddr); + if (i1_irelfn != irelend) + { + i1_irelfn->r_addend |= 1; + *again = TRUE; + } + if ((i2_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, + R_NDS32_INSN16)) != irelend) + i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + +} + +static bfd_boolean +nds32_relax_adjust_label (bfd *abfd, asection *sec, + Elf_Internal_Rela *internal_relocs, + bfd_byte *contents, + nds32_elf_blank_t **relax_blank_list, + int optimize, int opt_size) +{ + /* This code block is used to adjust 4-byte alignment by relax a pair + of instruction a time. + + It recognizes three types of relocations. + 1. R_NDS32_LABEL - a aligment. + 2. R_NDS32_INSN16 - relax a 32-bit instruction to 16-bit. + 3. is_16bit_NOP () - remove a 16-bit instruction. */ + + /* TODO: It seems currently implementation only support 4-byte aligment. + We should handle any-aligment. */ + + Elf_Internal_Rela *insn_rel = NULL, *label_rel = NULL, *irel; + Elf_Internal_Rela *tmp_rel, *tmp2_rel = NULL; + Elf_Internal_Rela rel_temp; + Elf_Internal_Rela *irelend; + bfd_vma address; + uint16_t insn16; + + /* Checking for branch relaxation relies on the relocations to + be sorted on 'r_offset'. This is not guaranteed so we must sort. */ + nds32_insertion_sort (internal_relocs, sec->reloc_count, + sizeof (Elf_Internal_Rela), compar_reloc); + + irelend = internal_relocs + sec->reloc_count; + + /* Force R_NDS32_LABEL before R_NDS32_INSN16. */ + /* FIXME: Can we generate the right order in assembler? + So we don't have to swapping them here. */ + + for (label_rel = internal_relocs, insn_rel = internal_relocs; + label_rel < irelend; label_rel++) + { + if (ELF32_R_TYPE (label_rel->r_info) != R_NDS32_LABEL) + continue; + + /* Find the first reloc has the same offset with label_rel. */ + while (insn_rel < irelend && insn_rel->r_offset < label_rel->r_offset) + insn_rel++; + + for (;insn_rel < irelend && insn_rel->r_offset == label_rel->r_offset; + insn_rel++) + /* Check if there were R_NDS32_INSN16 and R_NDS32_LABEL at the same + address. */ + if (ELF32_R_TYPE (insn_rel->r_info) == R_NDS32_INSN16) + break; + + if (insn_rel < irelend && insn_rel->r_offset == label_rel->r_offset + && insn_rel < label_rel) + { + /* Swap the two reloc if the R_NDS32_INSN16 is + before R_NDS32_LABEL. */ + memcpy (&rel_temp, insn_rel, sizeof (Elf_Internal_Rela)); + memcpy (insn_rel, label_rel, sizeof (Elf_Internal_Rela)); + memcpy (label_rel, &rel_temp, sizeof (Elf_Internal_Rela)); + } + } + + label_rel = NULL; + insn_rel = NULL; + /* If there were a sequence of R_NDS32_LABEL end up with .align 2 + or higher, remove other R_NDS32_LABEL with lower alignment. + If an R_NDS32_INSN16 in between R_NDS32_LABELs must be converted, + then the R_NDS32_LABEL sequence is broke. */ + for (tmp_rel = internal_relocs; tmp_rel < irelend; tmp_rel++) + { + if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_LABEL) + { + if (label_rel == NULL) + { + if (tmp_rel->r_addend < 2) + label_rel = tmp_rel; + continue; + } + else if (tmp_rel->r_addend > 1) + { + /* Remove all LABEL relocation from label_rel to tmp_rel + including relocations with same offset as tmp_rel. */ + for (tmp2_rel = label_rel; tmp2_rel < tmp_rel + || tmp2_rel->r_offset == tmp_rel->r_offset; tmp2_rel++) + { + if (ELF32_R_TYPE (tmp2_rel->r_info) == R_NDS32_LABEL + && tmp2_rel->r_addend < 2) + tmp2_rel->r_info = + ELF32_R_INFO (ELF32_R_SYM (tmp2_rel->r_info), + R_NDS32_NONE); + } + label_rel = NULL; + } + } + else if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_INSN16 && label_rel) + { + /* A new INSN16 which can be converted, so clear label_rel. */ + if (is_convert_32_to_16 (abfd, sec, tmp_rel, internal_relocs, + irelend, &insn16) + || is_16bit_NOP (abfd, sec, tmp_rel)) + label_rel = NULL; + } + } + + label_rel = NULL; + insn_rel = NULL; + /* Optimized for speed and nothing has not been relaxed. + It's time to align labels. + We may convert a 16-bit instruction right before a label to + 32-bit, in order to align the label if necessary + all reloc entries has been sorted by r_offset. */ + for (irel = internal_relocs; irel < irelend; irel++) + { + if (ELF32_R_TYPE (irel->r_info) != R_NDS32_INSN16 + && ELF32_R_TYPE (irel->r_info) != R_NDS32_LABEL) + continue; + + if (ELF32_R_TYPE (irel->r_info) == R_NDS32_INSN16) + { + /* A new INSN16 found, resize the old one. */ + if (is_convert_32_to_16 + (abfd, sec, irel, internal_relocs, irelend, &insn16) + || is_16bit_NOP (abfd, sec, irel)) + { + if (insn_rel) + { + /* Previous INSN16 reloc exists, reduce its + size to 16-bit. */ + if (is_convert_32_to_16 (abfd, sec, insn_rel, internal_relocs, + irelend, &insn16)) { - if (force_relax - || ((irel->r_offset - - get_nds32_elf_blank_total - (&relax_blank_list, irel->r_offset, 1)) - & 0x02) - || irel->r_addend == 1) - { - if (insn_rel != NULL) - { - /* Label not aligned. */ - /* Previous reloc exists, reduce its size to 16-bit. */ - if (is_convert_32_to_16 - (abfd, sec, insn_rel, internal_relocs, - irelend, &insn16)) - { - nds32_elf_write_16 (abfd, contents, insn_rel, - internal_relocs, irelend, - insn16); - - if (!insert_nds32_elf_blank_recalc_total - (&relax_blank_list, - insn_rel->r_offset + 2, 2)) - goto error_return; - } - else if (is_16bit_NOP (abfd, sec, insn_rel)) - { - if (!insert_nds32_elf_blank_recalc_total - (&relax_blank_list, insn_rel->r_offset, - 2)) - goto error_return; - } - else - { - goto error_return; - } - } - } + nds32_elf_write_16 (abfd, contents, insn_rel, + internal_relocs, irelend, insn16); + + if (!insert_nds32_elf_blank_recalc_total + (relax_blank_list, insn_rel->r_offset + 2, 2)) + return FALSE; + } + else if (is_16bit_NOP (abfd, sec, insn_rel)) + { + if (!insert_nds32_elf_blank_recalc_total + (relax_blank_list, insn_rel->r_offset, 2)) + return FALSE; + } + insn_rel->r_info = + ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info), R_NDS32_NONE); + } + /* Save the new one for later use. */ + insn_rel = irel; + } + else + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + R_NDS32_NONE); + } + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL) + { + /* Search for label. */ + int force_relax = 0; + + /* Label on 16-bit instruction or optimization + needless, just reset this reloc. */ + insn16 = bfd_getb16 (contents + irel->r_offset); + if ((irel->r_addend & 0x1f) < 2 && (!optimize || (insn16 & 0x8000))) + { + irel->r_info = + ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); + continue; + } + + address = + irel->r_offset - get_nds32_elf_blank_total (relax_blank_list, + irel->r_offset, 1); + + if (!insn_rel) + { + /* Check if there is case which can not be aligned. */ + if (irel->r_addend == 2 && address & 0x2) + return FALSE; + continue; + } + + /* Try to align this label. */ + + if ((irel->r_addend & 0x1f) < 2) + { + /* Check if there is a INSN16 at the same address. + Label_rel always seats before insn_rel after + our sort. */ + + /* Search for INSN16 at LABEL location. If INSN16 is at + same location and this LABEL alignment is lower than 2, + the INSN16 can be converted to 2-byte. */ + for (tmp_rel = irel; + tmp_rel < irelend && tmp_rel->r_offset == irel->r_offset; + tmp_rel++) + { + if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_INSN16 + && (is_convert_32_to_16 + (abfd, sec, tmp_rel, internal_relocs, + irelend, &insn16) + || is_16bit_NOP (abfd, sec, tmp_rel))) + { + force_relax = 1; + break; + } + } + } + + if (force_relax || irel->r_addend == 1 || address & 0x2) + { + /* Label not aligned. */ + /* Previous reloc exists, reduce its size to 16-bit. */ + if (is_convert_32_to_16 (abfd, sec, insn_rel, + internal_relocs, irelend, &insn16)) + { + nds32_elf_write_16 (abfd, contents, insn_rel, + internal_relocs, irelend, insn16); + + if (!insert_nds32_elf_blank_recalc_total + (relax_blank_list, insn_rel->r_offset + 2, 2)) + return FALSE; + } + else if (is_16bit_NOP (abfd, sec, insn_rel)) + { + if (!insert_nds32_elf_blank_recalc_total + (relax_blank_list, insn_rel->r_offset, 2)) + return FALSE; + } + + } + /* INSN16 reloc is used. */ + insn_rel = NULL; + } + } + + address = + sec->size - get_nds32_elf_blank_total (relax_blank_list, sec->size, 0); + if (insn_rel && (address & 0x2 || opt_size)) + { + if (is_convert_32_to_16 (abfd, sec, insn_rel, internal_relocs, + irelend, &insn16)) + { + nds32_elf_write_16 (abfd, contents, insn_rel, internal_relocs, + irelend, insn16); + if (!insert_nds32_elf_blank_recalc_total + (relax_blank_list, insn_rel->r_offset + 2, 2)) + return FALSE; + insn_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info), + R_NDS32_NONE); + } + else if (is_16bit_NOP (abfd, sec, insn_rel)) + { + if (!insert_nds32_elf_blank_recalc_total + (relax_blank_list, insn_rel->r_offset, 2)) + return FALSE; + insn_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info), + R_NDS32_NONE); + } + } + insn_rel = NULL; + 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; + 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; + + 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; + } + + if (!set && *again) + { + /* It is reentered when again is FALSE. */ + final_sec = sec; + return relax_round; + } + + /* The second round begins. */ + set = TRUE; + + relax_round = round_table[pass]; + + if (!init && final_sec == sec) + { + switch (relax_round) + { + case NDS32_RELAX_NORMAL_ROUND: + if (!*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) +{ + nds32_elf_blank_t *relax_blank_list = NULL; + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Rela *internal_relocs; + Elf_Internal_Rela *irel; + Elf_Internal_Rela *irelend; + Elf_Internal_Sym *isymbuf = NULL; + bfd_byte *contents = NULL; + bfd_boolean result = TRUE; + int optimize = 0; + int opt_size = 0; + uint32_t insn; + uint16_t insn16; + + /* Target dependnet option. */ + struct elf_nds32_link_hash_table *table; + int load_store_relax; + int relax_round; + + relax_blank_list = NULL; + + *again = FALSE; + + /* Nothing to do for + * relocatable link or + * non-relocatable section or + * non-code section or + * empty content or + * no reloc entry. */ + if (link_info->relocatable + || (sec->flags & SEC_RELOC) == 0 + || (sec->flags & SEC_EXCLUDE) == 1 + || (sec->flags & SEC_CODE) == 0 + || sec->size == 0) + return TRUE; + + /* 09.12.11 Workaround. */ + /* We have to adjust align for R_NDS32_LABEL if needed. + The adjust approach only can fix 2-byte align once. */ + if (sec->alignment_power > 2) + return TRUE; + + /* 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. */ + + if (is_SDA_BASE_set == 0) + { + bfd_vma gp; + is_SDA_BASE_set = 1; + nds32_elf_final_sda_base (sec->output_section->owner, link_info, + &gp, FALSE); + 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) (_("%B: error: Cannot set _ITB_BASE_"), abfd); + 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, + TRUE /* keep_memory */); + if (internal_relocs == NULL) + goto error_return; + + irelend = internal_relocs + sec->reloc_count; + irel = find_relocs_at_address (internal_relocs, internal_relocs, + irelend, R_NDS32_RELAX_ENTRY); + + if (irel == irelend) + return TRUE; + + if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY) + { + if (irel->r_addend & R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG) + return TRUE; + + if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FLAG) + optimize = 1; + + if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FOR_SPACE_FLAG) + opt_size = 1; + } + + load_store_relax = table->load_store_relax; + + /* Get symbol table and section content. */ + if (!nds32_get_section_contents (abfd, sec, &contents) + || !nds32_get_local_syms (abfd, sec, &isymbuf)) + goto error_return; + + /* Do relax loop only when finalize is not done. + Take care of relaxable relocs except INSN16. */ + for (irel = internal_relocs; irel < irelend; irel++) + { + int seq_len; /* Original length of instruction sequence. */ + int insn_len = 0; /* Final length of instruction sequence. */ + bfd_boolean removed; + + insn = 0; + if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL + && (irel->r_addend & 0x1f) >= 2) + optimize = 1; + + /* Relocation Types + R_NDS32_LONGCALL1 53 + R_NDS32_LONGCALL2 54 + R_NDS32_LONGCALL3 55 + R_NDS32_LONGJUMP1 56 + R_NDS32_LONGJUMP2 57 + R_NDS32_LONGJUMP3 58 + R_NDS32_LOADSTORE 59 */ + if (ELF32_R_TYPE (irel->r_info) >= R_NDS32_LONGCALL1 + && ELF32_R_TYPE (irel->r_info) <= R_NDS32_LOADSTORE) + seq_len = GET_SEQ_LEN (irel->r_addend); + + /* Relocation Types + R_NDS32_LONGCALL4 107 + R_NDS32_LONGCALL5 108 + R_NDS32_LONGCALL6 109 + R_NDS32_LONGJUMP4 110 + R_NDS32_LONGJUMP5 111 + R_NDS32_LONGJUMP6 112 + R_NDS32_LONGJUMP7 113 */ + else if (ELF32_R_TYPE (irel->r_info) >= R_NDS32_LONGCALL4 + && ELF32_R_TYPE (irel->r_info) <= R_NDS32_LONGJUMP7) + seq_len = 4; + + /* Relocation Types + R_NDS32_LO12S0_RELA 30 + R_NDS32_LO12S1_RELA 29 + R_NDS32_LO12S2_RELA 28 + R_NDS32_LO12S2_SP_RELA 71 + R_NDS32_LO12S2_DP_RELA 70 + R_NDS32_GOT_LO12 46 + R_NDS32_GOTOFF_LO12 50 + R_NDS32_PLTREL_LO12 65 + R_NDS32_PLT_GOTREL_LO12 67 + R_NDS32_17IFC_PCREL_RELA 96 + R_NDS32_GOT_SUFF 193 + R_NDS32_GOTOFF_SUFF 194 + R_NDS32_PLT_GOT_SUFF 195 + R_NDS32_MULCALL_SUFF 196 + R_NDS32_PTR 197 */ + else if ((ELF32_R_TYPE (irel->r_info) <= R_NDS32_LO12S0_RELA + && ELF32_R_TYPE (irel->r_info) >= R_NDS32_LO12S2_RELA) + || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_SP_RELA + || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_DP_RELA + || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_LO12 + || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_LO12 + || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTPC_LO12 + || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLTREL_LO12 + || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOTREL_LO12 + || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_GOT_SUFF + && ELF32_R_TYPE (irel->r_info) <= R_NDS32_PTR) + || ELF32_R_TYPE (irel->r_info) == R_NDS32_17IFC_PCREL_RELA + || ELF32_R_TYPE (irel->r_info) == R_NDS32_TLS_LE_LO12 + || ELF32_R_TYPE (irel->r_info) == R_NDS32_TLS_LE_ADD + || ELF32_R_TYPE (irel->r_info) == R_NDS32_TLS_LE_LS) + seq_len = 0; + else + continue; + + insn_len = seq_len; + removed = FALSE; + + switch (ELF32_R_TYPE (irel->r_info)) + { + case R_NDS32_LONGCALL1: + removed = nds32_elf_relax_longcall1 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGCALL2: + removed = nds32_elf_relax_longcall2 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGCALL3: + removed = nds32_elf_relax_longcall3 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGJUMP1: + removed = nds32_elf_relax_longjump1 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGJUMP2: + removed = nds32_elf_relax_longjump2 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGJUMP3: + removed = nds32_elf_relax_longjump3 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGCALL4: + removed = nds32_elf_relax_longcall4 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGCALL5: + removed = nds32_elf_relax_longcall5 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGCALL6: + removed = nds32_elf_relax_longcall6 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGJUMP4: + removed = nds32_elf_relax_longjump4 (abfd, sec, irel, internal_relocs, + &insn_len, contents, isymbuf, + symtab_hdr); + break; + case R_NDS32_LONGJUMP5: + removed = nds32_elf_relax_longjump5 (abfd, sec, irel, internal_relocs, + &insn_len, &seq_len, contents, + isymbuf, symtab_hdr); + break; + case R_NDS32_LONGJUMP6: + removed = nds32_elf_relax_longjump6 (abfd, sec, irel, internal_relocs, + &insn_len, &seq_len, contents, + isymbuf, symtab_hdr); + break; + case R_NDS32_LONGJUMP7: + removed = nds32_elf_relax_longjump7 (abfd, sec, irel, internal_relocs, + &insn_len, &seq_len, contents, + isymbuf, symtab_hdr); + break; + case R_NDS32_LOADSTORE: + removed = nds32_elf_relax_loadstore (link_info, abfd, sec, irel, + internal_relocs, &insn_len, + contents, isymbuf, symtab_hdr, + load_store_relax); + break; + case R_NDS32_LO12S0_RELA: + case R_NDS32_LO12S1_RELA: + case R_NDS32_LO12S2_DP_RELA: + case R_NDS32_LO12S2_SP_RELA: + case R_NDS32_LO12S2_RELA: + /* Relax for low part. */ + nds32_elf_relax_lo12 (link_info, abfd, sec, irel, internal_relocs, + contents, isymbuf, symtab_hdr); + + /* It is impossible to delete blank, so just continue. */ + continue; + case R_NDS32_GOT_LO12: + case R_NDS32_GOTOFF_LO12: + case R_NDS32_PLTREL_LO12: + case R_NDS32_PLT_GOTREL_LO12: + case R_NDS32_GOTPC_LO12: + /* Relax for PIC gp-relative low part. */ + nds32_elf_relax_piclo12 (link_info, abfd, sec, irel, contents, + isymbuf, symtab_hdr); - if (force_relax) - { - label_rel = irel; - } + /* It is impossible to delete blank, so just continue. */ + continue; + case R_NDS32_TLS_LE_LO12: + /* Relax for LE TLS low part. */ + nds32_elf_relax_letlslo12 (link_info, abfd, irel, contents, + isymbuf, symtab_hdr); - /* INSN16 reloc is used. */ - insn_rel = NULL; - } - } - } + /* It is impossible to delete blank, so just continue. */ + continue; + case R_NDS32_TLS_LE_ADD: + nds32_elf_relax_letlsadd (link_info, abfd, sec, irel, internal_relocs, + contents, isymbuf, symtab_hdr, again); + /* It is impossible to delete blank, so just continue. */ + continue; + case R_NDS32_TLS_LE_LS: + nds32_elf_relax_letlsls (link_info, abfd, sec, irel, internal_relocs, + contents, isymbuf, symtab_hdr, again); + continue; + case R_NDS32_PTR: + removed = nds32_elf_relax_ptr (abfd, sec, irel, internal_relocs, + &insn_len, &seq_len, contents); + break; + case R_NDS32_PLT_GOT_SUFF: + nds32_elf_relax_pltgot_suff (link_info, abfd, sec, irel, + internal_relocs, contents, + isymbuf, symtab_hdr, again); + /* It is impossible to delete blank, so just continue. */ + continue; + case R_NDS32_GOT_SUFF: + nds32_elf_relax_got_suff (link_info, abfd, sec, irel, + internal_relocs, contents, + symtab_hdr, again); + /* It is impossible to delete blank, so just continue. */ + continue; + case R_NDS32_GOTOFF_SUFF: + nds32_elf_relax_gotoff_suff (link_info, abfd, sec, irel, + internal_relocs, contents, + isymbuf, symtab_hdr, again); + /* It is impossible to delete blank, so just continue. */ + continue; + default: + continue; + + } + if (removed && seq_len - insn_len > 0) + { + if (!insert_nds32_elf_blank + (&relax_blank_list, irel->r_offset + insn_len, + seq_len - insn_len)) + goto error_return; + *again = TRUE; } + } + + calc_nds32_blank_total (relax_blank_list); + + if (table->relax_fp_as_gp) + { + if (!nds32_relax_fp_as_gp (link_info, abfd, sec, internal_relocs, + irelend, isymbuf)) + goto error_return; - if (insn_rel) + if (*again == FALSE) { - if (((sec->size - get_nds32_elf_blank_total (&relax_blank_list, sec->size, 0)) - - ((sec->size - get_nds32_elf_blank_total (&relax_blank_list, sec->size, 0)) - & (0xffffffff << sec->alignment_power)) == 2) - || optimize_for_space) - { - if (is_convert_32_to_16 - (abfd, sec, insn_rel, internal_relocs, irelend, - &insn16)) - { - nds32_elf_write_16 (abfd, contents, insn_rel, internal_relocs, - irelend, insn16); - if (!insert_nds32_elf_blank_recalc_total - (&relax_blank_list, insn_rel->r_offset + 2, 2)) - goto error_return; - insn_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info), - R_NDS32_NONE); - } - else if (is_16bit_NOP (abfd, sec, insn_rel)) - { - if (!insert_nds32_elf_blank_recalc_total - (&relax_blank_list, insn_rel->r_offset, 2)) - goto error_return; - insn_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info), - R_NDS32_NONE); - } - } - insn_rel = NULL; + if (!nds32_fag_remove_unused_fpbase (abfd, sec, internal_relocs, + irelend)) + goto error_return; } } - /* It doesn't matter optimize_for_space_no_align anymore. + + nds32_elf_pick_relax (FALSE, sec, again, table, link_info); + + if (*again == FALSE) + { + if (!nds32_relax_adjust_label (abfd, sec, internal_relocs, contents, + &relax_blank_list, optimize, opt_size)) + goto error_return; + } + + /* It doesn't matter optimize_for_space_no_align anymore. If object file is assembled with flag '-Os', the we don't adjust jump-destination on 4-byte boundary. */ @@ -10984,8 +12325,8 @@ nds32_elf_relax_section (bfd *abfd, asection *sec, sec->size += 4; } - tmp_rel = find_relocs_at_address (internal_relocs, internal_relocs, irelend, - R_NDS32_RELAX_ENTRY); + tmp_rel = find_relocs_at_address (internal_relocs, internal_relocs, + irelend, R_NDS32_RELAX_ENTRY); if (tmp_rel != irelend) tmp_rel->r_addend |= R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG; @@ -11096,8 +12437,9 @@ bfd_elf32_nds32_set_target_option (struct bfd_link_info *link_info, optimization. */ #define FAG_THRESHOLD 3 /* At least 3 gp-access. */ -#define FAG_BUMPER 8 /* Leave some space to avoid aligment issues. */ -#define FAG_WINDOW (512 - FAG_BUMPER) /* lwi37.fp covers 512 bytes. */ +/* lwi37.fp covers 508 bytes, but there may be 32-byte padding between + the read-only section and read-write section. */ +#define FAG_WINDOW (508 - 32) /* An nds32_fag represent a gp-relative access. We find best fp-base by using a sliding window @@ -11204,19 +12546,13 @@ nds32_fag_free_list (struct nds32_fag *head) } } -static bfd_boolean -nds32_fag_isempty (struct nds32_fag *head) -{ - return head->next == NULL; -} - /* Find the best fp-base address. The relocation associated with that address is returned, so we can track the symbol instead of a fixed address. When relaxation, the address of an datum may change, because a text section is shrinked, so the data section - moves forward. If the aligments of text and data section + moves forward. If the aligments of text and data section are different, their distance may change too. Therefore, tracking a fixed address is not appriate. */ @@ -11235,8 +12571,11 @@ nds32_fag_find_base (struct nds32_fag *head, struct nds32_fag **bestpp) and accumulate following fags which are inside the window, untill we each the end. */ - if (nds32_fag_isempty (head)) - return 0; + if (head->next == NULL) + { + *bestpp = NULL; + return 0; + } /* Initialize base. */ base = head->next; @@ -11250,22 +12589,22 @@ nds32_fag_find_base (struct nds32_fag *head, struct nds32_fag **bestpp) /* Record the best base in each iteration. */ while (base->next) - { - accu -= base->count; - base = base->next; - /* Account fags in window. */ - for (/* Nothing. */; - last && last->addr < base->addr + FAG_WINDOW; - last = last->next) - accu += last->count; - - /* A better fp-base? */ - if (accu > baccu) - { - best = base; - baccu = accu; - } - } + { + accu -= base->count; + base = base->next; + /* Account fags in window. */ + for (/* Nothing. */; + last && last->addr < base->addr + FAG_WINDOW; + last = last->next) + accu += last->count; + + /* A better fp-base? */ + if (accu > baccu) + { + best = base; + baccu = accu; + } + } if (bestpp) *bestpp = best; @@ -11291,8 +12630,8 @@ nds32_fag_mark_relax (struct bfd_link_info *link_info, nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE); best_fpbase = best_fag->addr; - if (best_fpbase > gp + sdata_range[4][1] - || best_fpbase < gp - sdata_range[4][0]) + if (best_fpbase > gp + sdata_range[1][1] + || best_fpbase < gp - sdata_range[1][0]) return FALSE; /* Mark these inside the window R_NDS32_INSN16_FP7U2_FLAG flag, @@ -11322,6 +12661,34 @@ nds32_fag_mark_relax (struct bfd_link_info *link_info, return TRUE; } +/* Reset INSN16 to clean fp as gp. */ + +static void +nds32_fag_unmark_relax (struct nds32_fag *fag, + Elf_Internal_Rela *internal_relocs, + Elf_Internal_Rela *irelend) +{ + struct nds32_fag *ifag; + int i; + Elf_Internal_Rela *insn16_rel; + Elf_Internal_Rela *fag_rel; + + for (ifag = fag; ifag; ifag = ifag->next) + { + for (i = 0; i < ifag->count; i++) + { + fag_rel = ifag->relas[i]; + + /* Restore the INSN16 relocation. */ + insn16_rel = find_relocs_at_address + (fag_rel, internal_relocs, irelend, R_NDS32_INSN16); + + if (insn16_rel != irelend) + insn16_rel->r_addend &= ~R_NDS32_INSN16_FP7U2_FLAG; + } + } +} + /* This is the main function of fp-as-gp optimization. It should be called by relax_section. */ @@ -11337,6 +12704,7 @@ nds32_relax_fp_as_gp (struct bfd_link_info *link_info, struct nds32_fag fag_head; Elf_Internal_Shdr *symtab_hdr; bfd_byte *contents; + bfd_boolean ifc_inside = FALSE; /* FIXME: Can we bfd_elf_link_read_relocs for the relocs? */ @@ -11385,12 +12753,13 @@ nds32_relax_fp_as_gp (struct bfd_link_info *link_info, begin_rel = irel; nds32_fag_init (&fag_head); + ifc_inside = FALSE; } else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END && (irel->r_addend & R_NDS32_RELAX_REGION_OMIT_FP_FLAG)) { int accu; - struct nds32_fag *best_fag; + struct nds32_fag *best_fag, *tmp_fag; int dist; /* End of the region. @@ -11404,6 +12773,10 @@ nds32_relax_fp_as_gp (struct bfd_link_info *link_info, accu = nds32_fag_find_base (&fag_head, &best_fag); + /* Clean FP7U2_FLAG because they may set ever. */ + tmp_fag = fag_head.next; + nds32_fag_unmark_relax (tmp_fag, internal_relocs, irelend); + /* Check if it is worth, and FP_BASE is near enough to SDA_BASE. */ if (accu < FAG_THRESHOLD || !nds32_fag_mark_relax (link_info, abfd, best_fag, @@ -11426,13 +12799,14 @@ nds32_relax_fp_as_gp (struct bfd_link_info *link_info, BFD_ASSERT (dist > 0 && dist < 0xffffff); /* Use high 16 bits of addend to record the _FP_BASE_ matched relocation. And get the base value when relocating. */ + begin_rel->r_addend &= (0x1 << 16) - 1; begin_rel->r_addend |= dist << 16; nds32_fag_free_list (&fag_head); begin_rel = NULL; } - if (begin_rel == NULL) + if (begin_rel == NULL || ifc_inside) /* Skip if we are not in the region of fp-as-gp. */ continue; @@ -11456,6 +12830,12 @@ nds32_relax_fp_as_gp (struct bfd_link_info *link_info, { begin_rel = NULL; } + else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_17IFC_PCREL_RELA + || ELF32_R_TYPE (irel->r_info) == R_NDS32_10IFCU_PCREL_RELA) + { + /* Suppress fp as gp when encounter ifc. */ + ifc_inside = TRUE; + } } return TRUE; @@ -11559,6 +12939,138 @@ error_return: result = FALSE; goto finish; } + +/* This is a version of bfd_generic_get_relocated_section_contents. + We need this variety because relaxation will modify the dwarf + infomation. When there is undefined symbol reference error mesage, + linker need to dump line number where the symbol be used. However + the address is be relaxed, it can not get the original dwarf contents. + The variety only modify function call for reading in the section. */ + +static bfd_byte * +nds32_elf_get_relocated_section_contents (bfd *abfd, + struct bfd_link_info *link_info, + struct bfd_link_order *link_order, + bfd_byte *data, + bfd_boolean relocatable, + asymbol **symbols) +{ + bfd *input_bfd = link_order->u.indirect.section->owner; + asection *input_section = link_order->u.indirect.section; + long reloc_size; + arelent **reloc_vector; + long reloc_count; + + reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); + if (reloc_size < 0) + return NULL; + + /* Read in the section. */ + if (!nds32_get_section_contents (input_bfd, input_section, &data)) + return NULL; + + if (reloc_size == 0) + return data; + + reloc_vector = (arelent **) bfd_malloc (reloc_size); + if (reloc_vector == NULL) + return NULL; + + reloc_count = bfd_canonicalize_reloc (input_bfd, input_section, + reloc_vector, symbols); + if (reloc_count < 0) + goto error_return; + + if (reloc_count > 0) + { + arelent **parent; + for (parent = reloc_vector; *parent != NULL; parent++) + { + char *error_message = NULL; + asymbol *symbol; + bfd_reloc_status_type r; + + symbol = *(*parent)->sym_ptr_ptr; + if (symbol->section && discarded_section (symbol->section)) + { + bfd_byte *p; + static reloc_howto_type none_howto + = HOWTO (0, 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL, + "unused", FALSE, 0, 0, FALSE); + + p = data + (*parent)->address * bfd_octets_per_byte (input_bfd); + _bfd_clear_contents ((*parent)->howto, input_bfd, input_section, + p); + (*parent)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + (*parent)->addend = 0; + (*parent)->howto = &none_howto; + r = bfd_reloc_ok; + } + else + r = bfd_perform_relocation (input_bfd, *parent, data, + input_section, + relocatable ? abfd : NULL, + &error_message); + + if (relocatable) + { + asection *os = input_section->output_section; + + /* A partial link, so keep the relocs. */ + os->orelocation[os->reloc_count] = *parent; + os->reloc_count++; + } + + if (r != bfd_reloc_ok) + { + switch (r) + { + case bfd_reloc_undefined: + if (!((*link_info->callbacks->undefined_symbol) + (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr), + input_bfd, input_section, (*parent)->address, TRUE))) + goto error_return; + break; + case bfd_reloc_dangerous: + BFD_ASSERT (error_message != NULL); + if (!((*link_info->callbacks->reloc_dangerous) + (link_info, error_message, input_bfd, input_section, + (*parent)->address))) + goto error_return; + break; + case bfd_reloc_overflow: + if (!((*link_info->callbacks->reloc_overflow) + (link_info, NULL, + bfd_asymbol_name (*(*parent)->sym_ptr_ptr), + (*parent)->howto->name, (*parent)->addend, + input_bfd, input_section, (*parent)->address))) + goto error_return; + break; + case bfd_reloc_outofrange: + /* PR ld/13730: + This error can result when processing some partially + complete binaries. Do not abort, but issue an error + message instead. */ + link_info->callbacks->einfo + (_("%X%P: %B(%A): relocation \"%R\" goes out of range\n"), + abfd, input_section, * parent); + goto error_return; + + default: + abort (); + break; + } + } + } + } + + free (reloc_vector); + return data; + +error_return: + free (reloc_vector); + return NULL; +} /* Link-time IFC relaxation. In this optimization, we chains jump instructions @@ -11682,7 +13194,7 @@ nds32_elf_ifc_calc (struct bfd_link_info *info, Elf_Internal_Rela *irel; Elf_Internal_Shdr *symtab_hdr; bfd_byte *contents = NULL; - unsigned long insn, insn_with_reg; + 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); @@ -11788,9 +13300,9 @@ nds32_elf_ifc_filter (struct bfd_link_info *info) } else { - /* Global symbol. We have to get the absolute address - and decide whether to keep it or not.*/ - + /* 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 @@ -11803,11 +13315,13 @@ nds32_elf_ifc_filter (struct bfd_link_info *info) 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) @@ -11817,6 +13331,7 @@ nds32_elf_ifc_filter (struct bfd_link_info *info) } irel_temp = irel_temp->next; } + if (irel_dest != irel_ptr) { if (irel_ptr_prev) @@ -11846,7 +13361,7 @@ nds32_elf_ifc_filter (struct bfd_link_info *info) } } - /* Ex9 enable. Reserve it for ex9. */ + /* Ex9 enable. Reserve it for ex9. */ if ((target_optimize & NDS32_RELAX_EX9_ON) && ptr->irel_head != irel_keeper) ptr->enable = 0; @@ -11932,7 +13447,8 @@ nds32_elf_ifc_replace (struct bfd_link_info *info) /* 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)) + || ((relax_status & NDS32_RELAX_JUMP_IFC_DONE) + && ptr->ex9_enable == 1)) { irel_ptr = ptr->irel_head; if (ptr->h == NULL) @@ -11942,17 +13458,19 @@ nds32_elf_ifc_replace (struct bfd_link_info *info) (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)) + if (!nds32_get_section_contents (ptr->sec->owner, ptr->sec, + &contents)) return FALSE; while (irel_ptr) { if (irel_ptr->keep == 0 && irel_ptr->next) { - /* The one can be replaced. We have to check whether + /* 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) + 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)) @@ -11960,9 +13478,9 @@ nds32_elf_ifc_replace (struct bfd_link_info *info) 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)) + && ((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); @@ -11970,7 +13488,8 @@ nds32_elf_ifc_replace (struct bfd_link_info *info) (&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_TRAN); + ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), + R_NDS32_10IFCU_PCREL_RELA); } } irel_ptr = irel_ptr->next; @@ -12029,7 +13548,8 @@ nds32_elf_ifc_replace (struct bfd_link_info *info) irel_ptr->sec, relax_blank_list); irel_ptr->irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), R_NDS32_TRAN); + ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), + R_NDS32_10IFCU_PCREL_RELA); relax_blank_list = NULL; } } @@ -12046,7 +13566,7 @@ nds32_elf_ifc_replace (struct bfd_link_info *info) /* Relocate ifcall. */ -bfd_boolean +static bfd_boolean nds32_elf_ifc_reloc (void) { struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head; @@ -12054,14 +13574,20 @@ nds32_elf_ifc_reloc (void) 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) { - /* Check the entry is enable ifcall. */ + /* Get the reserve jump. */ irel_ptr = ptr->irel_head; while (irel_ptr) { @@ -12083,7 +13609,7 @@ nds32_elf_ifc_reloc (void) while (irel_ptr) { if (irel_ptr->keep == 0 - && ELF32_R_TYPE (irel_ptr->irel->r_info) == R_NDS32_TRAN) + && 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; @@ -12114,7 +13640,9 @@ nds32_elf_ifc_reloc (void) 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); } @@ -12127,8 +13655,9 @@ nds32_elf_ifc_reloc (void) while (irel_ptr) { if (irel_ptr->keep == 0 - && ELF32_R_TYPE (irel_ptr->irel->r_info) == R_NDS32_TRAN) + && 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); @@ -12136,6 +13665,8 @@ nds32_elf_ifc_reloc (void) + 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; @@ -12170,10 +13701,13 @@ nds32_elf_ifc_reloc (void) return FALSE; } if (!nds32_get_section_contents - (irel_ptr->sec->owner, irel_ptr->sec, &contents)) - return FALSE; - insn16 = INSN_IFCALL9 | (relocation >> 1); - bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset); + (irel_ptr->sec->owner, irel_ptr->sec, &contents)) + 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; } @@ -12569,92 +14103,31 @@ 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; + struct elf_nds32_insn_times_entry *temp = NULL; struct elf_nds32_link_hash_table *table; - char *insn; int ex9_limit; - int number = 0, total = 0; - struct bfd_link_hash_entry *bh; + 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; - /* Get the minimun one of ex9 list and limitation. */ - while (ex9_insn) - { - total++; - ex9_insn = ex9_insn->next; - } - total = MIN (total, ex9_limit); - - temp = bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); - temp->string = bfd_malloc (sizeof (char) * 10); - temp->times = 0; - temp->sec = NULL; - temp->m_list = NULL; - temp->irel = NULL; - temp->next = NULL; - /* Since the struct elf_nds32_insn_times_entry string is const char, - it has to allocate another space to write break 0xea. */ - insn = bfd_malloc (sizeof (char) * 10); - snprintf (insn, sizeof (char) * 10, "%08x", INSN_BREAK_EA); - temp->string = (const char *) insn; - ex9_insn = ex9_insn_head; - while (ex9_insn != NULL && number <= ex9_limit) + while (ex9_insn != NULL && number < ex9_limit) { - /* Save 234th entry for break 0xea, because trace32 need to use - break16 0xea. If the number of entry is less than 234, adjust - the address of _ITB_BASE_ backward. */ - if (total < 234) - { - ex9_insn->order = number + 234 - total; - if (!ex9_insn->next) - { - /* Link break 0xea entry into list. */ - ex9_insn->next = temp; - temp->next = NULL; - temp ->order = number + 235 - total; - ex9_insn = NULL; - break; - } - } - else - ex9_insn->order = number; - + ex9_insn->order = number; number++; - - if (number == 234) - { - /* Link break 0xea entry into list. */ - temp->next = ex9_insn->next; - ex9_insn->next = temp; - temp->order = number; - number++; - ex9_insn = ex9_insn->next; - } - - if (number > ex9_limit) - { - temp = ex9_insn; - ex9_insn = ex9_insn->next; - temp->next = NULL; - break; - } + temp = ex9_insn; ex9_insn = ex9_insn->next; } - if (total < 234) - { - /* Adjust the address of _ITB_BASE_. */ - bh = bfd_link_hash_lookup (info->hash, "_ITB_BASE_", - FALSE, FALSE, FALSE); - if (bh) - bh->u.def.value = (total - 234) * 4; - } + if (ex9_insn && temp) + temp->next = NULL; while (ex9_insn != NULL) { @@ -12692,13 +14165,7 @@ nds32_elf_ex9_build_itable (struct bfd_link_info *link_info) table_sec->size = number * 4; if (number == 0) - { - /* There is no insntruction effective enough to convert to ex9. - Only add break 0xea into ex9 table. */ - table_sec->size = 4; - bfd_putb32 ((bfd_vma) INSN_BREAK_EA, (char *) contents); - return; - } + return; elf_elfheader (link_info->output_bfd)->e_flags |= E_NDS32_HAS_EX9_INST; number = 0; @@ -12719,7 +14186,7 @@ nds32_elf_ex9_build_itable (struct bfd_link_info *link_info) static void nds32_elf_get_insn_with_reg (Elf_Internal_Rela *irel, - unsigned long insn, unsigned long *insn_with_reg) + uint32_t insn, uint32_t *insn_with_reg) { reloc_howto_type *howto = NULL; @@ -12864,8 +14331,7 @@ nds32_elf_ex9_relocation_check (struct bfd_link_info *info, && ((*irel)->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG)) nested_loop = FALSE; } - else if (relax_blank_list - && ELF32_R_TYPE ((*irel)->r_info) == R_NDS32_LABEL + else if (ELF32_R_TYPE ((*irel)->r_info) == R_NDS32_LABEL && ((*irel)->r_addend & 0x1f) == 2) { /* Alignment exist in the region. */ @@ -12888,7 +14354,7 @@ nds32_elf_ex9_relocation_check (struct bfd_link_info *info, break; case R_NDS32_LABEL: - if (relax_blank_list && ((*irel)->r_addend & 0x1f) == 2) + if (((*irel)->r_addend & 0x1f) == 2) { /* Check this point is align and decide to do ex9 or not. */ result |= CLEAN_PRE; @@ -12948,7 +14414,8 @@ nds32_elf_ex9_relocation_check (struct bfd_link_info *info, 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_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. */ @@ -12983,6 +14450,27 @@ nds32_elf_ex9_relocation_check (struct bfd_link_info *info, 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 @@ -12990,11 +14478,11 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti { struct elf_nds32_insn_times_entry *ex9_insn = ex9_insn_head; bfd_byte *contents = NULL; - long unsigned int off; - unsigned short insn16, insn_ex9; + bfd_vma off; + uint16_t insn16, insn_ex9; /* `pre_*' are used to track previous instruction that can use ex9.it. */ - unsigned int pre_off = -1; - unsigned short pre_insn16 = 0; + 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; @@ -13002,30 +14490,32 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Sym *isym = NULL; nds32_elf_blank_t *relax_blank_list = NULL; - unsigned long insn = 0; - unsigned long insn_with_reg = 0; - unsigned long it_insn; - unsigned long it_insn_with_reg; + 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) || !nds32_get_local_syms (abfd, sec, &isym)) return FALSE; - internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, - TRUE /* keep_memory */); + 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); + irel = find_relocs_at_address (internal_relocs, internal_relocs, + irelend, R_NDS32_RELAX_ENTRY); /* Check this section trigger ex9 relaxation. */ if (irel == NULL @@ -13051,19 +14541,10 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti relax_blank_list, sec, &off, contents); if (data_flag & PUSH_PRE) - { - if (pre_insn16 != 0) - { - /* Implement the ex9 relaxation. */ - bfd_putb16 (pre_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); - } - } + 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) { @@ -13102,10 +14583,12 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti 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); + 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) + && (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. */ @@ -13146,13 +14629,12 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti h = sym_hashes[r_symndx - symtab_hdr->sh_info]; if (ex9_insn->m_list) { - struct elf_link_hash_entry_list *h_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) + && (ex9_insn->m_list->irel->r_addend == + irel->r_addend)) { do_replace = 1; save_irel = 1; @@ -13190,12 +14672,13 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti while (m_list) { - struct elf_link_hash_entry_list *h_list = m_list->h_list; + h_list = m_list->h_list; while (h_list) { if (h == h_list->h - && m_list->irel->r_addend == irel->r_addend) + && (m_list->irel->r_addend + == irel->r_addend)) { do_replace = 1; save_irel = 1; @@ -13234,19 +14717,19 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti 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 != NULL + && h->root.u.def.section->output_section != NULL && h->root.u.def.section->gc_mark == 1 - && strcmp (h->root.u.def.section->name, - BFD_ABS_SECTION_NAME) == 0 + && 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 = 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), "%08lx", insn); + insn = insn_with_reg + | ((relocation >> 1) & 0xffffff); + snprintf (code, sizeof (code), "%08x", insn); if (strcmp (code, ex9_insn->string) == 0) { do_replace = 1; @@ -13257,7 +14740,8 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti } } 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_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. */ @@ -13283,15 +14767,10 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti insn_ex9 = INSN_EX9_IT_1; insn16 = insn_ex9 | ex9_insn->order; - if (pre_insn16 != 0) - { - bfd_putb16 (pre_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); - } + /* 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; @@ -13313,16 +14792,10 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti off += 4; } - if (pre_insn16 != 0) - { - /* Implement the ex9 relaxation. */ - bfd_putb16 (pre_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); - } + /* 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) @@ -13416,8 +14889,6 @@ nds32_elf_ex9_total_relax (struct bfd_link_info *info) void nds32_elf_ex9_finish (struct bfd_link_info *link_info) { - struct elf_nds32_link_hash_table *table; - nds32_elf_code_hash_traverse (nds32_elf_examine_insn_times); nds32_elf_order_insn_times (link_info); nds32_elf_ex9_total_relax (link_info); @@ -13425,9 +14896,6 @@ nds32_elf_ex9_finish (struct bfd_link_info *link_info) nds32_elf_code_hash_traverse (nds32_elf_count_insn_times); nds32_elf_order_insn_times (link_info); nds32_elf_ex9_build_itable (link_info); - table = nds32_elf_hash_table (link_info); - if (table) - table->relax_round = NDS32_RELAX_EX9_REPLACE_ROUND; } /* Relocate the entries in ex9 table. */ @@ -13438,19 +14906,21 @@ nds32_elf_ex9_reloc_insn (struct elf_nds32_insn_times_entry *ptr, { Elf_Internal_Sym *isym = NULL; bfd_vma relocation = -1; + struct elf_link_hash_entry *h; if (ptr->m_list != NULL) { /* Global symbol. */ - if ((ptr->m_list->h_list->h->root.type == bfd_link_hash_defined - || ptr->m_list->h_list->h->root.type == bfd_link_hash_defweak) - && (ptr->m_list->h_list->h->root.u.def.section != NULL - && ptr->m_list->h_list->h->root.u.def.section->output_section != NULL)) + 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 = (ptr->m_list->h_list->h->root.u.def.value + - ptr->m_list->h_list->h->root.u.def.section->output_section->vma + - ptr->m_list->h_list->h->root.u.def.section->output_offset); + 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 @@ -13505,7 +14975,7 @@ nds32_elf_ex9_reloc_insn (struct elf_nds32_insn_times_entry *ptr, void nds32_elf_ex9_import_table (struct bfd_link_info *info) { - int count = 0, num = 1; + int num = 0; bfd_byte *contents; unsigned long insn; FILE *ex9_import_file; @@ -13514,30 +14984,21 @@ nds32_elf_ex9_import_table (struct bfd_link_info *info) 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); - /* Count the number of input file instructions. */ - while (!feof (ex9_import_file)) - { - fgetc (ex9_import_file); - count++; - } - count = count / 4; - rewind (ex9_import_file); /* Read instructions from the input file and build the list. */ - while (count != 0) + while (!feof (ex9_import_file)) { char *code; struct elf_nds32_insn_times_entry *ptr; size_t nread; nread = fread (contents, sizeof (bfd_byte) * 4, 1, ex9_import_file); - if (nread < sizeof (bfd_byte) * 4) - { - (*_bfd_error_handler) ("Unexpected size of imported ex9 table."); - break; - } + /* Ignore the final byte 0x0a. */ + if (nread < 1) + break; insn = bfd_getb32 (contents); code = bfd_malloc (sizeof (char) * 9); snprintf (code, 9, "%08lx", insn); @@ -13553,7 +15014,6 @@ nds32_elf_ex9_import_table (struct bfd_link_info *info) ptr->irel = NULL; ptr->next = NULL; nds32_elf_ex9_insert_entry (ptr); - count--; num++; } @@ -13585,14 +15045,14 @@ nds32_elf_ex9_export (struct bfd_link_info *info, /* Adjust relocations of J and JAL in ex9.itable. Export ex9 table. */ -void +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; - unsigned long insn, insn_with_reg, source_insn; + uint32_t insn, insn_with_reg, source_insn; bfd_byte *contents = NULL, *source_contents = NULL; int size = 0; bfd_vma gp; @@ -13601,7 +15061,13 @@ nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info) Elf_Internal_Rela rel_backup; unsigned short insn_ex9; struct elf_nds32_link_hash_table *table; - FILE *ex9_export_file, *ex9_import_file; + FILE *ex9_export_file; + static bfd_boolean done = FALSE; + + if (done) + return; + + done = TRUE; table = nds32_elf_hash_table (link_info); if (table) @@ -13623,7 +15089,6 @@ nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info) if (table_sec != NULL) { bfd *output_bfd; - struct bfd_link_hash_entry *bh = NULL; output_bfd = table_sec->output_section->owner; nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE); @@ -13632,10 +15097,6 @@ nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info) if (!nds32_get_section_contents (it_abfd, table_sec, &contents)) return; - /* Get the offset between _ITB_BASE_ and .ex9.itable. */ - bh = bfd_link_hash_lookup (link_info->hash, "_ITB_BASE_", - FALSE, FALSE, FALSE); - offset = bh->u.def.value; } } else @@ -13677,7 +15138,7 @@ nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info) insn = insn_with_reg | ((relocation >> shift) & nds32_elf_irel_mask (&rel_backup)); - bfd_putb32 (insn, contents + (ex9_insn->order) * 4 + offset); + 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) @@ -13692,27 +15153,27 @@ nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info) insn = insn_with_reg | (((relocation - gp) >> shift) & nds32_elf_irel_mask (&rel_backup)); - bfd_putb32 (insn, contents + (ex9_insn->order) * 4 + offset); + 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) - || (ex9_insn->m_list && ex9_insn->next->order == 234 - && ex9_insn->next->next - && ex9_insn->m_list == ex9_insn->next->next->m_list))) + 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) { - 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); + 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) @@ -13724,26 +15185,19 @@ nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info) /* 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 + offset); + 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) - || (ex9_insn->m_list && ex9_insn->next->order == 234 - && ex9_insn->next->next - && ex9_insn->m_list == ex9_insn->next->next->m_list))) + 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; - if (ex9_insn->order == 234) - { - 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 + offset); + bfd_putb32 (insn, contents + (ex9_insn->order) * 4); relocation = relocation + 0x1000; /* hi20 */ } @@ -13761,21 +15215,16 @@ nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info) 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->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) { - if (temp_ptr->order == 234) - { - temp_ptr = temp_ptr->next; - continue; - } - /* Match entry and source code. */ insn = bfd_getb32 (contents + (temp_ptr->order) * 4 + offset); if (insn == source_insn) @@ -13814,7 +15263,7 @@ nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info) 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 + offset); + bfd_putb32 (insn, contents + (ex9_insn->order) * 4); } } } @@ -13831,13 +15280,12 @@ nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info) ex9_export_file = table->ex9_export_file; if (ex9_export_file != NULL) - nds32_elf_ex9_export (link_info, contents + 4, table_sec->size - 4); + nds32_elf_ex9_export (link_info, contents, table_sec->size); else if (update_ex9_table == 1) { - ex9_import_file = table->ex9_import_file; - ex9_export_file = ex9_import_file; - rewind (ex9_export_file); - nds32_elf_ex9_export (link_info, contents + 4, size); + table->ex9_export_file = table->ex9_import_file; + rewind (table->ex9_export_file); + nds32_elf_ex9_export (link_info, contents, size); } } @@ -13859,8 +15307,7 @@ nds32_elf_ex9_build_hash_table (bfd * abfd, asection * sec, bfd_byte *contents = NULL; long unsigned int off = 0; unsigned long r_symndx; - unsigned long insn; - unsigned long insn_with_reg; + uint32_t insn, insn_with_reg; struct elf_link_hash_entry *h; int data_flag, shift, align; bfd_vma relocation; @@ -13902,8 +15349,8 @@ nds32_elf_ex9_build_hash_table (bfd * abfd, asection * sec, 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); + 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. */ @@ -13974,8 +15421,9 @@ nds32_elf_ex9_build_hash_table (bfd * abfd, asection * sec, h, sym_sec, relocation, unresolved_reloc, warned, ignored); relocation += irel->r_addend; - if (h->type != bfd_link_hash_defined - && h->type != bfd_link_hash_defweak) + 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; @@ -14025,7 +15473,8 @@ nds32_elf_ex9_build_hash_table (bfd * abfd, asection * sec, | ((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_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. */ @@ -14037,7 +15486,7 @@ nds32_elf_ex9_build_hash_table (bfd * abfd, asection * sec, } } - snprintf (code, sizeof (code), "%08lx", insn); + snprintf (code, sizeof (code), "%08x", insn); /* Copy "code". */ entry = (struct elf_nds32_code_hash_entry*) bfd_hash_lookup (&ex9_code_table, code, TRUE, TRUE); @@ -14162,16 +15611,17 @@ nds32_elf_ex9_itb_base (struct bfd_link_info *link_info) asection *sec; bfd *output_bfd = NULL; struct bfd_link_hash_entry *bh = NULL; - int target_optimize; - struct elf_nds32_link_hash_table *table; if (is_ITB_BASE_set == 1) return TRUE; is_ITB_BASE_set = 1; - table = nds32_elf_hash_table (link_info); - target_optimize = table->target_optimize; + 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) @@ -14195,9 +15645,7 @@ nds32_elf_ex9_itb_base (struct bfd_link_info *link_info) FALSE, FALSE, TRUE); return (_bfd_generic_link_add_one_symbol (link_info, output_bfd, "_ITB_BASE_", - BSF_GLOBAL | BSF_WEAK, sec, - /* We don't know its value yet, set it to 0. */ - (target_optimize & NDS32_RELAX_EX9_ON) ? 0 : (-234 * 4), + BSF_GLOBAL | BSF_WEAK, sec, 0, (const char *) NULL, FALSE, get_elf_backend_data (output_bfd)->collect, &bh)); } /* End EX9.IT */ @@ -14206,6 +15654,7 @@ nds32_elf_ex9_itb_base (struct bfd_link_info *link_info) #define ELF_ARCH bfd_arch_nds32 #define ELF_MACHINE_CODE EM_NDS32 #define ELF_MAXPAGESIZE 0x1000 +#define ELF_TARGET_ID NDS32_ELF_DATA #define TARGET_BIG_SYM nds32_elf32_be_vec #define TARGET_BIG_NAME "elf32-nds32be" @@ -14221,6 +15670,7 @@ nds32_elf_ex9_itb_base (struct bfd_link_info *link_info) #define bfd_elf32_bfd_relax_section nds32_elf_relax_section #define bfd_elf32_bfd_set_private_flags nds32_elf_set_private_flags +#define bfd_elf32_mkobject nds32_elf_mkobject #define elf_backend_action_discarded nds32_elf_action_discarded #define elf_backend_add_symbol_hook nds32_elf_add_symbol_hook #define elf_backend_check_relocs nds32_elf_check_relocs @@ -14241,6 +15691,8 @@ nds32_elf_ex9_itb_base (struct bfd_link_info *link_info) #define elf_backend_object_p nds32_elf_object_p #define elf_backend_final_write_processing nds32_elf_final_write_processing #define elf_backend_special_sections nds32_elf_special_sections +#define bfd_elf32_bfd_get_relocated_section_contents \ + nds32_elf_get_relocated_section_contents #define elf_backend_can_gc_sections 1 #define elf_backend_can_refcount 1 diff --git a/bfd/elf32-nds32.h b/bfd/elf32-nds32.h index 9aec0fc5253..d4d4e934fd7 100644 --- a/bfd/elf32-nds32.h +++ b/bfd/elf32-nds32.h @@ -46,6 +46,7 @@ /* Relocation flags for R_NDS32_INSN16. */ +/* Tag the nop16 can be removed. */ #define R_NDS32_INSN16_CONVERT_FLAG (1 << 0) /* Convert a gp-relative access (e.g., lwi.gp) to fp-as-gp access (lwi37.fp). @@ -67,15 +68,28 @@ in this region due to performance drop. */ #define R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG (1 << 4) +/* Tag range for LOADSTORE relocation. */ +enum +{ + NDS32_LOADSTORE_NONE = 0x0, + NDS32_LOADSTORE_BYTE = 0x1, + NDS32_LOADSTORE_HALF = 0x2, + NDS32_LOADSTORE_WORD = 0x4, + NDS32_LOADSTORE_FLOAT_S = 0x8, + NDS32_LOADSTORE_FLOAT_D = 0x10, + NDS32_LOADSTORE_IMM = 0x20 +}; + /* Relax tag for nds32_elf_relax_section, we have to specify which optimization do in this round. */ enum { NDS32_RELAX_NONE_ROUND = 0, - NDS32_RELAX_JUMP_IFC_ROUND = 1, + NDS32_RELAX_NORMAL_ROUND, + NDS32_RELAX_JUMP_IFC_ROUND, NDS32_RELAX_EX9_BUILD_ROUND, - NDS32_RELAX_EX9_REPLACE_ROUND - + NDS32_RELAX_EX9_REPLACE_ROUND, + NDS32_RELAX_EMPTY_ROUND }; /* Optimization status mask. */ @@ -85,29 +99,23 @@ enum /* Optimization turn on mask. */ #define NDS32_RELAX_JUMP_IFC_ON (1 << 0) #define NDS32_RELAX_EX9_ON (1 << 1) - -/* The break 0xea defined for ex9 table to keep for trace32 to use 0xeaea. */ -#define INSN_BREAK_EA 0x64001d4a extern void nds32_insertion_sort (void *, size_t, size_t, int (*) (const void *, const void *)); extern int nds32_elf_ex9_init (void); -extern void nds32_elf_ex9_reloc_jmp (struct bfd_link_info *); -extern void nds32_elf_ex9_finish (struct bfd_link_info *); -extern bfd_boolean nds32_elf_ex9_itb_base (struct bfd_link_info *); -extern void nds32_elf_ex9_import_table (struct bfd_link_info *); -extern bfd_boolean nds32_elf_ifc_reloc (void); -extern bfd_boolean nds32_elf_ifc_finish (struct bfd_link_info *); extern int nds32_convert_32_to_16 (bfd *, uint32_t, uint16_t *, int *); extern int nds32_convert_16_to_32 (bfd *, uint16_t, uint32_t *); -extern void bfd_elf32_nds32_set_target_option (struct bfd_link_info *, int, int, - FILE *, int, int, int, int, FILE *, FILE *, - int, int, bfd_boolean, bfd_boolean); +extern void bfd_elf32_nds32_set_target_option (struct bfd_link_info *, + int, int, FILE *, int, + int, int, int, FILE *, + FILE *, int, int, + bfd_boolean, bfd_boolean); #define nds32_elf_hash_table(info) \ (elf_hash_table_id ((struct elf_link_hash_table *) ((info)->hash)) \ - == NDS32_ELF_DATA ? ((struct elf_nds32_link_hash_table *) ((info)->hash)) : NULL) + == NDS32_ELF_DATA ? \ + ((struct elf_nds32_link_hash_table *) ((info)->hash)) : NULL) /* Hash table structure for target nds32. There are some members to save target options passed from nds32elf.em to bfd. */ diff --git a/bfd/libbfd.h b/bfd/libbfd.h index c0f4e96b38a..d43fec4ab1d 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -1797,6 +1797,13 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_NDS32_15_FIXED", "BFD_RELOC_NDS32_17_FIXED", "BFD_RELOC_NDS32_25_FIXED", + "BFD_RELOC_NDS32_LONGCALL4", + "BFD_RELOC_NDS32_LONGCALL5", + "BFD_RELOC_NDS32_LONGCALL6", + "BFD_RELOC_NDS32_LONGJUMP4", + "BFD_RELOC_NDS32_LONGJUMP5", + "BFD_RELOC_NDS32_LONGJUMP6", + "BFD_RELOC_NDS32_LONGJUMP7", "BFD_RELOC_NDS32_PLTREL_HI20", "BFD_RELOC_NDS32_PLTREL_LO12", "BFD_RELOC_NDS32_PLT_GOTREL_HI20", @@ -1838,11 +1845,25 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_NDS32_DIFF16", "BFD_RELOC_NDS32_DIFF32", "BFD_RELOC_NDS32_DIFF_ULEB128", + "BFD_RELOC_NDS32_EMPTY", "BFD_RELOC_NDS32_25_ABS", "BFD_RELOC_NDS32_DATA", "BFD_RELOC_NDS32_TRAN", "BFD_RELOC_NDS32_17IFC_PCREL", "BFD_RELOC_NDS32_10IFCU_PCREL", + "BFD_RELOC_NDS32_TPOFF", + "BFD_RELOC_NDS32_TLS_LE_HI20", + "BFD_RELOC_NDS32_TLS_LE_LO12", + "BFD_RELOC_NDS32_TLS_LE_ADD", + "BFD_RELOC_NDS32_TLS_LE_LS", + "BFD_RELOC_NDS32_GOTTPOFF", + "BFD_RELOC_NDS32_TLS_IE_HI20", + "BFD_RELOC_NDS32_TLS_IE_LO12S2", + "BFD_RELOC_NDS32_TLS_TPOFF", + "BFD_RELOC_NDS32_TLS_LE_20", + "BFD_RELOC_NDS32_TLS_LE_15S0", + "BFD_RELOC_NDS32_TLS_LE_15S1", + "BFD_RELOC_NDS32_TLS_LE_15S2", "BFD_RELOC_V850_9_PCREL", "BFD_RELOC_V850_22_PCREL", "BFD_RELOC_V850_SDA_16_16_OFFSET", diff --git a/bfd/reloc.c b/bfd/reloc.c index 79079cf056c..dc471734f61 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -4000,6 +4000,20 @@ ENUMX BFD_RELOC_NDS32_17_FIXED ENUMX BFD_RELOC_NDS32_25_FIXED +ENUMX + BFD_RELOC_NDS32_LONGCALL4 +ENUMX + BFD_RELOC_NDS32_LONGCALL5 +ENUMX + BFD_RELOC_NDS32_LONGCALL6 +ENUMX + BFD_RELOC_NDS32_LONGJUMP4 +ENUMX + BFD_RELOC_NDS32_LONGJUMP5 +ENUMX + BFD_RELOC_NDS32_LONGJUMP6 +ENUMX + BFD_RELOC_NDS32_LONGJUMP7 ENUMDOC for relax ENUM @@ -4102,8 +4116,14 @@ ENUMX ENUMX BFD_RELOC_NDS32_DIFF_ULEB128 ENUMX + BFD_RELOC_NDS32_EMPTY +ENUMDOC + relaxation relative relocation types +ENUM BFD_RELOC_NDS32_25_ABS -ENUMX +ENUMDOC + This is a 25 bit absolute address. +ENUM BFD_RELOC_NDS32_DATA ENUMX BFD_RELOC_NDS32_TRAN @@ -4112,7 +4132,35 @@ ENUMX ENUMX BFD_RELOC_NDS32_10IFCU_PCREL ENUMDOC - relaxation relative relocation types + For ex9 and ifc using. +ENUM + BFD_RELOC_NDS32_TPOFF +ENUMX + BFD_RELOC_NDS32_TLS_LE_HI20 +ENUMX + BFD_RELOC_NDS32_TLS_LE_LO12 +ENUMX + BFD_RELOC_NDS32_TLS_LE_ADD +ENUMX + BFD_RELOC_NDS32_TLS_LE_LS +ENUMX + BFD_RELOC_NDS32_GOTTPOFF +ENUMX + BFD_RELOC_NDS32_TLS_IE_HI20 +ENUMX + BFD_RELOC_NDS32_TLS_IE_LO12S2 +ENUMX + BFD_RELOC_NDS32_TLS_TPOFF +ENUMX + BFD_RELOC_NDS32_TLS_LE_20 +ENUMX + BFD_RELOC_NDS32_TLS_LE_15S0 +ENUMX + BFD_RELOC_NDS32_TLS_LE_15S1 +ENUMX + BFD_RELOC_NDS32_TLS_LE_15S2 +ENUMDOC + For TLS. ENUM diff --git a/gas/ChangeLog b/gas/ChangeLog index 0cbfb400a23..14a4e525b5c 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,20 @@ +2014-09-16 Kuan-Lin Chen + + * config/tc-nds32.c (nds32_fsrs, nds32_fdrs, nds32_gprs): Remove. + (relax_table): Add new relaxation pattern. + (do_pseudo_la_internal, do_pseudo_ls_bhw): Expand for PIC suffix. + (do_pseudo_move, do_pseudo_neg, do_pseudo_pushpopm): Fix. + (get_range_type, nds32_elf_record_fixup_exp, nds32_get_align, + nds32_elf_build_relax_relation, md_assemble, invalid_prev_frag, + nds32_relax_frag, md_estimate_size_before_relax): Adjust relaxation. + (relocation_table): Remove. + (relax_ls_table): Load-store relaxation pattern. + (hint_map): Define-use chain pattern. + (nds32_find_reloc_table, nds32_match_hint_insn): Analysis + relaxation pattern. + (nds32_parse_name): Parse PIC suffix. + * config/tc-nds32.h: Declare. + 2014-09-15 H.J. Lu * config/tc-i386.c (OPTION_omit_lock_prefix): Renamed to ... diff --git a/gas/config/tc-nds32.c b/gas/config/tc-nds32.c index 94479bac3ae..353a1657c3d 100644 --- a/gas/config/tc-nds32.c +++ b/gas/config/tc-nds32.c @@ -55,23 +55,26 @@ static int enable_16bit = 1; expanded from the pseudo instruction. */ static bfd_boolean pseudo_opcode = FALSE; static struct nds32_relocs_pattern *relocs_list = NULL; +/* Save instruction relation to inserting relaxation relocation. */ struct nds32_relocs_pattern { segT seg; fragS *frag; frchainS *frchain; symbolS *sym; - int reloc; - unsigned int insn; - unsigned int size; + fixS* fixP; + struct nds32_opcode *opcode; char *where; struct nds32_relocs_pattern *next; }; -/* -static int relax_jal_bound = 3; -static int multi_call_relax; -static int pltgot_call_relax; -*/ + +/* Suffix name and relocation. */ +struct suffix_name +{ + char *suffix; + short unsigned int reloc; + int pic; +}; static int vec_size = 0; /* If the assembly code is generated by compiler, it is supposed to have ".flag verbatim" at beginning of the content. We have @@ -79,6 +82,8 @@ static int vec_size = 0; static int verbatim = 0; static struct hash_control *nds32_gprs_hash; static struct hash_control *nds32_hint_hash; +#define TLS_REG "$r27" +#define GOT_NAME "_GLOBAL_OFFSET_TABLE_" /* Generate relocation for relax or not, and the default is true. */ static int enable_relax_relocs = 1; @@ -90,70 +95,13 @@ static int enable_relax_ifc = 0; static int optimize = 0; /* Save option -Os for code size. */ static int optimize_for_space = 0; - -struct nds32_keyword nds32_fsrs[] = -{ - /* Standard names. */ - {"$fs0", 0, 0}, {"$fs1", 1, 0}, {"$fs2", 2, 0}, {"$fs3", 3, 0}, - {"$fs4", 4, 0}, {"$fs5", 5, 0}, {"$fs6", 6, 0}, {"$fs7", 7, 0}, - {"$fs8", 8, 0}, {"$fs9", 9, 0}, {"$fs10", 10, 0}, {"$fs11", 11, 0}, - {"$fs12", 12, 0}, {"$fs13", 13, 0}, {"$fs14", 14, 0}, {"$fs15", 15, 0}, - {"$fs16", 16, 0}, {"$fs17", 17, 0}, {"$fs18", 18, 0}, {"$fs19", 19, 0}, - {"$fs20", 20, 0}, {"$fs21", 21, 0}, {"$fs22", 22, 0}, {"$fs23", 23, 0}, - {"$fs24", 24, 0}, {"$fs25", 25, 0}, {"$fs26", 26, 0}, {"$fs27", 27, 0}, - {"$fs28", 28, 0}, {"$fs29", 29, 0}, {"$fs30", 30, 0}, {"$fs31", 31, 0}, - {NULL, 0, 0} -}; - -struct nds32_keyword nds32_fdrs[] = -{ - /* Standard names. */ - {"$fd0", 0, 0}, {"$fd1", 1, 0}, {"$fd2", 2, 0}, {"$fd3", 3, 0}, - {"$fd4", 4, 0}, {"$fd5", 5, 0}, {"$fd6", 6, 0}, {"$fd7", 7, 0}, - {"$fd8", 8, 0}, {"$fd9", 9, 0}, {"$fd10", 10, 0}, {"$fd11", 11, 0}, - {"$fd12", 12, 0}, {"$fd13", 13, 0}, {"$fd14", 14, 0}, {"$fd15", 15, 0}, - {"$fd16", 16, 0}, {"$fd17", 17, 0}, {"$fd18", 18, 0}, {"$fd19", 19, 0}, - {"$fd20", 20, 0}, {"$fd21", 21, 0}, {"$fd22", 22, 0}, {"$fd23", 23, 0}, - {"$fd24", 24, 0}, {"$fd25", 25, 0}, {"$fd26", 26, 0}, {"$fd27", 27, 0}, - {"$fd28", 28, 0}, {"$fd29", 29, 0}, {"$fd30", 30, 0}, {"$fd31", 31, 0}, - {NULL, 0, 0} -}; - -struct nds32_keyword nds32_gprs[] = -{ - /* Standard names. */ - {"$r0", 0, 0}, {"$r1", 1, 0}, {"$r2", 2, 0}, {"$r3", 3, 0}, - {"$r4", 4, 0}, {"$r5", 5, 0}, {"$r6", 6, 0}, {"$r7", 7, 0}, - {"$r8", 8, 0}, {"$r9", 9, 0}, {"$r10", 10, 0}, {"$r11", 11, 0}, - {"$r12", 12, 0}, {"$r13", 13, 0}, {"$r14", 14, 0}, {"$r15", 15, 0}, - {"$r16", 16, 0}, {"$r17", 17, 0}, {"$r18", 18, 0}, {"$r19", 19, 0}, - {"$r20", 20, 0}, {"$r21", 21, 0}, {"$r22", 22, 0}, {"$r23", 23, 0}, - {"$r24", 24, 0}, {"$r25", 25, 0}, {"$r26", 26, 0}, {"$r27", 27, 0}, - {"$r28", 28, 0}, {"$r29", 29, 0}, {"$r30", 30, 0}, {"$r31", 31, 0}, - /* Names for parameter passing. */ - {"$a0", 0, 0}, {"$a1", 1, 0}, {"$a2", 2, 0}, {"$a3", 3, 0}, - {"$a4", 4, 0}, {"$a5", 5, 0}, - /* Names reserved for 5-bit addressing only. */ - {"$s0", 6, 0}, {"$s1", 7, 0}, {"$s2", 8, 0}, {"$s3", 9, 0}, - {"$s4", 10, 0}, {"$s5", 11, 0}, {"$s6", 12, 0}, {"$s7", 13, 0}, - {"$s8", 14, 0}, {"$s9", 28, 0}, - {"$ta", 15, 0}, - {"$t0", 16, 0}, {"$t1", 17, 0}, {"$t2", 18, 0}, {"$t3", 19, 0}, - {"$t4", 20, 0}, {"$t5", 21, 0}, {"$t6", 22, 0}, {"$t7", 23, 0}, - {"$t8", 24, 0}, {"$t9", 25, 0}, - {"$p0", 26, 0}, {"$p1", 27, 0}, - {"$fp", 28, 0}, {"$gp", 29, 0}, {"$lp", 30, 0}, {"$sp", 31, 0}, - /* Names reserved for 4-bit addressing only. */ - {"$h0", 0, 0}, {"$h1", 1, 0}, {"$h2", 2, 0}, {"$h3", 3, 0}, - {"$h4", 4, 0}, {"$h5", 5, 0}, {"$h6", 6, 0}, {"$h7", 7, 0}, - {"$h8", 8, 0}, {"$h9", 9, 0}, {"$h10", 10, 0}, {"$h11", 11, 0}, - {"$h12", 16, 0}, {"$h13", 17, 0}, {"$h14", 18, 0}, {"$h15", 19, 0}, - /* Names reserved for 3-bit addressing only. */ - {"$o0", 0, 0}, {"$o1", 1, 0}, {"$o2", 2, 0}, {"$o3", 3, 0}, - {"$o4", 4, 0}, {"$o5", 5, 0}, {"$o6", 6, 0}, {"$o7", 7, 0}, - {NULL, 0, 0} -}; - +/* Flag to save label exist. */ +static int label_exist = 0; +/* Flag to save state in omit_fp region. */ +static int in_omit_fp = 0; +extern struct nds32_keyword keyword_gpr[]; +/* Tag there is relax relocation having to link. */ +static bfd_boolean relaxing = FALSE; static struct hash_control *nds32_relax_info_hash; static relax_info_t relax_table[] = @@ -161,7 +109,7 @@ static relax_info_t relax_table[] = { "jal", /* opcode */ BR_RANGE_S16M, /* br_range */ - {{0, 0, 0}}, /* cond_field */ + {{0, 0, 0, FALSE}}, /* cond_field */ { { INSN_JAL /* jal label */ @@ -180,14 +128,14 @@ static relax_info_t relax_table[] = INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JRAL_TA }, /* BR_RANGE_U4G */ - }, /* relax_code_seq */ - { - {{0, 0, 0}}, /* BR_RANGE_S256 */ - {{0, 0, 0}}, /* BR_RANGE_S16K */ - {{0, 0, 0}}, /* BR_RANGE_S64K */ - {{0, 0, 0}}, /* BR_RANGE_S16M */ - {{0, 0, 0}} /* BR_RANGE_U4G */ - }, /* relax_code_condition */ + }, /* relax_code_seq */ + { + {{0, 0, 0, FALSE}}, /* BR_RANGE_S256 */ + {{0, 0, 0, FALSE}}, /* BR_RANGE_S16K */ + {{0, 0, 0, FALSE}}, /* BR_RANGE_S64K */ + {{0, 0, 0, FALSE}}, /* BR_RANGE_S16M */ + {{0, 0, 0, FALSE}} /* BR_RANGE_U4G */ + }, /* relax_code_condition */ {4, 4, 4, 4, 12}, /* relax_code_size */ {4, 4, 4, 4, 4}, /* relax_branch_isize */ { @@ -209,11 +157,13 @@ static relax_info_t relax_table[] = }, /* BR_RANGE_S16M */ { {0, 4, 0, BFD_RELOC_NDS32_HI20}, - {0, 12, NDS32_RELAX, BFD_RELOC_NDS32_LONGCALL1}, - {4, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {8, 4, NDS32_ORIGIN, 0}, - {8, 2, NDS32_CONVERT, 0}, - {0, 0, 0, 0} + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL4}, + {4, 4, NDS32_HINT | NDS32_FIX, BFD_RELOC_NDS32_LO12S0_ORI}, + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {8, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {8, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ }, @@ -221,9 +171,9 @@ static relax_info_t relax_table[] = "bltzal", /* opcode */ BR_RANGE_S64K, /* br_range */ { - {0, 20, 0x1F}, - { 0, 0, 0 } - }, /* cond_field */ + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} + }, /* cond_field */ { { INSN_BLTZAL /* bltzal $rt, label */ @@ -235,38 +185,38 @@ static relax_info_t relax_table[] = INSN_BLTZAL /* bltzal $rt, label */ }, /* BR_RANGE_S64K */ { - INSN_BGEZ, /* bgez $rt, $1 */ + INSN_BGEZ, /* bgez $rt, $1 */ INSN_JAL /* jal label */ }, /* BR_RANGE_S16M */ { - INSN_BGEZ, /* bgez $rt, $1 */ + INSN_BGEZ, /* bgez $rt, $1 */ INSN_SETHI_TA, /* sethi $ta, label */ INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JRAL_TA /* jral $ta */ } /* BR_RANGE_U4G */ - }, /* relax_code_seq */ + }, /* relax_code_seq */ { { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S256 */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S64K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16M */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} } /* BR_RANGE_U4G */ - }, /* relax_code_condition */ + }, /* relax_code_condition */ {4, 4, 4, 8, 16}, /* relax_code_size */ {4, 4, 4, 4, 4}, /* relax_branch_isize */ { @@ -283,18 +233,21 @@ static relax_info_t relax_table[] = {0, 0, 0, 0} }, /* BR_RANGE_S64K */ { - {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_17_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGCALL2}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_17_PCREL}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL5}, {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, {0, 0, 0, 0} }, /* BR_RANGE_S16M */ { - {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_17_PCREL}, - {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGCALL3}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_17_PCREL}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL6}, {4, 4, 0, BFD_RELOC_NDS32_HI20}, - {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {12, 4, NDS32_ORIGIN, 0}, - {12, 2, NDS32_CONVERT, 0}, + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ @@ -303,9 +256,9 @@ static relax_info_t relax_table[] = "bgezal", /* opcode */ BR_RANGE_S64K, /* br_range */ { - {0, 20, 0x1F}, - { 0, 0, 0 } - }, /* cond_field */ + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} + }, /* cond_field */ { { INSN_BGEZAL /* bgezal $rt, label */ @@ -317,38 +270,38 @@ static relax_info_t relax_table[] = INSN_BGEZAL /* bgezal $rt, label */ }, /* BR_RANGE_S64K */ { - INSN_BLTZ, /* bltz $rt, $1 */ + INSN_BLTZ, /* bltz $rt, $1 */ INSN_JAL /* jal label */ }, /* BR_RANGE_S16M */ { - INSN_BLTZ, /* bltz $rt, $1 */ + INSN_BLTZ, /* bltz $rt, $1 */ INSN_SETHI_TA, /* sethi $ta, label */ INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JRAL_TA /* jral $ta */ } /* BR_RANGE_U4G */ - }, /* relax_code_seq */ + }, /* relax_code_seq */ { { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S256 */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S64K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16M */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} } /* BR_RANGE_U4G */ - }, /* relax_code_condition */ + }, /* relax_code_condition */ {4, 4, 4, 8, 16}, /* relax_code_size */ {4, 4, 4, 4, 4}, /* relax_branch_isize */ { @@ -365,26 +318,29 @@ static relax_info_t relax_table[] = {0, 0, 0, 0} }, /* BR_RANGE_S64K */ { - {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_17_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGCALL2}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_17_PCREL}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL5}, {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, {0, 0, 0, 0} }, /* BR_RANGE_S16M */ { - {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_17_PCREL}, - {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGCALL3}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_17_PCREL}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL6}, {4, 4, 0, BFD_RELOC_NDS32_HI20}, - {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {12, 4, NDS32_ORIGIN, 0}, - {12, 2, NDS32_CONVERT, 0}, - {0, 0, 0, 0} + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ }, { "j", /* opcode */ BR_RANGE_S16M, /* br_range */ - {{0, 0, 0}}, /* cond_field */ + {{0, 0, 0, FALSE}}, /* cond_field */ { { (INSN_J8 << 16) /* j8 label */ @@ -403,14 +359,14 @@ static relax_info_t relax_table[] = INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JR_TA /* jr $ta */ }, /* BR_RANGE_U4G */ - }, /* relax_code_seq */ - { - {{0, 0, 0}}, /* BR_RANGE_S256 */ - {{0, 0, 0}}, /* BR_RANGE_S16K */ - {{0, 0, 0}}, /* BR_RANGE_S64K */ - {{0, 0, 0}}, /* BR_RANGE_S16M */ - {{0, 0, 0}} /* BR_RANGE_U4G */ - }, /* relax_code_condition */ + }, /* relax_code_seq */ + { + {{0, 0, 0, FALSE}}, /* BR_RANGE_S256 */ + {{0, 0, 0, FALSE}}, /* BR_RANGE_S16K */ + {{0, 0, 0, FALSE}}, /* BR_RANGE_S64K */ + {{0, 0, 0, FALSE}}, /* BR_RANGE_S16M */ + {{0, 0, 0, FALSE}} /* BR_RANGE_U4G */ + }, /* relax_code_condition */ {2, 4, 4, 4, 12}, /* relax_code_size */ {2, 4, 4, 4, 4}, /* relax_branch_isize */ { @@ -432,18 +388,20 @@ static relax_info_t relax_table[] = }, /* BR_RANGE_S16M */ { {0, 4, 0, BFD_RELOC_NDS32_HI20}, - {0, 12, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP1}, - {4, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {8, 4, NDS32_ORIGIN, 0}, - {8, 2, NDS32_CONVERT, 0}, - {0, 0, 0, 0} + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP4}, + {4, 4, NDS32_HINT | NDS32_FIX, BFD_RELOC_NDS32_LO12S0_ORI}, + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {8, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {8, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ }, { "j8", /* opcode */ BR_RANGE_S256, /* br_range */ - {{0, 0, 0}}, /* cond_field */ + {{0, 0, 0, FALSE}}, /* cond_field */ { { (INSN_J8 << 16) /* j8 label */ @@ -462,14 +420,14 @@ static relax_info_t relax_table[] = INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JR_TA /* jr $ta */ }, /* BR_RANGE_U4G */ - }, /* relax_code_seq */ - { - {{0, 0, 0}}, /* BR_RANGE_S256 */ - {{0, 0, 0}}, /* BR_RANGE_S16K */ - {{0, 0, 0}}, /* BR_RANGE_S64K */ - {{0, 0, 0}}, /* BR_RANGE_S16M */ - {{0, 0, 0}} /* BR_RANGE_U4G */ - }, /* relax_code_condition */ + }, /* relax_code_seq */ + { + {{0, 0, 0, FALSE}}, /* BR_RANGE_S256 */ + {{0, 0, 0, FALSE}}, /* BR_RANGE_S16K */ + {{0, 0, 0, FALSE}}, /* BR_RANGE_S64K */ + {{0, 0, 0, FALSE}}, /* BR_RANGE_S16M */ + {{0, 0, 0, FALSE}} /* BR_RANGE_U4G */ + }, /* relax_code_condition */ {2, 4, 4, 4, 12}, /* relax_code_size */ {2, 4, 4, 4, 4}, /* relax_branch_isize */ { @@ -491,11 +449,13 @@ static relax_info_t relax_table[] = }, /* BR_RANGE_S16M */ { {0, 4, 0, BFD_RELOC_NDS32_HI20}, - {0, 12, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP1}, - {4, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {8, 4, NDS32_ORIGIN, 0}, - {8, 2, NDS32_CONVERT, 0}, - {0, 0, 0, 0} + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP4}, + {4, 4, NDS32_HINT | NDS32_FIX, BFD_RELOC_NDS32_LO12S0_ORI}, + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {8, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {8, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ }, @@ -503,9 +463,9 @@ static relax_info_t relax_table[] = "beqz", /* opcode */ BR_RANGE_S64K, /* br_range */ { - {0, 20, 0x1F}, - { 0, 0, 0 } - }, /* cond_field */ + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} + }, /* cond_field */ { { INSN_BEQZ /* beqz $rt, label */ @@ -517,44 +477,44 @@ static relax_info_t relax_table[] = INSN_BEQZ /* beqz $rt, label */ }, /* BR_RANGE_S64K */ { - INSN_BNEZ, /* bnez $rt, $1 */ + INSN_BNEZ, /* bnez $rt, $1 */ INSN_J /* j label */ }, /* BR_RANGE_S16M */ { - INSN_BNEZ, /* bnez $rt, $1 */ + INSN_BNEZ, /* bnez $rt, $1 */ INSN_SETHI_TA, /* sethi $ta, label */ INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JR_TA /* jr $ta */ } /* BR_RANGE_U4G */ - }, /* relax_code_seq */ + }, /* relax_code_seq */ { { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S256 */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S64K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16M */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} } /* BR_RANGE_U4G */ - }, /* relax_code_condition */ + }, /* relax_code_condition */ {4, 4, 4, 8, 16}, /* relax_code_size */ {4, 4, 4, 4, 4}, /* relax_branch_isize */ { { - {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, - {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 4, NDS32_INSN16 , BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} }, /* BR_RANGE_S256 */ { @@ -566,20 +526,24 @@ static relax_info_t relax_table[] = {0, 0, 0, 0} }, /* BR_RANGE_S64K */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, - {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, - {0, 0, 0, 0} + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} }, /* BR_RANGE_S16M */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, - {4, 4, 0, BFD_RELOC_NDS32_HI20}, - {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {12, 4, NDS32_ORIGIN, 0}, - {12, 2, NDS32_CONVERT, 0}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ @@ -588,9 +552,9 @@ static relax_info_t relax_table[] = "bgez", /* opcode */ BR_RANGE_S64K, /* br_range */ { - {0, 20, 0x1F}, - { 0, 0, 0 } - }, /* cond_field */ + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} + }, /* cond_field */ { { INSN_BGEZ /* bgez $rt, label */ @@ -602,38 +566,38 @@ static relax_info_t relax_table[] = INSN_BGEZ /* bgez $rt, label */ }, /* BR_RANGE_S64K */ { - INSN_BLTZ, /* bltz $rt, $1 */ + INSN_BLTZ, /* bltz $rt, $1 */ INSN_J /* j label */ }, /* BR_RANGE_S16M */ { - INSN_BLTZ, /* bltz $rt, $1 */ + INSN_BLTZ, /* bltz $rt, $1 */ INSN_SETHI_TA, /* sethi $ta, label */ INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JR_TA /* jr $ta */ } /* BR_RANGE_U4G */ - }, /* relax_code_seq */ + }, /* relax_code_seq */ { { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S256 */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S64K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16M */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} } /* BR_RANGE_U4G */ - }, /* relax_code_condition */ + }, /* relax_code_condition */ {4, 4, 4, 8, 16}, /* relax_code_size */ {4, 4, 4, 4, 4}, /* relax_branch_isize */ { @@ -650,19 +614,22 @@ static relax_info_t relax_table[] = {0, 0, 0, 0} }, /* BR_RANGE_S64K */ { - {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, {0, 0, 0, 0} }, /* BR_RANGE_S16M */ { - {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, - {4, 4, 0, BFD_RELOC_NDS32_HI20}, - {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {12, 4, NDS32_ORIGIN, 0}, - {12, 2, NDS32_CONVERT, 0}, - {0, 0, 0, 0} + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ }, @@ -670,9 +637,9 @@ static relax_info_t relax_table[] = "bnez", /* opcode */ BR_RANGE_S64K, /* br_range */ { - {0, 20, 0x1F}, - { 0, 0, 0 } - }, /* cond_field */ + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} + }, /* cond_field */ { { INSN_BNEZ /* bnez $rt, label */ @@ -684,44 +651,44 @@ static relax_info_t relax_table[] = INSN_BNEZ /* bnez $rt, label */ }, /* BR_RANGE_S64K */ { - INSN_BEQZ, /* beqz $rt, $1 */ + INSN_BEQZ, /* beqz $rt, $1 */ INSN_J /* j label */ }, /* BR_RANGE_S16M */ { - INSN_BEQZ, /* beqz $rt, $1 */ + INSN_BEQZ, /* beqz $rt, $1 */ INSN_SETHI_TA, /* sethi $ta, label */ INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JR_TA /* jr $ta */ } /* BR_RANGE_U4G */ - }, /* relax_code_seq */ + }, /* relax_code_seq */ { { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S256 */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S64K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16M */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} } /* BR_RANGE_U4G */ - }, /* relax_code_condition */ + }, /* relax_code_condition */ {4, 4, 4, 8, 16}, /* relax_code_size */ {4, 4, 4, 4, 4}, /* relax_branch_isize */ { { - {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, - {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 4, NDS32_INSN16 , BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} }, /* BR_RANGE_S256 */ { @@ -733,21 +700,25 @@ static relax_info_t relax_table[] = {0, 0, 0, 0} }, /* BR_RANGE_S64K */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, - {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} }, /* BR_RANGE_S16M */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, - {4, 4, 0, BFD_RELOC_NDS32_HI20}, - {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {12, 4, NDS32_ORIGIN, 0}, - {12, 2, NDS32_CONVERT, 0}, - {0, 0, 0, 0} + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ }, @@ -755,9 +726,9 @@ static relax_info_t relax_table[] = "bgtz", /* opcode */ BR_RANGE_S64K, /* br_range */ { - {0, 20, 0x1F}, - { 0, 0, 0 } - }, /* cond_field */ + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} + }, /* cond_field */ { { INSN_BGTZ /* bgtz $rt, label */ @@ -769,38 +740,38 @@ static relax_info_t relax_table[] = INSN_BGTZ /* bgtz $rt, label */ }, /* BR_RANGE_S64K */ { - INSN_BLEZ, /* blez $rt, $1 */ + INSN_BLEZ, /* blez $rt, $1 */ INSN_J /* j label */ }, /* BR_RANGE_S16M */ { - INSN_BLEZ, /* blez $rt, $1 */ + INSN_BLEZ, /* blez $rt, $1 */ INSN_SETHI_TA, /* sethi $ta, label */ INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JR_TA /* jr $ta */ } /* BR_RANGE_U4G */ - }, /* relax_code_seq */ + }, /* relax_code_seq */ { { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S256 */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S64K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16M */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} } /* BR_RANGE_U4G */ - }, /* relax_code_condition */ + }, /* relax_code_condition */ {4, 4, 4, 8, 16}, /* relax_code_size */ {4, 4, 4, 4, 4}, /* relax_branch_isize */ { @@ -817,19 +788,22 @@ static relax_info_t relax_table[] = {0, 0, 0, 0} }, /* BR_RANGE_S64K */ { - {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, {0, 0, 0, 0} }, /* BR_RANGE_S16M */ { - {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, - {4, 4, 0, BFD_RELOC_NDS32_HI20}, - {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {12, 4, NDS32_ORIGIN, 0}, - {12, 2, NDS32_CONVERT, 0}, - {0, 0, 0, 0} + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ }, @@ -837,9 +811,9 @@ static relax_info_t relax_table[] = "blez", /* opcode */ BR_RANGE_S64K, /* br_range */ { - {0, 20, 0x1F}, - { 0, 0, 0 } - }, /* cond_field */ + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} + }, /* cond_field */ { { INSN_BLEZ /* blez $rt, label */ @@ -851,38 +825,38 @@ static relax_info_t relax_table[] = INSN_BLEZ /* blez $rt, label */ }, /* BR_RANGE_S64K */ { - INSN_BGTZ, /* bgtz $rt, $1 */ + INSN_BGTZ, /* bgtz $rt, $1 */ INSN_J /* j label */ }, /* BR_RANGE_S16M */ { - INSN_BGTZ, /* bgtz $rt, $1 */ + INSN_BGTZ, /* bgtz $rt, $1 */ INSN_SETHI_TA, /* sethi $ta, label */ INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JR_TA /* jr $ta */ } /* BR_RANGE_U4G */ - }, /* relax_code_seq */ + }, /* relax_code_seq */ { { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S256 */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S64K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16M */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} } /* BR_RANGE_U4G */ - }, /* relax_code_condition */ + }, /* relax_code_condition */ {4, 4, 4, 8, 16}, /* relax_code_size */ {4, 4, 4, 4, 4}, /* relax_branch_isize */ { @@ -899,19 +873,22 @@ static relax_info_t relax_table[] = {0, 0, 0, 0} }, /* BR_RANGE_S64K */ { - {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, {0, 0, 0, 0} }, /* BR_RANGE_S16M */ { - {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, - {4, 4, 0, BFD_RELOC_NDS32_HI20}, - {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {12, 4, NDS32_ORIGIN, 0}, - {12, 2, NDS32_CONVERT, 0}, - {0, 0, 0, 0} + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ }, @@ -919,9 +896,9 @@ static relax_info_t relax_table[] = "bltz", /* opcode */ BR_RANGE_S64K, /* br_range */ { - {0, 20, 0x1F}, - { 0, 0, 0 } - }, /* cond_field */ + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} + }, /* cond_field */ { { INSN_BLTZ /* bltz $rt, label */ @@ -933,38 +910,38 @@ static relax_info_t relax_table[] = INSN_BLTZ /* bltz $rt, label */ }, /* BR_RANGE_S64K */ { - INSN_BGEZ, /* bgez $rt, $1 */ + INSN_BGEZ, /* bgez $rt, $1 */ INSN_J /* j label */ }, /* BR_RANGE_S16M */ { - INSN_BGEZ, /* bgez $rt, $1 */ + INSN_BGEZ, /* bgez $rt, $1 */ INSN_SETHI_TA, /* sethi $ta, label */ INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JR_TA /* jr $ta */ } /* BR_RANGE_U4G */ - }, /* relax_code_seq */ + }, /* relax_code_seq */ { { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S256 */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S64K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16M */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} } /* BR_RANGE_U4G */ - }, /* relax_code_condition */ + }, /* relax_code_condition */ {4, 4, 4, 8, 16}, /* relax_code_size */ {4, 4, 4, 4, 4}, /* relax_branch_isize */ { @@ -981,19 +958,22 @@ static relax_info_t relax_table[] = {0, 0, 0, 0} }, /* BR_RANGE_S64K */ { - {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, {0, 0, 0, 0} }, /* BR_RANGE_S16M */ { - {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, - {4, 4, 0, BFD_RELOC_NDS32_HI20}, - {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {12, 4, NDS32_ORIGIN, 0}, - {12, 2, NDS32_CONVERT, 0}, - {0, 0, 0, 0} + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ }, @@ -1001,10 +981,10 @@ static relax_info_t relax_table[] = "beq", /* opcode */ BR_RANGE_S16K, /* br_range */ { - {0, 20, 0x1F}, - {0, 15, 0x1F}, - { 0, 0, 0 } - }, /* cond_field */ + {0, 20, 0x1F, FALSE}, + {0, 15, 0x1F, FALSE}, + {0, 0, 0, FALSE} + }, /* cond_field */ { { INSN_BEQ /* beq $rt, $ra, label */ @@ -1026,40 +1006,40 @@ static relax_info_t relax_table[] = INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JR_TA /* jr $ta */ } /* BR_RANGE_U4G */ - }, /* relax_code_seq */ + }, /* relax_code_seq */ { { - {0, 20, 0x1F}, - {0, 15, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 15, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S256 */ { - {0, 20, 0x1F}, - {0, 15, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 15, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16K */ { - {0, 20, 0x1F}, - {0, 15, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 15, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S64K */ { - {0, 20, 0x1F}, - {0, 15, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 15, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16M */ { - {0, 20, 0x1F}, - {0, 15, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 15, 0x1F, FALSE}, + {0, 0, 0, FALSE} } /* BR_RANGE_U4G */ - }, /* relax_code_condition */ + }, /* relax_code_condition */ {4, 4, 8, 8, 16}, /* relax_code_size */ {4, 4, 4, 4, 4}, /* relax_branch_isize */ { { - {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 4, 0, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} }, /* BR_RANGE_S256 */ { @@ -1067,28 +1047,34 @@ static relax_info_t relax_table[] = {0, 0, 0, 0} }, /* BR_RANGE_S16K */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, - {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} }, /* BR_RANGE_S64K */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, - {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {4, 4, NDS32_ABS, BFD_RELOC_NDS32_EMPTY}, + {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} }, /* BR_RANGE_S16M */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, - {4, 4, 0, BFD_RELOC_NDS32_HI20}, - {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {12, 4, NDS32_ORIGIN, 0}, - {12, 2, NDS32_CONVERT, 0}, - {0, 0, 0, 0} + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ }, @@ -1096,10 +1082,10 @@ static relax_info_t relax_table[] = "bne", /* opcode */ BR_RANGE_S16K, /* br_range */ { - {0, 20, 0x1F}, - {0, 15, 0x1F}, - { 0, 0, 0 } - }, /* cond_field */ + {0, 20, 0x1F, FALSE}, + {0, 15, 0x1F, FALSE}, + {0, 0, 0, FALSE} + }, /* cond_field */ { { INSN_BNE /* bne $rt, $ra, label */ @@ -1121,40 +1107,40 @@ static relax_info_t relax_table[] = INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JR_TA /* jr $ta */ } /* BR_RANGE_U4G */ - }, /* relax_code_seq */ + }, /* relax_code_seq */ { { - {0, 20, 0x1F}, - {0, 15, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 15, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S256 */ { - {0, 20, 0x1F}, - {0, 15, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 15, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16K */ { - {0, 20, 0x1F}, - {0, 15, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 15, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S64K */ { - {0, 20, 0x1F}, - {0, 15, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 15, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16M */ { - {0, 20, 0x1F}, - {0, 15, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 15, 0x1F, FALSE}, + {0, 0, 0, FALSE} } /* BR_RANGE_U4G */ - }, /* relax_code_condition */ + }, /* relax_code_condition */ {4, 4, 8, 8, 16}, /* relax_code_size */ {4, 4, 4, 4, 4}, /* relax_branch_isize */ { { - {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 4, 0, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} }, /* BR_RANGE_S256 */ { @@ -1162,28 +1148,33 @@ static relax_info_t relax_table[] = {0, 0, 0, 0} }, /* BR_RANGE_S16K */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, - {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} }, /* BR_RANGE_S64K */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, - {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} }, /* BR_RANGE_S16M */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, - {4, 4, 0, BFD_RELOC_NDS32_HI20}, - {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {12, 4, NDS32_ORIGIN, 0}, - {12, 2, NDS32_CONVERT, 0}, - {0, 0, 0, 0} + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ }, @@ -1191,12 +1182,12 @@ static relax_info_t relax_table[] = "beqz38", /* opcode */ BR_RANGE_S256, /* br_range */ { - {0, 8, 0x7}, - { 0, 0, 0 } - }, /* cond_field */ + {0, 8, 0x7, FALSE}, + {0, 0, 0, FALSE} + }, /* cond_field */ { { - INSN_BEQZ /* beqz $rt, label */ + INSN_BEQZ38 << 16 /* beqz $rt, label */ }, /* BR_RANGE_S256 */ { INSN_BEQZ /* beqz $rt, label */ @@ -1205,7 +1196,7 @@ static relax_info_t relax_table[] = INSN_BEQZ /* beqz $rt, label */ }, /* BR_RANGE_S64K */ { - INSN_BNEZ, /* bnez $rt, $1 */ + INSN_BNEZ, /* bnez $rt, $1 */ INSN_J /* j label */ }, /* BR_RANGE_S16M */ { @@ -1214,35 +1205,34 @@ static relax_info_t relax_table[] = INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JR_TA /* jr $ta */ } /* BR_RANGE_U4G */ - }, /* relax_code_seq */ + }, /* relax_code_seq */ { { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 8, 0x7, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S256 */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S64K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16M */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} } /* BR_RANGE_U4G */ - }, /* relax_code_condition */ - {4, 4, 4, 8, 16}, /* relax_code_size */ - {4, 4, 4, 4, 4}, /* relax_branch_isize */ + }, /* relax_code_condition */ + {2, 4, 4, 8, 16}, /* relax_code_size */ + {2, 4, 4, 4, 4}, /* relax_branch_isize */ { { - {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_17_PCREL}, - {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 2, 0, BFD_RELOC_NDS32_9_PCREL}, {0, 0, 0, 0} }, /* BR_RANGE_S256 */ { @@ -1254,21 +1244,25 @@ static relax_info_t relax_table[] = {0, 0, 0, 0} }, /* BR_RANGE_S64K */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, - {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} }, /* BR_RANGE_S16M */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, - {4, 4, 0, BFD_RELOC_NDS32_HI20}, - {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {12, 4, NDS32_ORIGIN, 0}, - {12, 2, NDS32_CONVERT, 0}, - {0, 0, 0, 0} + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ }, @@ -1276,12 +1270,12 @@ static relax_info_t relax_table[] = "bnez38", /* opcode */ BR_RANGE_S256, /* br_range */ { - {0, 8, 0x7}, - { 0, 0, 0 } - }, /* cond_field */ + {0, 8, 0x7, FALSE}, + {0, 0, 0, FALSE} + }, /* cond_field */ { { - INSN_BNEZ /* bnez $rt, label */ + INSN_BNEZ38 << 16 /* bnez $rt, label */ }, /* BR_RANGE_S256 */ { INSN_BNEZ /* bnez $rt, label */ @@ -1290,7 +1284,7 @@ static relax_info_t relax_table[] = INSN_BNEZ /* bnez $rt, label */ }, /* BR_RANGE_S64K */ { - INSN_BEQZ, /* beqz $rt, $1 */ + INSN_BEQZ, /* beqz $rt, $1 */ INSN_J /* j label */ }, /* BR_RANGE_S16M */ { @@ -1299,35 +1293,34 @@ static relax_info_t relax_table[] = INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JR_TA /* jr $ta */ } /* BR_RANGE_U4G */ - }, /* relax_code_seq */ + }, /* relax_code_seq */ { { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 8, 0x7, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S256 */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S64K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16M */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} } /* BR_RANGE_U4G */ - }, /* relax_code_condition */ - {4, 4, 4, 8, 16}, /* relax_code_size */ - {4, 4, 4, 4, 4}, /* relax_branch_isize */ + }, /* relax_code_condition */ + {2, 4, 4, 8, 16}, /* relax_code_size */ + {2, 4, 4, 4, 4}, /* relax_branch_isize */ { { - {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_17_PCREL}, - {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 2, 0, BFD_RELOC_NDS32_9_PCREL}, {0, 0, 0, 0} }, /* BR_RANGE_S256 */ { @@ -1339,40 +1332,44 @@ static relax_info_t relax_table[] = {0, 0, 0, 0} }, /* BR_RANGE_S64K */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, - {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} }, /* BR_RANGE_S16M */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, - {4, 4, 0, BFD_RELOC_NDS32_HI20}, - {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {12, 4, NDS32_ORIGIN, 0}, - {12, 2, NDS32_CONVERT, 0}, - {0, 0, 0, 0} + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ }, { "beqzs8", /* opcode */ BR_RANGE_S256, /* br_range */ - {{0, 0, 0}}, /* cond_field */ + {{0, 0, 0, FALSE}}, /* cond_field */ { { - INSN_BEQZ_TA /* beqz $r15, label */ + INSN_BEQZS8 << 16 /* beqz $r15, label */ }, /* BR_RANGE_S256 */ { - INSN_BNEZ /* bnez $rt, label */ + INSN_BEQZ_TA /* bnez $rt, label */ }, /* BR_RANGE_S16K */ { - INSN_BNEZ /* bnez $rt, label */ + INSN_BEQZ_TA /* bnez $rt, label */ }, /* BR_RANGE_S64K */ { - INSN_BNEZ_TA, /* bnez $r15, $1 */ + INSN_BNEZ_TA, /* bnez $r15, $1 */ INSN_J /* j label */ }, /* BR_RANGE_S16M */ { @@ -1381,20 +1378,19 @@ static relax_info_t relax_table[] = INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JR_TA /* jr $ta */ } /* BR_RANGE_U4G */ - }, /* relax_code_seq */ - { - {{0, 0, 0}}, /* BR_RANGE_S256 */ - {{0, 0, 0}}, /* BR_RANGE_S16K */ - {{0, 0, 0}}, /* BR_RANGE_S64K */ - {{0, 0, 0}}, /* BR_RANGE_S16M */ - {{0, 0, 0}} /* BR_RANGE_U4G */ - }, /* relax_code_condition */ - {4, 4, 4, 8, 16}, /* relax_code_size */ - {4, 4, 4, 4, 4}, /* relax_branch_isize */ + }, /* relax_code_seq */ + { + {{0, 0, 0, FALSE}}, /* BR_RANGE_S256 */ + {{0, 0, 0, FALSE}}, /* BR_RANGE_S16K */ + {{0, 0, 0, FALSE}}, /* BR_RANGE_S64K */ + {{0, 0, 0, FALSE}}, /* BR_RANGE_S16M */ + {{0, 0, 0, FALSE}} /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {2, 4, 4, 8, 16}, /* relax_code_size */ + {2, 4, 4, 4, 4}, /* relax_branch_isize */ { { - {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_17_PCREL}, - {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 2, 0, BFD_RELOC_NDS32_9_PCREL}, {0, 0, 0, 0} }, /* BR_RANGE_S256 */ { @@ -1406,20 +1402,24 @@ static relax_info_t relax_table[] = {0, 0, 0, 0} }, /* BR_RANGE_S64K */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, - {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} }, /* BR_RANGE_S16M */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, - {4, 4, 0, BFD_RELOC_NDS32_HI20}, - {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {12, 4, NDS32_ORIGIN, 0}, - {12, 2, NDS32_CONVERT, 0}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ @@ -1427,10 +1427,10 @@ static relax_info_t relax_table[] = { "bnezs8", /* opcode */ BR_RANGE_S256, /* br_range */ - {{0, 0, 0}}, /* cond_field */ + {{0, 0, 0, FALSE}}, /* cond_field */ { { - INSN_BNEZ_TA /* bnez $r15, label */ + INSN_BNEZS8 << 16 /* bnez $r15, label */ }, /* BR_RANGE_S256 */ { INSN_BNEZ_TA /* bnez $r15, label */ @@ -1439,29 +1439,28 @@ static relax_info_t relax_table[] = INSN_BNEZ_TA /* bnez $r15, label */ }, /* BR_RANGE_S64K */ { - INSN_BEQZ_TA, /* beqz $r15, $1 */ + INSN_BEQZ_TA, /* beqz $r15, $1 */ INSN_J /* j label */ }, /* BR_RANGE_S16M */ { - INSN_BEQZ_TA, /* beqz $r15, $1 */ + INSN_BEQZ_TA, /* beqz $r15, $1 */ INSN_SETHI_TA, /* sethi $ta, label */ INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JR_TA /* jr $ta */ } /* BR_RANGE_U4G */ - }, /* relax_code_seq */ - { - {{0, 0, 0}}, /* BR_RANGE_S256 */ - {{0, 0, 0}}, /* BR_RANGE_S16K */ - {{0, 0, 0}}, /* BR_RANGE_S64K */ - {{0, 0, 0}}, /* BR_RANGE_S16M */ - {{0, 0, 0}} /* BR_RANGE_U4G */ - }, /* relax_code_condition */ - {4, 4, 4, 8, 16}, /* relax_code_size */ - {4, 4, 4, 4, 4}, /* relax_branch_isize */ + }, /* relax_code_seq */ + { + {{0, 0, 0, FALSE}}, /* BR_RANGE_S256 */ + {{0, 0, 0, FALSE}}, /* BR_RANGE_S16K */ + {{0, 0, 0, FALSE}}, /* BR_RANGE_S64K */ + {{0, 0, 0, FALSE}}, /* BR_RANGE_S16M */ + {{0, 0, 0, FALSE}} /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {2, 4, 4, 8, 16}, /* relax_code_size */ + {2, 4, 4, 4, 4}, /* relax_branch_isize */ { { - {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_17_PCREL}, - {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 2, 0, BFD_RELOC_NDS32_9_PCREL}, {0, 0, 0, 0} }, /* BR_RANGE_S256 */ { @@ -1473,21 +1472,25 @@ static relax_info_t relax_table[] = {0, 0, 0, 0} }, /* BR_RANGE_S64K */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, - {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} }, /* BR_RANGE_S16M */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, - {4, 4, 0, BFD_RELOC_NDS32_HI20}, - {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {12, 4, NDS32_ORIGIN, 0}, - {12, 2, NDS32_CONVERT, 0}, - {0, 0, 0, 0} + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ }, @@ -1495,59 +1498,58 @@ static relax_info_t relax_table[] = "bnes38", /* opcode */ BR_RANGE_S256, /* br_range */ { - {0, 8, 0x7}, - { 0, 0, 0 } - }, /* cond_field */ + {0, 8, 0x7, FALSE}, + {0, 0, 0, FALSE} + }, /* cond_field */ { { - INSN_BNE_R5 /* bne $rt, $r5, label */ + INSN_BNES38 << 16 /* bne $rt, $R5, label */ }, /* BR_RANGE_S256 */ { - INSN_BNE_R5 /* bne $rt, $r5, label */ + INSN_BNE_R5 /* bne $rt, $R5, label */ }, /* BR_RANGE_S16K */ { - INSN_BEQ_R5, /* beq $rt, $r5, $1 */ + INSN_BEQ_R5, /* beq $rt, $R5, $1 */ INSN_J /* j label */ }, /* BR_RANGE_S64K */ { - INSN_BEQ_R5, /* beq $rt, $r5, $1 */ + INSN_BEQ_R5, /* beq $rt, $R5, $1 */ INSN_J /* j label */ }, /* BR_RANGE_S16M */ { - INSN_BEQ_R5, /* beq $rt, $r5, $1 */ + INSN_BEQ_R5, /* beq $rt, $R5, $1 */ INSN_SETHI_TA, /* sethi $ta, label */ INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JR_TA /* jr $ta */ } /* BR_RANGE_U4G */ - }, /* relax_code_seq */ + }, /* relax_code_seq */ { { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 8, 0x7, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S256 */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S64K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16M */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} } /* BR_RANGE_U4G */ - }, /* relax_code_condition */ - {4, 4, 8, 8, 16}, /* relax_code_size */ - {4, 4, 4, 4, 4}, /* relax_branch_isize */ + }, /* relax_code_condition */ + {2, 4, 8, 8, 16}, /* relax_code_size */ + {2, 4, 4, 4, 4}, /* relax_branch_isize */ { { - {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_17_PCREL}, - {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 2, 0, BFD_RELOC_NDS32_9_PCREL}, {0, 0, 0, 0} }, /* BR_RANGE_S256 */ { @@ -1555,28 +1557,33 @@ static relax_info_t relax_table[] = {0, 0, 0, 0} }, /* BR_RANGE_S16K */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, - {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} }, /* BR_RANGE_S64K */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, - {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} }, /* BR_RANGE_S16M */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, - {4, 4, 0, BFD_RELOC_NDS32_HI20}, - {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {12, 4, NDS32_ORIGIN, 0}, - {12, 2, NDS32_CONVERT, 0}, - {0, 0, 0, 0} + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ }, @@ -1584,59 +1591,58 @@ static relax_info_t relax_table[] = "beqs38", /* opcode */ BR_RANGE_S256, /* br_range */ { - {0, 8, 0x7}, - { 0, 0, 0 } - }, /* cond_field */ + {0, 8, 0x7, FALSE}, + {0, 0, 0, FALSE} + }, /* cond_field */ { { - INSN_BEQ_R5 /* beq $rt, $r5, label */ + INSN_BEQS38 << 16 /* beq $rt, $R5, label */ }, /* BR_RANGE_S256 */ { - INSN_BEQ_R5 /* beq $rt, $r5, label */ + INSN_BEQ_R5 /* beq $rt, $R5, label */ }, /* BR_RANGE_S16K */ { - INSN_BNE_R5, /* bne $rt, $r5, $1 */ + INSN_BNE_R5, /* bne $rt, $R5, $1 */ INSN_J /* j label */ }, /* BR_RANGE_S64K */ { - INSN_BNE_R5, /* bne $rt, $r5, $1 */ + INSN_BNE_R5, /* bne $rt, $R5, $1 */ INSN_J /* j label */ }, /* BR_RANGE_S16M */ { - INSN_BNE_R5, /* bne $rt, $r5, $1 */ + INSN_BNE_R5, /* bne $rt, $R5, $1 */ INSN_SETHI_TA, /* sethi $ta, label */ INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JR_TA /* jr $ta */ } /* BR_RANGE_U4G */ - }, /* relax_code_seq */ + }, /* relax_code_seq */ { { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 8, 0x7, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S256 */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S64K */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16M */ { - {0, 20, 0x1F}, - {0, 0, 0} + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} } /* BR_RANGE_U4G */ - }, /* relax_code_condition */ - {4, 4, 8, 8, 16}, /* relax_code_size */ - {4, 4, 4, 4, 4}, /* relax_branch_isize */ + }, /* relax_code_condition */ + {2, 4, 8, 8, 16}, /* relax_code_size */ + {2, 4, 4, 4, 4}, /* relax_branch_isize */ { { - {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_17_PCREL}, - {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 2, 0, BFD_RELOC_NDS32_9_PCREL}, {0, 0, 0, 0} }, /* BR_RANGE_S256 */ { @@ -1644,28 +1650,33 @@ static relax_info_t relax_table[] = {0, 0, 0, 0} }, /* BR_RANGE_S16K */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, - {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} }, /* BR_RANGE_S64K */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, - {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} }, /* BR_RANGE_S16M */ { - {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, - {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, - {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, - {4, 4, 0, BFD_RELOC_NDS32_HI20}, - {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {12, 4, NDS32_ORIGIN, 0}, - {12, 2, NDS32_CONVERT, 0}, - {0, 0, 0, 0} + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, + {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, + {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, + {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ }, @@ -1673,60 +1684,60 @@ static relax_info_t relax_table[] = "beqc", /* opcode */ BR_RANGE_S256, /* br_range */ { - {0, 8, 0x7FF}, - {0, 20, 0x1F}, - {0, 0, 0} - }, /* cond_field */ + {0, 8, 0x7FF, TRUE}, + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} + }, /* cond_field */ { { INSN_BEQC /* beqc $rt, imm11s, label */ }, /* BR_RANGE_S256 */ { - INSN_MOVI_TA, /* movi $ta, imm11s */ + INSN_MOVI_TA, /* movi $ta, imm11s */ INSN_BEQ_TA /* beq $rt, $ta, label */ }, /* BR_RANGE_S16K */ { - INSN_MOVI_TA, /* movi $ta, imm11s */ - INSN_BEQ_TA /* beq $rt, $ta, label */ + INSN_BNEC, /* bnec $rt, imm11s, $1 */ + INSN_J /* j label */ }, /* BR_RANGE_S64K */ { - INSN_BNEC, /* bnec $rt, imm11s, $1 */ + INSN_BNEC, /* bnec $rt, imm11s, $1 */ INSN_J /* j label */ }, /* BR_RANGE_S16M */ { - INSN_BNEC, /* bnec $rt, imm11s, $1 */ + INSN_BNEC, /* bnec $rt, imm11s, $1 */ INSN_SETHI_TA, /* sethi $ta, label */ INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JR_TA /* jr $ta */ } /* BR_RANGE_U4G */ - }, /* relax_code_seq */ + }, /* relax_code_seq */ { { - {0, 8, 0x7FF}, - {0, 20, 0x1F}, - {0, 0, 0} + {0, 8, 0x7FF, TRUE}, + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S256 */ { - {0, 0, 0xFFFFF}, - {4, 20, 0x1F}, - {0, 0, 0} + {0, 0, 0xFFFFF, FALSE}, + {4, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16K */ { - {0, 0, 0xFFFFF}, - {4, 20, 0x1F}, - {0, 0, 0} + {0, 8, 0x7FF, FALSE}, + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S64K */ { - {0, 8, 0x7FF}, - {0, 20, 0x1F}, - {0, 0, 0} + {0, 8, 0x7FF, FALSE}, + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16M */ { - {0, 8, 0x7FF}, - {0, 20, 0x1F}, - {0, 0, 0} + {0, 8, 0x7FF, FALSE}, + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} } /* BR_RANGE_U4G */ - }, /* relax_code_condition */ + }, /* relax_code_condition */ {4, 8, 8, 8, 16}, /* relax_code_size */ {4, 4, 4, 4, 4}, /* relax_branch_isize */ { @@ -1735,24 +1746,26 @@ static relax_info_t relax_table[] = {0, 0, 0, 0} }, /* BR_RANGE_S256 */ { + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP7}, {4, 4, 0, BFD_RELOC_NDS32_15_PCREL}, {0, 0, 0, 0} }, /* BR_RANGE_S16K */ { - {4, 4, 0, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_WORD_9_PCREL}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, {0, 0, 0, 0} }, /* BR_RANGE_S64K */ { - {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_WORD_9_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_WORD_9_PCREL}, {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, {0, 0, 0, 0} }, /* BR_RANGE_S16M */ { - {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_WORD_9_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_WORD_9_PCREL}, {4, 4, 0, BFD_RELOC_NDS32_HI20}, - {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {12, 4, NDS32_ORIGIN, 0}, - {12, 2, NDS32_CONVERT, 0}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_INSN16, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ @@ -1761,60 +1774,60 @@ static relax_info_t relax_table[] = "bnec", /* opcode */ BR_RANGE_S256, /* br_range */ { - {0, 8, 0x7FF}, - {0, 20, 0x1F}, - {0, 0, 0} - }, /* cond_field */ + {0, 8, 0x7FF, TRUE}, + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} + }, /* cond_field */ { { INSN_BNEC /* bnec $rt, imm11s, label */ }, /* BR_RANGE_S256 */ { - INSN_MOVI_TA, /* movi $ta, imm11s */ + INSN_MOVI_TA, /* movi $ta, imm11s */ INSN_BNE_TA /* bne $rt, $ta, label */ }, /* BR_RANGE_S16K */ { - INSN_MOVI_TA, /* movi $ta, imm11s */ - INSN_BNE_TA /* bne $rt, $ta, label */ + INSN_BEQC, /* beqc $rt, imm11s, $1 */ + INSN_J /* j label */ }, /* BR_RANGE_S64K */ { - INSN_BEQC, /* beqc $rt, imm11s, $1 */ + INSN_BEQC, /* beqc $rt, imm11s, $1 */ INSN_J /* j label */ }, /* BR_RANGE_S16M */ { - INSN_BEQC, /* beqc $rt, imm11s, $1 */ + INSN_BEQC, /* beqc $rt, imm11s, $1 */ INSN_SETHI_TA, /* sethi $ta, label */ INSN_ORI_TA, /* ori $ta, $ta, label */ INSN_JR_TA /* jr $ta */ } /* BR_RANGE_U4G */ - }, /* relax_code_seq */ + }, /* relax_code_seq */ { { - {0, 8, 0x7FF}, - {0, 20, 0x1F}, - {0, 0, 0} + {0, 8, 0x7FF, TRUE}, + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S256 */ { - {0, 0, 0xFFFFF}, - {4, 20, 0x1F}, - {0, 0, 0} + {0, 0, 0xFFFFF, FALSE}, + {4, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16K */ { - {0, 0, 0xFFFFF}, - {4, 20, 0x1F}, - {0, 0, 0} + {0, 8, 0x7FF, FALSE}, + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S64K */ { - {0, 8, 0x7FF}, - {0, 20, 0x1F}, - {0, 0, 0} + {0, 8, 0x7FF, FALSE}, + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} }, /* BR_RANGE_S16M */ { - {0, 8, 0x7FF}, - {0, 20, 0x1F}, - {0, 0, 0} + {0, 8, 0x7FF, FALSE}, + {0, 20, 0x1F, FALSE}, + {0, 0, 0, FALSE} } /* BR_RANGE_U4G */ - }, /* relax_code_condition */ + }, /* relax_code_condition */ {4, 8, 8, 8, 16}, /* relax_code_size */ {4, 4, 4, 4, 4}, /* relax_branch_isize */ { @@ -1823,40 +1836,41 @@ static relax_info_t relax_table[] = {0, 0, 0, 0} }, /* BR_RANGE_S256 */ { - {4, 4, 0, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, + {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP7}, + {4, 4, 0, BFD_RELOC_NDS32_15_PCREL}, {0, 0, 0, 0} }, /* BR_RANGE_S16K */ { - {4, 4, 0, BFD_RELOC_NDS32_15_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_WORD_9_PCREL}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, {0, 0, 0, 0} }, /* BR_RANGE_S64K */ { - {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_WORD_9_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_WORD_9_PCREL}, {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, {0, 0, 0, 0} }, /* BR_RANGE_S16M */ { - {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_WORD_9_PCREL}, + {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_WORD_9_PCREL}, {4, 4, 0, BFD_RELOC_NDS32_HI20}, {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, - {12, 4, NDS32_ORIGIN, 0}, - {12, 2, NDS32_CONVERT, 0}, + {12, 4, NDS32_INSN16, BFD_RELOC_NDS32_INSN16}, {0, 0, 0, 0} } /* BR_RANGE_U4G */ } /* relax_fixup */ }, { - NULL, /* opcode */ - 0, /* br_range */ - {{0, 0, 0}}, /* cond_field */ - {{0}}, /* relax_code_seq */ - {{{0, 0, 0}}}, /* relax_code_condition */ - {0}, /* relax_code_size */ - {0}, /* relax_branch_isize */ - {{{0, 0, 0, 0}}}, /* relax_fixup */ + NULL, /* opcode */ + 0, /* br_range */ + {{0, 0, 0, FALSE}}, /* cond_field */ + {{0}}, /* relax_code_seq */ + {{{0, 0, 0, FALSE}}}, /* relax_code_condition */ + {0}, /* relax_code_size */ + {0}, /* relax_branch_isize */ + {{{0, 0, 0, 0}}}, /* relax_fixup */ }, }; - /* GAS definitions for command-line options. */ enum options @@ -1872,7 +1886,7 @@ enum options OPTION_OPTIMIZE_SPACE }; -const char *md_shortopts = "m:G:O"; +const char *md_shortopts = "m:O:"; struct option md_longopts[] = { {"O1", no_argument, NULL, OPTION_OPTIMIZE}, @@ -1884,6 +1898,7 @@ struct option md_longopts[] = {"meb", no_argument, NULL, OPTION_BIG}, {"mel", no_argument, NULL, OPTION_LITTLE}, {"mall-ext", no_argument, NULL, OPTION_TURBO}, + {"mext-all", no_argument, NULL, OPTION_TURBO}, {"mpic", no_argument, NULL, OPTION_PIC}, /* Relaxation related options. */ {"mno-fp-as-gp-relax", no_argument, NULL, OPTION_RELAX_FP_AS_GP_OFF}, @@ -2131,7 +2146,9 @@ static int builtin_regnum (const char *s, const char *x ATTRIBUTE_UNUSED) { struct nds32_keyword *k; - + if (*s != '$') + return -1; + s++; k = hash_find (nds32_gprs_hash, s); if (k == NULL) @@ -2177,9 +2194,9 @@ static void do_pseudo_b (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) { char *arg_label = argv[0]; + relaxing = TRUE; /* b label */ - if (nds32_pic - && (strstr (arg_label, "@GOT") || strstr (arg_label, "@PLT"))) + if (nds32_pic && strstr (arg_label, "@PLT")) { md_assemblef ("sethi $ta,hi20(%s)", arg_label); md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label); @@ -2190,12 +2207,14 @@ do_pseudo_b (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) { md_assemblef ("j %s", arg_label); } + relaxing = FALSE; } static void do_pseudo_bal (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) { char *arg_label = argv[0]; + relaxing = TRUE; /* bal|call label */ if (nds32_pic && (strstr (arg_label, "@GOT") || strstr (arg_label, "@PLT"))) @@ -2209,6 +2228,7 @@ do_pseudo_bal (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) { md_assemblef ("jal %s", arg_label); } + relaxing = FALSE; } static void @@ -2291,21 +2311,38 @@ do_pseudo_bral (int argc, char *argv[], int pv ATTRIBUTE_UNUSED) } static void -do_pseudo_la_internal (const char *arg_reg, const char *arg_label, const char *line) +do_pseudo_la_internal (const char *arg_reg, const char *arg_label, + const char *line) { + relaxing = TRUE; /* rt, label */ - if (!nds32_pic) + if (!nds32_pic && !strstr(arg_label, "@")) { md_assemblef ("sethi %s,hi20(%s)", arg_reg, arg_label); md_assemblef ("ori %s,%s,lo12(%s)", arg_reg, arg_reg, arg_label); } - else if ((strstr (arg_label, "@PLT") || strstr (arg_label, "@GOTOFF"))) + else if (strstr (arg_label, "@TPOFF")) + { + /* la $rt, sym@TPOFF */ + md_assemblef ("sethi $ta,hi20(%s)", arg_label); + md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label); + md_assemblef ("add %s,$ta,%s", arg_reg, TLS_REG); + } + else if (strstr(arg_label, "@GOTTPOFF")) + { + /* la $rt, sym@GOTTPOFF*/ + md_assemblef ("sethi $ta,hi20(%s)", arg_label); + md_assemblef ("lwi $ta,[$ta+lo12(%s)]", arg_label); + md_assemblef ("add %s,$ta,%s", arg_reg, TLS_REG); + } + else if (nds32_pic && ((strstr (arg_label, "@PLT") + || strstr (arg_label, "@GOTOFF")))) { md_assemblef ("sethi $ta,hi20(%s)", arg_label); md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label); md_assemblef ("add %s,$ta,$gp", arg_reg); } - else if (strstr (arg_label, "@GOT")) + else if (nds32_pic && strstr (arg_label, "@GOT")) { long addend = builtin_addend (arg_label, NULL); @@ -2327,6 +2364,7 @@ do_pseudo_la_internal (const char *arg_reg, const char *arg_label, const char *l } else as_bad (_("need PIC qualifier with symbol. '%s'"), line); + relaxing = FALSE; } static void @@ -2390,16 +2428,36 @@ do_pseudo_ls_bhw (int argc ATTRIBUTE_UNUSED, char *argv[], int pv) if (builtin_isreg (argv[1], NULL)) { /* lwi */ - md_assemblef ("%c%c%si %s,[%s]", ls, size, argv[0], argv[1]); + md_assemblef ("%c%ci %s,[%s]", ls, size, argv[0], argv[1]); } else if (!nds32_pic) { - /* lwi */ - md_assemblef ("sethi $ta,hi20(%s)", argv[1]); - md_assemblef ("%c%c%si %s,[$ta+lo12(%s)]", ls, size, sign, argv[0], argv[1]); + relaxing = TRUE; + if (strstr (argv[1], "@TPOFF")) + { + /* ls.w $rt, sym@TPOFF */ + md_assemblef ("sethi $ta,hi20(%s)", argv[1]); + md_assemblef ("ori $ta,$ta,lo12(%s)", argv[1]); + md_assemblef ("%c%c%s %s,[$ta+%s]", ls, size, sign, argv[0], TLS_REG); + } + else if (strstr (argv[1], "@GOTTPOFF")) + { + /* ls.w $rt, sym@GOTTPOFF */ + md_assemblef ("sethi $ta,hi20(%s)", argv[1]); + md_assemblef ("lwi $ta,[$ta+lo12(%s)]", argv[1]); + md_assemblef ("%c%c%s %s,[$ta+%s]", ls, size, sign, argv[0], TLS_REG); + } + else + { + /* lwi */ + md_assemblef ("sethi $ta,hi20(%s)", argv[1]); + md_assemblef ("%c%c%si %s,[$ta+lo12(%s)]", ls, size, sign, argv[0], argv[1]); + } + relaxing = FALSE; } else { + relaxing = TRUE; /* PIC code. */ if (strstr (argv[1], "@GOTOFF")) { @@ -2430,6 +2488,7 @@ do_pseudo_ls_bhw (int argc ATTRIBUTE_UNUSED, char *argv[], int pv) { as_bad (_("needs @GOT or @GOTOFF. %s"), argv[argc]); } + relaxing = FALSE; } } @@ -2464,7 +2523,7 @@ static void do_pseudo_ls_bhwpc (int argc ATTRIBUTE_UNUSED, char *argv[], int pv) { char *arg_rt = argv[0]; - char *arg_inc = argv[2]; + char *arg_inc = argv[1]; char ls = 'r'; char size = 'x'; const char *sign = ""; @@ -2521,18 +2580,25 @@ do_pseudo_move_reg_internal (char *dst, char *src) static void do_pseudo_move (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) { + expressionS exp; + + parse_expression (argv[1], &exp); + if (builtin_isreg (argv[1], NULL)) do_pseudo_move_reg_internal (argv[0], argv[1]); + else if (exp.X_op == O_constant) + /* move $rt, imm -> li $rt, imm */ + do_pseudo_li_internal (argv[0], exp.X_add_number); else - /* move $rt, imm -> li $rt, imm */ - do_pseudo_li (argc, argv, PV_DONT_CARE); + /* l.w $rt, var -> l.w $rt, var */ + do_pseudo_ls_bhw (argc, argv, 2); } static void do_pseudo_neg (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) { - md_assemble ("movi $ta,0"); - md_assemblef ("sub %s,$ta,%s", argv[0], argv[1]); + /* Instead of "subri". */ + md_assemblef ("subri %s,%s,0", argv[0], argv[1]); } static void @@ -2586,10 +2652,21 @@ do_pseudo_pushpopm (int argc, char *argv[], int pv ATTRIBUTE_UNUSED) /* Adjust $re, $rb. */ if (rb >= 28) rb = re = 31; - else if (re >= 28) + else if (nds32_gpr16 != 1 && re >= 28) re = 27; - md_assemblef ("%s $r%d,[$sp],$r%d,%d", opc, rb, re, en4); + /* Reduce register. */ + if (nds32_gpr16 && re > 10 && !(rb == 31 && re == 31)) + { + if (re >= 15 && strstr(opc, "smw") != NULL) + md_assemblef ("%s $r15,[$sp],$r15,%d", opc, en4); + if (rb <= 10) + md_assemblef ("%s $r%d,[$sp],$r10, 0x0", opc, rb); + if (re >= 15 && strstr(opc, "lmw") != NULL) + md_assemblef ("%s $r15,[$sp],$r15,%d", opc, en4); + } + else + md_assemblef ("%s $r%d,[$sp],$r%d,%d", opc, rb, re, en4); } static void @@ -2842,7 +2919,7 @@ struct nds32_pseudo_opcode nds32_pseudo_opcode_table[] = {"swi.p", 3, do_pseudo_ls_bhwi, 2 | 0x80000000, 0}, {"lbsi.p", 3, do_pseudo_ls_bhwi, 0 | 0x10, 0}, {"lhsi.p", 3, do_pseudo_ls_bhwi, 1 | 0x10, 0}, - {"lwsi.p", 3, do_pseudo_ls_bhwi, 0 | 0x10, 0}, + {"lwsi.p", 3, do_pseudo_ls_bhwi, 2 | 0x10, 0}, {"move", 2, do_pseudo_move, 0, 0}, {"neg", 2, do_pseudo_neg, 0, 0}, @@ -3138,7 +3215,11 @@ nds32_parse_option (int c, char *arg) break; default: /* Determination of which option table to search for to save time. */ + if (!arg) + return 0; + ptr_arg = strchr (arg, '='); + if (ptr_arg) { /* Find the value after '='. */ @@ -3155,17 +3236,17 @@ nds32_parse_option (int c, char *arg) } else { - for (fine_tune = toggle_opts; fine_tune->name != NULL; fine_tune++) - { - int disable = 0; + int disable = 0; - /* Filter out the Disable option first. */ - if (strncmp (arg, "no-", 3) == 0) - { - disable = 1; - arg += 3; - } + /* Filter out the Disable option first. */ + if (strncmp (arg, "no-", 3) == 0) + { + disable = 1; + arg += 3; + } + for (fine_tune = toggle_opts; fine_tune->name != NULL; fine_tune++) + { if (strcmp (arg, fine_tune->name) == 0) { if (fine_tune->var != NULL) @@ -3409,12 +3490,8 @@ nds32_aligned_cons (int idx) exp.X_add_number = 0; exp.X_op = O_constant; - fix_new_exp (frag_now, - frag_now_fix () - (1 << idx), - 1 << idx, - &exp, - 0, - BFD_RELOC_NDS32_DATA); + fix_new_exp (frag_now, frag_now_fix () - (1 << idx), 1 << idx, + &exp, 0, BFD_RELOC_NDS32_DATA); } } @@ -3528,12 +3605,14 @@ nds32_omit_fp_begin (int mode) exp.X_add_symbol = abs_section_sym; if (mode == 1) { + in_omit_fp = 1; exp.X_add_number = R_NDS32_RELAX_REGION_OMIT_FP_FLAG; fix_new_exp (frag_now, frag_now_fix (), 0, &exp, 0, BFD_RELOC_NDS32_RELAX_REGION_BEGIN); } else { + in_omit_fp = 0; exp.X_add_number = R_NDS32_RELAX_REGION_OMIT_FP_FLAG; fix_new_exp (frag_now, frag_now_fix (), 0, &exp, 0, BFD_RELOC_NDS32_RELAX_REGION_END); @@ -3649,6 +3728,7 @@ nds32_relax_hint (int mode ATTRIBUTE_UNUSED) group = group->next; group->next = new; } + relaxing = TRUE; } /* Decide the size of vector entries, only accepts 4 or 16 now. */ @@ -3795,12 +3875,23 @@ void nds32_pre_do_align (int n, char *fill, int len, int max) { /* Only make a frag if we HAVE to... */ + fragS *fragP; if (n != 0 && !need_pass_2) { if (fill == NULL) { if (subseg_text_p (now_seg)) - frag_align_code (n, max); + { + fragP = frag_now; + frag_align_code (n, max); + + /* Tag this alignment when there is a lable before it. */ + if (label_exist) + { + fragP->tc_frag_data.flag = NDS32_FRAG_LABEL; + label_exist = 0; + } + } else frag_align (n, 0, max); } @@ -3888,7 +3979,7 @@ md_begin (void) /* Initial general pupose registers hash table. */ nds32_gprs_hash = hash_new (); - for (k = nds32_gprs; k->name; k++) + for (k = keyword_gpr; k->name; k++) hash_insert (nds32_gprs_hash, k->name, k); /* Initial branch hash table. */ @@ -3898,6 +3989,7 @@ md_begin (void) /* Initial relax hint hash table. */ nds32_hint_hash = hash_new (); + enable_16bit = nds32_16bit_ext; } /* HANDLE_ALIGN in write.c. */ @@ -3965,6 +4057,8 @@ nds32_frob_label (symbolS *label) int nds32_start_label (int asmdone ATTRIBUTE_UNUSED, int secdone ATTRIBUTE_UNUSED) { + if (optimize && subseg_text_p (now_seg)) + label_exist = 1; return 1; } @@ -4009,19 +4103,19 @@ get_range_type (const struct nds32_field *field) /* Save pseudo instruction relocation list. */ static struct nds32_relocs_pattern* -nds32_elf_save_pseudo_pattern (int reloc, struct nds32_asm_insn *insn, +nds32_elf_save_pseudo_pattern (fixS* fixP, struct nds32_opcode *opcode, char *out, symbolS *sym, - struct nds32_relocs_pattern *reloc_ptr) + struct nds32_relocs_pattern *reloc_ptr, + fragS *fragP) { if (!reloc_ptr) reloc_ptr = malloc (sizeof (struct nds32_relocs_pattern)); reloc_ptr->seg = now_seg; reloc_ptr->sym = sym; - reloc_ptr->frag = frag_now; + reloc_ptr->frag = fragP; reloc_ptr->frchain = frchain_now; - reloc_ptr->reloc = reloc; - reloc_ptr->insn = insn->opcode->value; - reloc_ptr->size = insn->opcode->isize; + reloc_ptr->fixP = fixP; + reloc_ptr->opcode = opcode; reloc_ptr->where = out; reloc_ptr->next = NULL; return reloc_ptr; @@ -4029,88 +4123,103 @@ nds32_elf_save_pseudo_pattern (int reloc, struct nds32_asm_insn *insn, /* Check X_md to transform relocation. */ -static void -nds32_elf_record_fixup_exp (char *str, const struct nds32_field *fld, +static fixS* +nds32_elf_record_fixup_exp (fragS *fragP, char *str, + const struct nds32_field *fld, expressionS *pexp, char* out, struct nds32_asm_insn *insn) { int reloc = -1; - symbolS *sym = NULL; - struct nds32_relocs_group *group; - struct nds32_relocs_pattern *reloc_ptr; + expressionS exp; + fixS *fixP = NULL; /* Handle instruction relocation. */ if (fld && fld->bitpos == 0 && (insn->attr & NASM_ATTR_HI20)) { /* Relocation for hi20 modifier. */ - sym = pexp->X_add_symbol; switch (pexp->X_md) { - case BFD_RELOC_NDS32_GOTOFF: - /* @GOTOFF */ + case BFD_RELOC_NDS32_GOTOFF: /* @GOTOFF */ reloc = BFD_RELOC_NDS32_GOTOFF_HI20; break; - case BFD_RELOC_NDS32_GOT20: - /* @GOT */ + case BFD_RELOC_NDS32_GOT20: /* @GOT */ reloc = BFD_RELOC_NDS32_GOT_HI20; break; - case BFD_RELOC_NDS32_25_PLTREL: - /* @PLT */ + case BFD_RELOC_NDS32_25_PLTREL: /* @PLT */ if (!nds32_pic) as_bad (_("Invalid PIC expression.")); else reloc = BFD_RELOC_NDS32_PLT_GOTREL_HI20; break; - default: - /* No suffix. */ + case BFD_RELOC_NDS32_GOTPC20: /* _GLOBAL_OFFSET_TABLE_ */ + reloc = BFD_RELOC_NDS32_GOTPC_HI20; + break; + case BFD_RELOC_NDS32_TPOFF: /* @TPOFF */ + reloc = BFD_RELOC_NDS32_TLS_LE_HI20; + break; + case BFD_RELOC_NDS32_GOTTPOFF: /* @GOTTPOFF */ + reloc = BFD_RELOC_NDS32_TLS_IE_HI20; + break; + default: /* No suffix. */ reloc = BFD_RELOC_NDS32_HI20; break; } - - fix_new_exp (frag_now, out - frag_now->fr_literal, - insn->opcode->isize, insn->info, 0 /* pcrel */, - reloc); + fixP = fix_new_exp (fragP, out - fragP->fr_literal, insn->opcode->isize, + insn->info, 0 /* pcrel */, reloc); } else if (fld && fld->bitpos == 0 && (insn->attr & NASM_ATTR_LO12)) { /* Relocation for lo12 modifier. */ if (fld->bitsize == 15 && fld->shift == 0) { + /* [ls]bi || ori */ switch (pexp->X_md) { - case BFD_RELOC_NDS32_GOTOFF: - /* @GOTOFF */ + case BFD_RELOC_NDS32_GOTOFF: /* @GOTOFF */ reloc = BFD_RELOC_NDS32_GOTOFF_LO12; break; - case BFD_RELOC_NDS32_GOT20: - /* @GOT */ + case BFD_RELOC_NDS32_GOT20: /* @GOT */ reloc = BFD_RELOC_NDS32_GOT_LO12; break; - case BFD_RELOC_NDS32_25_PLTREL: - /* @PLT */ + case BFD_RELOC_NDS32_25_PLTREL: /* @PLT */ if (!nds32_pic) as_bad (_("Invalid PIC expression.")); else reloc = BFD_RELOC_NDS32_PLT_GOTREL_LO12; break; - default: - /* No suffix. */ - reloc = BFD_RELOC_NDS32_LO12S0; /* [ls]bi || ori */ + case BFD_RELOC_NDS32_GOTPC20: /* _GLOBAL_OFFSET_TABLE_ */ + reloc = BFD_RELOC_NDS32_GOTPC_LO12; + break; + case BFD_RELOC_NDS32_TPOFF: /* @TPOFF */ + reloc = BFD_RELOC_NDS32_TLS_LE_LO12; + break; + default: /* No suffix. */ + reloc = BFD_RELOC_NDS32_LO12S0; break; } } else if (fld->bitsize == 15 && fld->shift == 1) reloc = BFD_RELOC_NDS32_LO12S1; /* [ls]hi */ else if (fld->bitsize == 15 && fld->shift == 2) - reloc = BFD_RELOC_NDS32_LO12S2; /* [ls]wi */ + { + /* [ls]wi */ + switch (pexp->X_md) + { + case BFD_RELOC_NDS32_GOTTPOFF: /* @GOTTPOFF */ + reloc = BFD_RELOC_NDS32_TLS_IE_LO12S2; + break; + default: /* No suffix. */ + reloc = BFD_RELOC_NDS32_LO12S2; + break; + } + } else if (fld->bitsize == 15 && fld->shift == 3) reloc = BFD_RELOC_NDS32_LO12S3; /* [ls]di */ else if (fld->bitsize == 12 && fld->shift == 2) - reloc = BFD_RELOC_NDS32_LO12S2; /* f[ls][sd]i */ + reloc = R_NDS32_LO12S2_SP_RELA; /* f[ls][sd]i */ - fix_new_exp (frag_now, out - frag_now->fr_literal, - insn->opcode->isize, insn->info, 0 /* pcrel */, - reloc); + fixP = fix_new_exp (fragP, out - fragP->fr_literal, insn->opcode->isize, + insn->info, 0 /* pcrel */, reloc); } else if (fld && fld->bitpos == 0 && insn->opcode->isize == 4 && (insn->attr & NASM_ATTR_PCREL)) @@ -4127,9 +4236,8 @@ nds32_elf_record_fixup_exp (char *str, const struct nds32_field *fld, else abort (); - fix_new_exp (frag_now, out - frag_now->fr_literal, - insn->opcode->isize, insn->info, 1 /* pcrel */, - reloc); + fixP = fix_new_exp (fragP, out - fragP->fr_literal, insn->opcode->isize, + insn->info, 1 /* pcrel */, reloc); } else if (fld && fld->bitpos == 0 && insn->opcode->isize == 4 && (insn->attr & NASM_ATTR_GPREL)) @@ -4144,9 +4252,16 @@ nds32_elf_record_fixup_exp (char *str, const struct nds32_field *fld, else abort (); - fix_new_exp (frag_now, out - frag_now->fr_literal, - insn->opcode->isize, insn->info, 0 /* pcrel */, - reloc); + fixP = fix_new_exp (fragP, out - fragP->fr_literal, insn->opcode->isize, + insn->info, 0 /* pcrel */, reloc); + /* Insert INSN16 for converting fp_as_gp. */ + exp.X_op = O_symbol; + exp.X_add_symbol = abs_section_sym; + exp.X_add_number = 0; + if (in_omit_fp && reloc == BFD_RELOC_NDS32_SDA17S2) + fix_new_exp (fragP, out - fragP->fr_literal, + insn->opcode->isize, &exp, 0 /* pcrel */, + BFD_RELOC_NDS32_INSN16); } else if (fld && fld->bitpos == 0 && insn->opcode->isize == 2 && (insn->attr & NASM_ATTR_PCREL)) @@ -4157,20 +4272,50 @@ nds32_elf_record_fixup_exp (char *str, const struct nds32_field *fld, else abort (); - fix_new_exp (frag_now, out - frag_now->fr_literal, - insn->opcode->isize, insn->info, 1 /* pcrel */, - reloc); + fixP = fix_new_exp (fragP, out - fragP->fr_literal, insn->opcode->isize, + insn->info, 1 /* pcrel */, reloc); } - else if (fld) - { - as_bad (_("Don't know how to handle this field. %s"), - str); + else if (fld && fld->bitpos == 0 && (insn->attr & NASM_ATTR_IFC_EXT)) + { + /* Relocation for ifcall instruction. */ + if (insn->opcode->isize == 2 && fld->bitsize == 9 && fld->shift == 1) + reloc = BFD_RELOC_NDS32_10IFCU_PCREL; + else if (insn->opcode->isize == 4 && fld->bitsize == 16 + && fld->shift == 1) + reloc = BFD_RELOC_NDS32_17IFC_PCREL; + else + abort (); + + fixP = fix_new_exp (fragP, out - fragP->fr_literal, insn->opcode->isize, + insn->info, 1 /* pcrel */, reloc); } + else if (fld) + as_bad (_("Don't know how to handle this field. %s"), str); + + return fixP; +} + +/* Build instruction pattern to relax. There are two type group pattern + including pseudo instruction and relax hint. */ + +static void +nds32_elf_build_relax_relation (fixS *fixP, expressionS *pexp, char* out, + struct nds32_opcode *opcode, fragS *fragP, + const struct nds32_field *fld) +{ + struct nds32_relocs_pattern *reloc_ptr; + struct nds32_relocs_group *group; + symbolS *sym = NULL; + + /* The expression may be used uninitialized. */ + if (fld) + sym = pexp->X_add_symbol; if (pseudo_opcode) { /* Save instruction relation for pseudo instruction expanding pattern. */ - reloc_ptr = nds32_elf_save_pseudo_pattern (reloc, insn, out, sym, NULL); + reloc_ptr = nds32_elf_save_pseudo_pattern (fixP, opcode, out, sym, + NULL, fragP); if (!relocs_list) relocs_list = reloc_ptr; else @@ -4187,267 +4332,120 @@ nds32_elf_record_fixup_exp (char *str, const struct nds32_field *fld, group = nds32_relax_hint_current; while (group) { - nds32_elf_save_pseudo_pattern (reloc, insn, out, sym, group->pattern); + nds32_elf_save_pseudo_pattern (fixP, opcode, out, sym, + group->pattern, fragP); group = group->next; free (nds32_relax_hint_current); nds32_relax_hint_current = group; } } + + /* Set relaxing false only for relax_hint trigger it. */ + if (!pseudo_opcode) + relaxing = FALSE; } -#define N32_MEM_EXT(insn) (N32_OP6_MEM<< 25| insn) +#define N32_MEM_EXT(insn) ((N32_OP6_MEM << 25) | insn) /* Relax pattern for link time relaxation. */ -static struct nds32_relocation_map relocation_table[] = +static struct nds32_relax_hint_table relax_ls_table[] = { + { + /* Set address: la -> sethi ori. */ + NDS32_RELAX_HINT_LA, /* main_type */ + 8, /* relax_code_size */ { - /* Load-Store: sethi lwi+ - Load address: sethi ori */ - BFD_RELOC_NDS32_HI20, /* main_type */ - { - { - {BFD_RELOC_NDS32_LOADSTORE, 0}, - {0, 0} - }, - { - {BFD_RELOC_NDS32_INSN16, 0}, - {0, 0} - }, - { - {0, 0} - } - }, - }, - { - /* Load-Store: sethi ori lwi+ - Load address: sethi ori add */ - BFD_RELOC_NDS32_GOTOFF_HI20, /* main_type */ - { - { - {BFD_RELOC_NDS32_LOADSTORE, 0}, - {0, 0} - }, - { - {BFD_RELOC_NDS32_INSN16, 0}, - {BFD_RELOC_NDS32_PTR, 0}, - {BFD_RELOC_NDS32_PTR_COUNT, 0}, - {0, 0} - }, - { - {BFD_RELOC_NDS32_GOTOFF_SUFF, 0}, - {BFD_RELOC_NDS32_PTR_RESOLVED, 0}, - {0, 0} - }, - { - {0, 0} - } - }, - }, + OP6 (SETHI), + OP6 (ORI), + }, /* relax_code_seq */ { - /* Load-Store: sethi ori lw lwi+ - Load address: sethi ori lw [addi|add] */ - BFD_RELOC_NDS32_GOT_HI20, /* main_type */ - { - { - {BFD_RELOC_NDS32_LOADSTORE, 0}, - {0, 0} - }, - { - {BFD_RELOC_NDS32_INSN16, 0}, - /* For pseudo la and l.w. - Lw is the next one instruction. */ - {BFD_RELOC_NDS32_PTR, N32_MEM_EXT (N32_MEM_LW)}, - {BFD_RELOC_NDS32_PTR_COUNT, 0}, - {0, 0} - }, - { - {BFD_RELOC_NDS32_GOT_SUFF, N32_MEM_EXT (N32_MEM_LW)}, - {BFD_RELOC_NDS32_PTR_RESOLVED, N32_MEM_EXT (N32_MEM_LW)}, - {0, 0} - }, - { - {0, 0}, - }, - }, - }, + {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE}, + {4, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_INSN16} + } /* relax_fixup */ + }, + { + /* Set address: l.w -> sethi ori. */ + NDS32_RELAX_HINT_LS, /* main_type */ + 8, /* relax_code_size */ { - BFD_RELOC_NDS32_PLT_GOTREL_HI20, /* main_type */ - { - { - {BFD_RELOC_NDS32_LOADSTORE, 0}, - {0, 0} - }, - { - {BFD_RELOC_NDS32_INSN16, 0}, - /* For pseudo bal. - jral is the target instruction. */ - {BFD_RELOC_NDS32_PTR, INSN_JRAL}, - {BFD_RELOC_NDS32_PTR, (INSN_JRAL | (REG_LP << 20))}, - {BFD_RELOC_NDS32_PTR_COUNT, 0}, - {0, 0} - }, - { - /* For pseudo bal. - jral is the target instruction. */ - {BFD_RELOC_NDS32_PTR, INSN_JRAL}, - {BFD_RELOC_NDS32_PTR, (INSN_JRAL | (REG_LP << 20))}, - {BFD_RELOC_NDS32_PTR_COUNT, 0}, - {0, 0} - }, - { - {BFD_RELOC_NDS32_PLT_GOT_SUFF, 0}, - {BFD_RELOC_NDS32_PTR_RESOLVED, 0}, - {0, 0} - }, - { - {0, 0}, - }, - }, - }, + OP6 (SETHI), + OP6 (LBI), + }, /* relax_code_seq */ { - 0, - { - { - {0, 0}, - }, - }, - } + {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE}, + {4, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_INSN16} + } /* relax_fixup */ + }, + { + 0, + 0, + {0}, + {{0, 0 , 0, 0}} + } }; /* Since sethi loadstore relocation has to using next instruction to determine elimination itself or not, we have to return the next instruction range. */ static int -nds32_elf_sethi_range (struct nds32_relocs_pattern *relocs_ptr) -{ - unsigned int insn = relocs_ptr->insn; - int range; - switch (insn) - { - case INSN_LBI: - case INSN_SBI: - case INSN_LBSI: - case N32_MEM_EXT (N32_MEM_LB): - case N32_MEM_EXT (N32_MEM_LBS): - case N32_MEM_EXT (N32_MEM_SB): - range = 0x01; - break; - case INSN_LHI: - case INSN_SHI: - case INSN_LHSI: - case N32_MEM_EXT (N32_MEM_LH): - case N32_MEM_EXT (N32_MEM_LHS): - case N32_MEM_EXT (N32_MEM_SH): - range = 0x02; - break; - case INSN_LWI: - case INSN_SWI: - case N32_MEM_EXT (N32_MEM_LW): - case N32_MEM_EXT (N32_MEM_SW): - range = 0x04; - break; - case INSN_FLSI: - case INSN_FSSI: - range = 0x08; - break; - case INSN_FLDI: - case INSN_FSDI: - range = 0x10; - break; - case INSN_ORI: - range = 0x20; - break; - default: - range = 0x0; - break; - } - return range; -} - -/* The args means: instruction size, the 1st instruction is converted to 16 or - not, optimize option, 16 bit instruction is enable. */ -#define SET_ADDEND( size, convertible, optimize, insn16_on ) \ - (((size) & 0xff) | ((convertible) ? 1 << 31 : 0) \ - | ((optimize) ? 1<< 30 : 0) | (insn16_on ? 1 << 29 : 0)) - -/* Insert new fix. */ - -static void -nds32_elf_insert_relocation (struct nds32_relocs_pattern *pattern, unsigned int reloc, - unsigned int insn_mask, symbolS *sym) +nds32_elf_sethi_range (struct nds32_relocs_pattern *pattern) { - expressionS exp; - symbolS *sym_t; - struct nds32_relocs_pattern *pattern_t; - int range; - fragS *frag = pattern->frag; - char *out = pattern->where; - unsigned int size = pattern->size; - static int ptr_count = 0; - - exp.X_op = O_symbol; - exp.X_add_symbol = abs_section_sym; - exp.X_add_number = 0; - - switch (reloc) + int range = 0; + while (pattern) { - case BFD_RELOC_NDS32_LOADSTORE: - /* To get the sethi match pattern. */ - range = nds32_elf_sethi_range (pattern->next); - exp.X_add_number = SET_ADDEND (4 /* size */, 0, optimize, enable_16bit); - exp.X_add_number |= ((range & 0x3f) << 8); - fix_new_exp (frag, out - frag->fr_literal, size, &exp, 0 /* pcrel */, reloc); - break; - - case BFD_RELOC_NDS32_PTR: - pattern_t = pattern->next; - while (pattern_t) + switch (pattern->opcode->value) { - if (insn_mask == 0 || pattern_t->insn == insn_mask) - { - sym_t = symbol_temp_new (pattern_t->seg, - pattern_t->where - pattern_t->frag->fr_literal, - pattern_t->frag); - exp.X_add_symbol = sym_t; - fix_new_exp (frag, out - frag->fr_literal, 0, &exp, 0 /* pcrel */, reloc); - ptr_count++; - break; - } - pattern_t = pattern_t->next; - } - break; - - case BFD_RELOC_NDS32_PTR_COUNT: - /* In current design, it only be referanced once. */ - if (ptr_count != 0) - { - exp.X_add_number = ptr_count; - fix_new_exp (frag, out - frag->fr_literal, size, &exp, 0, reloc); - } - ptr_count = 0; - break; - - case BFD_RELOC_NDS32_GOTOFF_SUFF: - case BFD_RELOC_NDS32_GOT_SUFF: - case BFD_RELOC_NDS32_PLT_GOT_SUFF: - /* It has to record symbol. */ - if (insn_mask == 0 || pattern->insn == insn_mask) - { - exp.X_add_symbol = sym; - fix_new_exp (frag, out - frag->fr_literal, size, &exp, 0, reloc); - } - break; - - case BFD_RELOC_NDS32_PTR_RESOLVED: - default: - if (insn_mask == 0 || pattern->insn == insn_mask) - { - fix_new_exp (frag, out - frag->fr_literal, size, &exp, 0, reloc); + case INSN_LBI: + case INSN_SBI: + case INSN_LBSI: + case N32_MEM_EXT (N32_MEM_LB): + case N32_MEM_EXT (N32_MEM_LBS): + case N32_MEM_EXT (N32_MEM_SB): + range = NDS32_LOADSTORE_BYTE; + break; + case INSN_LHI: + case INSN_SHI: + case INSN_LHSI: + case N32_MEM_EXT (N32_MEM_LH): + case N32_MEM_EXT (N32_MEM_LHS): + case N32_MEM_EXT (N32_MEM_SH): + range = NDS32_LOADSTORE_HALF; + break; + case INSN_LWI: + case INSN_SWI: + case N32_MEM_EXT (N32_MEM_LW): + case N32_MEM_EXT (N32_MEM_SW): + range = NDS32_LOADSTORE_WORD; + break; + case INSN_FLSI: + case INSN_FSSI: + range = NDS32_LOADSTORE_FLOAT_S; + break; + case INSN_FLDI: + case INSN_FSDI: + range = NDS32_LOADSTORE_FLOAT_D; + break; + case INSN_ORI: + range = NDS32_LOADSTORE_IMM; + break; + default: + range = NDS32_LOADSTORE_NONE; + break; } + if (range != NDS32_LOADSTORE_NONE) + break; + pattern = pattern->next; } + return range; } +/* The args means: instruction size, the 1st instruction is converted to 16 or + not, optimize option, 16 bit instruction is enable. */ +#define SET_ADDEND(size, convertible, optimize, insn16_on) \ + (((size) & 0xff) | ((convertible) ? 1 << 31 : 0) \ + | ((optimize) ? 1<< 30 : 0) | (insn16_on ? 1 << 29 : 0)) + static void nds32_set_elf_flags_by_insn (struct nds32_asm_insn * insn) { @@ -4562,58 +4560,525 @@ nds32_set_elf_flags_by_insn (struct nds32_asm_insn * insn) /* TODO: E_NDS32_HAS_SATURATION_INST */ } +/* Flag for analysis relaxation type. */ + +enum nds32_insn_type +{ + N32_RELAX_SETHI = 1, + N32_RELAX_BR = (1 << 1), + N32_RELAX_LSI = (1 << 2), + N32_RELAX_JUMP = (1 << 3), + N32_RELAX_CALL = (1 << 4), + N32_RELAX_ORI = (1 << 5), + N32_RELAX_MEM = (1 << 6), + N32_RELAX_MOVI = (1 << 7), +}; + +struct nds32_hint_map +{ + bfd_reloc_code_real_type hi_type; + char *opc; + enum nds32_relax_hint_type hint_type; + enum nds32_br_range range; + enum nds32_insn_type insn_list; +}; + +/* Table to match instructions with hint and relax pattern. */ + +static struct nds32_hint_map hint_map [] = +{ + { + /* LONGCALL4. */ + BFD_RELOC_NDS32_HI20, + "jal", + NDS32_RELAX_HINT_NONE, + BR_RANGE_U4G, + N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_CALL + }, + { + /* LONGCALL5. */ + _dummy_first_bfd_reloc_code_real, + "bgezal", + NDS32_RELAX_HINT_NONE, + BR_RANGE_S16M, + N32_RELAX_BR | N32_RELAX_CALL + }, + { + /* LONGCALL6. */ + BFD_RELOC_NDS32_HI20, + "bgezal", + NDS32_RELAX_HINT_NONE, + BR_RANGE_U4G, + N32_RELAX_BR | N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_CALL + }, + { + /* LONGJUMP4. */ + BFD_RELOC_NDS32_HI20, + "j", + NDS32_RELAX_HINT_NONE, + BR_RANGE_U4G, + N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_JUMP + }, + { + /* LONGJUMP5. */ + /* There is two kinds of veriation of LONGJUMP5. One of them + generate EMPTY relocation for converted INSN16 if needed. + But we don't distinguish them here. */ + _dummy_first_bfd_reloc_code_real, + "beq", + NDS32_RELAX_HINT_NONE, + BR_RANGE_S16M, + N32_RELAX_BR | N32_RELAX_JUMP + }, + { + /* LONGJUMP6. */ + BFD_RELOC_NDS32_HI20, + "beq", + NDS32_RELAX_HINT_NONE, + BR_RANGE_U4G, + N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_BR | N32_RELAX_JUMP + }, + { + /* LONGJUMP7. */ + _dummy_first_bfd_reloc_code_real, + "beqc", + NDS32_RELAX_HINT_NONE, + BR_RANGE_S16K, + N32_RELAX_MOVI | N32_RELAX_BR + }, + { + /* LOADSTORE ADDRESS. */ + BFD_RELOC_NDS32_HI20, + NULL, + NDS32_RELAX_HINT_LA, + BR_RANGE_U4G, + N32_RELAX_SETHI | N32_RELAX_ORI + }, + { + /* LOADSTORE ADDRESS. */ + BFD_RELOC_NDS32_HI20, + NULL, + NDS32_RELAX_HINT_LS, + BR_RANGE_U4G, + N32_RELAX_SETHI | N32_RELAX_LSI + }, + {0, NULL, 0, 0 ,0} +}; + +/* Find the relaxation pattern according to instructions. */ + +static bfd_boolean +nds32_find_reloc_table (struct nds32_relocs_pattern *relocs_pattern, + struct nds32_relax_hint_table *hint_info) +{ + unsigned int opcode, seq_size; + enum nds32_br_range range; + struct nds32_relocs_pattern *pattern, *hi_pattern = NULL; + char *opc = NULL; + relax_info_t *relax_info = NULL; + nds32_relax_fixup_info_t *fixup_info, *hint_fixup; + enum nds32_relax_hint_type hint_type = NDS32_RELAX_HINT_NONE; + struct nds32_relax_hint_table *table_ptr; + uint32_t *code_seq, *hint_code; + enum nds32_insn_type relax_type = 0; + struct nds32_hint_map *map_ptr = hint_map; + unsigned int i; + char *check_insn[] = + { "bnes38", "beqs38", "bnez38", "bnezs8", "beqz38", "beqzs8" }; + + /* TODO: PLT GOT. */ + /* Traverse all pattern instruction and set flag. */ + pattern = relocs_pattern; + while (pattern) + { + if (pattern->opcode->isize == 4) + { + /* 4 byte instruction. */ + opcode = N32_OP6 (pattern->opcode->value); + switch (opcode) + { + case N32_OP6_SETHI: + hi_pattern = pattern; + relax_type |= N32_RELAX_SETHI; + break; + case N32_OP6_MEM: + relax_type |= N32_RELAX_MEM; + break; + case N32_OP6_ORI: + relax_type |= N32_RELAX_ORI; + break; + case N32_OP6_BR1: + case N32_OP6_BR2: + case N32_OP6_BR3: + relax_type |= N32_RELAX_BR; + break; + case N32_OP6_MOVI: + relax_type |= N32_RELAX_MOVI; + break; + case N32_OP6_LBI: + case N32_OP6_SBI: + case N32_OP6_LBSI: + case N32_OP6_LHI: + case N32_OP6_SHI: + case N32_OP6_LHSI: + case N32_OP6_LWI: + case N32_OP6_SWI: + case N32_OP6_LWC: + case N32_OP6_SWC: + relax_type |= N32_RELAX_LSI; + break; + case N32_OP6_JREG: + if (__GF (pattern->opcode->value, 0, 1) == 1) + relax_type |= N32_RELAX_CALL; + else + relax_type |= N32_RELAX_JUMP; + break; + case N32_OP6_JI: + if (__GF (pattern->opcode->value, 24, 1) == 1) + relax_type |= N32_RELAX_CALL; + else + relax_type |= N32_RELAX_JUMP; + break; + default: + as_warn (_("relax hint unrecognized instruction: line %d."), + pattern->frag->fr_line); + return FALSE; + } + } + else + { + /* 2 byte instruction. Compare by opcode name because the opcode of + 2byte instruction is not regular. */ + for (i = 0; i < sizeof (check_insn) / sizeof (check_insn[0]); i++) + { + if (strcmp (pattern->opcode->opcode, check_insn[i]) == 0) + { + relax_type |= N32_RELAX_BR; + break; + } + } + if (strcmp (pattern->opcode->opcode, "movi55") == 0) + relax_type |= N32_RELAX_MOVI; + } + pattern = pattern->next; + } + + /* Analysis instruction flag to choose relaxation table. */ + while (map_ptr->insn_list != 0) + { + if (map_ptr->insn_list == relax_type + && (!hi_pattern + || (hi_pattern->fixP + && hi_pattern->fixP->fx_r_type == map_ptr->hi_type))) + { + opc = map_ptr->opc; + hint_type = map_ptr->hint_type; + range = map_ptr->range; + break; + } + map_ptr++; + } + + if (map_ptr->insn_list == 0) + { + as_warn (_("Can not find match relax hint. line : %d"), + relocs_pattern->frag->fr_line); + return FALSE; + } + + /* Get the match table. */ + if (opc) + { + /* Branch relax pattern. */ + relax_info = hash_find (nds32_relax_info_hash, opc); + if (!relax_info) + return FALSE; + fixup_info = relax_info->relax_fixup[range]; + code_seq = relax_info->relax_code_seq[range]; + seq_size = relax_info->relax_code_size[range]; + } + else if (hint_type) + { + /* Load-store relax pattern. */ + table_ptr = relax_ls_table; + while (table_ptr->main_type != 0) + { + if (table_ptr->main_type == hint_type) + { + fixup_info = table_ptr->relax_fixup; + code_seq = table_ptr->relax_code_seq; + seq_size = table_ptr->relax_code_size; + break; + } + table_ptr++; + } + if (table_ptr->main_type == 0) + return FALSE; + } + else + return FALSE; + + hint_fixup = hint_info->relax_fixup; + hint_code = hint_info->relax_code_seq; + hint_info->relax_code_size = seq_size; + + while (fixup_info->size != 0) + { + if (fixup_info->ramp & NDS32_HINT) + { + memcpy (hint_fixup, fixup_info, sizeof (nds32_relax_fixup_info_t)); + hint_fixup++; + } + fixup_info++; + } + /* Clear final relocation. */ + memset (hint_fixup, 0, sizeof (nds32_relax_fixup_info_t)); + /* Copy code sequance. */ + memcpy (hint_code, code_seq, seq_size); + return TRUE; +} + +/* Because there are a lot of variant of load-store, check + all these type here. */ + +#define CLEAN_REG(insn) ((insn) & 0xff0003ff) +static bfd_boolean +nds32_match_hint_insn (struct nds32_opcode *opcode, uint32_t seq) +{ + char *check_insn[] = + { "bnes38", "beqs38", "bnez38", "bnezs8", "beqz38", "beqzs8" }; + uint32_t insn = opcode->value; + unsigned int i; + + insn = CLEAN_REG (opcode->value); + if (insn == seq) + return TRUE; + + switch (seq) + { + case OP6 (LBI): + /* In relocation_table, it regards instruction LBI as representation + of all the NDS32_RELAX_HINT_LS pattern. */ + if (insn == OP6 (LBI) || insn == OP6 (SBI) || insn == OP6 (LBSI) + || insn == OP6 (LHI) || insn == OP6 (SHI) || insn == OP6 (LHSI) + || insn == OP6 (LWI) || insn == OP6 (SWI) + || insn == OP6 (LWC) || insn == OP6 (SWC)) + return TRUE; + break; + case OP6 (BR2): + /* This is for LONGCALL5 and LONGCALL6. */ + if (insn == OP6 (BR2)) + return TRUE; + break; + case OP6 (BR1): + /* This is for LONGJUMP5 and LONGJUMP6. */ + if (opcode->isize == 4 + && (insn == OP6 (BR1) || insn == OP6 (BR2) || insn == OP6 (BR3))) + return TRUE; + else if (opcode->isize == 2) + { + for (i = 0; i < sizeof (check_insn) / sizeof (check_insn[0]); i++) + if (strcmp (opcode->opcode, check_insn[i]) == 0) + return TRUE; + } + break; + case OP6 (MOVI): + /* This is for LONGJUMP7. */ + if (opcode->isize == 2 && strcmp (opcode->opcode, "movi55") == 0) + return TRUE; + break; + } + return FALSE; +} + /* Append relax relocation for link time relaxing. */ static void nds32_elf_append_relax_relocs (const char *key ATTRIBUTE_UNUSED, void *value) { - struct nds32_relocs_pattern *relocs_temp = + struct nds32_relocs_pattern *relocs_pattern = (struct nds32_relocs_pattern *) value; - unsigned int reloc, group_type, insn; - symbolS *sym; - unsigned int i = 0, x = 0, y; + struct nds32_relocs_pattern *pattern_temp, *pattern_now; + symbolS *sym, *hi_sym = NULL; + expressionS exp; + fragS *fragP; segT seg_bak = now_seg; frchainS *frchain_bak = frchain_now; + struct nds32_relax_hint_table hint_info; + nds32_relax_fixup_info_t *hint_fixup, *fixup_now; + size_t fixup_size; + offsetT branch_offset; + fixS *fixP; + int range, offset; + unsigned int ptr_offset, hint_count, relax_code_size, count = 0; + uint32_t *code_seq, code_insn; + char *where; + + if (!relocs_pattern) + return; - if (!relocs_temp) + if (!nds32_find_reloc_table (relocs_pattern, &hint_info)) return; - group_type = relocs_temp->reloc; - sym = relocs_temp->sym; + /* Save symbol for some EMPTY relocation using. */ + pattern_now = relocs_pattern; + while (pattern_now) + { + if (pattern_now->opcode->value == OP6 (SETHI)) + { + hi_sym = pattern_now->sym; + break; + } + pattern_now = pattern_now->next; + } + /* Inserting fix up must specify now_seg or frchain_now. */ - now_seg = relocs_temp->seg; - frchain_now = relocs_temp->frchain; + now_seg = relocs_pattern->seg; + frchain_now = relocs_pattern->frchain; + fragP = relocs_pattern->frag; + branch_offset = fragP->fr_offset; - /* Find pattern in relocation table. */ - while (i < (sizeof (relocation_table)/sizeof (relocation_table[0])) - &&relocation_table[i].main_type != group_type) - i++; + hint_fixup = hint_info.relax_fixup; + code_seq = hint_info.relax_code_seq; + relax_code_size = hint_info.relax_code_size; + pattern_now = relocs_pattern; - /* Can not find relocation pattern. */ - if (relocation_table[i].main_type == 0) - return; + /* Insert relaxation. */ + exp.X_op = O_symbol; - while (relocs_temp) + while (pattern_now) { - y = 0; + /* Choose the match fixup by instruction. */ + code_insn = CLEAN_REG (*(code_seq + count)); + if (!nds32_match_hint_insn (pattern_now->opcode, code_insn)) + { + count = 0; + code_insn = CLEAN_REG (*(code_seq + count)); - while (relocation_table[i].reloc_insn[x][y][0] != 0) + while (!nds32_match_hint_insn (pattern_now->opcode, code_insn)) + { + count++; + if (count >= relax_code_size / 4) + { + as_bad (_("Internal error: Relax hint error. %s: %x"), + now_seg->name, pattern_now->opcode->value); + goto restore; + } + code_insn = CLEAN_REG (*(code_seq + count)); + } + } + fragP = pattern_now->frag; + sym = pattern_now->sym; + branch_offset = fragP->fr_offset; + offset = count * 4; + where = pattern_now->where; + /* Find the instruction map fix. */ + fixup_now = hint_fixup; + while (fixup_now->offset != offset) + { + fixup_now++; + if (fixup_now->size == 0) + break; + } + /* This element is without relaxation relocation. */ + if (fixup_now->size == 0) { - reloc = relocation_table[i].reloc_insn[x][y][0]; - insn = relocation_table[i].reloc_insn[x][y][1]; - nds32_elf_insert_relocation (relocs_temp, reloc, insn, sym); - y++; + pattern_now = pattern_now->next; + continue; } + fixup_size = fixup_now->size; - /* Next instruction. */ - relocs_temp = relocs_temp->next; + /* Insert all fixup. */ + while (fixup_size != 0 && fixup_now->offset == offset) + { + /* Set the real instruction size in element. */ + fixup_size = pattern_now->opcode->isize; + if (fixup_now->ramp & NDS32_FIX) + { + /* Convert original relocation. */ + pattern_now->fixP->fx_r_type = fixup_now->r_type ; + fixup_size = 0; + } + else if ((fixup_now->ramp & NDS32_PTR) != 0) + { + /* This relocation has to point to another instruction. Make + sure each resolved relocation has to be pointed. */ + pattern_temp = relocs_pattern; + /* All instruction in relax_table should be 32-bit. */ + hint_count = hint_info.relax_code_size / 4; + code_insn = CLEAN_REG (*(code_seq + hint_count - 1)); + while (pattern_temp) + { + /* Point to every resolved relocation. */ + if (nds32_match_hint_insn (pattern_temp->opcode, code_insn)) + { + ptr_offset = + pattern_temp->where - pattern_temp->frag->fr_literal; + exp.X_add_symbol = symbol_temp_new (now_seg, ptr_offset, + pattern_temp->frag); + exp.X_add_number = 0; + fixP = + fix_new_exp (fragP, where - fragP->fr_literal, + fixup_size, &exp, 0, fixup_now->r_type); + fixP->fx_addnumber = fixP->fx_offset; + } + pattern_temp = pattern_temp->next; + } + fixup_size = 0; + } + else if (fixup_now->ramp & NDS32_ADDEND) + { + range = nds32_elf_sethi_range (relocs_pattern); + if (range == NDS32_LOADSTORE_NONE) + { + as_bad (_("Internal error: Range error. %s"), now_seg->name); + return; + } + exp.X_add_symbol = abs_section_sym; + exp.X_add_number = SET_ADDEND (4, 0, optimize, enable_16bit); + exp.X_add_number |= ((range & 0x3f) << 8); + } + else if ((fixup_now->ramp & NDS32_ABS) != 0) + { + /* This is a tag relocation. */ + exp.X_add_symbol = abs_section_sym; + exp.X_add_number = 0; + } + else if ((fixup_now->ramp & NDS32_INSN16) != 0) + { + if (!enable_16bit) + fixup_size = 0; + /* This is a tag relocation. */ + exp.X_add_symbol = abs_section_sym; + exp.X_add_number = 0; + } + else if ((fixup_now->ramp & NDS32_SYM) != 0) + { + /* For EMPTY relocation save the true symbol. */ + exp.X_add_symbol = hi_sym; + exp.X_add_number = branch_offset; + } + else + { + exp.X_add_symbol = sym; + exp.X_add_number = branch_offset; + } - /* There are load store instruction shared setting symbol part, so - re-using the final relocation. */ - if (relocation_table[i].reloc_insn[x+1][0][0] != 0) - x++; + if (fixup_size != 0) + { + fixP = fix_new_exp (fragP, where - fragP->fr_literal, + fixup_size, &exp, 0, fixup_now->r_type); + fixP->fx_addnumber = fixP->fx_offset; + } + fixup_now++; + fixup_size = fixup_now->size; + } + if (count < relax_code_size / 4) + count++; + pattern_now = pattern_now->next; } +restore: now_seg = seg_bak; frchain_now = frchain_bak; } @@ -4663,12 +5128,12 @@ md_assemble (char *str) char *out; struct nds32_pseudo_opcode *popcode; const struct nds32_field *fld = NULL; - fixS *fixP ATTRIBUTE_UNUSED; - int insn_type; + fixS *fixP; uint16_t insn_16; - uint32_t insn_32; struct nds32_relocs_pattern *relocs_temp; expressionS *pexp; + fragS *fragP; + int label = label_exist; popcode = nds32_lookup_pseudo_opcode (str); /* Note that we need to check 'verbatim' and @@ -4694,6 +5159,7 @@ md_assemble (char *str) return; } + label_exist = 0; insn.info = (expressionS *) alloca (sizeof (expressionS)); nds32_assemble (&asm_desc, &insn, str); @@ -4728,76 +5194,115 @@ md_assemble (char *str) if (!nds32_check_insn_available (insn, str)) return; - /* Create new frag if the instruction can be relaxed. */ + /* Make sure the begining of text being 2-byte align. */ + nds32_adjust_label (1); fld = insn.field; - if (!verbatim && fld && (insn.attr & NASM_ATTR_BRANCH)) + /* Try to allocate the max size to guarantee relaxable same branch + instructions in the same fragment. */ + frag_grow (NDS32_MAXCHAR); + fragP = frag_now; + if (fld && (insn.attr & NASM_ATTR_BRANCH) + && (pseudo_opcode || (insn.opcode->value != INSN_JAL + && insn.opcode->value != INSN_J)) + && (!verbatim || pseudo_opcode)) { /* User assembly code branch relax for it. */ - fragS *fragp = frag_now; - /* If fld is not NULL, it is a symbol. */ + /* Branch msut relax to proper pattern in user assembly code exclude + J and JAL. Keep these two in original type for users which wants + to keep their size be fixed. In general, assembler does not convert + instruction generated by compiler. But jump instruction may be + truncated in text virtual model. For workaround, compiler generate + pseudo jump to fix this issue currently. */ + /* Get branch range type. */ + dwarf2_emit_insn (0); enum nds32_br_range range_type; - range_type = get_range_type (fld); pexp = insn.info; + range_type = get_range_type (fld); - out = frag_var (rs_machine_dependent, - NDS32_MAXCHAR, + out = frag_var (rs_machine_dependent, NDS32_MAXCHAR, 0, /* VAR is un-used. */ range_type, /* SUBTYPE is used as range type. */ - pexp->X_add_symbol, - pexp->X_add_number, - 0); - /* If the original frag is full, the instruction must save in next - one. */ - while (fragp->fr_next != frag_now) - fragp = fragp->fr_next; - fragp->fr_fix += insn.opcode->isize; - fragp->tc_frag_data.opcode = insn.opcode; - fragp->tc_frag_data.insn = insn.insn; - dwarf2_emit_insn (insn.opcode->isize); + pexp->X_add_symbol, pexp->X_add_number, 0); + + fragP->fr_fix += insn.opcode->isize; + fragP->tc_frag_data.opcode = insn.opcode; + fragP->tc_frag_data.insn = insn.insn; if (insn.opcode->isize == 4) bfd_putb32 (insn.insn, out); else if (insn.opcode->isize == 2) bfd_putb16 (insn.insn, out); + fragP->tc_frag_data.flag |= NDS32_FRAG_BRANCH; return; /* md_convert_frag will insert relocations. */ } - else if (!verbatim && !fld && (optimize || optimize_for_space)) - { - /* User assembly code without relocating convert it to 16bits if needed. */ - insn_32 = insn.insn; + else if (!fld && !relaxing && enable_16bit && (optimize || optimize_for_space) + && ((!verbatim && insn.opcode->isize == 4 + && nds32_convert_32_to_16 (stdoutput, insn.insn, &insn_16, NULL)) + || (insn.opcode->isize == 2 + && nds32_convert_16_to_32 (stdoutput, insn.insn, NULL)))) + { + /* Record this one is relaxable. */ + dwarf2_emit_insn (0); + out = frag_var (rs_machine_dependent, + 4, /* Max size is 32-bit instruction. */ + 0, /* VAR is un-used. */ + 0, NULL, 0, NULL); + fragP->tc_frag_data.flag |= NDS32_FRAG_RELAXABLE; + fragP->tc_frag_data.opcode = insn.opcode; + fragP->tc_frag_data.insn = insn.insn; + fragP->fr_fix += 2; + + /* In original, we don't relax the instrucion with label on it, + but this may cause some redundant nop16. Therefore, tag this + relaxable instruction and relax it carefully. */ + if (label) + fragP->tc_frag_data.flag |= NDS32_FRAG_LABEL; - /* Convert instruction to 16-bits. */ - if (insn.opcode->isize == 4 - && nds32_convert_32_to_16 (stdoutput, insn_32, - &insn_16, &insn_type)) + if (insn.opcode->isize == 4) + bfd_putb16 (insn_16, out); + else if (insn.opcode->isize == 2) + bfd_putb16 (insn.insn, out); + return; + } + else if ((verbatim || !relaxing) && optimize && label) + { + /* This instruction is with label. */ + expressionS exp; + out = frag_var (rs_machine_dependent, insn.opcode->isize, + 0, 0, NULL, 0, NULL); + /* If this insturction is branch target, it is not relaxable. */ + fragP->tc_frag_data.flag = NDS32_FRAG_LABEL; + fragP->tc_frag_data.opcode = insn.opcode; + fragP->tc_frag_data.insn = insn.insn; + fragP->fr_fix += insn.opcode->isize; + if (insn.opcode->isize == 4) { - out = frag_more (2); - frag_var (rs_fill, 0, 0, 0, NULL, 0, NULL); - bfd_putb16 (insn_16, out); - dwarf2_emit_insn (2); - return; + exp.X_op = O_symbol; + exp.X_add_symbol = abs_section_sym; + exp.X_add_number = 0; + fixP = fix_new_exp (fragP, 0, 0, &exp, 0, BFD_RELOC_NDS32_LABEL); } } - - out = frag_more (insn.opcode->isize); + else + out = frag_more (insn.opcode->isize); if (insn.opcode->isize == 4) bfd_putb32 (insn.insn, out); - else if (insn.opcode->isize == 2) + if (insn.opcode->isize == 2) bfd_putb16 (insn.insn, out); dwarf2_emit_insn (insn.opcode->isize); - if (fld) - { - /* Compiler generating code and user assembly pseudo load-store, insert - fixup here. */ - pexp = insn.info; - nds32_elf_record_fixup_exp (str, fld, pexp, out, &insn); - } + /* Compiler generating code and user assembly pseudo load-store, insert + fixup here. */ + pexp = insn.info; + fixP = nds32_elf_record_fixup_exp (fragP, str, fld, pexp, out, &insn); + /* Build relaxation pattern when relaxing is enable. */ + if (relaxing) + nds32_elf_build_relax_relation (fixP, pexp, out, insn.opcode, fragP, fld); } /* md_macro_start */ @@ -4933,10 +5438,17 @@ nds32_elf_get_set_cond (relax_info_t *relax_info, int offset, uint32_t *insn, int i = 0; /* The instruction has conditions. Collect condition values. */ - while (offset == code_seq_cond[i].offset) + while (code_seq_cond[i].bitmask != 0) { - mask = (ori_insn >> cond_fields[i].bitpos) & cond_fields[i].bitmask; - *insn |= (mask & code_seq_cond[i].bitmask) << code_seq_cond[i].bitpos; + if (offset == code_seq_cond[i].offset) + { + mask = (ori_insn >> cond_fields[i].bitpos) & cond_fields[i].bitmask; + /* Sign extend. */ + if (cond_fields[i].signed_extend) + mask = (mask ^ ((cond_fields[i].bitmask + 1) >> 1)) - + ((cond_fields[i].bitmask + 1) >> 1); + *insn |= (mask & code_seq_cond[i].bitmask) << code_seq_cond[i].bitpos; + } i++; } } @@ -4959,8 +5471,6 @@ nds32_relax_branch_instructions (segT segment, fragS *fragP, uint32_t *code_seq; uint32_t insn; int insn_size; - uint16_t insn_16; - int insn_type; int code_seq_offset; /* Replace with gas_assert (fragP->fr_symbol != NULL); */ @@ -5023,18 +5533,6 @@ nds32_relax_branch_instructions (segT segment, fragS *fragP, while (relax_info->relax_fixup[i][k].size !=0 && relax_info->relax_fixup[i][k].offset < code_seq_offset) k++; - if (relax_info->relax_fixup[i][k].size !=0 - && relax_info->relax_fixup[i][k].ramp & NDS32_ORIGIN) - { - /* Set register num to insntruction. */ - nds32_elf_get_set_cond (relax_info, code_seq_offset, &insn, - fragP->tc_frag_data.insn, i); - - /* Try to convert to 16-bits instruction. */ - if (nds32_convert_32_to_16 (stdoutput, - insn, &insn_16, &insn_type)) - diff -= 2; - } } code_seq_offset += insn_size; @@ -5050,6 +5548,89 @@ nds32_relax_branch_instructions (segT segment, fragS *fragP, return diff + adjust; } +/* Adjust relaxable frag till current frag. */ + +static int +nds32_adjust_relaxable_frag (fragS *startP, fragS *fragP) +{ + int adj; + if (startP->tc_frag_data.flag & NDS32_FRAG_RELAXED) + adj = -2; + else + adj = 2; + + startP->tc_frag_data.flag ^= NDS32_FRAG_RELAXED; + + while (startP) + { + startP = startP->fr_next; + if (startP) + { + startP->fr_address += adj; + if (startP == fragP) + break; + } + } + return adj; +} + +static addressT +nds32_get_align (addressT address, int align) +{ + addressT mask, new_address; + + mask = ~((~0) << align); + new_address = (address + mask) & (~mask); + return (new_address - address); +} + +/* Check the prev_frag is legal. */ +static void +invalid_prev_frag (fragS * fragP, fragS **prev_frag) +{ + addressT address; + fragS *frag_start = *prev_frag; + + if (!frag_start) + return; + + if (frag_start->last_fr_address >= fragP->last_fr_address) + { + *prev_frag = NULL; + return; + } + + fragS *frag_t = *prev_frag; + while (frag_t != fragP) + { + if (frag_t->fr_type == rs_align + || frag_t->fr_type == rs_align_code + || frag_t->fr_type == rs_align_test) + { + /* Relax instruction can not walk across lable. */ + if (frag_t->tc_frag_data.flag & NDS32_FRAG_LABEL) + { + prev_frag = NULL; + return; + } + /* Relax previos relaxable to align rs_align frag. */ + address = frag_t->fr_address + frag_t->fr_fix; + addressT offset = nds32_get_align (address, (int) frag_t->fr_offset); + if (offset & 0x2) + { + /* If there is label on the prev_frag, check if it is aligned. */ + if (!((*prev_frag)->tc_frag_data.flag & NDS32_FRAG_LABEL) + || (((*prev_frag)->fr_address + (*prev_frag)->fr_fix - 2 ) + & 0x2) == 0) + nds32_adjust_relaxable_frag (*prev_frag, frag_t); + } + *prev_frag = NULL; + return; + } + frag_t = frag_t->fr_next; + } +} + /* md_relax_frag */ int @@ -5059,9 +5640,21 @@ nds32_relax_frag (segT segment, fragS *fragP, long stretch ATTRIBUTE_UNUSED) 1. relax for branch 2. relax for 32-bits to 16-bits */ - int adjust; + static fragS *prev_frag = NULL; + int adjust = 0; + + invalid_prev_frag (fragP, &prev_frag); - adjust = nds32_relax_branch_instructions (segment, fragP, stretch, 0); + if (fragP->tc_frag_data.flag & NDS32_FRAG_BRANCH) + adjust = nds32_relax_branch_instructions (segment, fragP, stretch, 0); + if (fragP->tc_frag_data.flag & NDS32_FRAG_LABEL) + prev_frag = NULL; + if (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXABLE + && (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXED) == 0) + /* Here is considered relaxed case originally. But it may cause + unendless loop when relaxing. Once the instruction is relaxed, + it can not be undo. */ + prev_frag = fragP; return adjust; } @@ -5083,9 +5676,20 @@ md_estimate_size_before_relax (fragS *fragP, segT segment) 1. relax for branch 2. relax for 32-bits to 16-bits */ - int adjust; + /* Save previos relaxable frag. */ + static fragS *prev_frag = NULL; + int adjust = 0; + + invalid_prev_frag (fragP, &prev_frag); - adjust = nds32_relax_branch_instructions (segment, fragP, 0, 1); + if (fragP->tc_frag_data.flag & NDS32_FRAG_BRANCH) + adjust = nds32_relax_branch_instructions (segment, fragP, 0, 1); + if (fragP->tc_frag_data.flag & NDS32_FRAG_LABEL) + prev_frag = NULL; + if (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXED) + adjust = 2; + else if (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXABLE) + prev_frag = fragP; return adjust; } @@ -5115,26 +5719,21 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragP) char *fr_buffer; int fr_where; int addend ATTRIBUTE_UNUSED; - offsetT branch_target_address; - offsetT branch_insn_address; + offsetT branch_target_address, branch_insn_address; expressionS exp; fixS *fixP; uint32_t *code_seq; - int code_size; uint32_t insn; - int insn_size; - int offset; - int i, j, k; - uint16_t insn_16; - int insn_type; + int code_size, insn_size, offset, fixup_size; int buf_offset; - nds32_relax_fixup_info_t fixup_info[MAX_RELAX_NUM]; + int i, k; + uint16_t insn_16; + nds32_relax_fixup_info_t fixup_info[MAX_RELAX_FIX]; /* Save the 1st instruction is converted to 16 bit or not. */ - bfd_boolean insn_convert = FALSE; - int fixup_size; + unsigned int branch_size; /* Replace with gas_assert (branch_symbol != NULL); */ - if (branch_symbol == NULL) + if (branch_symbol == NULL && !(fragP->tc_frag_data.flag & NDS32_FRAG_RELAXED)) return; /* If frag_var is not enough room, the previos frag is fr_full and with @@ -5142,142 +5741,150 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragP) if (opcode == NULL) return; - relax_info = hash_find (nds32_relax_info_hash, opcode->opcode); - - if (relax_info == NULL) - return; - - backup_endian = target_big_endian; - target_big_endian = 1; - - fr_where = fragP->fr_fix - opcode->isize; - fr_buffer = fragP->fr_literal + fr_where; - - if ((S_GET_SEGMENT (branch_symbol) != sec) - || S_IS_WEAK (branch_symbol)) + /* Relax the insntruction. */ + if (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXED) { - if (fragP->fr_offset & 3) - as_warn (_("Addend to unresolved symbol is not on word boundary.")); - addend = 0; + expressionS exp_t; + if (fragP->tc_frag_data.opcode->isize == 2) + { + insn_16 = fragP->tc_frag_data.insn; + nds32_convert_16_to_32 (stdoutput, insn_16, &insn); + } + else + insn = fragP->tc_frag_data.insn; + fragP->fr_fix += 2; + fr_where = fragP->fr_fix - 4; + fr_buffer = fragP->fr_literal + fr_where; + exp_t.X_op = O_symbol; + exp_t.X_add_symbol = abs_section_sym; + exp_t.X_add_number = 0; + fix_new_exp (fragP, fr_where, 4, &exp_t, 0, + BFD_RELOC_NDS32_INSN16); + number_to_chars_bigendian (fr_buffer, insn, 4); } else { - /* Calculate symbol-to-instruction offset. */ - branch_target_address = S_GET_VALUE (branch_symbol) + branch_offset; - branch_insn_address = fragP->fr_address + fr_where; - addend = (branch_target_address - branch_insn_address) >> 1; - } + /* Branch instruction adjust and append relocations. */ + relax_info = hash_find (nds32_relax_info_hash, opcode->opcode); + + if (relax_info == NULL) + return; - code_size = relax_info->relax_code_size[branch_range_type]; - code_seq = relax_info->relax_code_seq[branch_range_type]; + backup_endian = target_big_endian; + target_big_endian = 1; - memcpy (fixup_info, - relax_info->relax_fixup[branch_range_type], - sizeof (fixup_info)); + fr_where = fragP->fr_fix - opcode->isize; + fr_buffer = fragP->fr_literal + fr_where; - /* Fill in frag. */ - i = 0; - k = 0; - offset = 0; /* code_seq offset */ - buf_offset = 0; /* fr_buffer offset */ - while (offset < code_size) - { - insn = code_seq[i]; - if (insn & 0x80000000) /* 16-bits instruction. */ + if ((S_GET_SEGMENT (branch_symbol) != sec) + || S_IS_WEAK (branch_symbol)) { - insn = (insn >> 16) & 0xFFFF; - insn_size = 2; + if (fragP->fr_offset & 3) + as_warn (_("Addend to unresolved symbol is not on word boundary.")); + addend = 0; } - else /* 32-bits instruction. */ + else { - insn_size = 4; + /* Calculate symbol-to-instruction offset. */ + branch_target_address = S_GET_VALUE (branch_symbol) + branch_offset; + branch_insn_address = fragP->fr_address + fr_where; + addend = (branch_target_address - branch_insn_address) >> 1; } - nds32_elf_get_set_cond (relax_info, offset, &insn, - origin_insn, branch_range_type); + code_size = relax_info->relax_code_size[branch_range_type]; + code_seq = relax_info->relax_code_seq[branch_range_type]; - /* Try to convert to 16-bits instruction. Currently, only the first - insntruction in pattern can be converted. EX: bnez sethi ori jr, - only bnez can be converted to 16 bit and ori can't. */ + memcpy (fixup_info, relax_info->relax_fixup[branch_range_type], + sizeof (fixup_info)); - while (fixup_info[k].size != 0 - && relax_info->relax_fixup[branch_range_type][k].offset < offset) - k++; - if ((fixup_info[k].size != 0 - && fixup_info[k].ramp & NDS32_ORIGIN) - && nds32_convert_32_to_16 (stdoutput, insn, &insn_16, &insn_type)) + /* Fill in frag. */ + i = 0; + k = 0; + offset = 0; /* code_seq offset */ + buf_offset = 0; /* fr_buffer offset */ + while (offset < code_size) { - /* Reduce to 16-bits instructions, adjust fixup_info[j]->offset. */ - for (j = 0; fixup_info[j].size != 0; j++) + insn = code_seq[i]; + if (insn & 0x80000000) /* 16-bits instruction. */ { - if (fixup_info[j].ramp & NDS32_RELAX) - fixup_info[j].size -= 2; - - if (fixup_info[j].offset > buf_offset) - fixup_info[j].offset -= 2; + insn = (insn >> 16) & 0xFFFF; + insn_size = 2; + } + else /* 32-bits instruction. */ + { + insn_size = 4; } - md_number_to_chars (fr_buffer + buf_offset, insn_16, 2); - buf_offset += 2; - if (offset == 0) - insn_convert = TRUE; - } - else - { - md_number_to_chars (fr_buffer + buf_offset, insn, insn_size); - buf_offset += insn_size; - } + nds32_elf_get_set_cond (relax_info, offset, &insn, + origin_insn, branch_range_type); - offset += insn_size; - i++; - } - - /* Set up fixup. */ - exp.X_op = O_symbol; + /* Try to convert to 16-bits instruction. Currently, only the first + insntruction in pattern can be converted. EX: bnez sethi ori jr, + only bnez can be converted to 16 bit and ori can't. */ - for (i = 0; fixup_info[i].size != 0; i++) - { - fixup_size = fixup_info[i].size; + while (fixup_info[k].size != 0 + && relax_info->relax_fixup[branch_range_type][k].offset < offset) + k++; - if (((fixup_info[i].ramp & NDS32_ORIGIN) && insn_convert == TRUE) - ||((fixup_info[i].ramp & NDS32_CONVERT) && insn_convert == FALSE)) - continue; + md_number_to_chars (fr_buffer + buf_offset, insn, insn_size); + buf_offset += insn_size; - if ((fixup_info[i].ramp & NDS32_CREATE_LABLE) != 0) - { - /* This is a reverse branch. */ - exp.X_add_symbol = symbol_temp_new (sec, 0, fragP->fr_next); - exp.X_add_number = 0; - } - else if ((fixup_info[i].ramp & NDS32_RELAX) != 0) - { - /* This is a relax relocation. */ - exp.X_add_symbol = abs_section_sym; - exp.X_add_number = - SET_ADDEND (fixup_size /* size */ , - insn_convert , optimize, enable_16bit); - } - else - { - exp.X_add_symbol = branch_symbol; - exp.X_add_number = branch_offset; + offset += insn_size; + i++; } - if (fixup_info[i].r_type != 0) + /* Set up fixup. */ + exp.X_op = O_symbol; + + for (i = 0; fixup_info[i].size != 0; i++) { - fixP = fix_new_exp (fragP, - fr_where + fixup_info[i].offset, - fixup_size, - &exp, - 0, - fixup_info[i].r_type); - fixP->fx_addnumber = fixP->fx_offset; + fixup_size = fixup_info[i].size; + + if ((fixup_info[i].ramp & NDS32_CREATE_LABEL) != 0) + { + /* This is a reverse branch. */ + exp.X_add_symbol = symbol_temp_new (sec, 0, fragP->fr_next); + exp.X_add_number = 0; + } + else if ((fixup_info[i].ramp & NDS32_PTR) != 0) + { + /* This relocation has to point to another instruction. */ + branch_size = fr_where + code_size - 4; + exp.X_add_symbol = symbol_temp_new (sec, branch_size, fragP); + exp.X_add_number = 0; + } + else if ((fixup_info[i].ramp & NDS32_ABS) != 0) + { + /* This is a tag relocation. */ + exp.X_add_symbol = abs_section_sym; + exp.X_add_number = 0; + } + else if ((fixup_info[i].ramp & NDS32_INSN16) != 0) + { + if (!enable_16bit) + continue; + /* This is a tag relocation. */ + exp.X_add_symbol = abs_section_sym; + exp.X_add_number = 0; + } + else + { + exp.X_add_symbol = branch_symbol; + exp.X_add_number = branch_offset; + } + + if (fixup_info[i].r_type != 0) + { + fixP = fix_new_exp (fragP, fr_where + fixup_info[i].offset, + fixup_size, &exp, 0, fixup_info[i].r_type); + fixP->fx_addnumber = fixP->fx_offset; + } } - } - fragP->fr_fix = fr_where + buf_offset; + fragP->fr_fix = fr_where + buf_offset; - target_big_endian = backup_endian; + target_big_endian = backup_endian; + } } /* tc_frob_file_before_fix */ @@ -5287,15 +5894,62 @@ nds32_frob_file_before_fix (void) { } -/* TC_FORCE_RELOCATION */ - -int -nds32_force_relocation (fixS *fix ATTRIBUTE_UNUSED) +static bfd_boolean +nds32_relaxable_section (asection *sec) { - /* Always force relocation, because linker may adjust the code. */ - return 1; + return ((sec->flags & SEC_DEBUGGING) == 0 + && strcmp (sec->name, ".eh_frame") != 0); } +/* TC_FORCE_RELOCATION */ +int +nds32_force_relocation (fixS * fix) +{ + switch (fix->fx_r_type) + { + case BFD_RELOC_NDS32_INSN16: + case BFD_RELOC_NDS32_LABEL: + case BFD_RELOC_NDS32_LONGCALL1: + case BFD_RELOC_NDS32_LONGCALL2: + case BFD_RELOC_NDS32_LONGCALL3: + case BFD_RELOC_NDS32_LONGJUMP1: + case BFD_RELOC_NDS32_LONGJUMP2: + case BFD_RELOC_NDS32_LONGJUMP3: + case BFD_RELOC_NDS32_LOADSTORE: + case BFD_RELOC_NDS32_9_FIXED: + case BFD_RELOC_NDS32_15_FIXED: + case BFD_RELOC_NDS32_17_FIXED: + case BFD_RELOC_NDS32_25_FIXED: + case BFD_RELOC_NDS32_9_PCREL: + case BFD_RELOC_NDS32_15_PCREL: + case BFD_RELOC_NDS32_17_PCREL: + case BFD_RELOC_NDS32_WORD_9_PCREL: + case BFD_RELOC_NDS32_10_UPCREL: + case BFD_RELOC_NDS32_25_PCREL: + case BFD_RELOC_NDS32_MINUEND: + case BFD_RELOC_NDS32_SUBTRAHEND: + return 1; + + case BFD_RELOC_8: + case BFD_RELOC_16: + case BFD_RELOC_32: + case BFD_RELOC_NDS32_DIFF_ULEB128: + /* Linker should handle difference between two symbol. */ + return fix->fx_subsy != NULL + && nds32_relaxable_section (S_GET_SEGMENT (fix->fx_addsy)); + case BFD_RELOC_64: + if (fix->fx_subsy) + as_bad ("Double word for difference between two symbols " + "is not supported across relaxation."); + default: + ; + } + + if (generic_force_reloc (fix)) + return 1; + + return fix->fx_pcrel; +} /* TC_VALIDATE_FIX_SUB */ @@ -5446,7 +6100,7 @@ nds32_insert_relax_entry (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, fixS *fixp; seginfo = seg_info (sec); - if (!seginfo || !symbol_rootP || !subseg_text_p (sec)) + if (!seginfo || !symbol_rootP || !subseg_text_p (sec) || sec->size == 0) return; /* If there is no relocation and relax is disabled, it is not necessary to insert R_NDS32_RELAX_ENTRY for linker do EX9 or IFC optimization. */ @@ -5547,8 +6201,8 @@ nds32_set_section_relocs (asection *sec, arelent ** relocs ATTRIBUTE_UNUSED, { bfd *abfd ATTRIBUTE_UNUSED = sec->owner; if (bfd_get_section_flags (abfd, sec) & (flagword) SEC_RELOC) - nds32_insertion_sort (sec->orelocation, sec->reloc_count, sizeof (arelent**), - compar_relent); + nds32_insertion_sort (sec->orelocation, sec->reloc_count, + sizeof (arelent**), compar_relent); } long @@ -5573,8 +6227,6 @@ nds32_post_relax_hook (void) bfd_map_over_sections (stdoutput, nds32_insert_relax_entry, NULL); } - - /* tc_fix_adjustable () Return whether this symbol (fixup) can be replaced with @@ -5596,6 +6248,13 @@ nds32_fix_adjustable (fixS *fixP) case BFD_RELOC_16: case BFD_RELOC_32: case BFD_RELOC_NDS32_PTR: + case BFD_RELOC_NDS32_LONGCALL4: + case BFD_RELOC_NDS32_LONGCALL5: + case BFD_RELOC_NDS32_LONGCALL6: + case BFD_RELOC_NDS32_LONGJUMP4: + case BFD_RELOC_NDS32_LONGJUMP5: + case BFD_RELOC_NDS32_LONGJUMP6: + case BFD_RELOC_NDS32_LONGJUMP7: return 1; default: return 0; @@ -5607,13 +6266,14 @@ nds32_fix_adjustable (fixS *fixP) void elf_nds32_final_processing (void) { - /* An FPU_COM instruction is found without previous non-FPU_COM instruction. */ + /* An FPU_COM instruction is found without previous non-FPU_COM + instruction. */ if (nds32_fpu_com && !(nds32_elf_flags & (E_NDS32_HAS_FPU_INST | E_NDS32_HAS_FPU_DP_INST))) { /* Since only FPU_COM instructions are used and no other FPU instructions - are used. The nds32_elf_flags will be decided by the enabled options by - command line or default configuration. */ + are used. The nds32_elf_flags will be decided by the enabled options + by command line or default configuration. */ if (nds32_fpu_dp_ext || nds32_fpu_sp_ext) { nds32_elf_flags |= nds32_fpu_dp_ext ? E_NDS32_HAS_FPU_DP_INST : 0; @@ -5658,21 +6318,37 @@ nds32_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) && fixP->fx_r_type > BFD_RELOC_NONE && fixP->fx_r_type != BFD_RELOC_NDS32_DIFF_ULEB128) { - /* FIXME: This implementation is partially borrowed from our old - nds32 binutils. Its purpose is to leave original bfd - relocation untouched, while other relocation created by CGEN - will be converted into general bfd relocations. - However, since we no longer use CGEN, we can simply use - a little piece of code to deal with general bfd relocation, - especially for the BFD_RELOC_NDS32_DATA, which is just used - as a marker for different purpose. - It is believed that we can construct a better mechanism to - deal with the whole relocation issue in nds32 target - without using CGEN. */ + /* In our old nds32 binutils, it must convert relocations which is + generated by CGEN. However, it does not have to consider this anymore. + In current, it only deal with data relocations which enum + is smaller than BFD_RELOC_NONE and BFD_RELOC_NDS32_DIFF_ULEB128. + It is believed that we can construct a better mechanism to + deal with the whole relocation issue in nds32 target + without using CGEN. */ fixP->fx_addnumber = value; fixP->tc_fix_data = NULL; - if (fixP->fx_r_type == BFD_RELOC_NDS32_DATA) - fixP->fx_done = 1; + + /* Tranform specific relocations here for later relocation generation. + Tag data here for ex9 relaxtion and tag tls data for linker. */ + switch (fixP->fx_r_type) + { + case BFD_RELOC_NDS32_DATA: + if (!enable_relax_ex9) + fixP->fx_done = 1; + break; + case BFD_RELOC_NDS32_TPOFF: + case BFD_RELOC_NDS32_TLS_LE_HI20: + case BFD_RELOC_NDS32_TLS_LE_LO12: + case BFD_RELOC_NDS32_TLS_LE_ADD: + case BFD_RELOC_NDS32_TLS_LE_LS: + case BFD_RELOC_NDS32_GOTTPOFF: + case BFD_RELOC_NDS32_TLS_IE_HI20: + case BFD_RELOC_NDS32_TLS_IE_LO12S2: + S_SET_THREAD_LOCAL (fixP->fx_addsy); + break; + default: + break; + } return; } @@ -5772,7 +6448,8 @@ nds32_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) /* cvt_frag_to_fill () has called output_leb128 () for us. */ break; default: - as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex")); + as_bad_where (fixP->fx_file, fixP->fx_line, + _("expression too complex")); return; } } @@ -5796,7 +6473,8 @@ nds32_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) default: as_bad_where (fixP->fx_file, fixP->fx_line, _("Internal error: Unknown fixup type %d (`%s')"), - fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type)); + fixP->fx_r_type, + bfd_get_reloc_code_name (fixP->fx_r_type)); break; } } @@ -5847,6 +6525,15 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP) return reloc; } +struct suffix_name suffix_table[] = +{ + {"GOTOFF", BFD_RELOC_NDS32_GOTOFF, 1}, + {"GOT", BFD_RELOC_NDS32_GOT20, 1}, + {"TPOFF", BFD_RELOC_NDS32_TPOFF, 0}, + {"PLT", BFD_RELOC_NDS32_25_PLTREL, 1}, + {"GOTTPOFF", BFD_RELOC_NDS32_GOTTPOFF, 0} +}; + /* Implement md_parse_name. */ int @@ -5854,35 +6541,32 @@ nds32_parse_name (char const *name, expressionS *exprP, enum expr_mode mode ATTRIBUTE_UNUSED, char *nextcharP ATTRIBUTE_UNUSED) { - char *suffix_table[] = { "GOTOFF", "GOT", "PLT" }; - short unsigned int reloc_table [] = - { - BFD_RELOC_NDS32_GOTOFF, BFD_RELOC_NDS32_GOT20, - BFD_RELOC_NDS32_25_PLTREL - }; - segT segment; - exprP->X_op_symbol = NULL; exprP->X_md = BFD_RELOC_UNUSED; exprP->X_add_symbol = symbol_find_or_make (name); + exprP->X_op = O_symbol; + exprP->X_add_number = 0; - segment = S_GET_SEGMENT (exprP->X_add_symbol); - if (segment != undefined_section) - return 0; - - if (*nextcharP == '@') + if (strcmp (name, GOT_NAME) == 0 && *nextcharP != '@') + { + /* Set for _GOT_OFFSET_TABLE_. */ + exprP->X_md = BFD_RELOC_NDS32_GOTPC20; + } + else if (*nextcharP == '@') { size_t i; char *next; for (i = 0; i < ARRAY_SIZE (suffix_table); i++) { - next = input_line_pointer + 1 + strlen (suffix_table[i]); - if (strncasecmp (input_line_pointer + 1, suffix_table[i], - strlen (suffix_table[i])) == 0 + next = input_line_pointer + 1 + strlen(suffix_table[i].suffix); + if (strncasecmp (input_line_pointer + 1, suffix_table[i].suffix, + strlen (suffix_table[i].suffix)) == 0 && !is_part_of_name (*next)) { - exprP->X_md = reloc_table[i]; + if (!nds32_pic && suffix_table[i].pic) + as_bad (_("need PIC qualifier with symbol.")); + exprP->X_md = suffix_table[i].reloc; *input_line_pointer = *nextcharP; input_line_pointer = next; *nextcharP = *input_line_pointer; @@ -5891,10 +6575,6 @@ nds32_parse_name (char const *name, expressionS *exprP, } } } - - exprP->X_op = O_symbol; - exprP->X_add_number = 0; - return 1; } @@ -5903,18 +6583,18 @@ nds32_parse_name (char const *name, expressionS *exprP, int tc_nds32_regname_to_dw2regnum (char *regname) { - symbolS *sym = symbol_find (regname); + struct nds32_keyword *sym = hash_find (nds32_gprs_hash, regname); + + if (!sym) + return -1; - if (S_GET_SEGMENT (sym) == reg_section - && sym->sy_value.X_add_number < 32) - return sym->sy_value.X_add_number; - return -1; + return sym->value; } void tc_nds32_frame_initial_instructions (void) { /* CIE */ - /* Default cfa is register-28/sp. */ + /* Default cfa is register-31/sp. */ cfi_add_CFA_def_cfa (31, 0); } diff --git a/gas/config/tc-nds32.h b/gas/config/tc-nds32.h index 731bb871d7d..1483d51f9d8 100644 --- a/gas/config/tc-nds32.h +++ b/gas/config/tc-nds32.h @@ -42,10 +42,6 @@ #define TARGET_BYTES_BIG_ENDIAN 1 #endif -/* This is used to construct expressions out of @GOTOFF, @PLT and @GOT - symbols. The relocation type is stored in X_md. */ -#define O_PIC_reloc O_md1 - /* as.c. */ /* Extend GAS command line option handling capability. */ extern int nds32_parse_option (int, char *); @@ -154,6 +150,12 @@ extern void nds32_do_align (int); #define LOCAL_LABELS_FB 1 /* Permit temporary numeric labels. */ /* frags.c. */ + +#define NDS32_FRAG_RELAXABLE 0x1 +#define NDS32_FRAG_RELAXED 0x2 +#define NDS32_FRAG_BRANCH 0x4 +#define NDS32_FRAG_LABEL 0x8 + struct nds32_frag_type { relax_substateT flag; @@ -211,10 +213,16 @@ enum nds32_br_range enum nds32_ramp { - NDS32_CREATE_LABLE = 1, - NDS32_RELAX = 2, - NDS32_ORIGIN = 4, - NDS32_CONVERT = 8 + NDS32_CREATE_LABEL = 1, + NDS32_RELAX = (1 << 1), /* Obsolete in the future. */ + NDS32_ORIGIN = (1 << 2), + NDS32_INSN16 = (1 << 3), + NDS32_PTR = (1 << 4), + NDS32_ABS = (1 << 5), + NDS32_HINT = (1 << 6), + NDS32_FIX = (1 << 7), + NDS32_ADDEND = (1 << 8), + NDS32_SYM = (1 << 9) }; typedef struct nds32_relax_fixup_info @@ -231,13 +239,15 @@ typedef struct nds32_cond_field int offset; int bitpos; /* Register position. */ int bitmask; /* Number of register bits. */ + bfd_boolean signed_extend; } nds32_cond_field_t; /* The max relaxation pattern is 20-bytes including the nop. */ #define NDS32_MAXCHAR 20 /* In current, the max entend number of instruction for one pseudo instruction - is 4, but its number of relocation may be 5. */ -#define MAX_RELAX_NUM 8 + is 4, but its number of relocation may be 12. */ +#define MAX_RELAX_NUM 4 +#define MAX_RELAX_FIX 12 typedef struct nds32_relax_info { @@ -248,17 +258,24 @@ typedef struct nds32_relax_info /* Code sequences for different branch range. */ uint32_t relax_code_seq[BR_RANGE_NUM][MAX_RELAX_NUM]; nds32_cond_field_t relax_code_condition[BR_RANGE_NUM][MAX_RELAX_NUM]; - int relax_code_size[BR_RANGE_NUM]; + unsigned int relax_code_size[BR_RANGE_NUM]; int relax_branch_isize[BR_RANGE_NUM]; - nds32_relax_fixup_info_t relax_fixup[BR_RANGE_NUM][MAX_RELAX_NUM]; + nds32_relax_fixup_info_t relax_fixup[BR_RANGE_NUM][MAX_RELAX_FIX]; } relax_info_t; -/* Relocation table. */ -struct nds32_relocation_map +enum nds32_relax_hint_type +{ + NDS32_RELAX_HINT_NONE = 0, + NDS32_RELAX_HINT_LA, + NDS32_RELAX_HINT_LS +}; + +struct nds32_relax_hint_table { - unsigned int main_type; - /* Number of instructions, {relocations type, instruction type}. */ - unsigned int reloc_insn[6][6][3]; + enum nds32_relax_hint_type main_type; + unsigned int relax_code_size; + uint32_t relax_code_seq[MAX_RELAX_NUM]; + nds32_relax_fixup_info_t relax_fixup[MAX_RELAX_FIX]; }; #endif /* TC_NDS32 */ diff --git a/include/elf/ChangeLog b/include/elf/ChangeLog index ab0a5425483..dd9bd9b5d1a 100644 --- a/include/elf/ChangeLog +++ b/include/elf/ChangeLog @@ -1,3 +1,7 @@ +2014-09-16 Kuan-Lin Chen + + * nds32.h: Declare new relocations. + 2014-09-15 Andrew Bennett Matthew Fortune diff --git a/include/elf/nds32.h b/include/elf/nds32.h index 216bbc1cbbd..71aa4aa4149 100644 --- a/include/elf/nds32.h +++ b/include/elf/nds32.h @@ -76,7 +76,6 @@ START_RELOC_NUMBERS (elf_nds32_reloc_type) RELOC_NUMBER (R_NDS32_GOTOFF, 43) RELOC_NUMBER (R_NDS32_GOTPC20, 44) RELOC_NUMBER (R_NDS32_GOT_HI20, 45) - RELOC_NUMBER (R_NDS32_GOT_LO12, 46) RELOC_NUMBER (R_NDS32_GOTPC_HI20, 47) RELOC_NUMBER (R_NDS32_GOTPC_LO12, 48) @@ -95,8 +94,8 @@ START_RELOC_NUMBERS (elf_nds32_reloc_type) RELOC_NUMBER (R_NDS32_15_FIXED_RELA, 61) RELOC_NUMBER (R_NDS32_17_FIXED_RELA, 62) RELOC_NUMBER (R_NDS32_25_FIXED_RELA, 63) - RELOC_NUMBER (R_NDS32_PLTREL_HI20, 64) - RELOC_NUMBER (R_NDS32_PLTREL_LO12, 65) + RELOC_NUMBER (R_NDS32_PLTREL_HI20, 64) /* This is obsoleted. */ + RELOC_NUMBER (R_NDS32_PLTREL_LO12, 65) /* This is obsoleted. */ RELOC_NUMBER (R_NDS32_PLT_GOTREL_HI20, 66) RELOC_NUMBER (R_NDS32_PLT_GOTREL_LO12, 67) RELOC_NUMBER (R_NDS32_SDA12S2_DP_RELA, 68) @@ -123,22 +122,38 @@ START_RELOC_NUMBERS (elf_nds32_reloc_type) RELOC_NUMBER (R_NDS32_GOT15S2_RELA, 89) RELOC_NUMBER (R_NDS32_GOT17S2_RELA, 90) RELOC_NUMBER (R_NDS32_5_RELA, 91) - RELOC_NUMBER (R_NDS32_10_UPCREL_RELA, 92) + RELOC_NUMBER (R_NDS32_10_UPCREL_RELA, 92) /* This is obsoleted. */ RELOC_NUMBER (R_NDS32_SDA_FP7U2_RELA, 93) RELOC_NUMBER (R_NDS32_WORD_9_PCREL_RELA, 94) RELOC_NUMBER (R_NDS32_25_ABS_RELA, 95) RELOC_NUMBER (R_NDS32_17IFC_PCREL_RELA, 96) RELOC_NUMBER (R_NDS32_10IFCU_PCREL_RELA, 97) + RELOC_NUMBER (R_NDS32_TLS_LE_HI20, 98) + RELOC_NUMBER (R_NDS32_TLS_LE_LO12, 99) + RELOC_NUMBER (R_NDS32_TLS_IE_HI20, 100) + RELOC_NUMBER (R_NDS32_TLS_IE_LO12S2, 101) + RELOC_NUMBER (R_NDS32_TLS_TPOFF, 102) + RELOC_NUMBER (R_NDS32_TLS_LE_20, 103) + RELOC_NUMBER (R_NDS32_TLS_LE_15S0, 104) + RELOC_NUMBER (R_NDS32_TLS_LE_15S1, 105) + RELOC_NUMBER (R_NDS32_TLS_LE_15S2, 106) + RELOC_NUMBER (R_NDS32_LONGCALL4, 107) + RELOC_NUMBER (R_NDS32_LONGCALL5, 108) + RELOC_NUMBER (R_NDS32_LONGCALL6, 109) + RELOC_NUMBER (R_NDS32_LONGJUMP4, 110) + RELOC_NUMBER (R_NDS32_LONGJUMP5, 111) + RELOC_NUMBER (R_NDS32_LONGJUMP6, 112) + RELOC_NUMBER (R_NDS32_LONGJUMP7, 113) RELOC_NUMBER (R_NDS32_RELAX_ENTRY, 192) RELOC_NUMBER (R_NDS32_GOT_SUFF, 193) RELOC_NUMBER (R_NDS32_GOTOFF_SUFF, 194) RELOC_NUMBER (R_NDS32_PLT_GOT_SUFF, 195) - RELOC_NUMBER (R_NDS32_MULCALL_SUFF, 196) + RELOC_NUMBER (R_NDS32_MULCALL_SUFF, 196) /* This is obsoleted. */ RELOC_NUMBER (R_NDS32_PTR, 197) RELOC_NUMBER (R_NDS32_PTR_COUNT, 198) RELOC_NUMBER (R_NDS32_PTR_RESOLVED, 199) - RELOC_NUMBER (R_NDS32_PLTBLOCK, 200) + RELOC_NUMBER (R_NDS32_PLTBLOCK, 200) /* This is obsoleted. */ RELOC_NUMBER (R_NDS32_RELAX_REGION_BEGIN, 201) RELOC_NUMBER (R_NDS32_RELAX_REGION_END, 202) RELOC_NUMBER (R_NDS32_MINUEND, 203) @@ -149,7 +164,9 @@ START_RELOC_NUMBERS (elf_nds32_reloc_type) RELOC_NUMBER (R_NDS32_DIFF_ULEB128, 208) RELOC_NUMBER (R_NDS32_DATA, 209) RELOC_NUMBER (R_NDS32_TRAN, 210) - RELOC_NUMBER (R_NDS32_FPBASE, 211) + RELOC_NUMBER (R_NDS32_TLS_LE_ADD, 211) + RELOC_NUMBER (R_NDS32_TLS_LE_LS, 212) + RELOC_NUMBER (R_NDS32_EMPTY, 213) END_RELOC_NUMBERS (R_NDS32_max) diff --git a/ld/ChangeLog b/ld/ChangeLog index d50a4562806..ca27cc25470 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,10 @@ +2014-09-16 Kuan-Lin Chen + + * emultempl/nds32elf.em (nds32_elf_after_open): Do not keep + ex9 234th entry. + (nds32_elf_after_allocation): Move all optimizations into + nds32_elf_relax_section. + 2014-09-15 Andrew Bennett Matthew Fortune diff --git a/ld/emultempl/nds32elf.em b/ld/emultempl/nds32elf.em index cad67158ddc..592471e7028 100644 --- a/ld/emultempl/nds32elf.em +++ b/ld/emultempl/nds32elf.em @@ -52,7 +52,8 @@ nds32_elf_create_output_section_statements (void) if (strstr (bfd_get_target (link_info.output_bfd), "nds32") == NULL) { /* Check the output target is nds32. */ - einfo ("%F%X%P: error: Cannot change output format whilst linking NDS32 binaries.\n"); + einfo ("%F%X%P: error: Cannot change output format whilst " + "linking NDS32 binaries.\n"); return; } @@ -124,8 +125,9 @@ nds32_elf_after_open (void) einfo (_("%F%B: ABI version of object files mismatched\n"), abfd); } +#if defined NDS32_EX9_EXT /* Append .ex9.itable section in the last input object file. */ - if (!link_info.relocatable && abfd->link.next == NULL) + if (abfd->link_next == NULL && (target_optimize & NDS32_RELAX_EX9_ON)) { asection *itable; struct bfd_link_hash_entry *h; @@ -137,17 +139,8 @@ nds32_elf_after_open (void) { itable->gc_mark = 1; itable->alignment_power = 2; - if ((target_optimize & NDS32_RELAX_EX9_ON)) - { - itable->size = 0x1000; - itable->contents = bfd_zalloc (abfd, itable->size); - } - else - { - itable->size = 0x4; - itable->contents = bfd_zalloc (abfd, itable->size); - bfd_putb32 (INSN_BREAK_EA,itable->contents); - } + itable->size = 0x1000; + itable->contents = bfd_zalloc (abfd, itable->size); /* Add a symbol in the head of ex9.itable to objdump clearly. */ h = bfd_link_hash_lookup (link_info.hash, "_EX9_BASE_", @@ -158,6 +151,7 @@ nds32_elf_after_open (void) get_elf_backend_data (link_info.output_bfd)->collect, &h); } } +#endif } /* Check object files if the target is dynamic linked executable @@ -173,12 +167,14 @@ nds32_elf_after_open (void) if (link_info.shared || link_info.pie) { /* For PIE or shared object, all input must be PIC. */ - einfo (_("%B: must use -fpic to compile this file for shared object or PIE\n"), abfd); + einfo (_("%B: must use -fpic to compile this file " + "for shared object or PIE\n"), abfd); } else { /* Dynamic linked executable with SDA and non-PIC. Turn off load/store relaxtion. */ + /* TODO: This may support in the future. */ load_store_relax = 0 ; relax_fp_as_gp = 0; } @@ -192,108 +188,22 @@ nds32_elf_after_open (void) gld${EMULATION_NAME}_after_open (); } -static void nds32_elf_relax_stub (bfd_boolean relax) -{ - /* Re-caculate memory map address. */ - lang_do_assignments (lang_assigning_phase_enum); - lang_reset_memory_regions (); - one_lang_size_sections_pass (&relax, FALSE); -} - static void nds32_elf_after_allocation (void) { - struct elf_nds32_link_hash_table *table; - table = nds32_elf_hash_table (&link_info); + if (target_optimize & NDS32_RELAX_EX9_ON + || (ex9_import_file != NULL && update_ex9_table == 1)) + { + /* Initialize ex9 hash table. */ + if (!nds32_elf_ex9_init ()) + return; + } /* Call default after allocation callback. 1. This is where relaxation is done. 2. It calls gld${EMULATION_NAME}_map_segments to build ELF segment table. 3. Any relaxation requires relax being done must be called after it. */ gld${EMULATION_NAME}_after_allocation (); - - if (!table) - return; - - /* Use IFC */ - if ((target_optimize & NDS32_RELAX_JUMP_IFC_ON) - && !(table->relax_status & NDS32_RELAX_JUMP_IFC_DONE)) - { - table->relax_round = NDS32_RELAX_JUMP_IFC_ROUND; - /* Traverse all sections to build j and jal list. */ - nds32_elf_relax_stub (TRUE); - - /* Replace with ifc. */ - if (!nds32_elf_ifc_finish (&link_info)) - einfo (_("%F: Please report this bug. IFC error.\n")); - table->relax_round = NDS32_RELAX_NONE_ROUND; - - /* Adjust address after ifcall. */ - nds32_elf_relax_stub (FALSE); - - if (!nds32_elf_ifc_reloc ()) - einfo (_("%F: Please report this bug. IFC error.\n")); - } - - /* EX9 Instruction Table Relaxation. */ - if (!link_info.relocatable && !nds32_elf_ex9_itb_base (&link_info)) - einfo (_("%F: Please report this bug. Ex9 relocation error.\n")); - - - /* Generate ex9 table. */ - if ((target_optimize & NDS32_RELAX_EX9_ON) - && !(table->relax_status & NDS32_RELAX_EX9_DONE)) - { - /* Ex9 entry point. */ - table->relax_round = NDS32_RELAX_EX9_BUILD_ROUND; - - /* Initialize ex9 hash table. */ - if (!nds32_elf_ex9_init ()) - return; - - /* Build ex9 instruction table. */ - nds32_elf_relax_stub (TRUE); - nds32_elf_ex9_finish (&link_info); - /* Replace with ex9.it. */ - nds32_elf_relax_stub (TRUE); - table->relax_round = NDS32_RELAX_NONE_ROUND; - - /* Do ifc again. */ - if (target_optimize & NDS32_RELAX_JUMP_IFC_ON) - if (!nds32_elf_ifc_finish (&link_info)) - einfo (_("%F: Please report this bug. IFC error.\n")); - - /* Re-caculate memory map address. */ - lang_do_assignments (lang_assigning_phase_enum); - /* Relocation for .ex9.itable. */ - nds32_elf_ex9_reloc_jmp (&link_info); - } - else if (ex9_import_file != NULL - && !(table->relax_status = NDS32_RELAX_EX9_DONE)) - { - /* Import ex9 table. */ - - if (update_ex9_table == 1) - { - /* Build ex9 table. */ - table->relax_round = NDS32_RELAX_EX9_BUILD_ROUND; - /* Initialize ex9 hash table. */ - if (!nds32_elf_ex9_init ()) - return; - /* Build ex9 table. */ - nds32_elf_relax_stub (TRUE); - - /* Relocation for .ex9.itable. */ - lang_do_assignments (lang_assigning_phase_enum); - nds32_elf_ex9_reloc_jmp (&link_info); - } - nds32_elf_ex9_import_table (&link_info); - - /* Replace with ex9.it. */ - table->relax_round = NDS32_RELAX_EX9_REPLACE_ROUND; - table->relax_status |= NDS32_RELAX_EX9_DONE; - nds32_elf_relax_stub (TRUE); - } } EOF @@ -332,7 +242,7 @@ PARSE_AND_LIST_PROLOGUE=' PARSE_AND_LIST_LONGOPTS=' { "mfp-as-gp", no_argument, NULL, OPTION_FP_AS_GP}, { "mno-fp-as-gp", no_argument, NULL, OPTION_NO_FP_AS_GP}, - { "mgen-symbol-ld-script", required_argument, NULL, OPTION_EXPORT_SYMBOLS}, + { "mexport-symbols", required_argument, NULL, OPTION_EXPORT_SYMBOLS}, /* These are deprecated options. Remove them in the future. */ { "mrelax-reduce-fp-update", no_argument, NULL, OPTION_REDUCE_FP_UPDATE}, { "mrelax-no-reduce-fp-update", no_argument, NULL, OPTION_NO_REDUCE_FP_UPDATE}, @@ -399,7 +309,7 @@ PARSE_AND_LIST_ARGS_CASES=' break; case OPTION_EXPORT_SYMBOLS: if (!optarg) - einfo (_("Missing file for --mgen-symbol-ld-script.\n"), optarg); + einfo (_("Missing file for --mexport-symbols.\n"), optarg); if(strcmp (optarg, "-") == 0) sym_ld_script = stdout; @@ -425,7 +335,7 @@ PARSE_AND_LIST_ARGS_CASES=' ex9_export_file = stdout; else { - ex9_export_file = fopen (optarg, FOPEN_WT); + ex9_export_file = fopen (optarg, "wb"); if(ex9_export_file == NULL) einfo (_("ERROR %P%F: cannot open ex9 export file %s.\n"), optarg); } @@ -434,7 +344,7 @@ PARSE_AND_LIST_ARGS_CASES=' if (!optarg) einfo (_("Missing file for --mimport-ex9=.\n")); - ex9_import_file = fopen (optarg, "r+"); + ex9_import_file = fopen (optarg, "rb+"); if(ex9_import_file == NULL) einfo (_("ERROR %P%F: cannot open ex9 import file %s.\n"), optarg); break; -- 2.30.2