mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-25 13:27:26 +08:00
* config/tc-sparc.c (enforce_aligned_data): New static variable.
(sparc_cons_align): Don't do anything unless enforce_aligned_data is set. (md_longopts): Add "enforce-aligned-data". (md_show_usage): Mention --enforce-aligned-data. * doc/c-sparc.texi (Sparc-Aligned-Data): New node; document enforce-aligned-data.
This commit is contained in:
@ -5,6 +5,14 @@ Fri Jan 31 13:15:05 1997 Alan Modra <alan@spri.levels.unisa.edu.au>
|
||||
|
||||
Fri Jan 31 10:46:14 1997 Ian Lance Taylor <ian@cygnus.com>
|
||||
|
||||
* config/tc-sparc.c (enforce_aligned_data): New static variable.
|
||||
(sparc_cons_align): Don't do anything unless enforce_aligned_data
|
||||
is set.
|
||||
(md_longopts): Add "enforce-aligned-data".
|
||||
(md_show_usage): Mention --enforce-aligned-data.
|
||||
* doc/c-sparc.texi (Sparc-Aligned-Data): New node; document
|
||||
enforce-aligned-data.
|
||||
|
||||
* config/tc-ppc.c (md_pseudo_table): If OBJ_XCOFF, add "long",
|
||||
"word", and "short".
|
||||
(ppc_xcoff_cons): New static function.
|
||||
|
@ -34,7 +34,7 @@ static enum sparc_opcode_arch_val current_architecture = SPARC_OPCODE_ARCH_V6;
|
||||
|
||||
/* The maximum architecture level we can bump up to.
|
||||
In a 32 bit environment, don't allow bumping up to v9 by default.
|
||||
The native assembler works this way. The user is required to pass
|
||||
The native assembler works this way. The user is required to pass
|
||||
an explicit argument before we'll create v9 object files. However, if
|
||||
we don't see any v9 insns, a v9 object file is not created. */
|
||||
#ifdef SPARC_ARCH64
|
||||
@ -56,8 +56,18 @@ static enum sparc_opcode_arch_val warn_after_architecture;
|
||||
/* Non-zero if we are generating PIC code. */
|
||||
int sparc_pic_code;
|
||||
|
||||
/* Non-zero if we should give an error when misaligned data is seen. */
|
||||
static int enforce_aligned_data;
|
||||
|
||||
extern int target_big_endian;
|
||||
|
||||
/* V9 has big and little endian data, but instructions are always big endian.
|
||||
The sparclet has bi-endian support but both data and insns have the same
|
||||
endianness. Global `target_big_endian' is used for data. The following
|
||||
macro is used for instructions. */
|
||||
#define INSN_BIG_ENDIAN (target_big_endian \
|
||||
|| SPARC_OPCODE_ARCH_V9_P (max_architecture))
|
||||
|
||||
/* handle of the OPCODE hash table */
|
||||
static struct hash_control *op_hash;
|
||||
|
||||
@ -83,13 +93,16 @@ const pseudo_typeS md_pseudo_table[] =
|
||||
{"skip", s_space, 0},
|
||||
{"word", cons, 4},
|
||||
{"xword", cons, 8},
|
||||
{"uahalf", s_uacons, 2},
|
||||
{"uaword", s_uacons, 4},
|
||||
{"uaxword", s_uacons, 8},
|
||||
#ifdef OBJ_ELF
|
||||
/* these are specific to sparc/svr4 */
|
||||
{"pushsection", obj_elf_section, 0},
|
||||
{"popsection", obj_elf_previous, 0},
|
||||
{"uahalf", s_uacons, 2},
|
||||
{"uaword", s_uacons, 4},
|
||||
{"uaxword", s_uacons, 8},
|
||||
{"2byte", s_uacons, 2},
|
||||
{"4byte", s_uacons, 4},
|
||||
{"8byte", s_uacons, 8},
|
||||
#endif
|
||||
{NULL, 0, 0},
|
||||
};
|
||||
@ -185,6 +198,17 @@ sparc_ffs (mask)
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Implement big shift right. */
|
||||
static bfd_vma
|
||||
BSR (val, amount)
|
||||
bfd_vma val;
|
||||
int amount;
|
||||
{
|
||||
if (sizeof (bfd_vma) <= 4 && amount >= 32)
|
||||
as_fatal ("Support for 64-bit arithmetic not compiled in.");
|
||||
return val >> amount;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void print_insn PARAMS ((struct sparc_it *insn));
|
||||
#endif
|
||||
@ -198,7 +222,18 @@ static int special_case;
|
||||
* 4 bytes.
|
||||
*/
|
||||
#define SPECIAL_CASE_SET 1
|
||||
#define SPECIAL_CASE_FDIV 2
|
||||
#define SPECIAL_CASE_SETSW 2
|
||||
#define SPECIAL_CASE_SETX 3
|
||||
/* FIXME: sparc-opc.c doesn't have necessary "S" trigger to enable this. */
|
||||
#define SPECIAL_CASE_FDIV 4
|
||||
|
||||
/* Bit masks of various insns. */
|
||||
#define NOP_INSN 0x01000000
|
||||
#define OR_INSN 0x80100000
|
||||
#define FMOVS_INSN 0x81A00020
|
||||
#define SETHI_INSN 0x01000000
|
||||
#define SLLX_INSN 0x81281000
|
||||
#define SRA_INSN 0x81380000
|
||||
|
||||
/* The last instruction to be assembled. */
|
||||
static const struct sparc_opcode *last_insn;
|
||||
@ -582,9 +617,16 @@ s_uacons (bytes)
|
||||
cons (bytes);
|
||||
}
|
||||
|
||||
/* We require .word, et. al., to be aligned correctly. We do it by
|
||||
setting up an rs_align_code frag, and checking in HANDLE_ALIGN to
|
||||
make sure that no unexpected alignment was introduced. */
|
||||
/* If the --enforce-aligned-data option is used, we require .word,
|
||||
et. al., to be aligned correctly. We do it by setting up an
|
||||
rs_align_code frag, and checking in HANDLE_ALIGN to make sure that
|
||||
no unexpected alignment was introduced.
|
||||
|
||||
The SunOS and Solaris native assemblers enforce aligned data by
|
||||
default. We don't want to do that, because gcc can deliberately
|
||||
generate misaligned data if the packed attribute is used. Instead,
|
||||
we permit misaligned data by default, and permit the user to set an
|
||||
option to check for it. */
|
||||
|
||||
void
|
||||
sparc_cons_align (nbytes)
|
||||
@ -593,6 +635,10 @@ sparc_cons_align (nbytes)
|
||||
int nalign;
|
||||
char *p;
|
||||
|
||||
/* Only do this if we are enforcing aligned data. */
|
||||
if (! enforce_aligned_data)
|
||||
return;
|
||||
|
||||
if (sparc_no_align_cons)
|
||||
{
|
||||
/* This is an unaligned pseudo-op. */
|
||||
@ -722,8 +768,6 @@ md_begin ()
|
||||
qsort (priv_reg_table, sizeof (priv_reg_table) / sizeof (priv_reg_table[0]),
|
||||
sizeof (priv_reg_table[0]), cmp_reg_entry);
|
||||
|
||||
target_big_endian = 1;
|
||||
|
||||
/* If -bump, record the architecture level at which we start issuing
|
||||
warnings. The behaviour is different depending upon whether an
|
||||
architecture was explicitly specified. If it wasn't, we issue warnings
|
||||
@ -776,19 +820,46 @@ sparc_md_end ()
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Utility to output one insn. */
|
||||
|
||||
static void
|
||||
output_insn (insn, the_insn)
|
||||
const struct sparc_opcode *insn;
|
||||
struct sparc_it *the_insn;
|
||||
{
|
||||
char *toP = frag_more (4);
|
||||
|
||||
/* put out the opcode */
|
||||
if (INSN_BIG_ENDIAN)
|
||||
number_to_chars_bigendian (toP, (valueT) the_insn->opcode, 4);
|
||||
else
|
||||
number_to_chars_littleendian (toP, (valueT) the_insn->opcode, 4);
|
||||
|
||||
/* put out the symbol-dependent stuff */
|
||||
if (the_insn->reloc != BFD_RELOC_NONE)
|
||||
{
|
||||
fix_new_exp (frag_now, /* which frag */
|
||||
(toP - frag_now->fr_literal), /* where */
|
||||
4, /* size */
|
||||
&the_insn->exp,
|
||||
the_insn->pcrel,
|
||||
the_insn->reloc);
|
||||
}
|
||||
|
||||
last_insn = insn;
|
||||
}
|
||||
|
||||
void
|
||||
md_assemble (str)
|
||||
char *str;
|
||||
{
|
||||
const struct sparc_opcode *insn;
|
||||
char *toP;
|
||||
int rsd;
|
||||
|
||||
know (str);
|
||||
special_case = 0;
|
||||
sparc_ip (str, &insn);
|
||||
|
||||
/* We warn about attempts to put a floating point branch in a delay
|
||||
slot. */
|
||||
/* We warn about attempts to put a floating point branch in a delay slot. */
|
||||
if (insn != NULL
|
||||
&& last_insn != NULL
|
||||
&& (insn->flags & F_FBR) != 0
|
||||
@ -804,97 +875,233 @@ md_assemble (str)
|
||||
&& (insn->flags & F_FBR) != 0
|
||||
&& (last_insn->flags & F_FLOAT) != 0)
|
||||
{
|
||||
struct sparc_it nop_insn;
|
||||
|
||||
nop_insn.opcode = NOP_INSN;
|
||||
nop_insn.reloc = BFD_RELOC_NONE;
|
||||
output_insn (insn, &nop_insn);
|
||||
as_warn ("FP branch preceded by FP instruction; NOP inserted");
|
||||
toP = frag_more (4);
|
||||
md_number_to_chars (toP, (valueT) 0x01000000, 4);
|
||||
}
|
||||
|
||||
/* See if "set" operand is absolute and small; skip sethi if so. */
|
||||
if (special_case == SPECIAL_CASE_SET
|
||||
&& the_insn.exp.X_op == O_constant)
|
||||
{
|
||||
if (the_insn.exp.X_add_number >= -(1 << 12)
|
||||
&& the_insn.exp.X_add_number < (1 << 12))
|
||||
{
|
||||
the_insn.opcode = 0x80102000 /* or %g0,imm,... */
|
||||
| (the_insn.opcode & 0x3E000000) /* dest reg */
|
||||
| (the_insn.exp.X_add_number & 0x1FFF); /* imm */
|
||||
special_case = 0; /* No longer special */
|
||||
the_insn.reloc = BFD_RELOC_NONE; /* No longer relocated */
|
||||
}
|
||||
}
|
||||
|
||||
toP = frag_more (4);
|
||||
/* put out the opcode */
|
||||
md_number_to_chars (toP, (valueT) the_insn.opcode, 4);
|
||||
|
||||
/* put out the symbol-dependent stuff */
|
||||
if (the_insn.reloc != BFD_RELOC_NONE)
|
||||
{
|
||||
fix_new_exp (frag_now, /* which frag */
|
||||
(toP - frag_now->fr_literal), /* where */
|
||||
4, /* size */
|
||||
&the_insn.exp,
|
||||
the_insn.pcrel,
|
||||
the_insn.reloc);
|
||||
}
|
||||
|
||||
last_insn = insn;
|
||||
|
||||
switch (special_case)
|
||||
{
|
||||
case 0:
|
||||
/* normal insn */
|
||||
output_insn (insn, &the_insn);
|
||||
break;
|
||||
|
||||
case SPECIAL_CASE_SET:
|
||||
special_case = 0;
|
||||
assert (the_insn.reloc == BFD_RELOC_HI22);
|
||||
/* See if "set" operand has no low-order bits; skip OR if so. */
|
||||
if (the_insn.exp.X_op == O_constant
|
||||
&& ((the_insn.exp.X_add_number & 0x3FF) == 0))
|
||||
return;
|
||||
toP = frag_more (4);
|
||||
rsd = (the_insn.opcode >> 25) & 0x1f;
|
||||
the_insn.opcode = 0x80102000 | (rsd << 25) | (rsd << 14);
|
||||
md_number_to_chars (toP, (valueT) the_insn.opcode, 4);
|
||||
fix_new_exp (frag_now, /* which frag */
|
||||
(toP - frag_now->fr_literal), /* where */
|
||||
4, /* size */
|
||||
&the_insn.exp,
|
||||
the_insn.pcrel,
|
||||
BFD_RELOC_LO10);
|
||||
return;
|
||||
{
|
||||
int need_hi22_p = 0;
|
||||
|
||||
/* "set" is not defined for negative numbers in v9: it doesn't yield
|
||||
what you expect it to. */
|
||||
if (SPARC_OPCODE_ARCH_V9_P (max_architecture)
|
||||
&& the_insn.exp.X_op == O_constant)
|
||||
{
|
||||
if (the_insn.exp.X_add_number < 0)
|
||||
as_warn ("set: used with negative number");
|
||||
else if (the_insn.exp.X_add_number > 0xffffffff)
|
||||
as_warn ("set: number larger than 4294967295");
|
||||
}
|
||||
|
||||
/* See if operand is absolute and small; skip sethi if so. */
|
||||
if (the_insn.exp.X_op != O_constant
|
||||
|| the_insn.exp.X_add_number >= (1 << 12)
|
||||
|| the_insn.exp.X_add_number < -(1 << 12))
|
||||
{
|
||||
output_insn (insn, &the_insn);
|
||||
need_hi22_p = 1;
|
||||
}
|
||||
/* See if operand has no low-order bits; skip OR if so. */
|
||||
if (the_insn.exp.X_op != O_constant
|
||||
|| (need_hi22_p && (the_insn.exp.X_add_number & 0x3FF) != 0)
|
||||
|| ! need_hi22_p)
|
||||
{
|
||||
int rd = (the_insn.opcode & RD (~0)) >> 25;
|
||||
the_insn.opcode = (OR_INSN | (need_hi22_p ? RS1 (rd) : 0)
|
||||
| RD (rd)
|
||||
| IMMED
|
||||
| (the_insn.exp.X_add_number
|
||||
& (need_hi22_p ? 0x3ff : 0x1fff)));
|
||||
the_insn.reloc = (the_insn.exp.X_op != O_constant
|
||||
? BFD_RELOC_LO10
|
||||
: BFD_RELOC_NONE);
|
||||
output_insn (insn, &the_insn);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SPECIAL_CASE_SETSW:
|
||||
{
|
||||
/* FIXME: Not finished. */
|
||||
break;
|
||||
}
|
||||
|
||||
case SPECIAL_CASE_SETX:
|
||||
{
|
||||
#define SIGNEXT32(x) ((((x) & 0xffffffff) ^ 0x80000000) - 0x80000000)
|
||||
int upper32 = SIGNEXT32 (BSR (the_insn.exp.X_add_number, 32));
|
||||
int lower32 = SIGNEXT32 (the_insn.exp.X_add_number);
|
||||
#undef SIGNEXT32
|
||||
int tmpreg = (the_insn.opcode & RS1 (~0)) >> 14;
|
||||
int dstreg = (the_insn.opcode & RD (~0)) >> 25;
|
||||
/* Output directly to dst reg if lower 32 bits are all zero. */
|
||||
int upper_dstreg = (the_insn.exp.X_op == O_constant
|
||||
&& lower32 == 0) ? dstreg : tmpreg;
|
||||
int need_hh22_p = 0, need_hm10_p = 0, need_hi22_p = 0, need_lo10_p = 0;
|
||||
|
||||
/* The tmp reg should not be the dst reg. */
|
||||
if (tmpreg == dstreg)
|
||||
as_warn ("setx: temporary register same as destination register");
|
||||
|
||||
/* Reset X_add_number, we've extracted it as upper32/lower32.
|
||||
Otherwise fixup_segment will complain about not being able to
|
||||
write an 8 byte number in a 4 byte field. */
|
||||
the_insn.exp.X_add_number = 0;
|
||||
|
||||
/* ??? Obviously there are other optimizations we can do
|
||||
(e.g. sethi+shift for 0x1f0000000) and perhaps we shouldn't be
|
||||
doing some of these. Later. If you do change things, try to
|
||||
change all of this to be table driven as well. */
|
||||
|
||||
/* What to output depends on the number if it's constant.
|
||||
Compute that first, then output what we've decided upon. */
|
||||
if (the_insn.exp.X_op != O_constant)
|
||||
need_hh22_p = need_hm10_p = need_hi22_p = need_lo10_p = 1;
|
||||
else
|
||||
{
|
||||
/* Only need hh22 if `or' insn can't handle constant. */
|
||||
if (upper32 < -(1 << 12) || upper32 >= (1 << 12))
|
||||
need_hh22_p = 1;
|
||||
|
||||
/* Does bottom part (after sethi) have bits? */
|
||||
if ((need_hh22_p && (upper32 & 0x3ff) != 0)
|
||||
/* No hh22, but does upper32 still have bits we can't set
|
||||
from lower32? */
|
||||
|| (! need_hh22_p
|
||||
&& upper32 != 0
|
||||
&& (upper32 != -1 || lower32 >= 0)))
|
||||
need_hm10_p = 1;
|
||||
|
||||
/* If the lower half is all zero, we build the upper half directly
|
||||
into the dst reg. */
|
||||
if (lower32 != 0
|
||||
/* Need lower half if number is zero. */
|
||||
|| (! need_hh22_p && ! need_hm10_p))
|
||||
{
|
||||
/* No need for sethi if `or' insn can handle constant. */
|
||||
if (lower32 < -(1 << 12) || lower32 >= (1 << 12)
|
||||
/* Note that we can't use a negative constant in the `or'
|
||||
insn unless the upper 32 bits are all ones. */
|
||||
|| (lower32 < 0 && upper32 != -1))
|
||||
need_hi22_p = 1;
|
||||
|
||||
/* Does bottom part (after sethi) have bits? */
|
||||
if ((need_hi22_p && (lower32 & 0x3ff) != 0)
|
||||
/* No sethi. */
|
||||
|| (! need_hi22_p && (lower32 & 0x1fff) != 0)
|
||||
/* Need `or' if we didn't set anything else. */
|
||||
|| (! need_hi22_p && ! need_hh22_p && ! need_hm10_p))
|
||||
need_lo10_p = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (need_hh22_p)
|
||||
{
|
||||
the_insn.opcode = (SETHI_INSN | RD (upper_dstreg)
|
||||
| ((upper32 >> 10) & 0x3fffff));
|
||||
the_insn.reloc = (the_insn.exp.X_op != O_constant
|
||||
? BFD_RELOC_SPARC_HH22 : BFD_RELOC_NONE);
|
||||
output_insn (insn, &the_insn);
|
||||
}
|
||||
|
||||
if (need_hm10_p)
|
||||
{
|
||||
the_insn.opcode = (OR_INSN
|
||||
| (need_hh22_p ? RS1 (upper_dstreg) : 0)
|
||||
| RD (upper_dstreg)
|
||||
| IMMED
|
||||
| (upper32
|
||||
& (need_hh22_p ? 0x3ff : 0x1fff)));
|
||||
the_insn.reloc = (the_insn.exp.X_op != O_constant
|
||||
? BFD_RELOC_SPARC_HM10 : BFD_RELOC_NONE);
|
||||
output_insn (insn, &the_insn);
|
||||
}
|
||||
|
||||
if (need_hi22_p)
|
||||
{
|
||||
the_insn.opcode = (SETHI_INSN | RD (dstreg)
|
||||
| ((lower32 >> 10) & 0x3fffff));
|
||||
the_insn.reloc = BFD_RELOC_HI22;
|
||||
output_insn (insn, &the_insn);
|
||||
}
|
||||
|
||||
if (need_lo10_p)
|
||||
{
|
||||
/* FIXME: One nice optimization to do here is to OR the low part
|
||||
with the highpart if hi22 isn't needed and the low part is
|
||||
positive. */
|
||||
the_insn.opcode = (OR_INSN | (need_hi22_p ? RS1 (dstreg) : 0)
|
||||
| RD (dstreg)
|
||||
| IMMED
|
||||
| (lower32
|
||||
& (need_hi22_p ? 0x3ff : 0x1fff)));
|
||||
the_insn.reloc = BFD_RELOC_LO10;
|
||||
output_insn (insn, &the_insn);
|
||||
}
|
||||
|
||||
/* If we needed to build the upper part, shift it into place. */
|
||||
if (need_hh22_p || need_hm10_p)
|
||||
{
|
||||
the_insn.opcode = (SLLX_INSN | RS1 (upper_dstreg) | RD (upper_dstreg)
|
||||
| IMMED | 32);
|
||||
the_insn.reloc = BFD_RELOC_NONE;
|
||||
output_insn (insn, &the_insn);
|
||||
}
|
||||
|
||||
/* If we needed to build both upper and lower parts, OR them together. */
|
||||
if ((need_hh22_p || need_hm10_p)
|
||||
&& (need_hi22_p || need_lo10_p))
|
||||
{
|
||||
the_insn.opcode = (OR_INSN | RS1 (dstreg) | RS2 (upper_dstreg)
|
||||
| RD (dstreg));
|
||||
the_insn.reloc = BFD_RELOC_NONE;
|
||||
output_insn (insn, &the_insn);
|
||||
}
|
||||
/* We didn't need both regs, but we may have to sign extend lower32. */
|
||||
else if (need_hi22_p && upper32 == -1)
|
||||
{
|
||||
the_insn.opcode = (SRA_INSN | RS1 (dstreg) | RD (dstreg)
|
||||
| IMMED | 0);
|
||||
the_insn.reloc = BFD_RELOC_NONE;
|
||||
output_insn (insn, &the_insn);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SPECIAL_CASE_FDIV:
|
||||
/* According to information leaked from Sun, the "fdiv" instructions
|
||||
on early SPARC machines would produce incorrect results sometimes.
|
||||
The workaround is to add an fmovs of the destination register to
|
||||
itself just after the instruction. This was true on machines
|
||||
with Weitek 1165 float chips, such as the Sun-4/260 and /280. */
|
||||
special_case = 0;
|
||||
assert (the_insn.reloc == BFD_RELOC_NONE);
|
||||
toP = frag_more (4);
|
||||
rsd = (the_insn.opcode >> 25) & 0x1f;
|
||||
the_insn.opcode = 0x81A00020 | (rsd << 25) | rsd; /* fmovs dest,dest */
|
||||
md_number_to_chars (toP, (valueT) the_insn.opcode, 4);
|
||||
return;
|
||||
{
|
||||
int rd = (the_insn.opcode >> 25) & 0x1f;
|
||||
|
||||
case 0:
|
||||
return;
|
||||
output_insn (insn, &the_insn);
|
||||
|
||||
/* According to information leaked from Sun, the "fdiv" instructions
|
||||
on early SPARC machines would produce incorrect results sometimes.
|
||||
The workaround is to add an fmovs of the destination register to
|
||||
itself just after the instruction. This was true on machines
|
||||
with Weitek 1165 float chips, such as the Sun-4/260 and /280. */
|
||||
assert (the_insn.reloc == BFD_RELOC_NONE);
|
||||
the_insn.opcode = FMOVS_INSN | rd | RD (rd);
|
||||
output_insn (insn, &the_insn);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
as_fatal ("failed sanity check.");
|
||||
as_fatal ("failed special case insn sanity check");
|
||||
}
|
||||
}
|
||||
|
||||
/* Implement big shift right. */
|
||||
static bfd_vma
|
||||
BSR (val, amount)
|
||||
bfd_vma val;
|
||||
int amount;
|
||||
{
|
||||
if (sizeof (bfd_vma) <= 4 && amount >= 32)
|
||||
as_fatal ("Support for 64-bit arithmetic not compiled in.");
|
||||
return val >> amount;
|
||||
}
|
||||
|
||||
/* Parse an argument that can be expressed as a keyword.
|
||||
(eg: #StoreStore or %ccfr).
|
||||
The result is a boolean indicating success.
|
||||
@ -1621,6 +1828,10 @@ sparc_ip (str, pinsn)
|
||||
}
|
||||
break;
|
||||
|
||||
case '0': /* 64 bit immediate (setx insn) */
|
||||
the_insn.reloc = BFD_RELOC_NONE; /* reloc handled elsewhere */
|
||||
goto immediate;
|
||||
|
||||
case 'h': /* high 22 bits */
|
||||
the_insn.reloc = BFD_RELOC_HI22;
|
||||
goto immediate;
|
||||
@ -1691,7 +1902,7 @@ sparc_ip (str, pinsn)
|
||||
|
||||
char *s1;
|
||||
|
||||
for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++);;
|
||||
for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++) ;
|
||||
|
||||
if (s1 != s && isdigit (s1[-1]))
|
||||
{
|
||||
@ -1848,11 +2059,22 @@ sparc_ip (str, pinsn)
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
if (strcmp (str, "set") == 0)
|
||||
if (strcmp (str, "set") == 0
|
||||
|| strcmp (str, "setuw") == 0)
|
||||
{
|
||||
special_case = SPECIAL_CASE_SET;
|
||||
continue;
|
||||
}
|
||||
else if (strcmp (str, "setsw") == 0)
|
||||
{
|
||||
special_case = SPECIAL_CASE_SETSW;
|
||||
continue;
|
||||
}
|
||||
else if (strcmp (str, "setx") == 0)
|
||||
{
|
||||
special_case = SPECIAL_CASE_SETX;
|
||||
continue;
|
||||
}
|
||||
else if (strncmp (str, "fdiv", 4) == 0)
|
||||
{
|
||||
special_case = SPECIAL_CASE_FDIV;
|
||||
@ -2078,15 +2300,13 @@ md_atof (type, litP, sizeP)
|
||||
char *litP;
|
||||
int *sizeP;
|
||||
{
|
||||
int prec;
|
||||
int i,prec;
|
||||
LITTLENUM_TYPE words[MAX_LITTLENUMS];
|
||||
LITTLENUM_TYPE *wordP;
|
||||
char *t;
|
||||
char *atof_ieee ();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
|
||||
case 'f':
|
||||
case 'F':
|
||||
case 's':
|
||||
@ -2115,40 +2335,59 @@ md_atof (type, litP, sizeP)
|
||||
*sizeP = 0;
|
||||
return "Bad call to MD_ATOF()";
|
||||
}
|
||||
|
||||
t = atof_ieee (input_line_pointer, type, words);
|
||||
if (t)
|
||||
input_line_pointer = t;
|
||||
*sizeP = prec * sizeof (LITTLENUM_TYPE);
|
||||
for (wordP = words; prec--;)
|
||||
|
||||
if (target_big_endian)
|
||||
{
|
||||
md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE));
|
||||
litP += sizeof (LITTLENUM_TYPE);
|
||||
for (i = 0; i < prec; i++)
|
||||
{
|
||||
md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE));
|
||||
litP += sizeof (LITTLENUM_TYPE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = prec - 1; i >= 0; i--)
|
||||
{
|
||||
md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE));
|
||||
litP += sizeof (LITTLENUM_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out big-endian.
|
||||
*/
|
||||
/* Write a value out to the object file, using the appropriate
|
||||
endianness. */
|
||||
|
||||
void
|
||||
md_number_to_chars (buf, val, n)
|
||||
char *buf;
|
||||
valueT val;
|
||||
int n;
|
||||
{
|
||||
number_to_chars_bigendian (buf, val, n);
|
||||
if (target_big_endian)
|
||||
number_to_chars_bigendian (buf, val, n);
|
||||
else
|
||||
number_to_chars_littleendian (buf, val, n);
|
||||
}
|
||||
|
||||
/* Apply a fixS to the frags, now that we know the value it ought to
|
||||
hold. */
|
||||
|
||||
int
|
||||
md_apply_fix (fixP, value)
|
||||
md_apply_fix3 (fixP, value, segment)
|
||||
fixS *fixP;
|
||||
valueT *value;
|
||||
segT segment;
|
||||
{
|
||||
char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
|
||||
offsetT val;
|
||||
long insn;
|
||||
|
||||
val = *value;
|
||||
|
||||
@ -2164,9 +2403,17 @@ md_apply_fix (fixP, value)
|
||||
don't want to include the value of an externally visible symbol. */
|
||||
if (fixP->fx_addsy != NULL)
|
||||
{
|
||||
if ((S_IS_EXTERNAL (fixP->fx_addsy)
|
||||
|| S_IS_WEAK (fixP->fx_addsy)
|
||||
|| (sparc_pic_code && ! fixP->fx_pcrel))
|
||||
if (fixP->fx_addsy->sy_used_in_reloc
|
||||
&& (S_IS_EXTERNAL (fixP->fx_addsy)
|
||||
|| S_IS_WEAK (fixP->fx_addsy)
|
||||
|| (sparc_pic_code && ! fixP->fx_pcrel)
|
||||
|| (S_GET_SEGMENT (fixP->fx_addsy) != segment
|
||||
&& ((bfd_get_section_flags (stdoutput,
|
||||
S_GET_SEGMENT (fixP->fx_addsy))
|
||||
& SEC_LINK_ONCE) != 0
|
||||
|| strncmp (segment_name (S_GET_SEGMENT (fixP->fx_addsy)),
|
||||
".gnu.linkonce",
|
||||
sizeof ".gnu.linkonce" - 1) == 0)))
|
||||
&& S_GET_SEGMENT (fixP->fx_addsy) != absolute_section
|
||||
&& S_GET_SEGMENT (fixP->fx_addsy) != undefined_section
|
||||
&& ! bfd_is_com_section (S_GET_SEGMENT (fixP->fx_addsy)))
|
||||
@ -2205,172 +2452,148 @@ md_apply_fix (fixP, value)
|
||||
fixP->fx_addnumber -= 2 * S_GET_VALUE (fixP->fx_addsy);
|
||||
#endif
|
||||
|
||||
switch (fixP->fx_r_type)
|
||||
/* If this is a data relocation, just output VAL. */
|
||||
|
||||
if (fixP->fx_r_type == BFD_RELOC_16)
|
||||
{
|
||||
case BFD_RELOC_16:
|
||||
buf[0] = val >> 8;
|
||||
buf[1] = val;
|
||||
break;
|
||||
md_number_to_chars (buf, val, 2);
|
||||
}
|
||||
else if (fixP->fx_r_type == BFD_RELOC_32)
|
||||
{
|
||||
md_number_to_chars (buf, val, 4);
|
||||
}
|
||||
else if (fixP->fx_r_type == BFD_RELOC_64)
|
||||
{
|
||||
md_number_to_chars (buf, val, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* It's a relocation against an instruction. */
|
||||
|
||||
case BFD_RELOC_32:
|
||||
buf[0] = val >> 24;
|
||||
buf[1] = val >> 16;
|
||||
buf[2] = val >> 8;
|
||||
buf[3] = val;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_32_PCREL_S2:
|
||||
val = val >> 2;
|
||||
/* FIXME: This increment-by-one deserves a comment of why it's
|
||||
being done! */
|
||||
if (! sparc_pic_code
|
||||
|| fixP->fx_addsy == NULL
|
||||
|| (fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0)
|
||||
++val;
|
||||
buf[0] |= (val >> 24) & 0x3f;
|
||||
buf[1] = val >> 16;
|
||||
buf[2] = val >> 8;
|
||||
buf[3] = val;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_64:
|
||||
{
|
||||
bfd_vma valh = BSR (val, 32);
|
||||
buf[0] = valh >> 24;
|
||||
buf[1] = valh >> 16;
|
||||
buf[2] = valh >> 8;
|
||||
buf[3] = valh;
|
||||
buf[4] = val >> 24;
|
||||
buf[5] = val >> 16;
|
||||
buf[6] = val >> 8;
|
||||
buf[7] = val;
|
||||
}
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC_11:
|
||||
if (! in_signed_range (val, 0x7ff))
|
||||
as_bad ("relocation overflow.");
|
||||
|
||||
buf[2] |= (val >> 8) & 0x7;
|
||||
buf[3] = val;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC_10:
|
||||
if (! in_signed_range (val, 0x3ff))
|
||||
as_bad ("relocation overflow.");
|
||||
|
||||
buf[2] |= (val >> 8) & 0x3;
|
||||
buf[3] = val;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC_6:
|
||||
if (! in_bitfield_range (val, 0x3f))
|
||||
as_bad ("relocation overflow.");
|
||||
|
||||
buf[3] |= val & 0x3f;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC_5:
|
||||
if (! in_bitfield_range (val, 0x1f))
|
||||
as_bad ("relocation overflow.");
|
||||
|
||||
buf[3] |= val & 0x1f;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC_WDISP16:
|
||||
/* FIXME: simplify */
|
||||
if (((val > 0) && (val & ~0x3fffc))
|
||||
|| ((val < 0) && (~(val - 1) & ~0x3fffc)))
|
||||
{
|
||||
as_bad ("relocation overflow.");
|
||||
}
|
||||
|
||||
/* FIXME: The +1 deserves a comment. */
|
||||
val = (val >> 2) + 1;
|
||||
buf[1] |= ((val >> 14) & 0x3) << 4;
|
||||
buf[2] |= (val >> 8) & 0x3f;
|
||||
buf[3] = val;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC_WDISP19:
|
||||
/* FIXME: simplify */
|
||||
if (((val > 0) && (val & ~0x1ffffc))
|
||||
|| ((val < 0) && (~(val - 1) & ~0x1ffffc)))
|
||||
{
|
||||
as_bad ("relocation overflow.");
|
||||
}
|
||||
|
||||
/* FIXME: The +1 deserves a comment. */
|
||||
val = (val >> 2) + 1;
|
||||
buf[1] |= (val >> 16) & 0x7;
|
||||
buf[2] = (val >> 8) & 0xff;
|
||||
buf[3] = val;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC_HH22:
|
||||
val = BSR (val, 32);
|
||||
/* intentional fallthrough */
|
||||
|
||||
case BFD_RELOC_SPARC_LM22:
|
||||
case BFD_RELOC_HI22:
|
||||
if (!fixP->fx_addsy)
|
||||
{
|
||||
buf[1] |= (val >> 26) & 0x3f;
|
||||
buf[2] = val >> 18;
|
||||
buf[3] = val >> 10;
|
||||
}
|
||||
if (INSN_BIG_ENDIAN)
|
||||
insn = bfd_getb32 ((unsigned char *) buf);
|
||||
else
|
||||
insn = bfd_getl32 ((unsigned char *) buf);
|
||||
|
||||
switch (fixP->fx_r_type)
|
||||
{
|
||||
buf[2] = 0;
|
||||
buf[3] = 0;
|
||||
case BFD_RELOC_32_PCREL_S2:
|
||||
val = val >> 2;
|
||||
/* FIXME: This increment-by-one deserves a comment of why it's
|
||||
being done! */
|
||||
if (! sparc_pic_code
|
||||
|| fixP->fx_addsy == NULL
|
||||
|| (fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0)
|
||||
++val;
|
||||
insn |= val & 0x3fffffff;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC_11:
|
||||
if (! in_signed_range (val, 0x7ff))
|
||||
as_bad ("relocation overflow.");
|
||||
insn |= val & 0x7ff;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC_10:
|
||||
if (! in_signed_range (val, 0x3ff))
|
||||
as_bad ("relocation overflow.");
|
||||
insn |= val & 0x3ff;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC_6:
|
||||
if (! in_bitfield_range (val, 0x3f))
|
||||
as_bad ("relocation overflow.");
|
||||
insn |= val & 0x3f;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC_5:
|
||||
if (! in_bitfield_range (val, 0x1f))
|
||||
as_bad ("relocation overflow.");
|
||||
insn |= val & 0x1f;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC_WDISP16:
|
||||
/* FIXME: simplify */
|
||||
if (((val > 0) && (val & ~0x3fffc))
|
||||
|| ((val < 0) && (~(val - 1) & ~0x3fffc)))
|
||||
as_bad ("relocation overflow.");
|
||||
/* FIXME: The +1 deserves a comment. */
|
||||
val = (val >> 2) + 1;
|
||||
insn |= ((val & 0xc000) << 6) | (val & 0x3fff);
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC_WDISP19:
|
||||
/* FIXME: simplify */
|
||||
if (((val > 0) && (val & ~0x1ffffc))
|
||||
|| ((val < 0) && (~(val - 1) & ~0x1ffffc)))
|
||||
as_bad ("relocation overflow.");
|
||||
/* FIXME: The +1 deserves a comment. */
|
||||
val = (val >> 2) + 1;
|
||||
insn |= val & 0x7ffff;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC_HH22:
|
||||
val = BSR (val, 32);
|
||||
/* intentional fallthrough */
|
||||
|
||||
case BFD_RELOC_SPARC_LM22:
|
||||
case BFD_RELOC_HI22:
|
||||
if (!fixP->fx_addsy)
|
||||
{
|
||||
insn |= (val >> 10) & 0x3fffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: Need comment explaining why we do this. */
|
||||
insn &= ~0xffff;
|
||||
}
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC22:
|
||||
if (val & ~0x003fffff)
|
||||
as_bad ("relocation overflow");
|
||||
insn |= (val & 0x3fffff);
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC_HM10:
|
||||
val = BSR (val, 32);
|
||||
/* intentional fallthrough */
|
||||
|
||||
case BFD_RELOC_LO10:
|
||||
if (!fixP->fx_addsy)
|
||||
{
|
||||
insn |= val & 0x3ff;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: Need comment explaining why we do this. */
|
||||
insn &= ~0xff;
|
||||
}
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC13:
|
||||
if (! in_signed_range (val, 0x1fff))
|
||||
as_bad ("relocation overflow");
|
||||
insn |= val & 0x1fff;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC_WDISP22:
|
||||
val = (val >> 2) + 1;
|
||||
/* FALLTHROUGH */
|
||||
case BFD_RELOC_SPARC_BASE22:
|
||||
insn |= val & 0x3fffff;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_NONE:
|
||||
default:
|
||||
as_bad ("bad or unhandled relocation type: 0x%02x", fixP->fx_r_type);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC22:
|
||||
if (val & ~0x003fffff)
|
||||
{
|
||||
as_bad ("relocation overflow");
|
||||
} /* on overflow */
|
||||
buf[1] |= (val >> 16) & 0x3f;
|
||||
buf[2] = val >> 8;
|
||||
buf[3] = val;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC_HM10:
|
||||
val = BSR (val, 32);
|
||||
/* intentional fallthrough */
|
||||
|
||||
case BFD_RELOC_LO10:
|
||||
if (!fixP->fx_addsy)
|
||||
{
|
||||
buf[2] |= (val >> 8) & 0x03;
|
||||
buf[3] = val;
|
||||
}
|
||||
if (INSN_BIG_ENDIAN)
|
||||
bfd_putb32 (insn, (unsigned char *) buf);
|
||||
else
|
||||
buf[3] = 0;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC13:
|
||||
if (! in_signed_range (val, 0x1fff))
|
||||
as_bad ("relocation overflow");
|
||||
|
||||
buf[2] |= (val >> 8) & 0x1f;
|
||||
buf[3] = val;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_SPARC_WDISP22:
|
||||
val = (val >> 2) + 1;
|
||||
/* FALLTHROUGH */
|
||||
case BFD_RELOC_SPARC_BASE22:
|
||||
buf[1] |= (val >> 16) & 0x3f;
|
||||
buf[2] = val >> 8;
|
||||
buf[3] = val;
|
||||
break;
|
||||
|
||||
case BFD_RELOC_NONE:
|
||||
default:
|
||||
as_bad ("bad or unhandled relocation type: 0x%02x", fixP->fx_r_type);
|
||||
break;
|
||||
bfd_putl32 (insn, (unsigned char *) buf);
|
||||
}
|
||||
|
||||
/* Are we finished with this relocation now? */
|
||||
@ -2618,6 +2841,14 @@ struct option md_longopts[] = {
|
||||
{"sparc", no_argument, NULL, OPTION_SPARC},
|
||||
#define OPTION_XARCH (OPTION_MD_BASE + 2)
|
||||
{"xarch", required_argument, NULL, OPTION_XARCH},
|
||||
#ifdef SPARC_BIENDIAN
|
||||
#define OPTION_LITTLE_ENDIAN (OPTION_MD_BASE + 3)
|
||||
{"EL", no_argument, NULL, OPTION_LITTLE_ENDIAN},
|
||||
#define OPTION_BIG_ENDIAN (OPTION_MD_BASE + 4)
|
||||
{"EB", no_argument, NULL, OPTION_BIG_ENDIAN},
|
||||
#endif
|
||||
#define OPTION_ENFORCE_ALIGNED_DATA (OPTION_MD_BASE + 5)
|
||||
{"enforce-aligned-data", no_argument, NULL, OPTION_ENFORCE_ALIGNED_DATA},
|
||||
{NULL, no_argument, NULL, 0}
|
||||
};
|
||||
size_t md_longopts_size = sizeof(md_longopts);
|
||||
@ -2672,6 +2903,19 @@ md_parse_option (c, arg)
|
||||
/* Ignore -sparc, used by SunOS make default .s.o rule. */
|
||||
break;
|
||||
|
||||
case OPTION_ENFORCE_ALIGNED_DATA:
|
||||
enforce_aligned_data = 1;
|
||||
break;
|
||||
|
||||
#ifdef SPARC_BIENDIAN
|
||||
case OPTION_LITTLE_ENDIAN:
|
||||
target_big_endian = 0;
|
||||
break;
|
||||
case OPTION_BIG_ENDIAN:
|
||||
target_big_endian = 1;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef OBJ_AOUT
|
||||
case 'k':
|
||||
sparc_pic_code = 1;
|
||||
@ -2728,7 +2972,8 @@ md_show_usage (stream)
|
||||
fprintf (stream, "\
|
||||
specify variant of SPARC architecture\n\
|
||||
-bump warn when assembler switches architectures\n\
|
||||
-sparc ignored\n");
|
||||
-sparc ignored\n
|
||||
--enforce-aligned-data force .long, etc., to be aligned correctly\n");
|
||||
#ifdef OBJ_AOUT
|
||||
fprintf (stream, "\
|
||||
-k generate PIC\n");
|
||||
@ -2741,6 +2986,11 @@ md_show_usage (stream)
|
||||
-Qy, -Qn ignored\n\
|
||||
-s ignored\n");
|
||||
#endif
|
||||
#ifdef SPARC_BIENDIAN
|
||||
fprintf (stream, "\
|
||||
-EL generate code for a little endian machine\n\
|
||||
-EB generate code for a big endian machine\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* We have no need to default values of symbols. */
|
||||
|
Reference in New Issue
Block a user