aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorThiemo Seufer <ths@networkno.de>2001-10-04 20:07:00 +0000
committerThiemo Seufer <ths@networkno.de>2001-10-04 20:07:00 +0000
commitf668894301100e2e5ef05832e2dee08b90112a1e (patch)
treea8bfbe9fd3c04e571394c12e9f9e539d3da035b8 /gas
parent1ae008798a8be59993e58f3ac0d5a0852cf2ca77 (diff)
downloadgdb-f668894301100e2e5ef05832e2dee08b90112a1e.zip
gdb-f668894301100e2e5ef05832e2dee08b90112a1e.tar.gz
gdb-f668894301100e2e5ef05832e2dee08b90112a1e.tar.bz2
* config/tc-mips.c (prev_insn_reloc_type): Make it an array to hold a
relocation triple. (prev_insn_fixp): Likewise. (append_insn): Changed prototype to accept a relocation pointer. (imm_reloc): Make it an array. (offset_reloc): Likewise. (md_assemble): Handle triple relocations. (append_insn): Likewise. Add handling for some NewABI relocations. (mips_no_prev_insn): Handle triple relocations. (macro_build): Likewise. Add handling for some NewABI relocations. Move handling for the 'u' case to append_insn(). (mips16_macro_build): Handle triple relocations. (macro_build_lui): Likewise. Don't handle _gp_disp as special symbol for NewABI. (mips_ip): Handle triple relocations. (mips16_ip): Likewise. (mips_force_relocation): Force handling of triple relocations without symbols for NewABI. (md_apply_fix): Add handling for some NewABI relocations.
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog22
-rw-r--r--gas/config/tc-mips.c417
2 files changed, 328 insertions, 111 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index a74637a..c35a822 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,25 @@
+2001-10-04 Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
+
+ * config/tc-mips.c (prev_insn_reloc_type): Make it an array to hold a
+ relocation triple.
+ (prev_insn_fixp): Likewise.
+ (append_insn): Changed prototype to accept a relocation pointer.
+ (imm_reloc): Make it an array.
+ (offset_reloc): Likewise.
+ (md_assemble): Handle triple relocations.
+ (append_insn): Likewise. Add handling for some NewABI relocations.
+ (mips_no_prev_insn): Handle triple relocations.
+ (macro_build): Likewise. Add handling for some NewABI relocations.
+ Move handling for the 'u' case to append_insn().
+ (mips16_macro_build): Handle triple relocations.
+ (macro_build_lui): Likewise. Don't handle _gp_disp as special symbol
+ for NewABI.
+ (mips_ip): Handle triple relocations.
+ (mips16_ip): Likewise.
+ (mips_force_relocation): Force handling of triple relocations
+ without symbols for NewABI.
+ (md_apply_fix): Add handling for some NewABI relocations.
+
2001-10-05 Alan Modra <amodra@bigpond.net.au>
* config/tc-i386.c (parse_register): If not producing code for
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index cb6dd62..9a5abb1 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -430,10 +430,10 @@ static struct frag *prev_insn_frag;
static long prev_insn_where;
/* The reloc type for the previous instruction, if any. */
-static bfd_reloc_code_real_type prev_insn_reloc_type;
+static bfd_reloc_code_real_type prev_insn_reloc_type[3];
/* The reloc for the previous instruction, if any. */
-static fixS *prev_insn_fixp;
+static fixS *prev_insn_fixp[3];
/* Non-zero if the previous instruction was in a delay slot. */
static int prev_insn_is_delay_slot;
@@ -643,7 +643,7 @@ static void mips16_mark_labels PARAMS ((void));
static void append_insn PARAMS ((char *place,
struct mips_cl_insn * ip,
expressionS * p,
- bfd_reloc_code_real_type r,
+ bfd_reloc_code_real_type *r,
boolean));
static void mips_no_prev_insn PARAMS ((int));
static void mips_emit_delays PARAMS ((boolean));
@@ -868,8 +868,10 @@ static expressionS offset_expr;
/* Relocs associated with imm_expr and offset_expr. */
-static bfd_reloc_code_real_type imm_reloc;
-static bfd_reloc_code_real_type offset_reloc;
+static bfd_reloc_code_real_type imm_reloc[3]
+ = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
+static bfd_reloc_code_real_type offset_reloc[3]
+ = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
/* This is set by mips_ip if imm_reloc is an unmatched HI16_S reloc. */
@@ -1303,12 +1305,18 @@ md_assemble (str)
char *str;
{
struct mips_cl_insn insn;
+ bfd_reloc_code_real_type unused_reloc[3]
+ = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
imm_expr.X_op = O_absent;
- imm_reloc = BFD_RELOC_UNUSED;
imm_unmatched_hi = false;
offset_expr.X_op = O_absent;
- offset_reloc = BFD_RELOC_UNUSED;
+ imm_reloc[0] = BFD_RELOC_UNUSED;
+ imm_reloc[1] = BFD_RELOC_UNUSED;
+ imm_reloc[2] = BFD_RELOC_UNUSED;
+ offset_reloc[0] = BFD_RELOC_UNUSED;
+ offset_reloc[1] = BFD_RELOC_UNUSED;
+ offset_reloc[2] = BFD_RELOC_UNUSED;
if (mips_opts.mips16)
mips16_ip (str, &insn);
@@ -1340,7 +1348,7 @@ md_assemble (str)
else if (offset_expr.X_op != O_absent)
append_insn ((char *) NULL, &insn, &offset_expr, offset_reloc, false);
else
- append_insn ((char *) NULL, &insn, NULL, BFD_RELOC_UNUSED, false);
+ append_insn ((char *) NULL, &insn, NULL, unused_reloc, false);
}
}
@@ -1492,12 +1500,12 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
char *place;
struct mips_cl_insn *ip;
expressionS *address_expr;
- bfd_reloc_code_real_type reloc_type;
+ bfd_reloc_code_real_type *reloc_type;
boolean unmatched_hi;
{
register unsigned long prev_pinfo, pinfo;
char *f;
- fixS *fixp;
+ fixS *fixp[3];
int nops = 0;
/* Mark instruction labels in mips16 mode. */
@@ -1843,16 +1851,16 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
}
}
- if (reloc_type > BFD_RELOC_UNUSED)
+ if (*reloc_type > BFD_RELOC_UNUSED)
{
/* We need to set up a variant frag. */
assert (mips_opts.mips16 && address_expr != NULL);
f = frag_var (rs_machine_dependent, 4, 0,
- RELAX_MIPS16_ENCODE (reloc_type - BFD_RELOC_UNUSED,
+ RELAX_MIPS16_ENCODE (*reloc_type - BFD_RELOC_UNUSED,
mips16_small, mips16_ext,
(prev_pinfo
& INSN_UNCOND_BRANCH_DELAY),
- (prev_insn_reloc_type
+ (*prev_insn_reloc_type
== BFD_RELOC_MIPS16_JMP)),
make_expr_symbol (address_expr), (offsetT) 0,
(char *) NULL);
@@ -1861,7 +1869,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
f = place;
else if (mips_opts.mips16
&& ! ip->use_extend
- && reloc_type != BFD_RELOC_MIPS16_JMP)
+ && *reloc_type != BFD_RELOC_MIPS16_JMP)
{
/* Make sure there is enough room to swap this instruction with
a following jump instruction. */
@@ -1878,17 +1886,39 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
f = frag_more (4);
}
- fixp = NULL;
- if (address_expr != NULL && reloc_type < BFD_RELOC_UNUSED)
+ fixp[0] = fixp[1] = fixp[2] = NULL;
+ if (address_expr != NULL && *reloc_type < BFD_RELOC_UNUSED)
{
if (address_expr->X_op == O_constant)
{
- switch (reloc_type)
+ unsigned long tmp;
+
+ switch (*reloc_type)
{
case BFD_RELOC_32:
ip->insn_opcode |= address_expr->X_add_number;
break;
+ case BFD_RELOC_MIPS_HIGHEST:
+ tmp = (address_expr->X_add_number + 0x800080008000) >> 16;
+ tmp >>= 16;
+ ip->insn_opcode |= (tmp >> 16) & 0xffff;
+ break;
+
+ case BFD_RELOC_MIPS_HIGHER:
+ tmp = (address_expr->X_add_number + 0x80008000) >> 16;
+ ip->insn_opcode |= (tmp >> 16) & 0xffff;
+ break;
+
+ case BFD_RELOC_HI16_S:
+ ip->insn_opcode |= ((address_expr->X_add_number + 0x8000)
+ >> 16) & 0xffff;
+ break;
+
+ case BFD_RELOC_HI16:
+ ip->insn_opcode |= (address_expr->X_add_number >> 16) & 0xffff;
+ break;
+
case BFD_RELOC_LO16:
ip->insn_opcode |= address_expr->X_add_number & 0xffff;
break;
@@ -1924,34 +1954,122 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
else
{
need_reloc:
- /* Don't generate a reloc if we are writing into a variant
- frag. */
+ /* Don't generate a reloc if we are writing into a variant frag. */
if (place == NULL)
{
- fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 4,
- address_expr,
- (reloc_type == BFD_RELOC_16_PCREL
- || reloc_type == BFD_RELOC_16_PCREL_S2),
- reloc_type);
+ fixp[0] = fix_new_exp (frag_now, f - frag_now->fr_literal, 4,
+ address_expr,
+ (*reloc_type == BFD_RELOC_16_PCREL
+ || *reloc_type == BFD_RELOC_16_PCREL_S2),
+ reloc_type[0]);
+
+ /* These relocations can have a addend that won't fit in
+ 4 octets for 64bit assembly. */
+ if (HAVE_64BIT_GPRS &&
+ (*reloc_type == BFD_RELOC_16
+ || *reloc_type == BFD_RELOC_32
+ || *reloc_type == BFD_RELOC_MIPS_JMP
+ || *reloc_type == BFD_RELOC_HI16_S
+ || *reloc_type == BFD_RELOC_LO16
+ || *reloc_type == BFD_RELOC_GPREL16
+ || *reloc_type == BFD_RELOC_MIPS_LITERAL
+ || *reloc_type == BFD_RELOC_GPREL32
+ || *reloc_type == BFD_RELOC_64
+ || *reloc_type == BFD_RELOC_CTOR
+ || *reloc_type == BFD_RELOC_MIPS_SUB
+ || *reloc_type == BFD_RELOC_MIPS_HIGHEST
+ || *reloc_type == BFD_RELOC_MIPS_HIGHER
+ || *reloc_type == BFD_RELOC_MIPS_SCN_DISP
+ || *reloc_type == BFD_RELOC_MIPS_REL16
+ || *reloc_type == BFD_RELOC_MIPS_RELGOT))
+ fixp[0]->fx_no_overflow = 1;
+
if (unmatched_hi)
{
struct mips_hi_fixup *hi_fixup;
- assert (reloc_type == BFD_RELOC_HI16_S);
+ assert (*reloc_type == BFD_RELOC_HI16_S);
hi_fixup = ((struct mips_hi_fixup *)
xmalloc (sizeof (struct mips_hi_fixup)));
- hi_fixup->fixp = fixp;
+ hi_fixup->fixp = fixp[0];
hi_fixup->seg = now_seg;
hi_fixup->next = mips_hi_fixup_list;
mips_hi_fixup_list = hi_fixup;
}
+
+ if (reloc_type[1] != BFD_RELOC_UNUSED)
+ {
+ /* FIXME: This symbol can be one of
+ RSS_UNDEF, RSS_GP, RSS_GP0, RSS_LOC. */
+ address_expr->X_op = O_absent;
+ address_expr->X_add_symbol = 0;
+ address_expr->X_add_number = 0;
+
+ fixp[1] = fix_new_exp (frag_now, f - frag_now->fr_literal,
+ 4, address_expr, false,
+ reloc_type[1]);
+
+ /* These relocations can have a addend that won't fit in
+ 4 octets for 64bit assembly. */
+ if (HAVE_64BIT_GPRS &&
+ (*reloc_type == BFD_RELOC_16
+ || *reloc_type == BFD_RELOC_32
+ || *reloc_type == BFD_RELOC_MIPS_JMP
+ || *reloc_type == BFD_RELOC_HI16_S
+ || *reloc_type == BFD_RELOC_LO16
+ || *reloc_type == BFD_RELOC_GPREL16
+ || *reloc_type == BFD_RELOC_MIPS_LITERAL
+ || *reloc_type == BFD_RELOC_GPREL32
+ || *reloc_type == BFD_RELOC_64
+ || *reloc_type == BFD_RELOC_CTOR
+ || *reloc_type == BFD_RELOC_MIPS_SUB
+ || *reloc_type == BFD_RELOC_MIPS_HIGHEST
+ || *reloc_type == BFD_RELOC_MIPS_HIGHER
+ || *reloc_type == BFD_RELOC_MIPS_SCN_DISP
+ || *reloc_type == BFD_RELOC_MIPS_REL16
+ || *reloc_type == BFD_RELOC_MIPS_RELGOT))
+ fixp[1]->fx_no_overflow = 1;
+
+ if (reloc_type[2] != BFD_RELOC_UNUSED)
+ {
+ address_expr->X_op = O_absent;
+ address_expr->X_add_symbol = 0;
+ address_expr->X_add_number = 0;
+
+ fixp[2] = fix_new_exp (frag_now,
+ f - frag_now->fr_literal, 4,
+ address_expr, false,
+ reloc_type[2]);
+
+ /* These relocations can have a addend that won't fit in
+ 4 octets for 64bit assembly. */
+ if (HAVE_64BIT_GPRS &&
+ (*reloc_type == BFD_RELOC_16
+ || *reloc_type == BFD_RELOC_32
+ || *reloc_type == BFD_RELOC_MIPS_JMP
+ || *reloc_type == BFD_RELOC_HI16_S
+ || *reloc_type == BFD_RELOC_LO16
+ || *reloc_type == BFD_RELOC_GPREL16
+ || *reloc_type == BFD_RELOC_MIPS_LITERAL
+ || *reloc_type == BFD_RELOC_GPREL32
+ || *reloc_type == BFD_RELOC_64
+ || *reloc_type == BFD_RELOC_CTOR
+ || *reloc_type == BFD_RELOC_MIPS_SUB
+ || *reloc_type == BFD_RELOC_MIPS_HIGHEST
+ || *reloc_type == BFD_RELOC_MIPS_HIGHER
+ || *reloc_type == BFD_RELOC_MIPS_SCN_DISP
+ || *reloc_type == BFD_RELOC_MIPS_REL16
+ || *reloc_type == BFD_RELOC_MIPS_RELGOT))
+ fixp[2]->fx_no_overflow = 1;
+ }
+ }
}
}
}
if (! mips_opts.mips16)
md_number_to_chars (f, ip->insn_opcode, 4);
- else if (reloc_type == BFD_RELOC_MIPS16_JMP)
+ else if (*reloc_type == BFD_RELOC_MIPS16_JMP)
{
md_number_to_chars (f, ip->insn_opcode >> 16, 2);
md_number_to_chars (f + 2, ip->insn_opcode & 0xffff, 2);
@@ -2235,7 +2353,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
/* If the previous instruction had a fixup in mips16
mode, we can not swap. This normally means that the
previous instruction was a 4 byte branch anyhow. */
- || (mips_opts.mips16 && prev_insn_fixp)
+ || (mips_opts.mips16 && prev_insn_fixp[0])
/* If the previous instruction is a sync, sync.l, or
sync.p, we can not swap. */
|| (prev_pinfo & INSN_SYNC))
@@ -2261,15 +2379,35 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
memcpy (temp, prev_f, 4);
memcpy (prev_f, f, 4);
memcpy (f, temp, 4);
- if (prev_insn_fixp)
+ if (prev_insn_fixp[0])
+ {
+ prev_insn_fixp[0]->fx_frag = frag_now;
+ prev_insn_fixp[0]->fx_where = f - frag_now->fr_literal;
+ }
+ if (prev_insn_fixp[1])
+ {
+ prev_insn_fixp[1]->fx_frag = frag_now;
+ prev_insn_fixp[1]->fx_where = f - frag_now->fr_literal;
+ }
+ if (prev_insn_fixp[2])
{
- prev_insn_fixp->fx_frag = frag_now;
- prev_insn_fixp->fx_where = f - frag_now->fr_literal;
+ prev_insn_fixp[2]->fx_frag = frag_now;
+ prev_insn_fixp[2]->fx_where = f - frag_now->fr_literal;
}
- if (fixp)
+ if (fixp[0])
{
- fixp->fx_frag = prev_insn_frag;
- fixp->fx_where = prev_insn_where;
+ fixp[0]->fx_frag = prev_insn_frag;
+ fixp[0]->fx_where = prev_insn_where;
+ }
+ if (fixp[1])
+ {
+ fixp[1]->fx_frag = prev_insn_frag;
+ fixp[1]->fx_where = prev_insn_where;
+ }
+ if (fixp[2])
+ {
+ fixp[2]->fx_frag = prev_insn_frag;
+ fixp[2]->fx_where = prev_insn_where;
}
}
else
@@ -2277,13 +2415,15 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
char *prev_f;
char temp[2];
- assert (prev_insn_fixp == NULL);
+ assert (prev_insn_fixp[0] == NULL);
+ assert (prev_insn_fixp[1] == NULL);
+ assert (prev_insn_fixp[2] == NULL);
prev_f = prev_insn_frag->fr_literal + prev_insn_where;
memcpy (temp, prev_f, 2);
memcpy (prev_f, f, 2);
- if (reloc_type != BFD_RELOC_MIPS16_JMP)
+ if (*reloc_type != BFD_RELOC_MIPS16_JMP)
{
- assert (reloc_type == BFD_RELOC_UNUSED);
+ assert (*reloc_type == BFD_RELOC_UNUSED);
memcpy (f, temp, 2);
}
else
@@ -2291,10 +2431,20 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
memcpy (f, f + 2, 2);
memcpy (f + 2, temp, 2);
}
- if (fixp)
+ if (fixp[0])
+ {
+ fixp[0]->fx_frag = prev_insn_frag;
+ fixp[0]->fx_where = prev_insn_where;
+ }
+ if (fixp[1])
+ {
+ fixp[1]->fx_frag = prev_insn_frag;
+ fixp[1]->fx_where = prev_insn_where;
+ }
+ if (fixp[2])
{
- fixp->fx_frag = prev_insn_frag;
- fixp->fx_where = prev_insn_where;
+ fixp[2]->fx_frag = prev_insn_frag;
+ fixp[2]->fx_where = prev_insn_where;
}
}
@@ -2312,8 +2462,12 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
prev_insn.insn_mo = &dummy_opcode;
}
- prev_insn_fixp = NULL;
- prev_insn_reloc_type = BFD_RELOC_UNUSED;
+ prev_insn_fixp[0] = NULL;
+ prev_insn_fixp[1] = NULL;
+ prev_insn_fixp[2] = NULL;
+ prev_insn_reloc_type[0] = BFD_RELOC_UNUSED;
+ prev_insn_reloc_type[1] = BFD_RELOC_UNUSED;
+ prev_insn_reloc_type[2] = BFD_RELOC_UNUSED;
prev_insn_extended = 0;
}
else if (pinfo & INSN_COND_BRANCH_LIKELY)
@@ -2326,8 +2480,12 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
/* Update the previous insn information. */
prev_prev_insn = *ip;
prev_insn.insn_mo = &dummy_opcode;
- prev_insn_fixp = NULL;
- prev_insn_reloc_type = BFD_RELOC_UNUSED;
+ prev_insn_fixp[0] = NULL;
+ prev_insn_fixp[1] = NULL;
+ prev_insn_fixp[2] = NULL;
+ prev_insn_reloc_type[0] = BFD_RELOC_UNUSED;
+ prev_insn_reloc_type[1] = BFD_RELOC_UNUSED;
+ prev_insn_reloc_type[2] = BFD_RELOC_UNUSED;
prev_insn_extended = 0;
}
else
@@ -2344,11 +2502,15 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
is not in a delay slot. */
prev_insn_is_delay_slot = 0;
- prev_insn_fixp = fixp;
- prev_insn_reloc_type = reloc_type;
+ prev_insn_fixp[0] = fixp[0];
+ prev_insn_fixp[1] = fixp[1];
+ prev_insn_fixp[2] = fixp[2];
+ prev_insn_reloc_type[0] = reloc_type[0];
+ prev_insn_reloc_type[1] = reloc_type[1];
+ prev_insn_reloc_type[2] = reloc_type[2];
if (mips_opts.mips16)
prev_insn_extended = (ip->use_extend
- || reloc_type > BFD_RELOC_UNUSED);
+ || *reloc_type > BFD_RELOC_UNUSED);
}
prev_prev_insn_unreordered = prev_insn_unreordered;
@@ -2364,7 +2526,9 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
PC relative relocs. */
prev_prev_insn = prev_insn;
prev_insn = *ip;
- prev_insn_reloc_type = reloc_type;
+ prev_insn_reloc_type[0] = reloc_type[0];
+ prev_insn_reloc_type[1] = reloc_type[1];
+ prev_insn_reloc_type[2] = reloc_type[2];
prev_prev_insn_unreordered = prev_insn_unreordered;
prev_insn_unreordered = 1;
}
@@ -2404,7 +2568,9 @@ mips_no_prev_insn (preserve)
prev_insn_is_delay_slot = 0;
prev_insn_unreordered = 0;
prev_insn_extended = 0;
- prev_insn_reloc_type = BFD_RELOC_UNUSED;
+ prev_insn_reloc_type[0] = BFD_RELOC_UNUSED;
+ prev_insn_reloc_type[1] = BFD_RELOC_UNUSED;
+ prev_insn_reloc_type[2] = BFD_RELOC_UNUSED;
prev_prev_insn_unreordered = 0;
mips_clear_insn_labels ();
}
@@ -2544,7 +2710,7 @@ macro_build (place, counter, ep, name, fmt, va_alist)
#endif
{
struct mips_cl_insn insn;
- bfd_reloc_code_real_type r;
+ bfd_reloc_code_real_type r[3];
va_list args;
#ifdef USE_STDARG
@@ -2571,7 +2737,9 @@ macro_build (place, counter, ep, name, fmt, va_alist)
return;
}
- r = BFD_RELOC_UNUSED;
+ r[0] = BFD_RELOC_UNUSED;
+ r[1] = BFD_RELOC_UNUSED;
+ r[2] = BFD_RELOC_UNUSED;
insn.insn_mo = (struct mips_opcode *) hash_find (op_hash, name);
assert (insn.insn_mo);
assert (strcmp (name, insn.insn_mo->name) == 0);
@@ -2670,35 +2838,33 @@ macro_build (place, counter, ep, name, fmt, va_alist)
case 'i':
case 'j':
case 'o':
- r = (bfd_reloc_code_real_type) va_arg (args, int);
- assert (r == BFD_RELOC_MIPS_GPREL
- || r == BFD_RELOC_MIPS_LITERAL
- || r == BFD_RELOC_LO16
- || r == BFD_RELOC_MIPS_GOT16
- || r == BFD_RELOC_MIPS_CALL16
- || r == BFD_RELOC_MIPS_GOT_LO16
- || r == BFD_RELOC_MIPS_CALL_LO16
+ *r = (bfd_reloc_code_real_type) va_arg (args, int);
+ assert (*r == BFD_RELOC_MIPS_GPREL
+ || *r == BFD_RELOC_MIPS_LITERAL
+ || *r == BFD_RELOC_MIPS_HIGHER
+ || *r == BFD_RELOC_HI16_S
+ || *r == BFD_RELOC_LO16
+ || *r == BFD_RELOC_MIPS_GOT16
+ || *r == BFD_RELOC_MIPS_CALL16
+ || *r == BFD_RELOC_MIPS_GOT_LO16
+ || *r == BFD_RELOC_MIPS_CALL_LO16
|| (ep->X_op == O_subtract
- && r == BFD_RELOC_PCREL_LO16));
+ && *r == BFD_RELOC_PCREL_LO16));
continue;
case 'u':
- r = (bfd_reloc_code_real_type) va_arg (args, int);
+ *r = (bfd_reloc_code_real_type) va_arg (args, int);
assert (ep != NULL
&& (ep->X_op == O_constant
|| (ep->X_op == O_symbol
- && (r == BFD_RELOC_HI16_S
- || r == BFD_RELOC_HI16
- || r == BFD_RELOC_MIPS_GOT_HI16
- || r == BFD_RELOC_MIPS_CALL_HI16))
+ && (*r == BFD_RELOC_MIPS_HIGHEST
+ || *r == BFD_RELOC_HI16_S
+ || *r == BFD_RELOC_HI16
+ || *r == BFD_RELOC_GPREL16
+ || *r == BFD_RELOC_MIPS_GOT_HI16
+ || *r == BFD_RELOC_MIPS_CALL_HI16))
|| (ep->X_op == O_subtract
- && r == BFD_RELOC_PCREL_HI16_S)));
- if (ep->X_op == O_constant)
- {
- insn.insn_opcode |= (ep->X_add_number >> 16) & 0xffff;
- ep = NULL;
- r = BFD_RELOC_UNUSED;
- }
+ && *r == BFD_RELOC_PCREL_HI16_S)));
continue;
case 'p':
@@ -2717,14 +2883,14 @@ macro_build (place, counter, ep, name, fmt, va_alist)
}
else
if (mips_pic == EMBEDDED_PIC)
- r = BFD_RELOC_16_PCREL_S2;
+ *r = BFD_RELOC_16_PCREL_S2;
else
- r = BFD_RELOC_16_PCREL;
+ *r = BFD_RELOC_16_PCREL;
continue;
case 'a':
assert (ep != NULL);
- r = BFD_RELOC_MIPS_JMP;
+ *r = BFD_RELOC_MIPS_JMP;
continue;
case 'C':
@@ -2737,7 +2903,7 @@ macro_build (place, counter, ep, name, fmt, va_alist)
break;
}
va_end (args);
- assert (r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
+ assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
append_insn (place, &insn, ep, r, false);
}
@@ -2752,9 +2918,9 @@ mips16_macro_build (place, counter, ep, name, fmt, args)
va_list args;
{
struct mips_cl_insn insn;
- bfd_reloc_code_real_type r;
+ bfd_reloc_code_real_type r[3]
+ = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
- r = BFD_RELOC_UNUSED;
insn.insn_mo = (struct mips_opcode *) hash_find (mips16_op_hash, name);
assert (insn.insn_mo);
assert (strcmp (name, insn.insn_mo->name) == 0);
@@ -2843,14 +3009,14 @@ mips16_macro_build (place, counter, ep, name, fmt, args)
assert (ep != NULL);
if (ep->X_op != O_constant)
- r = BFD_RELOC_UNUSED + c;
+ *r = BFD_RELOC_UNUSED + c;
else
{
mips16_immed ((char *) NULL, 0, c, ep->X_add_number, false,
false, false, &insn.insn_opcode,
&insn.use_extend, &insn.extend);
ep = NULL;
- r = BFD_RELOC_UNUSED;
+ *r = BFD_RELOC_UNUSED;
}
}
continue;
@@ -2863,7 +3029,7 @@ mips16_macro_build (place, counter, ep, name, fmt, args)
break;
}
- assert (r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
+ assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
append_insn (place, &insn, ep, r, false);
}
@@ -2880,7 +3046,8 @@ macro_build_lui (place, counter, ep, regnum)
{
expressionS high_expr;
struct mips_cl_insn insn;
- bfd_reloc_code_real_type r;
+ bfd_reloc_code_real_type r[3]
+ = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
CONST char *name = "lui";
CONST char *fmt = "t,u";
@@ -2899,15 +3066,15 @@ macro_build_lui (place, counter, ep, regnum)
/* we can compute the instruction now without a relocation entry */
high_expr.X_add_number = ((high_expr.X_add_number + 0x8000)
>> 16) & 0xffff;
- r = BFD_RELOC_UNUSED;
+ *r = BFD_RELOC_UNUSED;
}
- else
+ else if (! HAVE_NEWABI)
{
assert (ep->X_op == O_symbol);
/* _gp_disp is a special case, used from s_cpload. */
assert (mips_pic == NO_PIC
|| strcmp (S_GET_NAME (ep->X_add_symbol), "_gp_disp") == 0);
- r = BFD_RELOC_HI16_S;
+ *r = BFD_RELOC_HI16_S;
}
/*
@@ -2927,7 +3094,7 @@ macro_build_lui (place, counter, ep, regnum)
assert (strcmp (fmt, insn.insn_mo->args) == 0);
insn.insn_opcode = insn.insn_mo->match | (regnum << OP_SH_RT);
- if (r == BFD_RELOC_UNUSED)
+ if (*r == BFD_RELOC_UNUSED)
{
insn.insn_opcode |= high_expr.X_add_number;
append_insn (place, &insn, NULL, r, false);
@@ -7492,7 +7659,7 @@ mips_ip (str, ip)
case 'A':
my_getExpression (&offset_expr, s);
- imm_reloc = BFD_RELOC_32;
+ *imm_reloc = BFD_RELOC_32;
s = expr_end;
continue;
@@ -7704,7 +7871,7 @@ mips_ip (str, ip)
case 'i': /* 16 bit unsigned immediate */
case 'j': /* 16 bit signed immediate */
- imm_reloc = BFD_RELOC_LO16;
+ *imm_reloc = BFD_RELOC_LO16;
c = my_getSmallExpression (&imm_expr, s);
if (c != S_EX_NONE)
{
@@ -7714,16 +7881,16 @@ mips_ip (str, ip)
imm_expr.X_add_number =
(imm_expr.X_add_number >> 16) & 0xffff;
else if (c == S_EX_HIGHEST)
- imm_reloc = BFD_RELOC_MIPS_HIGHEST;
+ *imm_reloc = BFD_RELOC_MIPS_HIGHEST;
else if (c == S_EX_HIGHER)
- imm_reloc = BFD_RELOC_MIPS_HIGHER;
+ *imm_reloc = BFD_RELOC_MIPS_HIGHER;
else if (c == S_EX_HI)
{
- imm_reloc = BFD_RELOC_HI16_S;
+ *imm_reloc = BFD_RELOC_HI16_S;
imm_unmatched_hi = true;
}
else
- imm_reloc = BFD_RELOC_HI16;
+ *imm_reloc = BFD_RELOC_HI16;
}
else if (imm_expr.X_op == O_constant)
imm_expr.X_add_number &= 0xffff;
@@ -7814,22 +7981,22 @@ mips_ip (str, ip)
offset_expr.X_add_number =
(offset_expr.X_add_number >> 16) & 0xffff;
}
- offset_reloc = BFD_RELOC_LO16;
+ *offset_reloc = BFD_RELOC_LO16;
s = expr_end;
continue;
case 'p': /* pc relative offset */
if (mips_pic == EMBEDDED_PIC)
- offset_reloc = BFD_RELOC_16_PCREL_S2;
+ *offset_reloc = BFD_RELOC_16_PCREL_S2;
else
- offset_reloc = BFD_RELOC_16_PCREL;
+ *offset_reloc = BFD_RELOC_16_PCREL;
my_getExpression (&offset_expr, s);
s = expr_end;
continue;
case 'u': /* upper 16 bits */
c = my_getSmallExpression (&imm_expr, s);
- imm_reloc = BFD_RELOC_LO16;
+ *imm_reloc = BFD_RELOC_LO16;
if (c != S_EX_NONE)
{
if (c != S_EX_LO)
@@ -7838,14 +8005,14 @@ mips_ip (str, ip)
imm_expr.X_add_number =
(imm_expr.X_add_number >> 16) & 0xffff;
else if (c == S_EX_HIGHEST)
- imm_reloc = BFD_RELOC_MIPS_HIGHEST;
+ *imm_reloc = BFD_RELOC_MIPS_HIGHEST;
else if (c == S_EX_HI)
{
- imm_reloc = BFD_RELOC_HI16_S;
+ *imm_reloc = BFD_RELOC_HI16_S;
imm_unmatched_hi = true;
}
else
- imm_reloc = BFD_RELOC_HI16;
+ *imm_reloc = BFD_RELOC_HI16;
}
else if (imm_expr.X_op == O_constant)
imm_expr.X_add_number &= 0xffff;
@@ -7860,7 +8027,7 @@ mips_ip (str, ip)
case 'a': /* 26 bit address */
my_getExpression (&offset_expr, s);
s = expr_end;
- offset_reloc = BFD_RELOC_MIPS_JMP;
+ *offset_reloc = BFD_RELOC_MIPS_JMP;
continue;
case 'N': /* 3 bit branch condition code */
@@ -8003,9 +8170,13 @@ mips16_ip (str, ip)
ip->insn_opcode = insn->match;
ip->use_extend = false;
imm_expr.X_op = O_absent;
- imm_reloc = BFD_RELOC_UNUSED;
+ imm_reloc[0] = BFD_RELOC_UNUSED;
+ imm_reloc[1] = BFD_RELOC_UNUSED;
+ imm_reloc[2] = BFD_RELOC_UNUSED;
offset_expr.X_op = O_absent;
- offset_reloc = BFD_RELOC_UNUSED;
+ offset_reloc[0] = BFD_RELOC_UNUSED;
+ offset_reloc[1] = BFD_RELOC_UNUSED;
+ offset_reloc[2] = BFD_RELOC_UNUSED;
for (args = insn->args; 1; ++args)
{
int c;
@@ -8025,16 +8196,16 @@ mips16_ip (str, ip)
{
/* Stuff the immediate value in now, if we can. */
if (imm_expr.X_op == O_constant
- && imm_reloc > BFD_RELOC_UNUSED
+ && *imm_reloc > BFD_RELOC_UNUSED
&& insn->pinfo != INSN_MACRO)
{
mips16_immed ((char *) NULL, 0,
- imm_reloc - BFD_RELOC_UNUSED,
+ *imm_reloc - BFD_RELOC_UNUSED,
imm_expr.X_add_number, true, mips16_small,
mips16_ext, &ip->insn_opcode,
&ip->use_extend, &ip->extend);
imm_expr.X_op = O_absent;
- imm_reloc = BFD_RELOC_UNUSED;
+ *imm_reloc = BFD_RELOC_UNUSED;
}
return;
@@ -8259,7 +8430,7 @@ mips16_ip (str, ip)
if (imm_expr.X_op == O_symbol)
{
mips16_ext = true;
- imm_reloc = BFD_RELOC_MIPS16_GPREL;
+ *imm_reloc = BFD_RELOC_MIPS16_GPREL;
s = expr_end;
ip->use_extend = true;
ip->extend = 0;
@@ -8286,7 +8457,7 @@ mips16_ip (str, ip)
explicit extensions correctly. */
imm_expr.X_op = O_constant;
imm_expr.X_add_number = 0;
- imm_reloc = (int) BFD_RELOC_UNUSED + c;
+ *imm_reloc = (int) BFD_RELOC_UNUSED + c;
continue;
}
@@ -8294,7 +8465,7 @@ mips16_ip (str, ip)
}
/* We need to relax this instruction. */
- imm_reloc = (int) BFD_RELOC_UNUSED + c;
+ *imm_reloc = (int) BFD_RELOC_UNUSED + c;
s = expr_end;
continue;
@@ -8312,7 +8483,7 @@ mips16_ip (str, ip)
break;
/* We need to relax this instruction. */
- offset_reloc = (int) BFD_RELOC_UNUSED + c;
+ *offset_reloc = (int) BFD_RELOC_UNUSED + c;
s = expr_end;
continue;
@@ -8334,7 +8505,7 @@ mips16_ip (str, ip)
case 'a': /* 26 bit address */
my_getExpression (&offset_expr, s);
s = expr_end;
- offset_reloc = BFD_RELOC_MIPS16_JMP;
+ *offset_reloc = BFD_RELOC_MIPS16_JMP;
ip->insn_opcode <<= 16;
continue;
@@ -9590,7 +9761,10 @@ mips_frob_file ()
/* When generating embedded PIC code we must keep all PC relative
relocations, in case the linker has to relax a call. We also need
- to keep relocations for switch table entries. */
+ to keep relocations for switch table entries.
+
+ We may have combined relocations without symbols in the N32/N64 ABI.
+ We have to prevent gas from dropping them. */
int
mips_force_relocation (fixp)
@@ -9600,6 +9774,13 @@ mips_force_relocation (fixp)
|| fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
return 1;
+ if (HAVE_NEWABI
+ && S_GET_SEGMENT (fixp->fx_addsy) == bfd_abs_section_ptr
+ && (fixp->fx_r_type == BFD_RELOC_MIPS_SUB
+ || fixp->fx_r_type == BFD_RELOC_HI16_S
+ || fixp->fx_r_type == BFD_RELOC_LO16))
+ return 1;
+
return (mips_pic == EMBEDDED_PIC
&& (fixp->fx_pcrel
|| SWITCH_TABLE (fixp)
@@ -9620,7 +9801,21 @@ md_apply_fix (fixP, valueP)
assert (fixP->fx_size == 4
|| fixP->fx_r_type == BFD_RELOC_16
+ || fixP->fx_r_type == BFD_RELOC_32
+ || fixP->fx_r_type == BFD_RELOC_MIPS_JMP
+ || fixP->fx_r_type == BFD_RELOC_HI16_S
+ || fixP->fx_r_type == BFD_RELOC_LO16
+ || fixP->fx_r_type == BFD_RELOC_GPREL16
+ || fixP->fx_r_type == BFD_RELOC_MIPS_LITERAL
+ || fixP->fx_r_type == BFD_RELOC_GPREL32
|| fixP->fx_r_type == BFD_RELOC_64
+ || fixP->fx_r_type == BFD_RELOC_CTOR
+ || fixP->fx_r_type == BFD_RELOC_MIPS_SUB
+ || fixP->fx_r_type == BFD_RELOC_MIPS_HIGHEST
+ || fixP->fx_r_type == BFD_RELOC_MIPS_HIGHER
+ || fixP->fx_r_type == BFD_RELOC_MIPS_SCN_DISP
+ || fixP->fx_r_type == BFD_RELOC_MIPS_REL16
+ || fixP->fx_r_type == BFD_RELOC_MIPS_RELGOT
|| fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY);