* 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.
This commit is contained in:
Ian Lance Taylor 1996-03-28 20:37:02 +00:00
parent d0352cbbe8
commit 867a58b368
3 changed files with 168 additions and 22 deletions

View File

@ -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*.

View File

@ -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

View File

@ -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 ();