static void s_cpreturn (int);
static void s_dtprelword (int);
static void s_dtpreldword (int);
+static void s_tprelword (int);
+static void s_tpreldword (int);
static void s_gpvalue (int);
static void s_gpword (int);
static void s_gpdword (int);
{"cpreturn", s_cpreturn, 0},
{"dtprelword", s_dtprelword, 0},
{"dtpreldword", s_dtpreldword, 0},
+ {"tprelword", s_tprelword, 0},
+ {"tpreldword", s_tpreldword, 0},
{"gpvalue", s_gpvalue, 0},
{"gpword", s_gpword, 0},
{"gpdword", s_gpdword, 0},
return 0;
}
-/* Move all labels in insn_labels to the current insertion point. */
+/* Move all labels in LABELS to the current insertion point. TEXT_P
+ says whether the labels refer to text or data. */
static void
-mips_move_labels (void)
+mips_move_labels (struct insn_label_list *labels, bfd_boolean text_p)
{
- segment_info_type *si = seg_info (now_seg);
struct insn_label_list *l;
valueT val;
- for (l = si->label_list; l != NULL; l = l->next)
+ for (l = labels; l != NULL; l = l->next)
{
gas_assert (S_GET_SEGMENT (l->label) == now_seg);
symbol_set_frag (l->label, frag_now);
val = (valueT) frag_now_fix ();
/* MIPS16/microMIPS text labels are stored as odd. */
- if (HAVE_CODE_COMPRESSION)
+ if (text_p && HAVE_CODE_COMPRESSION)
++val;
S_SET_VALUE (l->label, val);
}
}
+/* Move all labels in insn_labels to the current insertion point
+ and treat them as text labels. */
+
+static void
+mips_move_text_labels (void)
+{
+ mips_move_labels (seg_info (now_seg)->label_list, TRUE);
+}
+
static bfd_boolean
s_is_linkonce (symbolS *sym, segT from_seg)
{
frag_grow (40);
}
- mips_move_labels ();
+ mips_move_text_labels ();
#ifndef NO_ECOFF_DEBUGGING
if (ECOFF_DEBUGGING)
{
while (nops-- > 0)
add_fixed_insn (NOP_INSN);
- mips_move_labels ();
+ mips_move_text_labels ();
}
}
mips_no_prev_insn ();
decrease the size of prev_nop_frag. */
frag_wane (frag_now);
frag_new (0);
- mips_move_labels ();
+ mips_move_text_labels ();
}
mips_mark_labels ();
mips_clear_insn_labels ();
{"%gprel", BFD_RELOC_MIPS16_GPREL},
{"%got", BFD_RELOC_MIPS16_GOT16},
{"%call16", BFD_RELOC_MIPS16_CALL16},
- {"%hi", BFD_RELOC_MIPS16_HI16_S}
+ {"%hi", BFD_RELOC_MIPS16_HI16_S},
+ {"%tlsgd", BFD_RELOC_MIPS16_TLS_GD},
+ {"%tlsldm", BFD_RELOC_MIPS16_TLS_LDM},
+ {"%dtprel_hi", BFD_RELOC_MIPS16_TLS_DTPREL_HI16},
+ {"%dtprel_lo", BFD_RELOC_MIPS16_TLS_DTPREL_LO16},
+ {"%tprel_hi", BFD_RELOC_MIPS16_TLS_TPREL_HI16},
+ {"%tprel_lo", BFD_RELOC_MIPS16_TLS_TPREL_LO16},
+ {"%gottprel", BFD_RELOC_MIPS16_TLS_GOTTPREL}
};
case BFD_RELOC_MIPS_TLS_DTPREL_HI16:
case BFD_RELOC_MIPS_TLS_DTPREL_LO16:
case BFD_RELOC_MIPS_TLS_GOTTPREL:
+ case BFD_RELOC_MIPS_TLS_TPREL32:
+ case BFD_RELOC_MIPS_TLS_TPREL64:
case BFD_RELOC_MIPS_TLS_TPREL_HI16:
case BFD_RELOC_MIPS_TLS_TPREL_LO16:
case BFD_RELOC_MICROMIPS_TLS_GD:
case BFD_RELOC_MICROMIPS_TLS_GOTTPREL:
case BFD_RELOC_MICROMIPS_TLS_TPREL_HI16:
case BFD_RELOC_MICROMIPS_TLS_TPREL_LO16:
+ case BFD_RELOC_MIPS16_TLS_GD:
+ case BFD_RELOC_MIPS16_TLS_LDM:
+ case BFD_RELOC_MIPS16_TLS_DTPREL_HI16:
+ case BFD_RELOC_MIPS16_TLS_DTPREL_LO16:
+ case BFD_RELOC_MIPS16_TLS_GOTTPREL:
+ case BFD_RELOC_MIPS16_TLS_TPREL_HI16:
+ case BFD_RELOC_MIPS16_TLS_TPREL_LO16:
S_SET_THREAD_LOCAL (fixP->fx_addsy);
/* fall through */
fill byte should be used, FILL points to an integer that contains
that byte, otherwise FILL is null.
- The MIPS assembler also automatically adjusts any preceding
- label. */
+ This function used to have the comment:
+
+ The MIPS assembler also automatically adjusts any preceding label.
+
+ The implementation therefore applied the adjustment to a maximum of
+ one label. However, other label adjustments are applied to batches
+ of labels, and adjusting just one caused problems when new labels
+ were added for the sake of debugging or unwind information.
+ We therefore adjust all preceding labels (given as LABELS) instead. */
static void
-mips_align (int to, int *fill, symbolS *label)
+mips_align (int to, int *fill, struct insn_label_list *labels)
{
mips_emit_delays ();
mips_record_compressed_mode ();
else
frag_align (to, fill ? *fill : 0, 0);
record_alignment (now_seg, to);
- if (label != NULL)
- {
- gas_assert (S_GET_SEGMENT (label) == now_seg);
- symbol_set_frag (label, frag_now);
- S_SET_VALUE (label, (valueT) frag_now_fix ());
- }
+ mips_move_labels (labels, FALSE);
}
/* Align to a given power of two. .align 0 turns off the automatic
struct insn_label_list *l = si->label_list;
/* Auto alignment should be switched on by next section change. */
auto_align = 1;
- mips_align (temp, fill_ptr, l != NULL ? l->label : NULL);
+ mips_align (temp, fill_ptr, l);
}
else
{
{
segment_info_type *si = seg_info (now_seg);
struct insn_label_list *l = si->label_list;
- symbolS *label;
- label = l != NULL ? l->label : NULL;
mips_emit_delays ();
if (log_size > 0 && auto_align)
- mips_align (log_size, 0, label);
+ mips_align (log_size, 0, l);
cons (1 << log_size);
mips_clear_insn_labels ();
}
{
segment_info_type *si = seg_info (now_seg);
struct insn_label_list *l = si->label_list;
- symbolS *label;
-
- label = l != NULL ? l->label : NULL;
mips_emit_delays ();
if (auto_align)
{
if (type == 'd')
- mips_align (3, 0, label);
+ mips_align (3, 0, l);
else
- mips_align (2, 0, label);
+ mips_align (2, 0, l);
}
float_cons (type);
demand_empty_rest_of_line ();
}
-/* Handle the .dtprelword and .dtpreldword pseudo-ops. They generate
- a 32-bit or 64-bit DTP-relative relocation (BYTES says which) for
- use in DWARF debug information. */
+/* Handle a .dtprelword, .dtpreldword, .tprelword, or .tpreldword
+ pseudo-op; DIRSTR says which. The pseudo-op generates a BYTES-size
+ DTP- or TP-relative relocation of type RTYPE, for use in either DWARF
+ debug information or MIPS16 TLS. */
static void
-s_dtprel_internal (size_t bytes)
+s_tls_rel_directive (const size_t bytes, const char *dirstr,
+ bfd_reloc_code_real_type rtype)
{
expressionS ex;
char *p;
if (ex.X_op != O_symbol)
{
- as_bad (_("Unsupported use of %s"), (bytes == 8
- ? ".dtpreldword"
- : ".dtprelword"));
+ as_bad (_("Unsupported use of %s"), dirstr);
ignore_rest_of_line ();
}
p = frag_more (bytes);
md_number_to_chars (p, 0, bytes);
- fix_new_exp (frag_now, p - frag_now->fr_literal, bytes, &ex, FALSE,
- (bytes == 8
- ? BFD_RELOC_MIPS_TLS_DTPREL64
- : BFD_RELOC_MIPS_TLS_DTPREL32));
-
+ fix_new_exp (frag_now, p - frag_now->fr_literal, bytes, &ex, FALSE, rtype);
demand_empty_rest_of_line ();
+ mips_clear_insn_labels ();
}
/* Handle .dtprelword. */
static void
s_dtprelword (int ignore ATTRIBUTE_UNUSED)
{
- s_dtprel_internal (4);
+ s_tls_rel_directive (4, ".dtprelword", BFD_RELOC_MIPS_TLS_DTPREL32);
}
/* Handle .dtpreldword. */
static void
s_dtpreldword (int ignore ATTRIBUTE_UNUSED)
{
- s_dtprel_internal (8);
+ s_tls_rel_directive (8, ".dtpreldword", BFD_RELOC_MIPS_TLS_DTPREL64);
+}
+
+/* Handle .tprelword. */
+
+static void
+s_tprelword (int ignore ATTRIBUTE_UNUSED)
+{
+ s_tls_rel_directive (4, ".tprelword", BFD_RELOC_MIPS_TLS_TPREL32);
+}
+
+/* Handle .tpreldword. */
+
+static void
+s_tpreldword (int ignore ATTRIBUTE_UNUSED)
+{
+ s_tls_rel_directive (8, ".tpreldword", BFD_RELOC_MIPS_TLS_TPREL64);
}
/* Handle the .gpvalue pseudo-op. This is used when generating NewABI PIC
{
segment_info_type *si;
struct insn_label_list *l;
- symbolS *label;
expressionS ex;
char *p;
si = seg_info (now_seg);
l = si->label_list;
- label = l != NULL ? l->label : NULL;
mips_emit_delays ();
if (auto_align)
- mips_align (2, 0, label);
+ mips_align (2, 0, l);
expression (&ex);
mips_clear_insn_labels ();
{
segment_info_type *si;
struct insn_label_list *l;
- symbolS *label;
expressionS ex;
char *p;
si = seg_info (now_seg);
l = si->label_list;
- label = l != NULL ? l->label : NULL;
mips_emit_delays ();
if (auto_align)
- mips_align (3, 0, label);
+ mips_align (3, 0, l);
expression (&ex);
mips_clear_insn_labels ();
/* RMI Xlr */
{ "xlr", 0, ISA_MIPS64, CPU_XLR },
+ /* Broadcom XLP.
+ XLP is mostly like XLR, with the prominent exception that it is
+ MIPS64R2 rather than MIPS64. */
+ { "xlp", 0, ISA_MIPS64R2, CPU_XLR },
+
/* End marker */
{ NULL, 0, 0, 0 }
};