X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-mips.c;h=31acb77d78ad68a80a86638fd2a77b34b1d23084;hb=53fc67f8b2663261810353ae8e4f9920ae7a1c56;hp=6244d8ac091c562ddb5fdcf8611095d2790a343b;hpb=a8c4d40b578378be3b12575d127d4c7bd9972f32;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 6244d8ac09..31acb77d78 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -812,6 +812,9 @@ static int mips_debug = 0; fill a branch delay slot. */ static struct mips_cl_insn history[1 + MAX_NOPS + MAX_LLSC_RANGE]; +/* The maximum number of LABELS detect for the same address. */ +#define MAX_LABELS_SAME 10 + /* Arrays of operands for each instruction. */ #define MAX_OPERANDS 6 struct mips_operand_array @@ -4775,7 +4778,7 @@ gpr_read_mask (const struct mips_cl_insn *ip) if (pinfo2 & INSN2_READ_SP) mask |= 1 << SP; if (pinfo2 & INSN2_READ_GPR_31) - mask |= 1 << 31; + mask |= 1u << 31; /* Don't include register 0. */ return mask & ~1; } @@ -4794,7 +4797,7 @@ gpr_write_mask (const struct mips_cl_insn *ip) if (pinfo & INSN_WRITE_GPR_24) mask |= 1 << 24; if (pinfo & INSN_WRITE_GPR_31) - mask |= 1 << 31; + mask |= 1u << 31; if (pinfo & INSN_UDI) /* UDI instructions have traditionally been assumed to write to RD. */ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip); @@ -6901,7 +6904,21 @@ fix_loongson2f (struct mips_cl_insn * ip) fix_loongson2f_jump (ip); } -/* Fix loongson3 llsc errata: Insert sync before ll/lld. */ +static bfd_boolean +has_label_name (const char *arr[], size_t len ,const char *s) +{ + unsigned long i; + for (i = 0; i < len; i++) + { + if (!arr[i]) + return FALSE; + if (streq (arr[i], s)) + return TRUE; + } + return FALSE; +} + +/* Fix loongson3 llsc errata: Insert sync before ll/lld. */ static void fix_loongson3_llsc (struct mips_cl_insn * ip) @@ -6915,10 +6932,30 @@ fix_loongson3_llsc (struct mips_cl_insn * ip) && S_IS_LOCAL (seg_info (now_seg)->label_list->label) && (strcmp (ip->insn_mo->name, "sync") != 0)) { - const char *label_name = S_GET_NAME (seg_info (now_seg)->label_list->label); - unsigned long lookback = ARRAY_SIZE (history); unsigned long i; + valueT label_value; + const char *label_names[MAX_LABELS_SAME]; + const char *label_name; + + label_name = S_GET_NAME (seg_info (now_seg)->label_list->label); + label_names[0] = label_name; + struct insn_label_list *llist = seg_info (now_seg)->label_list; + label_value = S_GET_VALUE (llist->label); + for (i = 1; i < MAX_LABELS_SAME; i++) + { + llist = llist->next; + if (!llist) + break; + if (S_GET_VALUE (llist->label) == label_value) + label_names[i] = S_GET_NAME (llist->label); + else + break; + } + for (; i < MAX_LABELS_SAME; i++) + label_names[i] = NULL; + + unsigned long lookback = ARRAY_SIZE (history); for (i = 0; i < lookback; i++) { if (streq (history[i].insn_mo->name, "ll") @@ -6938,7 +6975,9 @@ fix_loongson3_llsc (struct mips_cl_insn * ip) if (delayed_branch_p (&history[j])) { - if (streq (history[j].target, label_name)) + if (has_label_name (label_names, + MAX_LABELS_SAME, + history[j].target)) { add_fixed_insn (&sync_insn); insert_into_history (0, 1, &sync_insn); @@ -6952,7 +6991,7 @@ fix_loongson3_llsc (struct mips_cl_insn * ip) } /* If we find a sc, we look forward to look for an branch insn, and see whether it jump back and out of ll/sc. */ - else if (streq(ip->insn_mo->name, "sc") || streq(ip->insn_mo->name, "scd")) + else if (streq (ip->insn_mo->name, "sc") || streq (ip->insn_mo->name, "scd")) { unsigned long lookback = ARRAY_SIZE (history) - 1; unsigned long i; @@ -16326,8 +16365,8 @@ s_change_sec (int sec) case 's': seg = subseg_new (".sdata", (subsegT) get_absolute_expression ()); - bfd_set_section_flags (seg, - SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA); + bfd_set_section_flags (seg, (SEC_ALLOC | SEC_LOAD | SEC_RELOC + | SEC_DATA | SEC_SMALL_DATA)); if (strncmp (TARGET_OS, "elf", 3) != 0) record_alignment (seg, 4); demand_empty_rest_of_line (); @@ -16335,7 +16374,7 @@ s_change_sec (int sec) case 'B': seg = subseg_new (".sbss", (subsegT) get_absolute_expression ()); - bfd_set_section_flags (seg, SEC_ALLOC); + bfd_set_section_flags (seg, SEC_ALLOC | SEC_SMALL_DATA); if (strncmp (TARGET_OS, "elf", 3) != 0) record_alignment (seg, 4); demand_empty_rest_of_line ();