summaryrefslogtreecommitdiffstats
path: root/contrib/binutils/gas/config/tc-sparc.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/binutils/gas/config/tc-sparc.c')
-rw-r--r--contrib/binutils/gas/config/tc-sparc.c1565
1 files changed, 1109 insertions, 456 deletions
diff --git a/contrib/binutils/gas/config/tc-sparc.c b/contrib/binutils/gas/config/tc-sparc.c
index 18d6572..149610e 100644
--- a/contrib/binutils/gas/config/tc-sparc.c
+++ b/contrib/binutils/gas/config/tc-sparc.c
@@ -1,5 +1,5 @@
/* tc-sparc.c -- Assemble for the SPARC
- Copyright (C) 1989, 90-96, 97, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1989, 90-96, 97, 98, 99, 2000 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
@@ -31,11 +31,14 @@
static struct sparc_arch *lookup_arch PARAMS ((char *));
static void init_default_arch PARAMS ((void));
-static void sparc_ip PARAMS ((char *, const struct sparc_opcode **));
+static int sparc_ip PARAMS ((char *, const struct sparc_opcode **));
static int in_signed_range PARAMS ((bfd_signed_vma, bfd_signed_vma));
static int in_unsigned_range PARAMS ((bfd_vma, bfd_vma));
static int in_bitfield_range PARAMS ((bfd_signed_vma, bfd_signed_vma));
static int sparc_ffs PARAMS ((unsigned int));
+static void synthetize_setuw PARAMS ((const struct sparc_opcode *));
+static void synthetize_setsw PARAMS ((const struct sparc_opcode *));
+static void synthetize_setx PARAMS ((const struct sparc_opcode *));
static bfd_vma BSR PARAMS ((bfd_vma, int));
static int cmp_reg_entry PARAMS ((const PTR, const PTR));
static int parse_keyword_arg PARAMS ((int (*) (const char *), char **, int *));
@@ -84,6 +87,10 @@ static int warn_on_bump;
architecture, issue a warning. */
static enum sparc_opcode_arch_val warn_after_architecture;
+/* Non-zero if as should generate error if an undeclared g[23] register
+ has been used in -64. */
+static int no_undeclared_regs;
+
/* Non-zero if we are generating PIC code. */
int sparc_pic_code;
@@ -92,16 +99,25 @@ 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. */
+static int target_little_endian_data;
+
+/* Symbols for global registers on v9. */
+static symbolS *globals[8];
+
+/* V9 and 86x have 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. */
+#ifndef INSN_BIG_ENDIAN
#define INSN_BIG_ENDIAN (target_big_endian \
+ || default_arch_type == sparc86x \
|| SPARC_OPCODE_ARCH_V9_P (max_architecture))
+#endif
/* handle of the OPCODE hash table */
static struct hash_control *op_hash;
+static int log2 PARAMS ((int));
static void s_data1 PARAMS ((void));
static void s_seg PARAMS ((int));
static void s_proc PARAMS ((int));
@@ -109,6 +125,8 @@ static void s_reserve PARAMS ((int));
static void s_common PARAMS ((int));
static void s_empty PARAMS ((int));
static void s_uacons PARAMS ((int));
+static void s_ncons PARAMS ((int));
+static void s_register PARAMS ((int));
const pseudo_typeS md_pseudo_table[] =
{
@@ -117,6 +135,7 @@ const pseudo_typeS md_pseudo_table[] =
{"empty", s_empty, 0},
{"global", s_globl, 0},
{"half", cons, 2},
+ {"nword", s_ncons, 0},
{"optim", s_ignore, 0},
{"proc", s_proc, 0},
{"reserve", s_reserve, 0},
@@ -129,11 +148,10 @@ const pseudo_typeS md_pseudo_table[] =
{"uaxword", s_uacons, 8},
#ifdef OBJ_ELF
/* these are specific to sparc/svr4 */
- {"pushsection", obj_elf_section, 0},
- {"popsection", obj_elf_previous, 0},
{"2byte", s_uacons, 2},
{"4byte", s_uacons, 4},
{"8byte", s_uacons, 8},
+ {"register", s_register, 0},
#endif
{NULL, 0, 0},
};
@@ -168,9 +186,7 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
changed in read.c. Ideally it shouldn't have to know about it at all,
but nothing is ideal around here. */
-static unsigned char octal[256];
-#define isoctal(c) octal[(unsigned char) (c)]
-static unsigned char toHex[256];
+#define isoctal(c) ((unsigned)((c) - '0') < '8')
struct sparc_it
{
@@ -178,6 +194,7 @@ struct sparc_it
unsigned long opcode;
struct nlist *nlistp;
expressionS exp;
+ expressionS exp2;
int pcrel;
bfd_reloc_code_real_type reloc;
};
@@ -192,30 +209,38 @@ static void output_insn
for this use. That table is for opcodes only. This table is for opcodes
and file formats. */
+enum sparc_arch_types {v6, v7, v8, sparclet, sparclite, sparc86x, v8plus,
+ v8plusa, v9, v9a, v9_64};
+
static struct sparc_arch {
char *name;
char *opcode_arch;
+ enum sparc_arch_types arch_type;
/* Default word size, as specified during configuration.
A value of zero means can't be used to specify default architecture. */
int default_arch_size;
/* Allowable arg to -A? */
int user_option_p;
} sparc_arch_table[] = {
- { "v6", "v6", 0, 1 },
- { "v7", "v7", 0, 1 },
- { "v8", "v8", 32, 1 },
- { "sparclet", "sparclet", 32, 1 },
- { "sparclite", "sparclite", 32, 1 },
- { "v8plus", "v9", 0, 1 },
- { "v8plusa", "v9a", 0, 1 },
- { "v9", "v9", 0, 1 },
- { "v9a", "v9a", 0, 1 },
+ { "v6", "v6", v6, 0, 1 },
+ { "v7", "v7", v7, 0, 1 },
+ { "v8", "v8", v8, 32, 1 },
+ { "sparclet", "sparclet", sparclet, 32, 1 },
+ { "sparclite", "sparclite", sparclite, 32, 1 },
+ { "sparc86x", "sparclite", sparc86x, 32, 1 },
+ { "v8plus", "v9", v9, 0, 1 },
+ { "v8plusa", "v9a", v9, 0, 1 },
+ { "v9", "v9", v9, 0, 1 },
+ { "v9a", "v9a", v9, 0, 1 },
/* This exists to allow configure.in/Makefile.in to pass one
value to specify both the default machine and default word size. */
- { "v9-64", "v9", 64, 0 },
- { NULL, NULL, 0 }
+ { "v9-64", "v9", v9, 64, 0 },
+ { NULL, NULL, v8, 0, 0 }
};
+/* Variant of default_arch */
+static enum sparc_arch_types default_arch_type;
+
static struct sparc_arch *
lookup_arch (name)
char *name;
@@ -240,13 +265,14 @@ init_default_arch ()
if (sa == NULL
|| sa->default_arch_size == 0)
- as_fatal ("Invalid default architecture, broken assembler.");
+ as_fatal (_("Invalid default architecture, broken assembler."));
max_architecture = sparc_opcode_lookup_arch (sa->opcode_arch);
if (max_architecture == SPARC_OPCODE_ARCH_BAD)
- as_fatal ("Bad opcode table, broken assembler.");
+ as_fatal (_("Bad opcode table, broken assembler."));
default_arch_size = sparc_arch_size = sa->default_arch_size;
default_init_p = 1;
+ default_arch_type = sa->arch_type;
}
/* Called by TARGET_FORMAT. */
@@ -264,7 +290,11 @@ sparc_target_format ()
return "a.out-sparc-netbsd";
#else
#ifdef TE_SPARCAOUT
- return target_big_endian ? "a.out-sunos-big" : "a.out-sparc-little";
+ if (target_big_endian)
+ return "a.out-sunos-big";
+ else if (default_arch_type == sparc86x && target_little_endian_data)
+ return "a.out-sunos-big";
+ else return "a.out-sparc-little";
#else
return "a.out-sunos-big";
#endif
@@ -377,6 +407,14 @@ struct option md_longopts[] = {
#endif
#define OPTION_ENFORCE_ALIGNED_DATA (OPTION_MD_BASE + 10)
{"enforce-aligned-data", no_argument, NULL, OPTION_ENFORCE_ALIGNED_DATA},
+#define OPTION_LITTLE_ENDIAN_DATA (OPTION_MD_BASE + 11)
+ {"little-endian-data", no_argument, NULL, OPTION_LITTLE_ENDIAN_DATA},
+#ifdef OBJ_ELF
+#define OPTION_NO_UNDECLARED_REGS (OPTION_MD_BASE + 12)
+ {"no-undeclared-regs", no_argument, NULL, OPTION_NO_UNDECLARED_REGS},
+#define OPTION_UNDECLARED_REGS (OPTION_MD_BASE + 13)
+ {"undeclared-regs", no_argument, NULL, OPTION_UNDECLARED_REGS},
+#endif
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof(md_longopts);
@@ -403,7 +441,7 @@ md_parse_option (c, arg)
if (strcmp (arg, "v8plus") != 0
&& strcmp (arg, "v8plusa") != 0)
{
- as_bad ("invalid architecture -xarch=%s", arg);
+ as_bad (_("invalid architecture -xarch=%s"), arg);
return 0;
}
@@ -418,13 +456,13 @@ md_parse_option (c, arg)
if (sa == NULL
|| ! sa->user_option_p)
{
- as_bad ("invalid architecture -A%s", arg);
+ as_bad (_("invalid architecture -A%s"), arg);
return 0;
}
opcode_arch = sparc_opcode_lookup_arch (sa->opcode_arch);
if (opcode_arch == SPARC_OPCODE_ARCH_BAD)
- as_fatal ("Bad opcode table, broken assembler.");
+ as_fatal (_("Bad opcode table, broken assembler."));
max_architecture = opcode_arch;
architecture_requested = 1;
@@ -442,6 +480,15 @@ md_parse_option (c, arg)
#ifdef SPARC_BIENDIAN
case OPTION_LITTLE_ENDIAN:
target_big_endian = 0;
+ if (default_arch_type != sparclet)
+ as_fatal ("This target does not support -EL");
+ break;
+ case OPTION_LITTLE_ENDIAN_DATA:
+ target_little_endian_data = 1;
+ target_big_endian = 0;
+ if (default_arch_type != sparc86x
+ && default_arch_type != v9)
+ as_fatal ("This target does not support --little-endian-data");
break;
case OPTION_BIG_ENDIAN:
target_big_endian = 1;
@@ -476,7 +523,7 @@ md_parse_option (c, arg)
}
}
if (*l == NULL)
- as_fatal ("No compiled in support for %d bit object file format",
+ as_fatal (_("No compiled in support for %d bit object file format"),
sparc_arch_size);
free (list);
}
@@ -513,10 +560,18 @@ md_parse_option (c, arg)
case 'K':
if (strcmp (arg, "PIC") != 0)
- as_warn ("Unrecognized option following -K");
+ as_warn (_("Unrecognized option following -K"));
else
sparc_pic_code = 1;
break;
+
+ case OPTION_NO_UNDECLARED_REGS:
+ no_undeclared_regs = 1;
+ break;
+
+ case OPTION_UNDECLARED_REGS:
+ no_undeclared_regs = 0;
+ break;
#endif
default:
@@ -537,7 +592,7 @@ md_show_usage (stream)
if (! default_init_p)
init_default_arch ();
- fprintf(stream, "SPARC options:\n");
+ fprintf(stream, _("SPARC options:\n"));
for (arch = &sparc_arch_table[0]; arch->name; arch++)
{
if (arch != &sparc_arch_table[0])
@@ -545,42 +600,69 @@ md_show_usage (stream)
if (arch->user_option_p)
fprintf (stream, "-A%s", arch->name);
}
- fprintf (stream, "\n-xarch=v8plus | -xarch=v8plusa\n");
- fprintf (stream, "\
+ fprintf (stream, _("\n-xarch=v8plus | -xarch=v8plusa\n"));
+ fprintf (stream, _("\
specify variant of SPARC architecture\n\
-bump warn when assembler switches architectures\n\
-sparc ignored\n\
---enforce-aligned-data force .long, etc., to be aligned correctly\n");
+--enforce-aligned-data force .long, etc., to be aligned correctly\n"));
#ifdef OBJ_AOUT
- fprintf (stream, "\
--k generate PIC\n");
+ fprintf (stream, _("\
+-k generate PIC\n"));
#endif
#ifdef OBJ_ELF
- fprintf (stream, "\
+ fprintf (stream, _("\
-32 create 32 bit object file\n\
--64 create 64 bit object file\n");
- fprintf (stream, "\
- [default is %d]\n", default_arch_size);
- fprintf (stream, "\
+-64 create 64 bit object file\n"));
+ fprintf (stream, _("\
+ [default is %d]\n"), default_arch_size);
+ fprintf (stream, _("\
-TSO use Total Store Ordering\n\
-PSO use Partial Store Ordering\n\
--RMO use Relaxed Memory Ordering\n");
- fprintf (stream, "\
- [default is %s]\n", (default_arch_size == 64) ? "RMO" : "TSO");
- fprintf (stream, "\
+-RMO use Relaxed Memory Ordering\n"));
+ fprintf (stream, _("\
+ [default is %s]\n"), (default_arch_size == 64) ? "RMO" : "TSO");
+ fprintf (stream, _("\
-KPIC generate PIC\n\
-V print assembler version number\n\
+-undeclared-regs ignore application global register usage without\n\
+ appropriate .register directive (default)\n\
+-no-undeclared-regs force error on application global register usage\n\
+ without appropriate .register directive\n\
-q ignored\n\
-Qy, -Qn ignored\n\
--s ignored\n");
+-s ignored\n"));
#endif
#ifdef SPARC_BIENDIAN
- fprintf (stream, "\
+ fprintf (stream, _("\
-EL generate code for a little endian machine\n\
--EB generate code for a big endian machine\n");
+-EB generate code for a big endian machine\n\
+--little-endian-data generate code for a machine having big endian\n\
+ instructions and little endian data.\n"));
#endif
}
+/* native operand size opcode translation */
+struct
+ {
+ char *name;
+ char *name32;
+ char *name64;
+ } native_op_table[] =
+{
+ {"ldn", "ld", "ldx"},
+ {"ldna", "lda", "ldxa"},
+ {"stn", "st", "stx"},
+ {"stna", "sta", "stxa"},
+ {"slln", "sll", "sllx"},
+ {"srln", "srl", "srlx"},
+ {"sran", "sra", "srax"},
+ {"casn", "cas", "casx"},
+ {"casna", "casa", "casxa"},
+ {"clrn", "clr", "clrx"},
+ {NULL, NULL, NULL},
+};
+
/* sparc64 priviledged registers */
struct priv_reg_entry
@@ -661,16 +743,16 @@ md_begin ()
retval = hash_insert (op_hash, name, (PTR) &sparc_opcodes[i]);
if (retval != NULL)
{
- fprintf (stderr, "internal error: can't hash `%s': %s\n",
- sparc_opcodes[i].name, retval);
+ as_bad (_("Internal error: can't hash `%s': %s\n"),
+ sparc_opcodes[i].name, retval);
lose = 1;
}
do
{
if (sparc_opcodes[i].match & sparc_opcodes[i].lose)
{
- fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n",
- sparc_opcodes[i].name, sparc_opcodes[i].args);
+ as_bad (_("Internal error: losing opcode: `%s' \"%s\"\n"),
+ sparc_opcodes[i].name, sparc_opcodes[i].args);
lose = 1;
}
++i;
@@ -679,17 +761,32 @@ md_begin ()
&& !strcmp (sparc_opcodes[i].name, name));
}
- if (lose)
- as_fatal ("Broken assembler. No assembly attempted.");
+ for (i = 0; native_op_table[i].name; i++)
+ {
+ const struct sparc_opcode *insn;
+ char *name = sparc_arch_size == 32 ? native_op_table[i].name32 :
+ native_op_table[i].name64;
+ insn = (struct sparc_opcode *)hash_find (op_hash, name);
+ if (insn == NULL)
+ {
+ as_bad (_("Internal error: can't find opcode `%s' for `%s'\n"),
+ name, native_op_table[i].name);
+ lose = 1;
+ }
+ else
+ {
+ retval = hash_insert (op_hash, native_op_table[i].name, (PTR) insn);
+ if (retval != NULL)
+ {
+ as_bad (_("Internal error: can't hash `%s': %s\n"),
+ sparc_opcodes[i].name, retval);
+ lose = 1;
+ }
+ }
+ }
- for (i = '0'; i < '8'; ++i)
- octal[i] = 1;
- for (i = '0'; i <= '9'; ++i)
- toHex[i] = i - '0';
- for (i = 'a'; i <= 'f'; ++i)
- toHex[i] = i + 10 - 'a';
- for (i = 'A'; i <= 'F'; ++i)
- toHex[i] = i + 10 - 'A';
+ if (lose)
+ as_fatal (_("Broken assembler. No assembly attempted."));
qsort (priv_reg_table, sizeof (priv_reg_table) / sizeof (priv_reg_table[0]),
sizeof (priv_reg_table[0]), cmp_reg_entry);
@@ -739,6 +836,8 @@ sparc_md_end ()
bfd_set_arch_mach (stdoutput, bfd_arch_sparc, bfd_mach_sparc_v8plusa);
else if (current_architecture == SPARC_OPCODE_ARCH_SPARCLET)
bfd_set_arch_mach (stdoutput, bfd_arch_sparc, bfd_mach_sparc_sparclet);
+ else if (default_arch_type == sparc86x && target_little_endian_data)
+ bfd_set_arch_mach (stdoutput, bfd_arch_sparc, bfd_mach_sparc_sparclite_le);
else
{
/* The sparclite is treated like a normal sparc. Perhaps it shouldn't
@@ -757,6 +856,13 @@ in_signed_range (val, max)
{
if (max <= 0)
abort ();
+ /* Sign-extend the value from the architecture word size, so that
+ 0xffffffff is always considered -1 on sparc32. */
+ if (sparc_arch_size == 32)
+ {
+ bfd_signed_vma sign = (bfd_signed_vma)1 << 31;
+ val = ((val & 0xffffffff) ^ sign) - sign;
+ }
if (val > max)
return 0;
if (val < ~max)
@@ -812,16 +918,13 @@ BSR (val, amount)
int amount;
{
if (sizeof (bfd_vma) <= 4 && amount >= 32)
- as_fatal ("Support for 64-bit arithmetic not compiled in.");
+ as_fatal (_("Support for 64-bit arithmetic not compiled in."));
return val >> amount;
}
/* For communication between sparc_ip and get_expression. */
static char *expr_end;
-/* For communication between md_assemble and sparc_ip. */
-static int special_case;
-
/* Values for `special_case'.
Instructions that require wierd handling because they're longer than
4 bytes. */
@@ -835,6 +938,7 @@ static int special_case;
/* Bit masks of various insns. */
#define NOP_INSN 0x01000000
#define OR_INSN 0x80100000
+#define XOR_INSN 0x80180000
#define FMOVS_INSN 0x81A00020
#define SETHI_INSN 0x01000000
#define SLLX_INSN 0x81281000
@@ -845,6 +949,281 @@ static const struct sparc_opcode *last_insn;
/* The assembled opcode of `last_insn'. */
static unsigned long last_opcode;
+/* Handle the set and setuw synthetic instructions. */
+static void
+synthetize_setuw (insn)
+ const struct sparc_opcode *insn;
+{
+ int need_hi22_p = 0;
+ int rd = (the_insn.opcode & RD (~0)) >> 25;
+
+ if (the_insn.exp.X_op == O_constant)
+ {
+ if (SPARC_OPCODE_ARCH_V9_P (max_architecture))
+ {
+ if (sizeof(offsetT) > 4
+ && (the_insn.exp.X_add_number < 0
+ || the_insn.exp.X_add_number > (offsetT) 0xffffffff))
+ as_warn (_("set: number not in 0..4294967295 range"));
+ }
+ else
+ {
+ if (sizeof(offsetT) > 4
+ && (the_insn.exp.X_add_number < -(offsetT) 0x80000000
+ || the_insn.exp.X_add_number > (offsetT) 0xffffffff))
+ as_warn (_("set: number not in -2147483648..4294967295 range"));
+ the_insn.exp.X_add_number = (int)the_insn.exp.X_add_number;
+ }
+ }
+
+ /* 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))
+ {
+ the_insn.opcode = (SETHI_INSN | RD (rd)
+ | ((the_insn.exp.X_add_number >> 10)
+ & (the_insn.exp.X_op == O_constant ? 0x3fffff : 0)));
+ the_insn.reloc = (the_insn.exp.X_op != O_constant
+ ? BFD_RELOC_HI22
+ : BFD_RELOC_NONE);
+ 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)
+ {
+ the_insn.opcode = (OR_INSN | (need_hi22_p ? RS1 (rd) : 0)
+ | RD (rd) | IMMED
+ | (the_insn.exp.X_add_number
+ & (the_insn.exp.X_op != O_constant ? 0 :
+ 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);
+ }
+}
+
+/* Handle the setsw synthetic instruction. */
+static void
+synthetize_setsw (insn)
+ const struct sparc_opcode *insn;
+{
+ int low32, rd, opc;
+
+ rd = (the_insn.opcode & RD (~0)) >> 25;
+
+ if (the_insn.exp.X_op != O_constant)
+ {
+ synthetize_setuw (insn);
+
+ /* Need to sign extend it. */
+ the_insn.opcode = (SRA_INSN | RS1 (rd) | RD (rd));
+ the_insn.reloc = BFD_RELOC_NONE;
+ output_insn (insn, &the_insn);
+ return;
+ }
+
+ if (sizeof(offsetT) > 4
+ && (the_insn.exp.X_add_number < -(offsetT) 0x80000000
+ || the_insn.exp.X_add_number > (offsetT) 0xffffffff))
+ as_warn (_("setsw: number not in -2147483648..4294967295 range"));
+
+ low32 = the_insn.exp.X_add_number;
+
+ if (low32 >= 0)
+ {
+ synthetize_setuw (insn);
+ return;
+ }
+
+ opc = OR_INSN;
+
+ the_insn.reloc = BFD_RELOC_NONE;
+ /* See if operand is absolute and small; skip sethi if so. */
+ if (low32 < -(1 << 12))
+ {
+ the_insn.opcode = (SETHI_INSN | RD (rd)
+ | (((~the_insn.exp.X_add_number) >> 10) & 0x3fffff));
+ output_insn (insn, &the_insn);
+ low32 = 0x1c00 | (low32 & 0x3ff);
+ opc = RS1 (rd) | XOR_INSN;
+ }
+
+ the_insn.opcode = (opc | RD (rd) | IMMED
+ | (low32 & 0x1fff));
+ output_insn (insn, &the_insn);
+}
+
+/* Handle the setsw synthetic instruction. */
+static void
+synthetize_setx (insn)
+ const struct sparc_opcode *insn;
+{
+ int upper32, lower32;
+ int tmpreg = (the_insn.opcode & RS1 (~0)) >> 14;
+ int dstreg = (the_insn.opcode & RD (~0)) >> 25;
+ int upper_dstreg;
+ int need_hh22_p = 0, need_hm10_p = 0, need_hi22_p = 0, need_lo10_p = 0;
+ int need_xor10_p = 0;
+
+#define SIGNEXT32(x) ((((x) & 0xffffffff) ^ 0x80000000) - 0x80000000)
+ lower32 = SIGNEXT32 (the_insn.exp.X_add_number);
+ upper32 = SIGNEXT32 (BSR (the_insn.exp.X_add_number, 32));
+#undef SIGNEXT32
+
+ upper_dstreg = tmpreg;
+ /* The tmp reg should not be the dst reg. */
+ if (tmpreg == dstreg)
+ as_warn (_("setx: temporary register same as destination register"));
+
+ /* ??? 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)
+ {
+ if (sparc_arch_size == 32)
+ {
+ /* When arch size is 32, we want setx to be equivalent
+ to setuw for anything but constants. */
+ the_insn.exp.X_add_number &= 0xffffffff;
+ synthetize_setuw (insn);
+ return;
+ }
+ need_hh22_p = need_hm10_p = need_hi22_p = need_lo10_p = 1;
+ lower32 = 0; upper32 = 0;
+ }
+ else
+ {
+ /* 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;
+
+ /* 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))
+ 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 or 0xffffffff00000000. */
+ || (! 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)
+ || (lower32 >= 0 && upper32 == -1))
+ need_hi22_p = 1;
+
+ if (need_hi22_p && upper32 == -1)
+ need_xor10_p = 1;
+
+ /* Does bottom part (after sethi) have bits? */
+ else 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;
+ }
+ else
+ /* Output directly to dst reg if lower 32 bits are all zero. */
+ upper_dstreg = dstreg;
+ }
+
+ if (!upper_dstreg && dstreg)
+ as_warn (_("setx: illegal temporary register g0"));
+
+ 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_hi22_p)
+ {
+ the_insn.opcode = (SETHI_INSN | RD (dstreg)
+ | (((need_xor10_p ? ~lower32 : lower32)
+ >> 10) & 0x3fffff));
+ the_insn.reloc = (the_insn.exp.X_op != O_constant
+ ? BFD_RELOC_SPARC_LM22 : 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_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 = (the_insn.exp.X_op != O_constant
+ ? BFD_RELOC_LO10 : BFD_RELOC_NONE);
+ 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);
+ }
+
+ /* To get -1 in upper32, we do sethi %hi(~x), r; xor r, -0x400 | x, r. */
+ if (need_xor10_p)
+ {
+ the_insn.opcode = (XOR_INSN | RS1 (dstreg) | RD (dstreg) | IMMED
+ | 0x1c00 | (lower32 & 0x3ff));
+ the_insn.reloc = BFD_RELOC_NONE;
+ output_insn (insn, &the_insn);
+ }
+
+ /* If we needed to build both upper and lower parts, OR them together. */
+ else 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);
+ }
+}
+
/* Main entry point to assemble one instruction. */
void
@@ -852,10 +1231,10 @@ md_assemble (str)
char *str;
{
const struct sparc_opcode *insn;
+ int special_case;
know (str);
- special_case = SPECIAL_CASE_NONE;
- sparc_ip (str, &insn);
+ special_case = sparc_ip (str, &insn);
/* We warn about attempts to put a floating point branch in a delay slot,
unless the delay slot has been annulled. */
@@ -867,7 +1246,7 @@ md_assemble (str)
F_{UNBR,CONDBR,FBR} set is annullable. */
&& ((last_insn->flags & (F_UNBR | F_CONDBR | F_FBR)) == 0
|| (last_opcode & ANNUL) == 0))
- as_warn ("FP branch in delay slot");
+ as_warn (_("FP branch in delay slot"));
/* SPARC before v9 requires a nop instruction between a floating
point instruction and a floating point branch. We insert one
@@ -883,7 +1262,7 @@ md_assemble (str)
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");
+ as_warn (_("FP branch preceded by FP instruction; NOP inserted"));
}
switch (special_case)
@@ -893,202 +1272,24 @@ md_assemble (str)
output_insn (insn, &the_insn);
break;
- case SPECIAL_CASE_SET:
- {
- 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 > (offsetT) 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;
- }
+ synthetize_setsw (insn);
+ break;
+
+ case SPECIAL_CASE_SET:
+ synthetize_setuw (insn);
+ 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;
- }
-
+ synthetize_setx (insn);
+ break;
+
case SPECIAL_CASE_FDIV:
{
int rd = (the_insn.opcode >> 25) & 0x1f;
-
+
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
@@ -1097,17 +1298,17 @@ md_assemble (str)
assert (the_insn.reloc == BFD_RELOC_NONE);
the_insn.opcode = FMOVS_INSN | rd | RD (rd);
output_insn (insn, &the_insn);
- break;
+ return;
}
-
+
default:
- as_fatal ("failed special case insn sanity check");
+ as_fatal (_("failed special case insn sanity check"));
}
}
/* Subroutine of md_assemble to do the actual parsing. */
-static void
+static int
sparc_ip (str, pinsn)
char *str;
const struct sparc_opcode **pinsn;
@@ -1123,9 +1324,15 @@ sparc_ip (str, pinsn)
int match = 0;
int comma = 0;
int v9_arg_p;
+ int special_case = SPECIAL_CASE_NONE;
- for (s = str; islower ((unsigned char) *s) || (*s >= '0' && *s <= '3'); ++s)
- ;
+ s = str;
+ if (islower ((unsigned char) *s))
+ {
+ do
+ ++s;
+ while (islower ((unsigned char) *s) || isdigit ((unsigned char) *s));
+ }
switch (*s)
{
@@ -1142,14 +1349,14 @@ sparc_ip (str, pinsn)
break;
default:
- as_fatal ("Unknown opcode: `%s'", str);
+ as_fatal (_("Unknown opcode: `%s'"), str);
}
insn = (struct sparc_opcode *) hash_find (op_hash, str);
*pinsn = insn;
if (insn == NULL)
{
- as_bad ("Unknown opcode: `%s'", str);
- return;
+ as_bad (_("Unknown opcode: `%s'"), str);
+ return special_case;
}
if (comma)
{
@@ -1186,7 +1393,7 @@ sparc_ip (str, pinsn)
if (! parse_keyword_arg (sparc_encode_membar, &s,
&mask))
{
- error_message = ": invalid membar mask name";
+ error_message = _(": invalid membar mask name");
goto error;
}
kmask |= mask;
@@ -1200,12 +1407,12 @@ sparc_ip (str, pinsn)
{
if (! parse_const_expr_arg (&s, &kmask))
{
- error_message = ": invalid membar mask expression";
+ error_message = _(": invalid membar mask expression");
goto error;
}
if (kmask < 0 || kmask > 127)
{
- error_message = ": invalid membar mask number";
+ error_message = _(": invalid membar mask number");
goto error;
}
}
@@ -1223,7 +1430,7 @@ sparc_ip (str, pinsn)
{
if (! parse_keyword_arg (sparc_encode_prefetch, &s, &fcn))
{
- error_message = ": invalid prefetch function name";
+ error_message = _(": invalid prefetch function name");
goto error;
}
}
@@ -1231,12 +1438,12 @@ sparc_ip (str, pinsn)
{
if (! parse_const_expr_arg (&s, &fcn))
{
- error_message = ": invalid prefetch function expression";
+ error_message = _(": invalid prefetch function expression");
goto error;
}
if (fcn < 0 || fcn > 31)
{
- error_message = ": invalid prefetch function number";
+ error_message = _(": invalid prefetch function number");
goto error;
}
}
@@ -1264,7 +1471,7 @@ sparc_ip (str, pinsn)
}
if (p->name[0] != s[0])
{
- error_message = ": unrecognizable privileged register";
+ error_message = _(": unrecognizable privileged register");
goto error;
}
if (*args == '?')
@@ -1276,7 +1483,7 @@ sparc_ip (str, pinsn)
}
else
{
- error_message = ": unrecognizable privileged register";
+ error_message = _(": unrecognizable privileged register");
goto error;
}
@@ -1300,12 +1507,12 @@ sparc_ip (str, pinsn)
}
if (p->name[0] != s[0])
{
- error_message = ": unrecognizable v9a ancillary state register";
+ error_message = _(": unrecognizable v9a ancillary state register");
goto error;
}
if (*args == '/' && (p->regnum == 20 || p->regnum == 21))
{
- error_message = ": rd on write only ancillary state register";
+ error_message = _(": rd on write only ancillary state register");
goto error;
}
if (*args == '/')
@@ -1317,7 +1524,7 @@ sparc_ip (str, pinsn)
}
else
{
- error_message = ": unrecognizable v9a ancillary state register";
+ error_message = _(": unrecognizable v9a ancillary state register");
goto error;
}
@@ -1341,7 +1548,7 @@ sparc_ip (str, pinsn)
{
if (num < 16 || 31 < num)
{
- error_message = ": asr number must be between 16 and 31";
+ error_message = _(": asr number must be between 16 and 31");
goto error;
}
}
@@ -1349,7 +1556,7 @@ sparc_ip (str, pinsn)
{
if (num < 0 || 31 < num)
{
- error_message = ": asr number must be between 0 and 31";
+ error_message = _(": asr number must be between 0 and 31");
goto error;
}
}
@@ -1359,7 +1566,7 @@ sparc_ip (str, pinsn)
}
else
{
- error_message = ": expecting %asrN";
+ error_message = _(": expecting %asrN");
goto error;
}
} /* if %asr */
@@ -1608,7 +1815,8 @@ sparc_ip (str, pinsn)
goto error;
case 'g': /* global register */
- if (isoctal (c = *s++))
+ c = *s++;
+ if (isoctal (c))
{
mask = c - '0';
break;
@@ -1616,7 +1824,8 @@ sparc_ip (str, pinsn)
goto error;
case 'i': /* in register */
- if (isoctal (c = *s++))
+ c = *s++;
+ if (isoctal (c))
{
mask = c - '0' + 24;
break;
@@ -1624,7 +1833,8 @@ sparc_ip (str, pinsn)
goto error;
case 'l': /* local register */
- if (isoctal (c = *s++))
+ c = *s++;
+ if (isoctal (c))
{
mask = (c - '0' + 16);
break;
@@ -1632,7 +1842,8 @@ sparc_ip (str, pinsn)
goto error;
case 'o': /* out register */
- if (isoctal (c = *s++))
+ c = *s++;
+ if (isoctal (c))
{
mask = (c - '0' + 8);
break;
@@ -1681,6 +1892,10 @@ sparc_ip (str, pinsn)
goto error;
}
+ if ((mask & ~1) == 2 && sparc_arch_size == 64
+ && no_undeclared_regs && ! globals [mask])
+ as_bad (_("detected global register use not covered by .register pseudo-op"));
+
/* Got the register, now figure out where
it goes in the opcode. */
switch (*args)
@@ -1750,9 +1965,9 @@ sparc_ip (str, pinsn)
if (mask >= 64)
{
if (SPARC_OPCODE_ARCH_V9_P (max_architecture))
- error_message = ": There are only 64 f registers; [0-63]";
+ error_message = _(": There are only 64 f registers; [0-63]");
else
- error_message = ": There are only 32 f registers; [0-31]";
+ error_message = _(": There are only 32 f registers; [0-31]");
goto error;
} /* on error */
else if (mask >= 32)
@@ -1764,7 +1979,7 @@ sparc_ip (str, pinsn)
}
else
{
- error_message = ": There are only 32 f registers; [0-31]";
+ error_message = _(": There are only 32 f registers; [0-31]");
goto error;
}
}
@@ -1808,14 +2023,10 @@ sparc_ip (str, pinsn)
}
break;
- case '0': /* 64 bit immediate (setx insn) */
+ case '0': /* 64 bit immediate (set, setsw, 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;
-
case 'l': /* 22 bit PC relative immediate */
the_insn.reloc = BFD_RELOC_SPARC_WDISP22;
the_insn.pcrel = 1;
@@ -1826,6 +2037,7 @@ sparc_ip (str, pinsn)
the_insn.pcrel = 1;
goto immediate;
+ case 'h':
case 'n': /* 22 bit immediate */
the_insn.reloc = BFD_RELOC_SPARC22;
goto immediate;
@@ -1839,89 +2051,227 @@ sparc_ip (str, pinsn)
if (*s == ' ')
s++;
- /* Check for %hi, etc. */
- if (*s == '%')
- {
- static struct ops {
- /* The name as it appears in assembler. */
- char *name;
- /* strlen (name), precomputed for speed */
- int len;
- /* The reloc this pseudo-op translates to. */
- int reloc;
- /* Non-zero if for v9 only. */
- int v9_p;
- /* Non-zero if can be used in pc-relative contexts. */
- int pcrel_p;/*FIXME:wip*/
- } ops[] = {
- /* hix/lox must appear before hi/lo so %hix won't be
- mistaken for %hi. */
- { "hix", 3, BFD_RELOC_SPARC_HIX22, 1, 0 },
- { "lox", 3, BFD_RELOC_SPARC_LOX10, 1, 0 },
- { "hi", 2, BFD_RELOC_HI22, 0, 1 },
- { "lo", 2, BFD_RELOC_LO10, 0, 1 },
- { "hh", 2, BFD_RELOC_SPARC_HH22, 1, 1 },
- { "hm", 2, BFD_RELOC_SPARC_HM10, 1, 1 },
- { "lm", 2, BFD_RELOC_SPARC_LM22, 1, 1 },
- { "h44", 3, BFD_RELOC_SPARC_H44, 1, 0 },
- { "m44", 3, BFD_RELOC_SPARC_M44, 1, 0 },
- { "l44", 3, BFD_RELOC_SPARC_L44, 1, 0 },
- { "uhi", 3, BFD_RELOC_SPARC_HH22, 1, 0 },
- { "ulo", 3, BFD_RELOC_SPARC_HM10, 1, 0 },
- { NULL }
- };
- struct ops *o;
-
- for (o = ops; o->name; o++)
- if (strncmp (s + 1, o->name, o->len) == 0)
+ {
+ char *s1;
+ char *op_arg = NULL;
+ expressionS op_exp;
+ bfd_reloc_code_real_type old_reloc = the_insn.reloc;
+
+ /* Check for %hi, etc. */
+ if (*s == '%')
+ {
+ static const struct ops {
+ /* The name as it appears in assembler. */
+ char *name;
+ /* strlen (name), precomputed for speed */
+ int len;
+ /* The reloc this pseudo-op translates to. */
+ int reloc;
+ /* Non-zero if for v9 only. */
+ int v9_p;
+ /* Non-zero if can be used in pc-relative contexts. */
+ int pcrel_p;/*FIXME:wip*/
+ } ops[] = {
+ /* hix/lox must appear before hi/lo so %hix won't be
+ mistaken for %hi. */
+ { "hix", 3, BFD_RELOC_SPARC_HIX22, 1, 0 },
+ { "lox", 3, BFD_RELOC_SPARC_LOX10, 1, 0 },
+ { "hi", 2, BFD_RELOC_HI22, 0, 1 },
+ { "lo", 2, BFD_RELOC_LO10, 0, 1 },
+ { "hh", 2, BFD_RELOC_SPARC_HH22, 1, 1 },
+ { "hm", 2, BFD_RELOC_SPARC_HM10, 1, 1 },
+ { "lm", 2, BFD_RELOC_SPARC_LM22, 1, 1 },
+ { "h44", 3, BFD_RELOC_SPARC_H44, 1, 0 },
+ { "m44", 3, BFD_RELOC_SPARC_M44, 1, 0 },
+ { "l44", 3, BFD_RELOC_SPARC_L44, 1, 0 },
+ { "uhi", 3, BFD_RELOC_SPARC_HH22, 1, 0 },
+ { "ulo", 3, BFD_RELOC_SPARC_HM10, 1, 0 },
+ { NULL }
+ };
+ const struct ops *o;
+
+ for (o = ops; o->name; o++)
+ if (strncmp (s + 1, o->name, o->len) == 0)
+ break;
+ if (o->name == NULL)
break;
- if (o->name == NULL)
- break;
+
+ if (s[o->len + 1] != '(')
+ {
+ as_bad (_("Illegal operands: %%%s requires arguments in ()"), o->name);
+ return special_case;
+ }
- the_insn.reloc = o->reloc;
- s += o->len + 1;
- v9_arg_p = o->v9_p;
- }
+ op_arg = o->name;
+ the_insn.reloc = o->reloc;
+ s += o->len + 2;
+ v9_arg_p = o->v9_p;
+ }
+
+ /* Note that if the get_expression() fails, we will still
+ have created U entries in the symbol table for the
+ 'symbols' in the input string. Try not to create U
+ symbols for registers, etc. */
- /* Note that if the get_expression() fails, we will still
- have created U entries in the symbol table for the
- 'symbols' in the input string. Try not to create U
- symbols for registers, etc. */
- {
/* This stuff checks to see if the expression ends in
+%reg. If it does, it removes the register from
the expression, and re-sets 's' to point to the
right place. */
- char *s1;
+ if (op_arg)
+ {
+ int npar = 0;
+
+ for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++)
+ if (*s1 == '(')
+ npar++;
+ else if (*s1 == ')')
+ {
+ if (!npar)
+ break;
+ npar--;
+ }
+
+ if (*s1 != ')')
+ {
+ as_bad (_("Illegal operands: %%%s requires arguments in ()"), op_arg);
+ return special_case;
+ }
+
+ *s1 = '\0';
+ (void) get_expression (s);
+ *s1 = ')';
+ s = s1 + 1;
+ if (*s == ',' || *s == ']' || !*s)
+ continue;
+ if (*s != '+' && *s != '-')
+ {
+ as_bad (_("Illegal operands: Can't do arithmetics other than + and - involving %%%s()"), op_arg);
+ return special_case;
+ }
+ *s1 = '0';
+ s = s1;
+ op_exp = the_insn.exp;
+ memset (&the_insn.exp, 0, sizeof(the_insn.exp));
+ }
for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++) ;
if (s1 != s && isdigit ((unsigned char) s1[-1]))
{
if (s1[-2] == '%' && s1[-3] == '+')
+ s1 -= 3;
+ else if (strchr ("goli0123456789", s1[-2]) && s1[-3] == '%' && s1[-4] == '+')
+ s1 -= 4;
+ else
+ s1 = NULL;
+ if (s1)
{
- s1 -= 3;
*s1 = '\0';
- (void) get_expression (s);
+ if (op_arg && s1 == s + 1)
+ the_insn.exp.X_op = O_absent;
+ else
+ (void) get_expression (s);
*s1 = '+';
+ if (op_arg)
+ *s = ')';
s = s1;
- continue;
}
- else if (strchr ("goli0123456789", s1[-2]) && s1[-3] == '%' && s1[-4] == '+')
+ }
+ else
+ s1 = NULL;
+
+ if (!s1)
+ {
+ (void) get_expression (s);
+ if (op_arg)
+ *s = ')';
+ s = expr_end;
+ }
+
+ if (op_arg)
+ {
+ the_insn.exp2 = the_insn.exp;
+ the_insn.exp = op_exp;
+ if (the_insn.exp2.X_op == O_absent)
+ the_insn.exp2.X_op = O_illegal;
+ else if (the_insn.exp.X_op == O_absent)
{
- s1 -= 4;
- *s1 = '\0';
- (void) get_expression (s);
- *s1 = '+';
- s = s1;
- continue;
+ the_insn.exp = the_insn.exp2;
+ the_insn.exp2.X_op = O_illegal;
+ }
+ else if (the_insn.exp.X_op == O_constant)
+ {
+ valueT val = the_insn.exp.X_add_number;
+ switch (the_insn.reloc)
+ {
+ default:
+ break;
+
+ case BFD_RELOC_SPARC_HH22:
+ val = BSR (val, 32);
+ /* intentional fallthrough */
+
+ case BFD_RELOC_SPARC_LM22:
+ case BFD_RELOC_HI22:
+ val = (val >> 10) & 0x3fffff;
+ break;
+
+ case BFD_RELOC_SPARC_HM10:
+ val = BSR (val, 32);
+ /* intentional fallthrough */
+
+ case BFD_RELOC_LO10:
+ val &= 0x3ff;
+ break;
+
+ case BFD_RELOC_SPARC_H44:
+ val >>= 22;
+ val &= 0x3fffff;
+ break;
+
+ case BFD_RELOC_SPARC_M44:
+ val >>= 12;
+ val &= 0x3ff;
+ break;
+
+ case BFD_RELOC_SPARC_L44:
+ val &= 0xfff;
+ break;
+
+ case BFD_RELOC_SPARC_HIX22:
+ val = ~ val;
+ val = (val >> 10) & 0x3fffff;
+ break;
+
+ case BFD_RELOC_SPARC_LOX10:
+ val = (val & 0x3ff) | 0x1c00;
+ break;
+ }
+ the_insn.exp = the_insn.exp2;
+ the_insn.exp.X_add_number += val;
+ the_insn.exp2.X_op = O_illegal;
+ the_insn.reloc = old_reloc;
+ }
+ else if (the_insn.exp2.X_op != O_constant)
+ {
+ as_bad (_("Illegal operands: Can't add non-constant expression to %%%s()"), op_arg);
+ return special_case;
+ }
+ else
+ {
+ if (old_reloc != BFD_RELOC_SPARC13
+ || the_insn.reloc != BFD_RELOC_LO10
+ || sparc_arch_size != 64
+ || sparc_pic_code)
+ {
+ as_bad (_("Illegal operands: Can't do arithmetics involving %%%s() of a relocatable symbol"), op_arg);
+ return special_case;
+ }
+ the_insn.reloc = BFD_RELOC_SPARC_OLO10;
}
}
}
- (void) get_expression (s);
- s = expr_end;
-
/* Check for constants that don't require emitting a reloc. */
if (the_insn.exp.X_op == O_constant
&& the_insn.exp.X_add_symbol == 0
@@ -1933,7 +2283,7 @@ sparc_ip (str, pinsn)
&& the_insn.reloc == BFD_RELOC_32_PCREL_S2
&& in_signed_range (the_insn.exp.X_add_number, 0x3fff))
{
- error_message = ": PC-relative operand can't be a constant";
+ error_message = _(": PC-relative operand can't be a constant");
goto error;
}
@@ -1966,7 +2316,7 @@ sparc_ip (str, pinsn)
{
if (! parse_keyword_arg (sparc_encode_asi, &s, &asi))
{
- error_message = ": invalid ASI name";
+ error_message = _(": invalid ASI name");
goto error;
}
}
@@ -1974,12 +2324,12 @@ sparc_ip (str, pinsn)
{
if (! parse_const_expr_arg (&s, &asi))
{
- error_message = ": invalid ASI expression";
+ error_message = _(": invalid ASI expression");
goto error;
}
if (asi < 0 || asi > 255)
{
- error_message = ": invalid ASI number";
+ error_message = _(": invalid ASI number");
goto error;
}
}
@@ -2076,12 +2426,12 @@ sparc_ip (str, pinsn)
{
int n = e.X_add_number;
if (n != e.X_add_number || (n & ~0x1ff) != 0)
- as_bad ("OPF immediate operand out of range (0-0x1ff)");
+ as_bad (_("OPF immediate operand out of range (0-0x1ff)"));
else
opcode |= e.X_add_number << 5;
}
else
- as_bad ("non-immediate OPF operand, ignored");
+ as_bad (_("non-immediate OPF operand, ignored"));
s = input_line_pointer;
input_line_pointer = push;
continue;
@@ -2100,7 +2450,7 @@ sparc_ip (str, pinsn)
int cpreg;
if (! parse_keyword_arg (sparc_encode_sparclet_cpreg, &s, &cpreg))
{
- error_message = ": invalid cpreg name";
+ error_message = _(": invalid cpreg name");
goto error;
}
opcode |= (*args == 'U' ? RS1 (cpreg) : RD (cpreg));
@@ -2108,7 +2458,7 @@ sparc_ip (str, pinsn)
}
default:
- as_fatal ("failed sanity check.");
+ as_fatal (_("failed sanity check."));
} /* switch on arg code */
/* Break out of for() loop. */
@@ -2129,8 +2479,8 @@ sparc_ip (str, pinsn)
}
else
{
- as_bad ("Illegal operands%s", error_message);
- return;
+ as_bad (_("Illegal operands%s"), error_message);
+ return special_case;
}
}
else
@@ -2158,7 +2508,7 @@ sparc_ip (str, pinsn)
if (warn_on_bump
&& needed_architecture > warn_after_architecture)
{
- as_warn ("architecture bumped from \"%s\" to \"%s\" on \"%s\"",
+ as_warn (_("architecture bumped from \"%s\" to \"%s\" on \"%s\""),
sparc_opcode_archs[current_architecture].name,
sparc_opcode_archs[needed_architecture].name,
str);
@@ -2194,11 +2544,11 @@ sparc_ip (str, pinsn)
++arch;
}
- as_bad ("Architecture mismatch on \"%s\".", str);
- as_tsktsk (" (Requires %s; requested architecture is %s.)",
+ as_bad (_("Architecture mismatch on \"%s\"."), str);
+ as_tsktsk (_(" (Requires %s; requested architecture is %s.)"),
required_archs,
sparc_opcode_archs[max_architecture].name);
- return;
+ return special_case;
}
} /* if no match */
@@ -2206,6 +2556,7 @@ sparc_ip (str, pinsn)
} /* forever looking for a match */
the_insn.opcode = opcode;
+ return special_case;
}
/* Parse an argument that can be expressed as a keyword.
@@ -2289,7 +2640,7 @@ get_expression (str)
&& seg != bss_section
&& seg != undefined_section)
{
- the_insn.error = "bad segment";
+ the_insn.error = _("bad segment");
expr_end = input_line_pointer;
input_line_pointer = save_in;
return 1;
@@ -2328,6 +2679,8 @@ output_insn (insn, the_insn)
the insn size is 4 and fixup_segment will signal an overflow for
large 8 byte quantities. */
fixP->fx_no_overflow = 1;
+ if (the_insn->reloc == BFD_RELOC_SPARC_OLO10)
+ fixP->tc_fix_data = the_insn->exp2.X_add_number;
}
last_insn = insn;
@@ -2384,7 +2737,7 @@ md_atof (type, litP, sizeP)
default:
*sizeP = 0;
- return "Bad call to MD_ATOF()";
+ return _("Bad call to MD_ATOF()");
}
t = atof_ieee (input_line_pointer, type, words);
@@ -2423,7 +2776,11 @@ md_number_to_chars (buf, val, n)
{
if (target_big_endian)
number_to_chars_bigendian (buf, val, n);
- else
+ else if (target_little_endian_data
+ && ((n == 4 || n == 2) && ~now_seg->flags & SEC_ALLOC))
+ /* Output debug words, which are not in allocated sections, as big endian */
+ number_to_chars_bigendian (buf, val, n);
+ else if (target_little_endian_data || ! target_big_endian)
number_to_chars_littleendian (buf, val, n);
}
@@ -2454,7 +2811,7 @@ md_apply_fix3 (fixP, value, segment)
don't want to include the value of an externally visible symbol. */
if (fixP->fx_addsy != NULL)
{
- if (fixP->fx_addsy->sy_used_in_reloc
+ if (symbol_used_in_reloc_p (fixP->fx_addsy)
&& (S_IS_EXTERNAL (fixP->fx_addsy)
|| S_IS_WEAK (fixP->fx_addsy)
|| (sparc_pic_code && ! fixP->fx_pcrel)
@@ -2499,8 +2856,23 @@ md_apply_fix3 (fixP, value, segment)
&& fixP->fx_r_type != BFD_RELOC_32_PCREL_S2
&& fixP->fx_addsy != NULL
&& ! S_IS_COMMON (fixP->fx_addsy)
- && (fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) == 0)
+ && symbol_section_p (fixP->fx_addsy))
fixP->fx_addnumber -= 2 * S_GET_VALUE (fixP->fx_addsy);
+
+ /* When generating PIC code, we need to fiddle to get
+ bfd_install_relocation to do the right thing for a PC relative
+ reloc against a local symbol which we are going to keep. */
+ if (sparc_pic_code
+ && fixP->fx_r_type == BFD_RELOC_32_PCREL_S2
+ && fixP->fx_addsy != NULL
+ && (S_IS_EXTERNAL (fixP->fx_addsy)
+ || S_IS_WEAK (fixP->fx_addsy))
+ && S_IS_DEFINED (fixP->fx_addsy)
+ && ! S_IS_COMMON (fixP->fx_addsy))
+ {
+ val = 0;
+ fixP->fx_addnumber -= 2 * S_GET_VALUE (fixP->fx_addsy);
+ }
#endif
/* If this is a data relocation, just output VAL. */
@@ -2509,7 +2881,8 @@ md_apply_fix3 (fixP, value, segment)
{
md_number_to_chars (buf, val, 2);
}
- else if (fixP->fx_r_type == BFD_RELOC_32)
+ else if (fixP->fx_r_type == BFD_RELOC_32
+ || fixP->fx_r_type == BFD_RELOC_SPARC_REV32)
{
md_number_to_chars (buf, val, 4);
}
@@ -2517,6 +2890,12 @@ md_apply_fix3 (fixP, value, segment)
{
md_number_to_chars (buf, val, 8);
}
+ else if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+ || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+ {
+ fixP->fx_done = 0;
+ return 1;
+ }
else
{
/* It's a relocation against an instruction. */
@@ -2534,38 +2913,43 @@ md_apply_fix3 (fixP, value, segment)
being done! */
if (! sparc_pic_code
|| fixP->fx_addsy == NULL
- || (fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0)
+ || symbol_section_p (fixP->fx_addsy))
++val;
insn |= val & 0x3fffffff;
break;
case BFD_RELOC_SPARC_11:
if (! in_signed_range (val, 0x7ff))
- as_bad_where (fixP->fx_file, fixP->fx_line, "relocation overflow");
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("relocation overflow"));
insn |= val & 0x7ff;
break;
case BFD_RELOC_SPARC_10:
if (! in_signed_range (val, 0x3ff))
- as_bad_where (fixP->fx_file, fixP->fx_line, "relocation overflow");
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("relocation overflow"));
insn |= val & 0x3ff;
break;
case BFD_RELOC_SPARC_7:
if (! in_bitfield_range (val, 0x7f))
- as_bad_where (fixP->fx_file, fixP->fx_line, "relocation overflow");
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("relocation overflow"));
insn |= val & 0x7f;
break;
case BFD_RELOC_SPARC_6:
if (! in_bitfield_range (val, 0x3f))
- as_bad_where (fixP->fx_file, fixP->fx_line, "relocation overflow");
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("relocation overflow"));
insn |= val & 0x3f;
break;
case BFD_RELOC_SPARC_5:
if (! in_bitfield_range (val, 0x1f))
- as_bad_where (fixP->fx_file, fixP->fx_line, "relocation overflow");
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("relocation overflow"));
insn |= val & 0x1f;
break;
@@ -2573,7 +2957,8 @@ md_apply_fix3 (fixP, value, segment)
/* FIXME: simplify */
if (((val > 0) && (val & ~0x3fffc))
|| ((val < 0) && (~(val - 1) & ~0x3fffc)))
- as_bad_where (fixP->fx_file, fixP->fx_line, "relocation overflow");
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("relocation overflow"));
/* FIXME: The +1 deserves a comment. */
val = (val >> 2) + 1;
insn |= ((val & 0xc000) << 6) | (val & 0x3fff);
@@ -2583,7 +2968,8 @@ md_apply_fix3 (fixP, value, segment)
/* FIXME: simplify */
if (((val > 0) && (val & ~0x1ffffc))
|| ((val < 0) && (~(val - 1) & ~0x1ffffc)))
- as_bad_where (fixP->fx_file, fixP->fx_line, "relocation overflow");
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("relocation overflow"));
/* FIXME: The +1 deserves a comment. */
val = (val >> 2) + 1;
insn |= val & 0x7ffff;
@@ -2608,7 +2994,8 @@ md_apply_fix3 (fixP, value, segment)
case BFD_RELOC_SPARC22:
if (val & ~0x003fffff)
- as_bad_where (fixP->fx_file, fixP->fx_line, "relocation overflow");
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("relocation overflow"));
insn |= (val & 0x3fffff);
break;
@@ -2628,9 +3015,15 @@ md_apply_fix3 (fixP, value, segment)
}
break;
+ case BFD_RELOC_SPARC_OLO10:
+ val &= 0x3ff;
+ val += fixP->tc_fix_data;
+ /* intentional fallthrough */
+
case BFD_RELOC_SPARC13:
if (! in_signed_range (val, 0x1fff))
- as_bad_where (fixP->fx_file, fixP->fx_line, "relocation overflow");
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("relocation overflow"));
insn |= val & 0x1fff;
break;
@@ -2676,7 +3069,7 @@ md_apply_fix3 (fixP, value, segment)
case BFD_RELOC_NONE:
default:
as_bad_where (fixP->fx_file, fixP->fx_line,
- "bad or unhandled relocation type: 0x%02x",
+ _("bad or unhandled relocation type: 0x%02x"),
fixP->fx_r_type);
break;
}
@@ -2696,17 +3089,20 @@ md_apply_fix3 (fixP, value, segment)
/* Translate internal representation of relocation info to BFD target
format. */
-arelent *
+arelent **
tc_gen_reloc (section, fixp)
asection *section;
fixS *fixp;
{
+ static arelent *relocs[3];
arelent *reloc;
bfd_reloc_code_real_type code;
- reloc = (arelent *) xmalloc (sizeof (arelent));
+ relocs[0] = reloc = (arelent *) xmalloc (sizeof (arelent));
+ relocs[1] = NULL;
- reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+ reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
switch (fixp->fx_r_type)
@@ -2717,6 +3113,7 @@ tc_gen_reloc (section, fixp)
case BFD_RELOC_LO10:
case BFD_RELOC_32_PCREL_S2:
case BFD_RELOC_SPARC13:
+ case BFD_RELOC_SPARC22:
case BFD_RELOC_SPARC_BASE13:
case BFD_RELOC_SPARC_WDISP16:
case BFD_RELOC_SPARC_WDISP19:
@@ -2738,6 +3135,10 @@ tc_gen_reloc (section, fixp)
case BFD_RELOC_SPARC_L44:
case BFD_RELOC_SPARC_HIX22:
case BFD_RELOC_SPARC_LOX10:
+ case BFD_RELOC_SPARC_REV32:
+ case BFD_RELOC_SPARC_OLO10:
+ case BFD_RELOC_VTABLE_ENTRY:
+ case BFD_RELOC_VTABLE_INHERIT:
code = fixp->fx_r_type;
break;
default:
@@ -2755,6 +3156,8 @@ tc_gen_reloc (section, fixp)
#define GOT_NAME "__GLOBAL_OFFSET_TABLE_"
#endif
+ /* This code must be parallel to the OBJ_ELF tc_fix_adjustable. */
+
if (sparc_pic_code)
{
switch (code)
@@ -2789,13 +3192,18 @@ tc_gen_reloc (section, fixp)
}
#endif /* defined (OBJ_ELF) || defined (OBJ_AOUT) */
- reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
+ if (code == BFD_RELOC_SPARC_OLO10)
+ reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_LO10);
+ else
+ reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
if (reloc->howto == 0)
{
as_bad_where (fixp->fx_file, fixp->fx_line,
- "internal error: can't export reloc type %d (`%s')",
+ _("internal error: can't export reloc type %d (`%s')"),
fixp->fx_r_type, bfd_get_reloc_code_name (code));
- return 0;
+ xfree (reloc);
+ relocs[0] = NULL;
+ return relocs;
}
/* @@ Why fx_addnumber sometimes and fx_offset other times? */
@@ -2805,6 +3213,14 @@ tc_gen_reloc (section, fixp)
|| code == BFD_RELOC_SPARC_PC10
|| code == BFD_RELOC_SPARC_PC22)
reloc->addend = fixp->fx_addnumber;
+ else if (sparc_pic_code
+ && fixp->fx_r_type == BFD_RELOC_32_PCREL_S2
+ && fixp->fx_addsy != NULL
+ && (S_IS_EXTERNAL (fixp->fx_addsy)
+ || S_IS_WEAK (fixp->fx_addsy))
+ && S_IS_DEFINED (fixp->fx_addsy)
+ && ! S_IS_COMMON (fixp->fx_addsy))
+ reloc->addend = fixp->fx_addnumber;
else
reloc->addend = fixp->fx_offset - reloc->address;
@@ -2814,7 +3230,7 @@ tc_gen_reloc (section, fixp)
|| code == BFD_RELOC_SPARC_PC10
|| code == BFD_RELOC_SPARC_PC22)
reloc->addend = fixp->fx_addnumber;
- else if ((fixp->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0)
+ else if (symbol_section_p (fixp->fx_addsy))
reloc->addend = (section->vma
+ fixp->fx_addnumber
+ md_pcrel_from (fixp));
@@ -2822,7 +3238,21 @@ tc_gen_reloc (section, fixp)
reloc->addend = fixp->fx_offset;
#endif
- return reloc;
+ /* We expand R_SPARC_OLO10 to R_SPARC_LO10 and R_SPARC_13
+ on the same location. */
+ if (code == BFD_RELOC_SPARC_OLO10)
+ {
+ relocs[1] = reloc = (arelent *) xmalloc (sizeof (arelent));
+ relocs[2] = NULL;
+
+ reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ *reloc->sym_ptr_ptr = symbol_get_bfdsym (section_symbol (absolute_section));
+ reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+ reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_SPARC13);
+ reloc->addend = fixp->tc_fix_data;
+ }
+
+ return relocs;
}
/* We have no need to default values of symbols. */
@@ -2869,11 +3299,29 @@ md_pcrel_from (fixP)
ret = fixP->fx_where + fixP->fx_frag->fr_address;
if (! sparc_pic_code
|| fixP->fx_addsy == NULL
- || (fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0)
+ || symbol_section_p (fixP->fx_addsy))
ret += fixP->fx_size;
return ret;
}
+/* Return log2 (VALUE), or -1 if VALUE is not an exact positive power
+ of two. */
+
+static int
+log2 (value)
+ int value;
+{
+ int shift;
+
+ if (value <= 0)
+ return -1;
+
+ for (shift = 0; (value & 1) == 0; value >>= 1)
+ ++shift;
+
+ return (value == 1) ? shift : -1;
+}
+
/*
* sort of like s_lcomm
*/
@@ -2902,7 +3350,7 @@ s_reserve (ignore)
if (*input_line_pointer != ',')
{
- as_bad ("Expected comma after name");
+ as_bad (_("Expected comma after name"));
ignore_rest_of_line ();
return;
}
@@ -2911,7 +3359,7 @@ s_reserve (ignore)
if ((size = get_absolute_expression ()) < 0)
{
- as_bad ("BSS length (%d.) <0! Ignored.", size);
+ as_bad (_("BSS length (%d.) <0! Ignored."), size);
ignore_rest_of_line ();
return;
} /* bad length */
@@ -2923,7 +3371,7 @@ s_reserve (ignore)
if (strncmp (input_line_pointer, ",\"bss\"", 6) != 0
&& strncmp (input_line_pointer, ",\".bss\"", 7) != 0)
{
- as_bad ("bad .reserve segment -- expected BSS segment");
+ as_bad (_("bad .reserve segment -- expected BSS segment"));
return;
}
@@ -2940,38 +3388,43 @@ s_reserve (ignore)
SKIP_WHITESPACE ();
if (*input_line_pointer == '\n')
{
- as_bad ("Missing alignment");
+ as_bad (_("missing alignment"));
+ ignore_rest_of_line ();
return;
}
- align = get_absolute_expression ();
+ align = (int) get_absolute_expression ();
+
#ifndef OBJ_ELF
if (align > max_alignment)
{
align = max_alignment;
- as_warn ("Alignment too large: %d. assumed.", align);
+ as_warn (_("alignment too large; assuming %d"), align);
}
#endif
+
if (align < 0)
{
- align = 0;
- as_warn ("Alignment negative. 0 assumed.");
+ as_bad (_("negative alignment"));
+ ignore_rest_of_line ();
+ return;
}
- record_alignment (bss_section, align);
-
- /* convert to a power of 2 alignment */
- for (temp = 0; (align & 1) == 0; align >>= 1, ++temp);;
-
- if (align != 1)
+ if (align != 0)
{
- as_bad ("Alignment not a power of 2");
- ignore_rest_of_line ();
- return;
- } /* not a power of two */
+ temp = log2 (align);
+ if (temp < 0)
+ {
+ as_bad (_("alignment not a power of 2"));
+ ignore_rest_of_line ();
+ return;
+ }
+
+ align = temp;
+ }
- align = temp;
- } /* if has optional alignment */
+ record_alignment (bss_section, align);
+ }
else
align = 0;
@@ -2995,9 +3448,9 @@ s_reserve (ignore)
/* detach from old frag */
if (S_GET_SEGMENT(symbolP) == bss_section)
- symbolP->sy_frag->fr_symbol = NULL;
+ symbol_get_frag (symbolP)->fr_symbol = NULL;
- symbolP->sy_frag = frag_now;
+ symbol_set_frag (symbolP, frag_now);
pfrag = frag_var (rs_org, 1, 1, (relax_substateT)0, symbolP,
(offsetT) size, (char *)0);
*pfrag = 0;
@@ -3005,6 +3458,10 @@ s_reserve (ignore)
S_SET_SEGMENT (symbolP, bss_section);
subseg_set (current_seg, current_subseg);
+
+#ifdef OBJ_ELF
+ S_SET_SIZE (symbolP, size);
+#endif
}
}
else
@@ -3034,14 +3491,14 @@ s_common (ignore)
SKIP_WHITESPACE ();
if (*input_line_pointer != ',')
{
- as_bad ("Expected comma after symbol-name");
+ as_bad (_("Expected comma after symbol-name"));
ignore_rest_of_line ();
return;
}
input_line_pointer++; /* skip ',' */
if ((temp = get_absolute_expression ()) < 0)
{
- as_bad (".COMMon length (%d.) <0! Ignored.", temp);
+ as_bad (_(".COMMon length (%d.) <0! Ignored."), temp);
ignore_rest_of_line ();
return;
}
@@ -3051,7 +3508,7 @@ s_common (ignore)
*p = c;
if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
{
- as_bad ("Ignoring attempt to re-define symbol");
+ as_bad (_("Ignoring attempt to re-define symbol"));
ignore_rest_of_line ();
return;
}
@@ -3059,7 +3516,7 @@ s_common (ignore)
{
if (S_GET_VALUE (symbolP) != (valueT) size)
{
- as_warn ("Length of .comm \"%s\" is already %ld. Not changed to %d.",
+ as_warn (_("Length of .comm \"%s\" is already %ld. Not changed to %d."),
S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size);
}
}
@@ -3070,10 +3527,10 @@ s_common (ignore)
S_SET_EXTERNAL (symbolP);
#endif
}
- know (symbolP->sy_frag == &zero_address_frag);
+ know (symbol_get_frag (symbolP) == &zero_address_frag);
if (*input_line_pointer != ',')
{
- as_bad ("Expected comma after common length");
+ as_bad (_("Expected comma after common length"));
ignore_rest_of_line ();
return;
}
@@ -3082,20 +3539,24 @@ s_common (ignore)
if (*input_line_pointer != '"')
{
temp = get_absolute_expression ();
+
#ifndef OBJ_ELF
if (temp > max_alignment)
{
temp = max_alignment;
- as_warn ("Common alignment too large: %d. assumed", temp);
+ as_warn (_("alignment too large; assuming %d"), temp);
}
#endif
+
if (temp < 0)
{
- temp = 0;
- as_warn ("Common alignment negative; 0 assumed");
+ as_bad (_("negative alignment"));
+ ignore_rest_of_line ();
+ return;
}
+
#ifdef OBJ_ELF
- if (symbolP->local)
+ if (symbol_get_obj (symbolP)->local)
{
segT old_sec;
int old_subsec;
@@ -3104,28 +3565,42 @@ s_common (ignore)
old_sec = now_seg;
old_subsec = now_subseg;
- align = temp;
+
+ if (temp == 0)
+ align = 0;
+ else
+ align = log2 (temp);
+
+ if (align < 0)
+ {
+ as_bad (_("alignment not a power of 2"));
+ ignore_rest_of_line ();
+ return;
+ }
+
record_alignment (bss_section, align);
subseg_set (bss_section, 0);
if (align)
frag_align (align, 0, 0);
if (S_GET_SEGMENT (symbolP) == bss_section)
- symbolP->sy_frag->fr_symbol = 0;
- symbolP->sy_frag = frag_now;
+ symbol_get_frag (symbolP)->fr_symbol = 0;
+ symbol_set_frag (symbolP, frag_now);
p = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP,
(offsetT) size, (char *) 0);
*p = 0;
S_SET_SEGMENT (symbolP, bss_section);
S_CLEAR_EXTERNAL (symbolP);
+ S_SET_SIZE (symbolP, size);
subseg_set (old_sec, old_subsec);
}
else
-#endif
+#endif /* OBJ_ELF */
{
allocate_common:
S_SET_VALUE (symbolP, (valueT) size);
#ifdef OBJ_ELF
S_SET_ALIGN (symbolP, temp);
+ S_SET_SIZE (symbolP, size);
#endif
S_SET_EXTERNAL (symbolP);
S_SET_SEGMENT (symbolP, bfd_com_section_ptr);
@@ -3152,7 +3627,7 @@ s_common (ignore)
}
#ifdef BFD_ASSEMBLER
- symbolP->bsym->flags |= BSF_OBJECT;
+ symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
#endif
demand_empty_rest_of_line ();
@@ -3165,7 +3640,7 @@ s_common (ignore)
p++;
c = *p;
*p = '\0';
- as_bad ("bad .common segment %s", input_line_pointer + 1);
+ as_bad (_("bad .common segment %s"), input_line_pointer + 1);
*p = c;
input_line_pointer = p;
ignore_rest_of_line ();
@@ -3217,7 +3692,7 @@ s_seg (ignore)
subseg_set (data_section, 255); /* FIXME-SOMEDAY */
return;
}
- as_bad ("Unknown segment type");
+ as_bad (_("Unknown segment type"));
demand_empty_rest_of_line ();
}
@@ -3257,6 +3732,134 @@ s_uacons (bytes)
cons (bytes);
}
+/* This handles the native word allocation pseudo-op .nword.
+ For sparc_arch_size 32 it is equivalent to .word, for
+ sparc_arch_size 64 it is equivalent to .xword. */
+
+static void
+s_ncons (bytes)
+ int bytes;
+{
+ cons (sparc_arch_size == 32 ? 4 : 8);
+}
+
+#ifdef OBJ_ELF
+/* Handle the SPARC ELF .register pseudo-op. This sets the binding of a
+ global register.
+ The syntax is:
+
+ .register %g[2367],{#scratch|symbolname|#ignore}
+ */
+
+static void
+s_register (ignore)
+ int ignore;
+{
+ char c;
+ int reg;
+ int flags;
+ const char *regname;
+
+ if (input_line_pointer[0] != '%'
+ || input_line_pointer[1] != 'g'
+ || ((input_line_pointer[2] & ~1) != '2'
+ && (input_line_pointer[2] & ~1) != '6')
+ || input_line_pointer[3] != ',')
+ as_bad (_("register syntax is .register %%g[2367],{#scratch|symbolname|#ignore}"));
+ reg = input_line_pointer[2] - '0';
+ input_line_pointer += 4;
+
+ if (*input_line_pointer == '#')
+ {
+ ++input_line_pointer;
+ regname = input_line_pointer;
+ c = get_symbol_end ();
+ if (strcmp (regname, "scratch") && strcmp (regname, "ignore"))
+ as_bad (_("register syntax is .register %%g[2367],{#scratch|symbolname|#ignore}"));
+ if (regname [0] == 'i')
+ regname = NULL;
+ else
+ regname = "";
+ }
+ else
+ {
+ regname = input_line_pointer;
+ c = get_symbol_end ();
+ }
+ if (sparc_arch_size == 64)
+ {
+ if (globals [reg])
+ {
+ if ((regname && globals [reg] != (symbolS *)1
+ && strcmp (S_GET_NAME (globals [reg]), regname))
+ || ((regname != NULL) ^ (globals [reg] != (symbolS *)1)))
+ as_bad (_("redefinition of global register"));
+ }
+ else
+ {
+ if (regname == NULL)
+ globals [reg] = (symbolS *)1;
+ else
+ {
+ if (*regname)
+ {
+ if (symbol_find (regname))
+ as_bad (_("Register symbol %s already defined."),
+ regname);
+ }
+ globals [reg] = symbol_make (regname);
+ flags = symbol_get_bfdsym (globals [reg])->flags;
+ if (! *regname)
+ flags = flags & ~(BSF_GLOBAL|BSF_LOCAL|BSF_WEAK);
+ if (! (flags & (BSF_GLOBAL|BSF_LOCAL|BSF_WEAK)))
+ flags |= BSF_GLOBAL;
+ symbol_get_bfdsym (globals [reg])->flags = flags;
+ S_SET_VALUE (globals [reg], (valueT)reg);
+ S_SET_ALIGN (globals [reg], reg);
+ S_SET_SIZE (globals [reg], 0);
+ /* Although we actually want undefined_section here,
+ we have to use absolute_section, because otherwise
+ generic as code will make it a COM section.
+ We fix this up in sparc_adjust_symtab. */
+ S_SET_SEGMENT (globals [reg], absolute_section);
+ S_SET_OTHER (globals [reg], 0);
+ elf_symbol (symbol_get_bfdsym (globals [reg]))
+ ->internal_elf_sym.st_info =
+ ELF_ST_INFO(STB_GLOBAL, STT_REGISTER);
+ elf_symbol (symbol_get_bfdsym (globals [reg]))
+ ->internal_elf_sym.st_shndx = SHN_UNDEF;
+ }
+ }
+ }
+
+ *input_line_pointer = c;
+
+ demand_empty_rest_of_line ();
+}
+
+/* Adjust the symbol table. We set undefined sections for STT_REGISTER
+ symbols which need it. */
+
+void
+sparc_adjust_symtab ()
+{
+ symbolS *sym;
+
+ for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
+ {
+ if (ELF_ST_TYPE (elf_symbol (symbol_get_bfdsym (sym))
+ ->internal_elf_sym.st_info) != STT_REGISTER)
+ continue;
+
+ if (ELF_ST_TYPE (elf_symbol (symbol_get_bfdsym (sym))
+ ->internal_elf_sym.st_shndx != SHN_UNDEF))
+ continue;
+
+ S_SET_SEGMENT (sym, undefined_section);
+ }
+}
+#endif
+
/* 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
@@ -3286,20 +3889,16 @@ sparc_cons_align (nbytes)
return;
}
- nalign = 0;
- while ((nbytes & 1) == 0)
- {
- ++nalign;
- nbytes >>= 1;
- }
-
+ nalign = log2 (nbytes);
if (nalign == 0)
return;
+ assert (nalign > 0);
+
if (now_seg == absolute_section)
{
if ((abs_section_offset & ((1 << nalign) - 1)) != 0)
- as_bad ("misaligned data");
+ as_bad (_("misaligned data"));
return;
}
@@ -3318,21 +3917,34 @@ sparc_handle_align (fragp)
{
if (fragp->fr_type == rs_align_code && !fragp->fr_subtype
&& fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix != 0)
- as_bad_where (fragp->fr_file, fragp->fr_line, "misaligned data");
+ as_bad_where (fragp->fr_file, fragp->fr_line, _("misaligned data"));
if (fragp->fr_type == rs_align_code && fragp->fr_subtype == 1024)
{
int count = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
- if (count >= 4 && !(count & 3) && count <= 1024 && !((long)(fragp->fr_literal + fragp->fr_fix) & 3))
+ if (count >= 4
+ && !(count & 3)
+ && count <= 1024
+ && !((long)(fragp->fr_literal + fragp->fr_fix) & 3))
{
unsigned *p = (unsigned *)(fragp->fr_literal + fragp->fr_fix);
int i;
- for (i = 0; i < count; i += 4)
- *p++ = 0x01000000; /* nop */
+ for (i = 0; i < count; i += 4, p++)
+ if (INSN_BIG_ENDIAN)
+ number_to_chars_bigendian ((char *)p, 0x01000000, 4); /* emit nops */
+ else
+ number_to_chars_littleendian ((char *)p, 0x10000000, 4);
+
if (SPARC_OPCODE_ARCH_V9_P (max_architecture) && count > 8)
- *(unsigned *)(fragp->fr_literal + fragp->fr_fix) =
- 0x30680000 | (count >> 2); /* ba,a,pt %xcc, 1f */
+ {
+ char *waddr = &fragp->fr_literal[fragp->fr_fix];
+ unsigned wval = (0x30680000 | count >> 2); /* ba,a,pt %xcc, 1f */
+ if (INSN_BIG_ENDIAN)
+ number_to_chars_bigendian (waddr, wval, 4);
+ else
+ number_to_chars_littleendian (waddr, wval, 4);
+ }
fragp->fr_var = count;
}
}
@@ -3347,18 +3959,59 @@ sparc_elf_final_processing ()
/* Set the Sparc ELF flag bits. FIXME: There should probably be some
sort of BFD interface for this. */
if (sparc_arch_size == 64)
- switch (sparc_memory_model)
- {
- case MM_RMO:
- elf_elfheader (stdoutput)->e_flags |= EF_SPARCV9_RMO;
- break;
- case MM_PSO:
- elf_elfheader (stdoutput)->e_flags |= EF_SPARCV9_PSO;
- break;
- }
+ {
+ switch (sparc_memory_model)
+ {
+ case MM_RMO:
+ elf_elfheader (stdoutput)->e_flags |= EF_SPARCV9_RMO;
+ break;
+ case MM_PSO:
+ elf_elfheader (stdoutput)->e_flags |= EF_SPARCV9_PSO;
+ break;
+ default:
+ break;
+ }
+ }
else if (current_architecture >= SPARC_OPCODE_ARCH_V9)
elf_elfheader (stdoutput)->e_flags |= EF_SPARC_32PLUS;
if (current_architecture == SPARC_OPCODE_ARCH_V9A)
elf_elfheader (stdoutput)->e_flags |= EF_SPARC_SUN_US1;
}
#endif
+
+/* This is called by emit_expr via TC_CONS_FIX_NEW when creating a
+ reloc for a cons. We could use the definition there, except that
+ we want to handle little endian relocs specially. */
+
+void
+cons_fix_new_sparc (frag, where, nbytes, exp)
+ fragS *frag;
+ int where;
+ unsigned int nbytes;
+ expressionS *exp;
+{
+ bfd_reloc_code_real_type r;
+
+ r = (nbytes == 1 ? BFD_RELOC_8 :
+ (nbytes == 2 ? BFD_RELOC_16 :
+ (nbytes == 4 ? BFD_RELOC_32 : BFD_RELOC_64)));
+
+ if (target_little_endian_data && nbytes == 4
+ && now_seg->flags & SEC_ALLOC)
+ r = BFD_RELOC_SPARC_REV32;
+ fix_new_exp (frag, where, (int) nbytes, exp, 0, r);
+}
+
+#ifdef OBJ_ELF
+int
+elf32_sparc_force_relocation (fixp)
+ struct fix *fixp;
+{
+ if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+ || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+ return 1;
+
+ return 0;
+}
+#endif
+
OpenPOWER on IntegriCloud