aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog14
-rw-r--r--gas/config/tc-mips.c172
-rw-r--r--gas/config/tc-mips.h4
3 files changed, 168 insertions, 22 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 763d0b5..d2d1a05 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,17 @@
+Thu Mar 28 15:27:47 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * config/tc-mips.h (tc_frob_file): Define.
+ (mips_frob_file): Declare.
+ * config/tc-mips.c (struct mips_hi_fixup): Define.
+ (mips_hi_fixup_list): New static variable.
+ (imm_unmatched_hi): New static variable.
+ (md_assemble): Clear imm_reloc, imm_unmatched_hi, and
+ offset_reloc. Pass imm_unmatched_hi to append_insn.
+ (append_insn): Add unmatched_hi parameter. If it is set, add the
+ new fixup to mips_hi_fixup_list. Change all callers.
+ (mips_ip): Set imm_unmatched_hi when appropriate.
+ (mips_frob_file): New function.
+
Thu Mar 28 11:47:59 1996 Doug Evans <dje@canuck.cygnus.com>
* configure.in (sparc-*-solaris2*): Renamed from sparc*-*-solaris2*.
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index da69803..19b271d 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -292,6 +292,31 @@ static int prev_insn_unreordered;
/* Non-zero if the previous previous instruction was in a .set
noreorder. */
static int prev_prev_insn_unreordered;
+
+/* For ECOFF and ELF, relocations against symbols are done in two
+ parts, with a HI relocation and a LO relocation. Each relocation
+ has only 16 bits of space to store an addend. This means that in
+ order for the linker to handle carries correctly, it must be able
+ to locate both the HI and the LO relocation. This means that the
+ relocations must appear in order in the relocation table.
+
+ In order to implement this, we keep track of each unmatched HI
+ relocation. We then sort them so that they immediately precede the
+ corresponding LO relocation. */
+
+struct mips_hi_fixup
+{
+ /* Next HI fixup. */
+ struct mips_hi_fixup *next;
+ /* This fixup. */
+ fixS *fixp;
+ /* The section this fixup is in. */
+ segT seg;
+};
+
+/* The list of unmatched HI relocs. */
+
+static struct mips_hi_fixup *mips_hi_fixup_list;
/* Since the MIPS does not have multiple forms of PC relative
instructions, we do not have to do relaxing as is done on other
@@ -384,7 +409,8 @@ static int reg_needs_delay PARAMS ((int));
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 ((void));
static void mips_emit_delays PARAMS ((void));
#ifdef USE_STDARG
@@ -519,11 +545,21 @@ mips_pop_insert ()
static char *expr_end;
+/* Expressions which appear in instructions. These are set by
+ mips_ip. */
+
static expressionS imm_expr;
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;
+/* This is set by mips_ip if imm_reloc is an unmatched HI16_S reloc. */
+
+static boolean imm_unmatched_hi;
+
/*
* This function is called once, at assembler startup time. It should
* set up all the tables, etc. that the MD part of the assembler will need.
@@ -775,7 +811,10 @@ md_assemble (str)
struct mips_cl_insn insn;
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;
mips_ip (str, &insn);
if (insn_error)
@@ -790,11 +829,12 @@ md_assemble (str)
else
{
if (imm_expr.X_op != O_absent)
- append_insn ((char *) NULL, &insn, &imm_expr, imm_reloc);
+ append_insn ((char *) NULL, &insn, &imm_expr, imm_reloc,
+ imm_unmatched_hi);
else if (offset_expr.X_op != O_absent)
- append_insn ((char *) NULL, &insn, &offset_expr, offset_reloc);
+ append_insn ((char *) NULL, &insn, &offset_expr, offset_reloc, false);
else
- append_insn ((char *) NULL, &insn, NULL, BFD_RELOC_UNUSED);
+ append_insn ((char *) NULL, &insn, NULL, BFD_RELOC_UNUSED, false);
}
}
@@ -876,11 +916,12 @@ reg_needs_delay (reg)
used with RELOC_TYPE. */
static void
-append_insn (place, ip, address_expr, reloc_type)
+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;
+ boolean unmatched_hi;
{
register unsigned long prev_pinfo, pinfo;
char *f;
@@ -1112,10 +1153,24 @@ append_insn (place, ip, address_expr, reloc_type)
/* 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_S2,
- reloc_type);
+ {
+ fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 4,
+ address_expr,
+ reloc_type == BFD_RELOC_16_PCREL_S2,
+ reloc_type);
+ if (unmatched_hi)
+ {
+ struct mips_hi_fixup *hi_fixup;
+
+ 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->seg = now_seg;
+ hi_fixup->next = mips_hi_fixup_list;
+ mips_hi_fixup_list = hi_fixup;
+ }
+ }
}
}
@@ -1633,7 +1688,7 @@ macro_build (place, counter, ep, name, fmt, va_alist)
va_end (args);
assert (r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
- append_insn (place, &insn, ep, r);
+ append_insn (place, &insn, ep, r, false);
}
/*
@@ -1698,10 +1753,10 @@ macro_build_lui (place, counter, ep, regnum)
if (r == BFD_RELOC_UNUSED)
{
insn.insn_opcode |= high_expr.X_add_number;
- append_insn (place, &insn, NULL, r);
+ append_insn (place, &insn, NULL, r, false);
}
else
- append_insn (place, &insn, &high_expr, r);
+ append_insn (place, &insn, &high_expr, r, false);
}
/* set_at()
@@ -3648,7 +3703,8 @@ macro (ip)
"d,v,t", tempreg, tempreg, GP);
macro_build ((char *) NULL, &icnt, &offset_expr,
mips_isa < 3 ? "lw" : "ld",
- "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT_LO16);
+ "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT_LO16,
+ tempreg);
p = frag_var (rs_machine_dependent, 12 + gpdel, 0,
RELAX_ENCODE (12, 12 + gpdel, gpdel, 8 + gpdel, 0, 0),
offset_expr.X_add_symbol, (long) 0, (char *) NULL);
@@ -3659,7 +3715,7 @@ macro (ip)
}
macro_build (p, &icnt, &offset_expr,
mips_isa < 3 ? "lw" : "ld",
- "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16);
+ "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16, GP);
p += 4;
macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
p += 4;
@@ -4904,12 +4960,11 @@ macro2 (ip)
as_warn ("Macro used $at after \".set noat\"");
}
+/* This routine assembles an instruction into its binary format. As a
+ side effect, it sets one of the global variables imm_reloc or
+ offset_reloc to the type of relocation to do if one of the operands
+ is an address expression. */
-/*
-This routine assembles an instruction into its binary format. As a side
-effect it sets one of the global variables imm_reloc or offset_reloc to the
-type of relocation to do if one of the operands is an address expression.
-*/
static void
mips_ip (str, ip)
char *str;
@@ -5478,7 +5533,10 @@ mips_ip (str, ip)
imm_expr.X_add_number =
(imm_expr.X_add_number >> 16) & 0xffff;
else if (c == 'h')
- imm_reloc = BFD_RELOC_HI16_S;
+ {
+ imm_reloc = BFD_RELOC_HI16_S;
+ imm_unmatched_hi = true;
+ }
else
imm_reloc = BFD_RELOC_HI16;
}
@@ -5590,7 +5648,10 @@ mips_ip (str, ip)
imm_expr.X_add_number =
(imm_expr.X_add_number >> 16) & 0xffff;
else if (c == 'h')
- imm_reloc = BFD_RELOC_HI16_S;
+ {
+ imm_reloc = BFD_RELOC_HI16_S;
+ imm_unmatched_hi = true;
+ }
else
imm_reloc = BFD_RELOC_HI16;
}
@@ -6240,6 +6301,75 @@ cons_fix_new_mips (frag, where, nbytes, exp)
nbytes == 2 ? BFD_RELOC_16 : BFD_RELOC_32);
}
+/* Sort any unmatched HI16_S relocs so that they immediately precede
+ the corresponding LO reloc. This is called before md_apply_fix and
+ tc_gen_reloc. Unmatched HI16_S relocs can only be generated by
+ explicit use of the %hi modifier. */
+
+void
+mips_frob_file ()
+{
+ struct mips_hi_fixup *l;
+
+ for (l = mips_hi_fixup_list; l != NULL; l = l->next)
+ {
+ segment_info_type *seginfo;
+ fixS *f, *prev;
+
+ assert (l->fixp->fx_r_type == BFD_RELOC_HI16_S);
+
+ /* Check quickly whether the next fixup happens to be a matching
+ %lo. */
+ if (l->fixp->fx_next != NULL
+ && l->fixp->fx_next->fx_r_type == BFD_RELOC_LO16
+ && l->fixp->fx_addsy == l->fixp->fx_next->fx_addsy
+ && l->fixp->fx_offset == l->fixp->fx_next->fx_offset)
+ continue;
+
+ /* Look through the fixups for this segment for a matching %lo.
+ When we find one, move the %hi just in front of it. */
+ seginfo = seg_info (l->seg);
+ prev = NULL;
+ for (f = seginfo->fix_root; f != NULL; f = f->fx_next)
+ {
+ /* Check whether this is a %lo fixup which matches l->fixp;
+ we can't use it if the %lo is already matching a %hi. */
+ if (f->fx_r_type == BFD_RELOC_LO16
+ && f->fx_addsy == l->fixp->fx_addsy
+ && f->fx_offset == l->fixp->fx_offset
+ && (prev == NULL
+ || prev->fx_r_type != BFD_RELOC_HI16_S
+ || prev->fx_addsy != f->fx_addsy
+ || prev->fx_offset != f->fx_offset))
+ {
+ fixS **pf;
+
+ /* Move l->fixp before f. */
+ for (pf = &seginfo->fix_root;
+ *pf != l->fixp;
+ pf = &(*pf)->fx_next)
+ assert (*pf != NULL);
+
+ *pf = l->fixp->fx_next;
+
+ l->fixp->fx_next = f;
+ if (prev == NULL)
+ seginfo->fix_root = l->fixp;
+ else
+ prev->fx_next = l->fixp;
+
+ break;
+ }
+
+ prev = f;
+ }
+
+ if (f == NULL)
+ as_warn_where (l->fixp->fx_file, l->fixp->fx_line,
+ "Unmatched %%hi reloc");
+ }
+}
+
/* When generating embedded PIC code we need to use a special
relocation to represent the difference of two symbols in the .text
section (switch tables use a difference of this sort). See
diff --git a/gas/config/tc-mips.h b/gas/config/tc-mips.h
index a701e76..c8672b7 100644
--- a/gas/config/tc-mips.h
+++ b/gas/config/tc-mips.h
@@ -27,7 +27,6 @@
#define TARGET_ARCH bfd_arch_mips
#define ONLY_STANDARD_ESCAPES
-#define BACKSLASH_V
#define WORKING_DOT_WORD 1
#define OLD_FLOAT_READS
#define REPEAT_CONS_EXPRESSIONS
@@ -79,6 +78,9 @@ extern int mips_parse_long_option PARAMS ((const char *));
#define tc_frob_label(sym) mips_define_label (sym)
extern void mips_define_label PARAMS ((struct symbol *));
+#define tc_frob_file() mips_frob_file ()
+extern void mips_frob_file PARAMS ((void));
+
#define TC_CONS_FIX_NEW cons_fix_new_mips
extern void cons_fix_new_mips ();