/* tc-mips.c -- assemble code for a MIPS chip.
- Copyright (C) 1993-2019 Free Software Foundation, Inc.
+ Copyright (C) 1993-2020 Free Software Foundation, Inc.
Contributed by the OSF and Ralph Campbell.
Written by Keith Knowles and Ralph Campbell, working independently.
Modified for ECOFF and R4000 support by Ian Lance Taylor of Cygnus
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
if (strncmp (TARGET_OS, "elf", 3) != 0
&& strncmp (TARGET_OS, "vxworks", 7) != 0)
{
- (void) bfd_set_section_alignment (stdoutput, text_section, 4);
- (void) bfd_set_section_alignment (stdoutput, data_section, 4);
- (void) bfd_set_section_alignment (stdoutput, bss_section, 4);
+ bfd_set_section_alignment (text_section, 4);
+ bfd_set_section_alignment (data_section, 4);
+ bfd_set_section_alignment (bss_section, 4);
}
/* Create a .reginfo section for register masks and a .mdebug
{
sec = subseg_new (".reginfo", (subsegT) 0);
- bfd_set_section_flags (stdoutput, sec, flags);
- bfd_set_section_alignment (stdoutput, sec, HAVE_NEWABI ? 3 : 2);
+ bfd_set_section_flags (sec, flags);
+ bfd_set_section_alignment (sec, HAVE_NEWABI ? 3 : 2);
mips_regmask_frag = frag_more (sizeof (Elf32_External_RegInfo));
}
/* The 64-bit ABI uses a .MIPS.options section rather than
.reginfo section. */
sec = subseg_new (".MIPS.options", (subsegT) 0);
- bfd_set_section_flags (stdoutput, sec, flags);
- bfd_set_section_alignment (stdoutput, sec, 3);
+ bfd_set_section_flags (sec, flags);
+ bfd_set_section_alignment (sec, 3);
/* Set up the option header. */
{
}
sec = subseg_new (".MIPS.abiflags", (subsegT) 0);
- bfd_set_section_flags (stdoutput, sec,
+ bfd_set_section_flags (sec,
SEC_READONLY | SEC_DATA | SEC_ALLOC | SEC_LOAD);
- bfd_set_section_alignment (stdoutput, sec, 3);
+ bfd_set_section_alignment (sec, 3);
mips_flags_frag = frag_more (sizeof (Elf_External_ABIFlags_v0));
if (ECOFF_DEBUGGING)
{
sec = subseg_new (".mdebug", (subsegT) 0);
- (void) bfd_set_section_flags (stdoutput, sec,
- SEC_HAS_CONTENTS | SEC_READONLY);
- (void) bfd_set_section_alignment (stdoutput, sec, 2);
+ bfd_set_section_flags (sec, SEC_HAS_CONTENTS | SEC_READONLY);
+ bfd_set_section_alignment (sec, 2);
}
else if (mips_flag_pdr)
{
pdr_seg = subseg_new (".pdr", (subsegT) 0);
- (void) bfd_set_section_flags (stdoutput, pdr_seg,
- SEC_READONLY | SEC_RELOC
- | SEC_DEBUGGING);
- (void) bfd_set_section_alignment (stdoutput, pdr_seg, 2);
+ bfd_set_section_flags (pdr_seg,
+ SEC_READONLY | SEC_RELOC | SEC_DEBUGGING);
+ bfd_set_section_alignment (pdr_seg, 2);
}
subseg_set (seg, subseg);
if (symseg != from_seg && !S_IS_LOCAL (sym))
{
- if ((bfd_get_section_flags (stdoutput, symseg) & SEC_LINK_ONCE))
+ if ((bfd_section_flags (symseg) & SEC_LINK_ONCE))
linkonce = TRUE;
/* The GNU toolchain uses an extension for ELF: a section
beginning with the magic string .gnu.linkonce is a
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;
}
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);
}
new_seg = subseg_new (newname, (subsegT) 0);
- bfd_set_section_flags (stdoutput, new_seg,
+ bfd_set_section_flags (new_seg,
SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA);
frag_align (length == 4 ? 2 : 3, 0, 0);
if (strncmp (TARGET_OS, "elf", 3) != 0)
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)
&& 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")
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);
}
/* 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;
return (val & 0x3) != isa_bit;
}
+/* Calculate the relocation target by masking off ISA mode bit before
+ combining symbol and addend. */
+
+static valueT
+fix_bad_misaligned_address (fixS *fixP)
+{
+ valueT val;
+ valueT off;
+ unsigned isa_mode;
+ gas_assert (fixP != NULL && fixP->fx_addsy != NULL);
+ val = S_GET_VALUE (fixP->fx_addsy);
+ off = fixP->fx_offset;
+ isa_mode = (ELF_ST_IS_COMPRESSED (S_GET_OTHER (fixP->fx_addsy))
+ ? 1 : 0);
+
+ return ((val & ~isa_mode) + off);
+}
+
/* Make the necessary checks on a regular MIPS branch pointed to by FIXP
and its calculated value VAL. */
else if (fix_bad_misaligned_branch_p (fixP))
as_bad_where (fixP->fx_file, fixP->fx_line,
_("branch to misaligned address (0x%lx)"),
- (long) (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset));
+ (long) fix_bad_misaligned_address (fixP));
else if (HAVE_IN_PLACE_ADDENDS && (fixP->fx_offset & 0x3) != 0)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("cannot encode misaligned addend "
else if (fix_bad_misaligned_jump_p (fixP, shift))
as_bad_where (fixP->fx_file, fixP->fx_line,
_("jump to misaligned address (0x%lx)"),
- (long) (S_GET_VALUE (fixP->fx_addsy)
- + fixP->fx_offset));
+ (long) fix_bad_misaligned_address (fixP));
else if (HAVE_IN_PLACE_ADDENDS
&& (fixP->fx_offset & ((1 << shift) - 1)) != 0)
as_bad_where (fixP->fx_file, fixP->fx_line,
&& fixP->fx_done
&& fixP->fx_frag->fr_address >= text_section->vma
&& (fixP->fx_frag->fr_address
- < text_section->vma + bfd_get_section_size (text_section))
+ < text_section->vma + bfd_section_size (text_section))
&& ((insn & 0xffff0000) == 0x10000000 /* beq $0,$0 */
|| (insn & 0xffff0000) == 0x04010000 /* bgez $0 */
|| (insn & 0xffff0000) == 0x04110000)) /* bgezal $0 */
&& (fixP->fx_offset & 0x1) != 0)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("branch to misaligned address (0x%lx)"),
- (long) (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset));
+ (long) fix_bad_misaligned_address (fixP));
else if (HAVE_IN_PLACE_ADDENDS && (fixP->fx_offset & 0x1) != 0)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("cannot encode misaligned addend "
case 'r':
seg = subseg_new (RDATA_SECTION_NAME,
(subsegT) get_absolute_expression ());
- bfd_set_section_flags (stdoutput, seg, (SEC_ALLOC | SEC_LOAD
- | SEC_READONLY | SEC_RELOC
- | SEC_DATA));
+ bfd_set_section_flags (seg, (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+ | SEC_RELOC | SEC_DATA));
if (strncmp (TARGET_OS, "elf", 3) != 0)
record_alignment (seg, 4);
demand_empty_rest_of_line ();
case 's':
seg = subseg_new (".sdata", (subsegT) get_absolute_expression ());
- bfd_set_section_flags (stdoutput, 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 ();
case 'B':
seg = subseg_new (".sbss", (subsegT) get_absolute_expression ());
- bfd_set_section_flags (stdoutput, 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 ();
if (section_type == SHT_MIPS_DWARF)
section_type = SHT_PROGBITS;
- obj_elf_change_section (section_name, section_type, 0, section_flag,
+ obj_elf_change_section (section_name, section_type, section_flag,
section_entry_size, 0, 0, 0);
if (now_seg->name != section_name)
valueT
md_section_align (asection *seg, valueT addr)
{
- int align = bfd_get_section_alignment (stdoutput, seg);
+ int align = bfd_section_alignment (seg);
/* We don't need to align ELF sections to the full alignment.
However, Irix 5 may prefer that we align them at least to a 16
else if ((fragp->fr_offset & 0x1) != 0)
as_bad_where (fragp->fr_file, fragp->fr_line,
_("branch to misaligned address (0x%lx)"),
- (long) val);
+ (long) (resolve_symbol_value (fragp->fr_symbol)
+ + (fragp->fr_offset & ~1)));
}
val = mips16_pcrel_val (fragp, pcrel_op, val, 0);
else
p = NULL;
- if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) == 0)
+ if ((bfd_section_flags (now_seg) & SEC_CODE) == 0)
as_warn (_(".end not in text section"));
if (!cur_proc_ptr)
|| *input_line_pointer == '-')
get_number ();
- if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) == 0)
+ if ((bfd_section_flags (now_seg) & SEC_CODE) == 0)
as_warn (_(".ent or .aent not in text section"));
if (!aent && cur_proc_ptr)