From a5d72d66758619418e91b4274aeba6de21c4548f Mon Sep 17 00:00:00 2001 From: Nelson Chu Date: Thu, 23 Aug 2018 09:33:26 +0800 Subject: [PATCH 07/13] NDS32: Update assemble-time relaxations (pesudo and load-store). NDS32 has two main assemble-time relaxations, this patch focuses on the update for the relaxations with .relax_hint directives. 1. Update the PIC load-store relax pattenrs (GOT, GOTOFF and PLT) and merge the LA and LS patterns into one (LALS). 2. It is hard to konw the current ID number of the .relax_hint directive when inserting inline assmebly code. Therefore, we support `begin' and `end' keywords to mark the relax patterns without giving the exactly ID number. .relax_hint begin relax_insn_1 ... .relax_hint relax_insn_2 ... .relax_hint end relax_insn_n 3. Allow .relax_hint directives can be attached at the pseudo instructions. We need this modification for some specific relax patterns. 4. Use xmalloc to fix the overflow issue when looking up the pseudo opcodes in the nds32_lookup_pseudo_opcode. gas/ * config/tc-nds32.c (struct nds32_relocs_pattern): Add `insn' field. (struct nds32_hint_map): Add `option_list' field. (struct suffix_name, suffix_table): Remove the unused `pic' field. (do_pseudo_b, do_pseudo_bal): Remove the suffix checking. (do_pseudo_la_internal, do_pseudo_pushpopm): Indent. (relax_hint_bias, relax_hint_id_current): New static variables. (reset_bias, relax_hint_begin): New variables. (nds_itoa): New function. (CLEAN_REG, GET_OPCODE): New macros. (struct relax_hint_id): New. (nds32_relax_hint): For .relax_hint directive, we can use `begin' and `end' to mark the relax pattern without giving exactly id number. (nds32_elf_append_relax_relocs): Handle the case that the .relax_hint directives are attached to pseudo instruction. (nds32_elf_save_pseudo_pattern): Change the second parameter from instruction's opcode to byte code. (nds32_elf_build_relax_relation): Add new bfd_boolean parameter `pseudo_hint'. (nds32_lookup_pseudo_opcode): Fix the overflow issue. (enum nds32_insn_type): Add N32_RELAX_ALU1 and N32_RELAX_16BIT. (nds32_elf_record_fixup_exp, relax_ls_table, hint_map, nds32_find_reloc_table, nds32_match_hint_insn, nds32_parse_name): Updated. * config/tc-nds32.h (MAX_RELAX_NUM): Extend it to 6. (enum nds32_relax_hint_type): Merge NDS32_RELAX_HINT_LA and NDS32_RELAX_HINT_LS into NDS32_RELAX_HINT_LALS. Add NDS32_RELAX_HINT_LA_PLT, NDS32_RELAX_HINT_LA_GOT and NDS32_RELAX_HINT_LA_GOTOFF. --- gas/config/tc-nds32.c | 623 ++++++++++++++++++++++++++++++------------ gas/config/tc-nds32.h | 10 +- 2 files changed, 459 insertions(+), 174 deletions(-) diff --git a/gas/config/tc-nds32.c b/gas/config/tc-nds32.c index 1d8f9287e2..1f468ab928 100644 --- a/gas/config/tc-nds32.c +++ b/gas/config/tc-nds32.c @@ -66,6 +66,8 @@ struct nds32_relocs_pattern struct nds32_opcode *opcode; char *where; struct nds32_relocs_pattern *next; + /* Assembled instruction bytes. */ + uint32_t insn; }; /* Suffix name and relocation. */ @@ -73,7 +75,6 @@ struct suffix_name { const 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 @@ -2632,7 +2633,7 @@ do_pseudo_b (int argc ATTRIBUTE_UNUSED, char *argv[], char *arg_label = argv[0]; relaxing = TRUE; /* b label */ - if (nds32_pic && strstr (arg_label, "@PLT")) + if (nds32_pic) { md_assemblef ("sethi $ta,hi20(%s)", arg_label); md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label); @@ -2653,12 +2654,11 @@ do_pseudo_bal (int argc ATTRIBUTE_UNUSED, char *argv[], char *arg_label = argv[0]; relaxing = TRUE; /* bal|call label */ - if (nds32_pic - && (strstr (arg_label, "@GOT") || strstr (arg_label, "@PLT"))) + if (nds32_pic) { md_assemblef ("sethi $ta,hi20(%s)", arg_label); md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label); - md_assemble ((char *) "add $ta,$ta,$gp"); + md_assemble ((char *) "add $ta,$ta,$gp"); md_assemble ((char *) "jral $ta"); } else @@ -2772,7 +2772,7 @@ do_pseudo_la_internal (const char *arg_reg, char *arg_label, relaxing = TRUE; /* rt, label */ - if (!nds32_pic && !strstr(arg_label, "@")) + 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); @@ -3126,11 +3126,11 @@ do_pseudo_pushpopm (int argc, char *argv[], /* Reduce register. */ if (nds32_gpr16 && re > 10 && !(rb == 31 && re == 31)) { - if (re >= 15 && strstr(opc, "smw") != NULL) + 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) + if (re >= 15 && strstr (opc, "lmw") != NULL) md_assemblef ("%s $r15,[$sp],$r15,%d", opc, en4); } else @@ -3451,22 +3451,23 @@ nds32_init_nds32_pseudo_opcodes (void) static struct nds32_pseudo_opcode * nds32_lookup_pseudo_opcode (const char *str) { + struct nds32_pseudo_opcode *result; int i = 0; - /* Assume pseudo-opcode are less than 16-char in length. */ - char op[16] = {0}; - for (i = 0; i < (int)ARRAY_SIZE (op); i++) + /* (*op) is the first word of current source line (*str) */ + int maxlen = strlen (str); + char *op = xmalloc (maxlen + 1); + + for (i = 0; i < maxlen; i++) { if (ISSPACE (op[i] = str[i])) break; } - - if (i >= (int)ARRAY_SIZE (op)) - return NULL; - op[i] = '\0'; - return hash_find (nds32_pseudo_opcode_hash, op); + result = hash_find (nds32_pseudo_opcode_hash, op); + free (op); + return result; } static void @@ -4192,16 +4193,49 @@ struct nds32_relocs_group }; static struct nds32_relocs_group *nds32_relax_hint_current = NULL; +/* Used to reorder the id for ".relax_hint id". */ +static int relax_hint_bias = 0; +/* Record current relax hint id. */ +static int relax_hint_id_current = -1; +int reset_bias = 0; +/* If ".relax_hint begin" is triggered? */ +int relax_hint_begin = 0; + +/* Record the reordered relax hint id. */ + +struct relax_hint_id +{ + int old_id; + int new_id; + struct relax_hint_id *next; +}; + +/* FIXME: Need to find somewhere to free the list. */ +struct relax_hint_id *record_id_head = NULL; + +/* Is the buffer large enough? */ +#define MAX_BUFFER 12 + +static char *nds_itoa (int n); + +static char * +nds_itoa (int n) +{ + char *buf = xmalloc (MAX_BUFFER * sizeof (char)); + snprintf (buf, MAX_BUFFER, "%d", n); + return buf; +} /* Insert a relax hint. */ static void nds32_relax_hint (int mode ATTRIBUTE_UNUSED) { - char *name; + char *name = NULL; char saved_char; struct nds32_relocs_pattern *relocs = NULL; struct nds32_relocs_group *group, *new; + struct relax_hint_id *record_id; name = input_line_pointer; while (*input_line_pointer && !ISSPACE (*input_line_pointer)) @@ -4210,12 +4244,57 @@ nds32_relax_hint (int mode ATTRIBUTE_UNUSED) *input_line_pointer = 0; name = strdup (name); + if (name && strcmp (name, "begin") == 0) + { + if (relax_hint_id_current == -1) + reset_bias = 1; + relax_hint_bias++; + relax_hint_id_current++; + relax_hint_begin = 1; + } + + /* Original case ".relax_hint id". It's id may need to be reordered. */ + if (!relax_hint_begin) + { + int tmp = strtol (name, NULL, 10); + record_id = record_id_head; + while (record_id) + { + if (record_id->old_id == tmp) + { + name = nds_itoa (record_id->new_id); + goto reordered_id; + } + record_id = record_id->next; + } + if (reset_bias) + { + relax_hint_bias = relax_hint_id_current - atoi (name) + 1; + reset_bias = 0; + } + relax_hint_id_current = tmp + relax_hint_bias; + + /* Insert the element to the head of the link list. */ + struct relax_hint_id *tmp_id = malloc (sizeof (struct relax_hint_id)); + tmp_id->old_id = tmp; + tmp_id->new_id = relax_hint_id_current; + tmp_id->next = record_id_head; + record_id_head = tmp_id; + } + + if (name && strcmp (name, "end") == 0) + relax_hint_begin = 0; + name = nds_itoa (relax_hint_id_current); + +reordered_id: + /* Find relax hint entry for next instruction, and all member will be initialized at that time. */ relocs = hash_find (nds32_hint_hash, name); if (relocs == NULL) { relocs = XNEW (struct nds32_relocs_pattern); + memset (relocs, 0, sizeof (struct nds32_relocs_pattern)); hash_insert (nds32_hint_hash, name, relocs); } else @@ -4224,6 +4303,7 @@ nds32_relax_hint (int mode ATTRIBUTE_UNUSED) relocs=relocs->next; relocs->next = XNEW (struct nds32_relocs_pattern); relocs = relocs->next; + memset (relocs, 0, sizeof (struct nds32_relocs_pattern)); } relocs->next = NULL; @@ -4236,6 +4316,7 @@ nds32_relax_hint (int mode ATTRIBUTE_UNUSED) instructions relative to the same instruction. It to connect to next instruction after md_assemble. */ new = XNEW (struct nds32_relocs_group); + memset (new, 0, sizeof (struct nds32_relocs_group)); new->pattern = relocs; new->next = NULL; group = nds32_relax_hint_current; @@ -4666,11 +4747,12 @@ get_range_type (const struct nds32_field *field) /* Save pseudo instruction relocation list. */ static struct nds32_relocs_pattern* -nds32_elf_save_pseudo_pattern (fixS* fixP, struct nds32_opcode *opcode, +nds32_elf_save_pseudo_pattern (fixS* fixP, struct nds32_asm_insn *insn, char *out, symbolS *sym, struct nds32_relocs_pattern *reloc_ptr, fragS *fragP) { + struct nds32_opcode *opcode = insn->opcode; if (!reloc_ptr) reloc_ptr = XNEW (struct nds32_relocs_pattern); reloc_ptr->seg = now_seg; @@ -4680,6 +4762,7 @@ nds32_elf_save_pseudo_pattern (fixS* fixP, struct nds32_opcode *opcode, reloc_ptr->fixP = fixP; reloc_ptr->opcode = opcode; reloc_ptr->where = out; + reloc_ptr->insn = insn->insn; reloc_ptr->next = NULL; return reloc_ptr; } @@ -4723,8 +4806,13 @@ nds32_elf_record_fixup_exp (fragS *fragP, const char *str, case BFD_RELOC_NDS32_GOTTPOFF: /* @GOTTPOFF */ reloc = BFD_RELOC_NDS32_TLS_IE_HI20; break; - default: /* No suffix. */ - reloc = BFD_RELOC_NDS32_HI20; + default: /* No suffix */ + if (nds32_pic) + /* When the file is pic, the address must be offset to gp. + It may define another relocation or use GOTOFF. */ + reloc = BFD_RELOC_NDS32_PLT_GOTREL_HI20; + else + reloc = BFD_RELOC_NDS32_HI20; break; } fixP = fix_new_exp (fragP, out - fragP->fr_literal, insn->opcode->isize, @@ -4756,8 +4844,13 @@ nds32_elf_record_fixup_exp (fragS *fragP, const char *str, case BFD_RELOC_NDS32_TPOFF: /* @TPOFF */ reloc = BFD_RELOC_NDS32_TLS_LE_LO12; break; - default: /* No suffix. */ - reloc = BFD_RELOC_NDS32_LO12S0; + default: /* No suffix */ + if (nds32_pic) + /* When the file is pic, the address must be offset to gp. + It may define another relocation or use GOTOFF. */ + reloc = BFD_RELOC_NDS32_PLT_GOTREL_LO12; + else + reloc = BFD_RELOC_NDS32_LO12S0; break; } } @@ -4771,7 +4864,7 @@ nds32_elf_record_fixup_exp (fragS *fragP, const char *str, case BFD_RELOC_NDS32_GOTTPOFF: /* @GOTTPOFF */ reloc = BFD_RELOC_NDS32_TLS_IE_LO12S2; break; - default: /* No suffix. */ + default: /* No suffix */ reloc = BFD_RELOC_NDS32_LO12S2; break; } @@ -4779,7 +4872,7 @@ nds32_elf_record_fixup_exp (fragS *fragP, const char *str, else if (fld->bitsize == 15 && fld->shift == 3) reloc = BFD_RELOC_NDS32_LO12S3; /* [ls]di */ else if (fld->bitsize == 12 && fld->shift == 2) - reloc = R_NDS32_LO12S2_SP_RELA; /* f[ls][sd]i */ + reloc = BFD_RELOC_NDS32_LO12S2_SP; /* f[ls][sd]i */ fixP = fix_new_exp (fragP, out - fragP->fr_literal, insn->opcode->isize, insn->info, 0 /* pcrel */, reloc); @@ -4849,8 +4942,9 @@ nds32_elf_record_fixup_exp (fragS *fragP, const char *str, 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_asm_insn *insn, fragS *fragP, + const struct nds32_field *fld, + bfd_boolean pseudo_hint) { struct nds32_relocs_pattern *reloc_ptr; struct nds32_relocs_group *group; @@ -4860,10 +4954,32 @@ nds32_elf_build_relax_relation (fixS *fixP, expressionS *pexp, char* out, if (fld) sym = pexp->X_add_symbol; - if (pseudo_opcode) + if (pseudo_hint) + { + /* We cannot know how many instructions will be expanded for + the pseudo instruction here. The first expanded instruction fills + the memory created by relax_hint. The follower will created and link + here. */ + group = nds32_relax_hint_current; + while (group) + { + if (group->pattern->opcode == NULL) + nds32_elf_save_pseudo_pattern (fixP, insn, out, sym, + group->pattern, fragP); + else + { + group->pattern->next = + nds32_elf_save_pseudo_pattern (fixP, insn, out, sym, + NULL, fragP); + group->pattern = group->pattern->next; + } + group = group->next; + } + } + else if (pseudo_opcode) { /* Save instruction relation for pseudo instruction expanding pattern. */ - reloc_ptr = nds32_elf_save_pseudo_pattern (fixP, opcode, out, sym, + reloc_ptr = nds32_elf_save_pseudo_pattern (fixP, insn, out, sym, NULL, fragP); if (!relocs_list) relocs_list = reloc_ptr; @@ -4881,7 +4997,7 @@ nds32_elf_build_relax_relation (fixS *fixP, expressionS *pexp, char* out, group = nds32_relax_hint_current; while (group) { - nds32_elf_save_pseudo_pattern (fixP, opcode, out, sym, + nds32_elf_save_pseudo_pattern (fixP, insn, out, sym, group->pattern, fragP); group = group->next; free (nds32_relax_hint_current); @@ -4897,40 +5013,96 @@ nds32_elf_build_relax_relation (fixS *fixP, expressionS *pexp, char* out, #define N32_MEM_EXT(insn) ((N32_OP6_MEM << 25) | insn) /* Relax pattern for link time relaxation. */ +/* Relaxation types only! relocation types are not necessary. */ +/* Refer to nds32_elf_record_fixup_exp (). */ static struct nds32_relax_hint_table relax_ls_table[] = { { - /* Set address: la -> sethi ori. */ - NDS32_RELAX_HINT_LA, /* main_type */ - 8, /* relax_code_size */ - { - OP6 (SETHI), - OP6 (ORI), - }, /* relax_code_seq */ - { - {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE}, - {4, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_INSN16} - } /* relax_fixup */ + /* Load Address / Load-Store (LALS). */ + .main_type = NDS32_RELAX_HINT_LALS, + .relax_code_size = 12, + .relax_code_seq = + { + OP6 (SETHI), + OP6 (ORI), + OP6 (LBI), + }, + .relax_fixup = + { + {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE}, + {4, 4, NDS32_HINT | NDS32_INSN16, BFD_RELOC_NDS32_INSN16}, + {8, 4, NDS32_HINT | NDS32_INSN16, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} + } }, { - /* Set address: l.w -> sethi ori. */ - NDS32_RELAX_HINT_LS, /* main_type */ - 8, /* relax_code_size */ - { - OP6 (SETHI), - OP6 (LBI), - }, /* relax_code_seq */ - { - {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE}, - {4, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_INSN16} - } /* relax_fixup */ + /* B(AL) symbol@PLT */ + .main_type = NDS32_RELAX_HINT_LA_PLT, + .relax_code_size = 16, + .relax_code_seq = + { + OP6 (SETHI), + OP6 (ORI), + OP6 (ALU1), + OP6 (JREG), + }, + .relax_fixup = + { + {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE}, + {4, 4, NDS32_HINT | NDS32_PTR, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_HINT | NDS32_PTR, BFD_RELOC_NDS32_PTR}, + {12, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PLT_GOT_SUFF}, + {12, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED}, + {12, 4, NDS32_HINT | NDS32_INSN16, BFD_RELOC_NDS32_INSN16}, + {0, 0, 0, 0} + } }, { - 0, - 0, - {0}, - {{0, 0 , 0, 0}} + /* LA (@GOT). */ + .main_type = NDS32_RELAX_HINT_LA_GOT, + .relax_code_size = 12, + .relax_code_seq = + { + OP6 (SETHI), + OP6 (ORI), + OP6 (MEM), + }, + .relax_fixup = + { + {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE}, + {4, 4, NDS32_HINT | NDS32_PTR, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED}, + {8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_GOT_SUFF}, + {0, 0, 0, 0} + } + }, + { + /* LA (@GOTOFF). */ + .main_type = NDS32_RELAX_HINT_LA_GOTOFF, + .relax_code_size = 16, + .relax_code_seq = + { + OP6 (SETHI), + OP6 (ORI), + OP6 (ALU1), + OP6 (MEM), + }, + .relax_fixup = + { + {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE}, + {4, 4, NDS32_HINT | NDS32_PTR, BFD_RELOC_NDS32_PTR}, + {8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED}, + {8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_GOTOFF_SUFF}, + {12, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED}, + {12, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_GOTOFF_SUFF}, + {0, 0, 0, 0} + } + }, + { + .main_type = 0, + .relax_code_seq = {0}, + .relax_fixup = {{0, 0 , 0, 0}} } }; @@ -4991,6 +5163,7 @@ nds32_elf_sethi_range (struct nds32_relocs_pattern *pattern) /* 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)) @@ -5188,97 +5361,144 @@ enum nds32_insn_type N32_RELAX_ORI = (1 << 5), N32_RELAX_MEM = (1 << 6), N32_RELAX_MOVI = (1 << 7), + N32_RELAX_ALU1 = (1 << 8), + N32_RELAX_16BIT = (1 << 9), }; struct nds32_hint_map { + /* the preamble relocation */ bfd_reloc_code_real_type hi_type; + /* mnemonic */ const char *opc; + /* relax pattern ID */ enum nds32_relax_hint_type hint_type; + /* range */ enum nds32_br_range range; + /* pattern character flags */ enum nds32_insn_type insn_list; + /* optional pattern character flags */ + enum nds32_insn_type option_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 variations 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} + { + /* LONGCALL4. */ + BFD_RELOC_NDS32_HI20, + "jal", + NDS32_RELAX_HINT_NONE, + BR_RANGE_U4G, + N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_CALL, + 0, + }, + { + /* LONGCALL5. */ + _dummy_first_bfd_reloc_code_real, + "bgezal", + NDS32_RELAX_HINT_NONE, + BR_RANGE_S16M, + N32_RELAX_BR | N32_RELAX_CALL, + 0, + }, + { + /* 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, + 0, + }, + { + /* LONGJUMP4. */ + BFD_RELOC_NDS32_HI20, + "j", + NDS32_RELAX_HINT_NONE, + BR_RANGE_U4G, + N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_JUMP, + 0, + }, + { + /* LONGJUMP5. */ + /* There is two kinds of variation 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, + 0, + }, + { + /* 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, + 0, + }, + { + /* LONGJUMP7. */ + _dummy_first_bfd_reloc_code_real, + "beqc", + NDS32_RELAX_HINT_NONE, + BR_RANGE_S16K, + N32_RELAX_MOVI | N32_RELAX_BR, + 0, + }, + { + /* LONGCALL (BAL|JR|LA symbol@PLT). */ + BFD_RELOC_NDS32_PLT_GOTREL_HI20, + NULL, + NDS32_RELAX_HINT_LA_PLT, + BR_RANGE_U4G, + N32_RELAX_SETHI | N32_RELAX_ORI, + N32_RELAX_ALU1 | N32_RELAX_CALL | N32_RELAX_JUMP, + }, + /* relative issue: #11685 #11602 */ + { + /* load address / load-store (LALS). */ + BFD_RELOC_NDS32_HI20, + NULL, + NDS32_RELAX_HINT_LALS, + BR_RANGE_U4G, + N32_RELAX_SETHI, + N32_RELAX_ORI | N32_RELAX_LSI, + }, + { + /* setup $GP (_GLOBAL_OFFSET_TABLE_) */ + BFD_RELOC_NDS32_GOTPC_HI20, + NULL, + NDS32_RELAX_HINT_LALS, + BR_RANGE_U4G, + N32_RELAX_SETHI | N32_RELAX_ORI, + 0, + }, + { + /* GOT LA/LS (symbol@GOT) */ + BFD_RELOC_NDS32_GOT_HI20, + NULL, + NDS32_RELAX_HINT_LA_GOT, + BR_RANGE_U4G, + N32_RELAX_SETHI | N32_RELAX_ORI, + N32_RELAX_MEM, + }, + { + /* GOTOFF LA/LS (symbol@GOTOFF) */ + BFD_RELOC_NDS32_GOTOFF_HI20, + NULL, + NDS32_RELAX_HINT_LA_GOTOFF, + BR_RANGE_U4G, + N32_RELAX_SETHI | N32_RELAX_ORI, + N32_RELAX_ALU1 | N32_RELAX_MEM, /* | N32_RELAX_LSI, */ + }, + /* last one */ + {0, NULL, 0, 0 ,0, 0} }; /* Find the relaxation pattern according to instructions. */ @@ -5320,6 +5540,9 @@ nds32_find_reloc_table (struct nds32_relocs_pattern *relocs_pattern, case N32_OP6_MEM: relax_type |= N32_RELAX_MEM; break; + case N32_OP6_ALU1: + relax_type |= N32_RELAX_ALU1; + break; case N32_OP6_ORI: relax_type |= N32_RELAX_ORI; break; @@ -5363,18 +5586,20 @@ nds32_find_reloc_table (struct nds32_relocs_pattern *relocs_pattern, } 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++) + /* 2 byte instruction. Compare by opcode name because + the opcode of 2byte instruction is not regular. */ + int is_matched = 0; + for (i = 0; i < ARRAY_SIZE (check_insn); i++) { if (strcmp (pattern->opcode->opcode, check_insn[i]) == 0) { relax_type |= N32_RELAX_BR; + is_matched += 1; break; } } - if (strcmp (pattern->opcode->opcode, "movi55") == 0) - relax_type |= N32_RELAX_MOVI; + if (!is_matched) + relax_type |= N32_RELAX_16BIT; } pattern = pattern->next; } @@ -5382,23 +5607,35 @@ nds32_find_reloc_table (struct nds32_relocs_pattern *relocs_pattern, /* 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))) + struct nds32_hint_map *hint = map_ptr++; + enum nds32_insn_type must = hint->insn_list; + enum nds32_insn_type optional = hint->option_list; + enum nds32_insn_type extra; + + if (must != (must & relax_type)) + continue; + + extra = relax_type ^ must; + if (extra != (extra & optional)) + continue; + + if (!hi_pattern + || (hi_pattern->fixP + && hi_pattern->fixP->fx_r_type == hint->hi_type)) { - opc = map_ptr->opc; - hint_type = map_ptr->hint_type; - range = map_ptr->range; + opc = hint->opc; + hint_type = hint->hint_type; + range = hint->range; + map_ptr = hint; break; } - map_ptr++; } if (map_ptr->insn_list == 0) { - as_warn (_("Can not find match relax hint. Line: %d"), - relocs_pattern->frag->fr_line); + if (!nds32_pic) + as_warn (_("Can not find match relax hint. Line: %d"), + relocs_pattern->frag->fr_line); return FALSE; } @@ -5457,12 +5694,14 @@ nds32_find_reloc_table (struct nds32_relocs_pattern *relocs_pattern, /* Because there are a lot of variant of load-store, check all these type here. */ -#define CLEAN_REG(insn) ((insn) & 0xff0003ff) +#define CLEAN_REG(insn) ((insn) & 0xfe0003ff) +#define GET_OPCODE(insn) ((insn) & 0xfe000000) + static bfd_boolean nds32_match_hint_insn (struct nds32_opcode *opcode, uint32_t seq) { const char *check_insn[] = - { "bnes38", "beqs38", "bnez38", "bnezs8", "beqz38", "beqzs8" }; + { "bnes38", "beqs38", "bnez38", "bnezs8", "beqz38", "beqzs8", "jral5" }; uint32_t insn = opcode->value; unsigned int i; @@ -5479,21 +5718,21 @@ nds32_match_hint_insn (struct nds32_opcode *opcode, uint32_t seq) || insn == OP6 (LHI) || insn == OP6 (SHI) || insn == OP6 (LHSI) || insn == OP6 (LWI) || insn == OP6 (SWI) || insn == OP6 (LWC) || insn == OP6 (SWC)) - return TRUE; + return TRUE; break; case OP6 (BR2): /* This is for LONGCALL5 and LONGCALL6. */ if (insn == OP6 (BR2)) - return TRUE; + 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; + return TRUE; else if (opcode->isize == 2) { - for (i = 0; i < sizeof (check_insn) / sizeof (check_insn[0]); i++) + for (i = 0; i < ARRAY_SIZE (check_insn); i++) if (strcmp (opcode->opcode, check_insn[i]) == 0) return TRUE; } @@ -5501,8 +5740,28 @@ nds32_match_hint_insn (struct nds32_opcode *opcode, uint32_t seq) case OP6 (MOVI): /* This is for LONGJUMP7. */ if (opcode->isize == 2 && strcmp (opcode->opcode, "movi55") == 0) - return TRUE; + return TRUE; + break; + case OP6 (MEM): + if (OP6 (MEM) == GET_OPCODE (insn)) + return TRUE; break; + case OP6 (JREG): + /* bit 24: N32_JI_JAL */ /* feed me! */ + if ((insn & ~(N32_BIT (24))) == JREG (JRAL)) + return TRUE; + break; + default: + if (opcode->isize == 2) + { + for (i = 0; i < ARRAY_SIZE (check_insn); i++) + if (strcmp (opcode->opcode, check_insn[i]) == 0) + return TRUE; + + if ((strcmp (opcode->opcode, "add5.pc") == 0) || + (strcmp (opcode->opcode, "add45") == 0)) + return TRUE; + } } return FALSE; } @@ -5510,7 +5769,7 @@ nds32_match_hint_insn (struct nds32_opcode *opcode, uint32_t seq) /* Append relax relocation for link time relaxing. */ static void -nds32_elf_append_relax_relocs (const char *key ATTRIBUTE_UNUSED, void *value) +nds32_elf_append_relax_relocs (const char *key, void *value) { struct nds32_relocs_pattern *relocs_pattern = (struct nds32_relocs_pattern *) value; @@ -5523,7 +5782,7 @@ nds32_elf_append_relax_relocs (const char *key ATTRIBUTE_UNUSED, void *value) struct nds32_relax_hint_table hint_info; nds32_relax_fixup_info_t *hint_fixup, *fixup_now; size_t fixup_size; - offsetT branch_offset; + offsetT branch_offset, hi_branch_offset = 0; fixS *fixP; int range, offset; unsigned int ptr_offset, hint_count, relax_code_size, count = 0; @@ -5544,6 +5803,7 @@ nds32_elf_append_relax_relocs (const char *key ATTRIBUTE_UNUSED, void *value) if (pattern_now->opcode->value == OP6 (SETHI)) { hi_sym = pattern_now->sym; + hi_branch_offset = pattern_now->fixP->fx_offset; break; } pattern_now = pattern_now->next; @@ -5563,12 +5823,17 @@ nds32_elf_append_relax_relocs (const char *key ATTRIBUTE_UNUSED, void *value) /* Insert relaxation. */ exp.X_op = O_symbol; + /* For each instruction in the hint group. */ while (pattern_now) { + if (count >= relax_code_size / 4) + count = 0; + /* Choose the match fixup by instruction. */ code_insn = CLEAN_REG (*(code_seq + count)); if (!nds32_match_hint_insn (pattern_now->opcode, code_insn)) { + /* Try search from head again */ count = 0; code_insn = CLEAN_REG (*(code_seq + count)); @@ -5577,8 +5842,11 @@ nds32_elf_append_relax_relocs (const char *key ATTRIBUTE_UNUSED, void *value) count++; if (count >= relax_code_size / 4) { - as_bad (_("Internal error: Relax hint error. %s: %x"), - now_seg->name, pattern_now->opcode->value); + as_bad (_("Internal error: Relax hint (%s) error. %s: %s (%x)"), + key, + now_seg->name, + pattern_now->opcode->opcode, + pattern_now->opcode->value); goto restore; } code_insn = CLEAN_REG (*(code_seq + count)); @@ -5674,7 +5942,7 @@ nds32_elf_append_relax_relocs (const char *key ATTRIBUTE_UNUSED, void *value) { /* For EMPTY relocation save the true symbol. */ exp.X_add_symbol = hi_sym; - exp.X_add_number = branch_offset; + exp.X_add_number = hi_branch_offset; } else { @@ -5691,6 +5959,7 @@ nds32_elf_append_relax_relocs (const char *key ATTRIBUTE_UNUSED, void *value) fixup_now++; fixup_size = fixup_now->size; } + if (count < relax_code_size / 4) count++; pattern_now = pattern_now->next; @@ -5785,8 +6054,10 @@ md_assemble (char *str) fixS *fixP; uint16_t insn_16; struct nds32_relocs_pattern *relocs_temp; + struct nds32_relocs_group *group_temp; fragS *fragP; int label = label_exist; + static bfd_boolean pseudo_hint = FALSE; popcode = nds32_lookup_pseudo_opcode (str); /* Note that we need to check 'verbatim' and @@ -5795,11 +6066,23 @@ md_assemble (char *str) need to perform pseudo instruction expansion/transformation. */ if (popcode && !(verbatim && popcode->physical_op)) { + /* Pseudo instruction is with relax_hint. */ + if (relaxing) + pseudo_hint = TRUE; pseudo_opcode = TRUE; nds32_pseudo_opcode_wrapper (str, popcode); pseudo_opcode = FALSE; + pseudo_hint = FALSE; nds32_elf_append_relax_relocs (NULL, relocs_list); + /* Free relax_hint group list. */ + while (nds32_relax_hint_current) + { + group_temp = nds32_relax_hint_current->next; + free (nds32_relax_hint_current); + nds32_relax_hint_current = group_temp; + } + /* Free pseudo list. */ relocs_temp = relocs_list; while (relocs_temp) @@ -5975,7 +6258,8 @@ md_assemble (char *str) 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); + nds32_elf_build_relax_relation (fixP, pexp, out, &insn, fragP, fld, + pseudo_hint); free (insn.info); } @@ -6128,7 +6412,6 @@ nds32_elf_get_set_cond (relax_info_t *relax_info, int offset, uint32_t *insn, } } - static int nds32_relax_branch_instructions (segT segment, fragS *fragP, long stretch ATTRIBUTE_UNUSED, @@ -6860,6 +7143,7 @@ nds32_insert_relax_entry (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next) if (!fixp->fx_done) break; + if (!fixp && !verbatim && ict_flag == ICT_NONE) return; @@ -7312,13 +7596,13 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP) return reloc; } -struct suffix_name suffix_table[] = +static 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} + {"GOTOFF", BFD_RELOC_NDS32_GOTOFF}, + {"GOT", BFD_RELOC_NDS32_GOT20}, + {"TPOFF", BFD_RELOC_NDS32_TPOFF}, + {"PLT", BFD_RELOC_NDS32_25_PLTREL}, + {"GOTTPOFF", BFD_RELOC_NDS32_GOTTPOFF}, }; /* Implement md_parse_name. */ @@ -7339,7 +7623,7 @@ nds32_parse_name (char const *name, expressionS *exprP, /* Check the special name if a symbol. */ segment = S_GET_SEGMENT (exprP->X_add_symbol); - if (segment != undefined_section) + if ((segment != undefined_section) && (*nextcharP != '@')) return 0; if (strcmp (name, GOT_NAME) == 0 && *nextcharP != '@') @@ -7353,13 +7637,11 @@ nds32_parse_name (char const *name, expressionS *exprP, char *next; for (i = 0; i < ARRAY_SIZE (suffix_table); i++) { - next = input_line_pointer + 1 + strlen(suffix_table[i].suffix); + 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)) { - 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; @@ -7369,6 +7651,7 @@ nds32_parse_name (char const *name, expressionS *exprP, } } } + return 1; } diff --git a/gas/config/tc-nds32.h b/gas/config/tc-nds32.h index edcbd4a3f1..9fecdbdf76 100644 --- a/gas/config/tc-nds32.h +++ b/gas/config/tc-nds32.h @@ -269,8 +269,8 @@ typedef struct nds32_cond_field /* The max relaxation pattern is 20-bytes including the nop. */ #define NDS32_MAXCHAR 20 /* In current, the max extended number of instruction for one pseudo instruction - is 4, but its number of relocation may be 12. */ -#define MAX_RELAX_NUM 4 + is 6, but its number of relocation may be 12. */ +#define MAX_RELAX_NUM 6 #define MAX_RELAX_FIX 12 typedef struct nds32_relax_info @@ -290,8 +290,10 @@ typedef struct nds32_relax_info enum nds32_relax_hint_type { NDS32_RELAX_HINT_NONE = 0, - NDS32_RELAX_HINT_LA, - NDS32_RELAX_HINT_LS + NDS32_RELAX_HINT_LALS, + NDS32_RELAX_HINT_LA_PLT, + NDS32_RELAX_HINT_LA_GOT, + NDS32_RELAX_HINT_LA_GOTOFF, }; struct nds32_relax_hint_table -- 2.19.0