/* tc-frv.c -- Assembler for the Fujitsu FRV.
- Copyright 2002, 2003 Free Software Foundation.
+ Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ Free Software Foundation. Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street - Fifth Floor,
+ Boston, MA 02110-1301, USA. */
-#include <stdio.h>
#include "as.h"
#include "subsegs.h"
#include "symcat.h"
const char comment_chars[] = ";";
const char line_comment_chars[] = "#";
-const char line_separator_chars[] = "";
+const char line_separator_chars[] = "!";
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "dD";
#define DEFAULT_FLAGS EF_FRV_CPU_FR400
#else
+#ifdef DEFAULT_CPU_FR550
+#define DEFAULT_MACHINE bfd_mach_fr550
+#define DEFAULT_FLAGS EF_FRV_CPU_FR550
+
+#else
#define DEFAULT_MACHINE bfd_mach_fr500
#define DEFAULT_FLAGS EF_FRV_CPU_FR500
#endif
#endif
#endif
#endif
+#endif
+
+#ifdef TE_LINUX
+# define DEFAULT_FDPIC EF_FRV_FDPIC
+#else
+# define DEFAULT_FDPIC 0
+#endif
static unsigned long frv_mach = bfd_mach_frv;
+static bfd_boolean fr400_audio;
/* Flags to set in the elf header */
-static flagword frv_flags = DEFAULT_FLAGS;
+static flagword frv_flags = DEFAULT_FLAGS | DEFAULT_FDPIC;
static int frv_user_set_flags_p = 0;
static int frv_pic_p = 0;
-static const char *frv_pic_flag = (const char *)0;
+static const char *frv_pic_flag = DEFAULT_FDPIC ? "-mfdpic" : (const char *)0;
/* Print tomcat-specific debugging info. */
static int tomcat_debug = 0;
static int tomcat_singles = 0;
/* Forward reference to static functions */
-static void frv_set_flags PARAMS ((int));
-static void frv_pic_ptr PARAMS ((int));
-static void frv_frob_file_section PARAMS ((bfd *, asection *, PTR));
+static void frv_set_flags (int);
+static void frv_pic_ptr (int);
/* The target specific pseudo-ops which we support. */
const pseudo_typeS md_pseudo_table[] =
#define OPTION_TOMCAT_STATS (OPTION_MD_BASE + 18)
#define OPTION_PACK (OPTION_MD_BASE + 19)
#define OPTION_NO_PACK (OPTION_MD_BASE + 20)
+#define OPTION_FDPIC (OPTION_MD_BASE + 21)
+#define OPTION_NOPIC (OPTION_MD_BASE + 22)
struct option md_longopts[] =
{
{ "mtomcat-stats", no_argument, NULL, OPTION_TOMCAT_STATS },
{ "mpack", no_argument, NULL, OPTION_PACK },
{ "mno-pack", no_argument, NULL, OPTION_NO_PACK },
+ { "mfdpic", no_argument, NULL, OPTION_FDPIC },
+ { "mnopic", no_argument, NULL, OPTION_NOPIC },
{ NULL, no_argument, NULL, 0 },
};
static int g_switch_value = 8;
int
-md_parse_option (c, arg)
- int c;
- char * arg;
+md_parse_option (int c, char *arg)
{
switch (c)
{
frv_mach = bfd_mach_fr500;
}
+ else if (strcmp (p, "fr550") == 0)
+ {
+ cpu_flags = EF_FRV_CPU_FR550;
+ frv_mach = bfd_mach_fr550;
+ }
+
+ else if (strcmp (p, "fr450") == 0)
+ {
+ cpu_flags = EF_FRV_CPU_FR450;
+ frv_mach = bfd_mach_fr450;
+ }
+
+ else if (strcmp (p, "fr405") == 0)
+ {
+ cpu_flags = EF_FRV_CPU_FR405;
+ frv_mach = bfd_mach_fr400;
+ fr400_audio = TRUE;
+ }
+
else if (strcmp (p, "fr400") == 0)
{
cpu_flags = EF_FRV_CPU_FR400;
frv_mach = bfd_mach_fr400;
+ fr400_audio = FALSE;
}
else if (strcmp (p, "fr300") == 0)
else
{
- as_fatal ("Unknown cpu -mcpu=%s", arg);
+ as_fatal (_("Unknown cpu -mcpu=%s"), arg);
return 0;
}
g_switch_value = 0;
break;
+ case OPTION_FDPIC:
+ frv_flags |= EF_FRV_FDPIC;
+ frv_pic_flag = "-mfdpic";
+ break;
+
+ case OPTION_NOPIC:
+ frv_flags &= ~(EF_FRV_FDPIC | EF_FRV_PIC
+ | EF_FRV_BIGPIC | EF_FRV_LIBPIC);
+ frv_pic_flag = 0;
+ break;
+
case OPTION_TOMCAT_DEBUG:
tomcat_debug = 1;
break;
}
void
-md_show_usage (stream)
- FILE * stream;
+md_show_usage (FILE * stream)
{
fprintf (stream, _("FRV specific command line options:\n"));
- fprintf (stream, _("-G n Data >= n bytes is in small data area\n"));
- fprintf (stream, _("-mgpr-32 Note 32 gprs are used\n"));
- fprintf (stream, _("-mgpr-64 Note 64 gprs are used\n"));
- fprintf (stream, _("-mfpr-32 Note 32 fprs are used\n"));
- fprintf (stream, _("-mfpr-64 Note 64 fprs are used\n"));
- fprintf (stream, _("-msoft-float Note software fp is used\n"));
- fprintf (stream, _("-mdword Note stack is aligned to a 8 byte boundary\n"));
- fprintf (stream, _("-mno-dword Note stack is aligned to a 4 byte boundary\n"));
- fprintf (stream, _("-mdouble Note fp double insns are used\n"));
- fprintf (stream, _("-mmedia Note media insns are used\n"));
- fprintf (stream, _("-mmuladd Note multiply add/subtract insns are used\n"));
- fprintf (stream, _("-mpack Note instructions are packed\n"));
- fprintf (stream, _("-mno-pack Do not allow instructions to be packed\n"));
- fprintf (stream, _("-mpic Note small position independent code\n"));
- fprintf (stream, _("-mPIC Note large position independent code\n"));
- fprintf (stream, _("-mlibrary-pic Compile library for large position indepedent code\n"));
- fprintf (stream, _("-mcpu={fr500|fr400|fr300|frv|simple|tomcat}\n"));
- fprintf (stream, _(" Record the cpu type\n"));
- fprintf (stream, _("-mtomcat-stats Print out stats for tomcat workarounds\n"));
- fprintf (stream, _("-mtomcat-debug Debug tomcat workarounds\n"));
+ fprintf (stream, _("-G n Put data <= n bytes in the small data area\n"));
+ fprintf (stream, _("-mgpr-32 Mark generated file as only using 32 GPRs\n"));
+ fprintf (stream, _("-mgpr-64 Mark generated file as using all 64 GPRs\n"));
+ fprintf (stream, _("-mfpr-32 Mark generated file as only using 32 FPRs\n"));
+ fprintf (stream, _("-mfpr-64 Mark generated file as using all 64 FPRs\n"));
+ fprintf (stream, _("-msoft-float Mark generated file as using software FP\n"));
+ fprintf (stream, _("-mdword Mark generated file as using a 8-byte stack alignment\n"));
+ fprintf (stream, _("-mno-dword Mark generated file as using a 4-byte stack alignment\n"));
+ fprintf (stream, _("-mdouble Mark generated file as using double precision FP insns\n"));
+ fprintf (stream, _("-mmedia Mark generated file as using media insns\n"));
+ fprintf (stream, _("-mmuladd Mark generated file as using multiply add/subtract insns\n"));
+ fprintf (stream, _("-mpack Allow instructions to be packed\n"));
+ fprintf (stream, _("-mno-pack Do not allow instructions to be packed\n"));
+ fprintf (stream, _("-mpic Mark generated file as using small position independent code\n"));
+ fprintf (stream, _("-mPIC Mark generated file as using large position independent code\n"));
+ fprintf (stream, _("-mlibrary-pic Mark generated file as using position indepedent code for libraries\n"));
+ fprintf (stream, _("-mfdpic Assemble for the FDPIC ABI\n"));
+ fprintf (stream, _("-mnopic Disable -mpic, -mPIC, -mlibrary-pic and -mfdpic\n"));
+ fprintf (stream, _("-mcpu={fr500|fr550|fr400|fr405|fr450|fr300|frv|simple|tomcat}\n"));
+ fprintf (stream, _(" Record the cpu type\n"));
+ fprintf (stream, _("-mtomcat-stats Print out stats for tomcat workarounds\n"));
+ fprintf (stream, _("-mtomcat-debug Debug tomcat workarounds\n"));
}
\f
void
-md_begin ()
+md_begin (void)
{
/* Initialize the `cgen' interface. */
frv_vliw_reset (& vliw, frv_mach, frv_flags);
}
-int chain_num = 0;
+bfd_boolean
+frv_md_fdpic_enabled (void)
+{
+ return (frv_flags & EF_FRV_FDPIC) != 0;
+}
-struct vliw_insn_list *frv_insert_vliw_insn PARAMS ((bfd_boolean));
+int chain_num = 0;
-struct vliw_insn_list *
-frv_insert_vliw_insn (count)
- bfd_boolean count;
+static struct vliw_insn_list *
+frv_insert_vliw_insn (bfd_boolean count)
{
struct vliw_insn_list *vliw_insn_list_entry;
struct vliw_chain *vliw_chain_entry;
/* Check a vliw insn for an insn of type containing the sym passed in label_sym. */
-static struct vliw_insn_list *frv_find_in_vliw
- PARAMS ((enum vliw_insn_type, struct vliw_chain *, symbolS *));
-
static struct vliw_insn_list *
-frv_find_in_vliw (vliw_insn_type, this_chain, label_sym)
- enum vliw_insn_type vliw_insn_type;
- struct vliw_chain *this_chain;
- symbolS *label_sym;
+frv_find_in_vliw (enum vliw_insn_type vliw_insn_type,
+ struct vliw_chain *this_chain,
+ symbolS *label_sym)
{
struct vliw_insn_list *the_insn;
VLIW_DOUBLE_THEN_SINGLE_NOP
};
-static void frv_debug_tomcat PARAMS ((struct vliw_chain *));
-
static void
-frv_debug_tomcat (start_chain)
- struct vliw_chain *start_chain;
+frv_debug_tomcat (struct vliw_chain *start_chain)
{
struct vliw_chain *this_chain;
struct vliw_insn_list *this_insn;
for (this_insn = this_chain->insn_list; this_insn; this_insn = this_insn->next)
{
if (this_insn->type == VLIW_LABEL_TYPE)
- fprintf (stderr, "Label Value: %d\n", (int) this_insn->sym);
+ fprintf (stderr, "Label Value: %p\n", this_insn->sym);
else if (this_insn->type == VLIW_BRANCH_TYPE)
- fprintf (stderr, "%s to %d\n", this_insn->insn->base->name, (int) this_insn->sym);
+ fprintf (stderr, "%s to %p\n", this_insn->insn->base->name, this_insn->sym);
else if (this_insn->type == VLIW_BRANCH_HAS_NOPS)
- fprintf (stderr, "nop'd %s to %d\n", this_insn->insn->base->name, (int) this_insn->sym);
+ fprintf (stderr, "nop'd %s to %p\n", this_insn->insn->base->name, this_insn->sym);
else if (this_insn->type == VLIW_NOP_TYPE)
fprintf (stderr, "Nop\n");
else
}
}
-static void frv_adjust_vliw_count PARAMS ((struct vliw_chain *));
-
static void
-frv_adjust_vliw_count (this_chain)
- struct vliw_chain *this_chain;
+frv_adjust_vliw_count (struct vliw_chain *this_chain)
{
struct vliw_insn_list *this_insn;
/* Insert the desired nop combination in the vliw chain before insert_before_insn.
Rechain the vliw insn. */
-static struct vliw_chain *frv_tomcat_shuffle
- PARAMS ((enum vliw_nop_type, struct vliw_chain *, struct vliw_insn_list *));
-
static struct vliw_chain *
-frv_tomcat_shuffle (this_nop_type, vliw_to_split, insert_before_insn)
- enum vliw_nop_type this_nop_type;
- struct vliw_chain *vliw_to_split;
- struct vliw_insn_list *insert_before_insn;
+frv_tomcat_shuffle (enum vliw_nop_type this_nop_type,
+ struct vliw_chain *vliw_to_split,
+ struct vliw_insn_list *insert_before_insn)
{
bfd_boolean pack_prev = FALSE;
/* Set the packing bit on the previous insn. */
if (pack_prev)
{
- unsigned char *buffer = prev_insn->address;
+ char *buffer = prev_insn->address;
buffer[0] |= 0x80;
}
/* The branch is in the middle. Split this vliw insn into first
/* Set the packing bit on the previous insn. */
if (pack_prev)
{
- unsigned char *buffer = prev_insn->address;
+ char *buffer = prev_insn->address;
buffer[0] |= 0x80;
}
/* Set the packing bit on the previous insn. */
if (pack_prev)
{
- unsigned char *buffer = prev_insn->address;
+ char *buffer = prev_insn->address;
buffer[0] |= 0x80;
}
return return_me;
}
-static void frv_tomcat_analyze_vliw_chains PARAMS ((void));
-
static void
-frv_tomcat_analyze_vliw_chains ()
+frv_tomcat_analyze_vliw_chains (void)
{
struct vliw_chain *vliw1 = NULL;
struct vliw_chain *vliw2 = NULL;
}
void
-frv_tomcat_workaround ()
+frv_tomcat_workaround (void)
{
if (frv_mach != bfd_mach_frvtomcat)
return;
}
}
+static int
+fr550_check_insn_acc_range (frv_insn *insn, int low, int hi)
+{
+ int acc;
+ switch (CGEN_INSN_NUM (insn->insn))
+ {
+ case FRV_INSN_MADDACCS:
+ case FRV_INSN_MSUBACCS:
+ case FRV_INSN_MDADDACCS:
+ case FRV_INSN_MDSUBACCS:
+ case FRV_INSN_MASACCS:
+ case FRV_INSN_MDASACCS:
+ acc = insn->fields.f_ACC40Si;
+ if (acc < low || acc > hi)
+ return 1; /* out of range */
+ acc = insn->fields.f_ACC40Sk;
+ if (acc < low || acc > hi)
+ return 1; /* out of range */
+ break;
+ case FRV_INSN_MMULHS:
+ case FRV_INSN_MMULHU:
+ case FRV_INSN_MMULXHS:
+ case FRV_INSN_MMULXHU:
+ case FRV_INSN_CMMULHS:
+ case FRV_INSN_CMMULHU:
+ case FRV_INSN_MQMULHS:
+ case FRV_INSN_MQMULHU:
+ case FRV_INSN_MQMULXHS:
+ case FRV_INSN_MQMULXHU:
+ case FRV_INSN_CMQMULHS:
+ case FRV_INSN_CMQMULHU:
+ case FRV_INSN_MMACHS:
+ case FRV_INSN_MMRDHS:
+ case FRV_INSN_CMMACHS:
+ case FRV_INSN_MQMACHS:
+ case FRV_INSN_CMQMACHS:
+ case FRV_INSN_MQXMACHS:
+ case FRV_INSN_MQXMACXHS:
+ case FRV_INSN_MQMACXHS:
+ case FRV_INSN_MCPXRS:
+ case FRV_INSN_MCPXIS:
+ case FRV_INSN_CMCPXRS:
+ case FRV_INSN_CMCPXIS:
+ case FRV_INSN_MQCPXRS:
+ case FRV_INSN_MQCPXIS:
+ acc = insn->fields.f_ACC40Sk;
+ if (acc < low || acc > hi)
+ return 1; /* out of range */
+ break;
+ case FRV_INSN_MMACHU:
+ case FRV_INSN_MMRDHU:
+ case FRV_INSN_CMMACHU:
+ case FRV_INSN_MQMACHU:
+ case FRV_INSN_CMQMACHU:
+ case FRV_INSN_MCPXRU:
+ case FRV_INSN_MCPXIU:
+ case FRV_INSN_CMCPXRU:
+ case FRV_INSN_CMCPXIU:
+ case FRV_INSN_MQCPXRU:
+ case FRV_INSN_MQCPXIU:
+ acc = insn->fields.f_ACC40Uk;
+ if (acc < low || acc > hi)
+ return 1; /* out of range */
+ break;
+ default:
+ break;
+ }
+ return 0; /* all is ok */
+}
+
+static int
+fr550_check_acc_range (FRV_VLIW *vliw, frv_insn *insn)
+{
+ switch ((*vliw->current_vliw)[vliw->next_slot - 1])
+ {
+ case UNIT_FM0:
+ case UNIT_FM2:
+ return fr550_check_insn_acc_range (insn, 0, 3);
+ case UNIT_FM1:
+ case UNIT_FM3:
+ return fr550_check_insn_acc_range (insn, 4, 7);
+ default:
+ break;
+ }
+ return 0; /* all is ok */
+}
+
+/* Return true if the target implements instruction INSN. */
+
+static bfd_boolean
+target_implements_insn_p (const CGEN_INSN *insn)
+{
+ switch (frv_mach)
+ {
+ default:
+ /* bfd_mach_frv or generic. */
+ return TRUE;
+
+ case bfd_mach_fr300:
+ case bfd_mach_frvsimple:
+ return CGEN_INSN_MACH_HAS_P (insn, MACH_SIMPLE);
+
+ case bfd_mach_fr400:
+ return ((fr400_audio || !CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_AUDIO))
+ && CGEN_INSN_MACH_HAS_P (insn, MACH_FR400));
+
+ case bfd_mach_fr450:
+ return CGEN_INSN_MACH_HAS_P (insn, MACH_FR450);
+
+ case bfd_mach_fr500:
+ return CGEN_INSN_MACH_HAS_P (insn, MACH_FR500);
+
+ case bfd_mach_fr550:
+ return CGEN_INSN_MACH_HAS_P (insn, MACH_FR550);
+ }
+}
+
void
-md_assemble (str)
- char * str;
+md_assemble (char *str)
{
frv_insn insn;
char *errmsg;
/* Initialize GAS's cgen interface for a new instruction. */
gas_cgen_init_parse ();
+ memset (&insn, 0, sizeof (insn));
+
insn.insn = frv_cgen_assemble_insn
(gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, &errmsg);
instructions, don't do vliw checking. */
else if (frv_mach != bfd_mach_frv)
{
+ if (!target_implements_insn_p (insn.insn))
+ {
+ as_bad (_("Instruction not supported by this architecture"));
+ return;
+ }
packing_constraint = frv_vliw_add_insn (& vliw, insn.insn);
+ if (frv_mach == bfd_mach_fr550 && ! packing_constraint)
+ packing_constraint = fr550_check_acc_range (& vliw, & insn);
if (insn.fields.f_pack)
frv_vliw_reset (& vliw, frv_mach, frv_flags);
if (packing_constraint)
We just ignore it. */
void
-md_operand (expressionP)
- expressionS * expressionP;
+md_operand (expressionS *expressionP)
{
if (* input_line_pointer == '#')
{
}
valueT
-md_section_align (segment, size)
- segT segment;
- valueT size;
+md_section_align (segT segment, valueT size)
{
int align = bfd_get_section_alignment (stdoutput, segment);
return ((size + (1 << align) - 1) & (-1 << align));
}
symbolS *
-md_undefined_symbol (name)
- char * name ATTRIBUTE_UNUSED;
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
{
return 0;
}
};
long
-frv_relax_frag (fragP, stretch)
- fragS *fragP ATTRIBUTE_UNUSED;
- long stretch ATTRIBUTE_UNUSED;
+frv_relax_frag (fragS *fragP ATTRIBUTE_UNUSED, long stretch ATTRIBUTE_UNUSED)
{
return 0;
}
0 value. */
int
-md_estimate_size_before_relax (fragP, segment)
- fragS * fragP;
- segT segment ATTRIBUTE_UNUSED;
+md_estimate_size_before_relax (fragS *fragP, segT segment ATTRIBUTE_UNUSED)
{
switch (fragP->fr_subtype)
{
fragP->fr_subtype is the subtype of what the address relaxed to. */
void
-md_convert_frag (abfd, sec, fragP)
- bfd * abfd ATTRIBUTE_UNUSED;
- segT sec ATTRIBUTE_UNUSED;
- fragS * fragP;
+md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
+ segT sec ATTRIBUTE_UNUSED,
+ fragS *fragP)
{
switch (fragP->fr_subtype)
{
given a PC relative reloc. */
long
-md_pcrel_from_section (fixP, sec)
- fixS * fixP;
- segT sec;
+md_pcrel_from_section (fixS *fixP, segT sec)
{
- if (fixP->fx_addsy != (symbolS *) NULL
- && (! S_IS_DEFINED (fixP->fx_addsy)
- || S_GET_SEGMENT (fixP->fx_addsy) != sec))
+ if (TC_FORCE_RELOCATION (fixP)
+ || (fixP->fx_addsy != (symbolS *) NULL
+ && S_GET_SEGMENT (fixP->fx_addsy) != sec))
{
- /* The symbol is undefined (or is defined but not in this section).
- Let the linker figure it out. */
+ /* If we can't adjust this relocation, or if it references a
+ local symbol in a different section (which
+ TC_FORCE_RELOCATION can't check), let the linker figure it
+ out. */
return 0;
}
*FIXP may be modified if desired. */
bfd_reloc_code_real_type
-md_cgen_lookup_reloc (insn, operand, fixP)
- const CGEN_INSN * insn ATTRIBUTE_UNUSED;
- const CGEN_OPERAND * operand;
- fixS * fixP;
+md_cgen_lookup_reloc (const CGEN_INSN *insn ATTRIBUTE_UNUSED,
+ const CGEN_OPERAND *operand,
+ fixS *fixP)
{
switch (operand->type)
{
case FRV_OPERAND_LABEL24:
fixP->fx_pcrel = TRUE;
+
+ if (fixP->fx_cgen.opinfo != 0)
+ return fixP->fx_cgen.opinfo;
+
return BFD_RELOC_FRV_LABEL24;
case FRV_OPERAND_UHI16:
case FRV_OPERAND_ULO16:
case FRV_OPERAND_SLO16:
-
+ case FRV_OPERAND_CALLANN:
+ case FRV_OPERAND_LDANN:
+ case FRV_OPERAND_LDDANN:
/* The relocation type should be recorded in opinfo */
if (fixP->fx_cgen.opinfo != 0)
return fixP->fx_cgen.opinfo;
case FRV_OPERAND_D12:
case FRV_OPERAND_S12:
+ if (fixP->fx_cgen.opinfo != 0)
+ return fixP->fx_cgen.opinfo;
+
return BFD_RELOC_FRV_GPREL12;
case FRV_OPERAND_U12:
relaxing. */
int
-frv_force_relocation (fix)
- fixS * fix;
+frv_force_relocation (fixS *fix)
{
- if (fix->fx_r_type == BFD_RELOC_FRV_GPREL12
- || fix->fx_r_type == BFD_RELOC_FRV_GPRELU12)
- return 1;
+ switch (fix->fx_r_type < BFD_RELOC_UNUSED
+ ? (int) fix->fx_r_type
+ : fix->fx_cgen.opinfo)
+ {
+ case BFD_RELOC_FRV_GPREL12:
+ case BFD_RELOC_FRV_GPRELU12:
+ case BFD_RELOC_FRV_GPREL32:
+ case BFD_RELOC_FRV_GPRELHI:
+ case BFD_RELOC_FRV_GPRELLO:
+ case BFD_RELOC_FRV_GOT12:
+ case BFD_RELOC_FRV_GOTHI:
+ case BFD_RELOC_FRV_GOTLO:
+ case BFD_RELOC_FRV_FUNCDESC_VALUE:
+ case BFD_RELOC_FRV_FUNCDESC_GOTOFF12:
+ case BFD_RELOC_FRV_FUNCDESC_GOTOFFHI:
+ case BFD_RELOC_FRV_FUNCDESC_GOTOFFLO:
+ case BFD_RELOC_FRV_GOTOFF12:
+ case BFD_RELOC_FRV_GOTOFFHI:
+ case BFD_RELOC_FRV_GOTOFFLO:
+ case BFD_RELOC_FRV_GETTLSOFF:
+ case BFD_RELOC_FRV_TLSDESC_VALUE:
+ case BFD_RELOC_FRV_GOTTLSDESC12:
+ case BFD_RELOC_FRV_GOTTLSDESCHI:
+ case BFD_RELOC_FRV_GOTTLSDESCLO:
+ case BFD_RELOC_FRV_TLSMOFF12:
+ case BFD_RELOC_FRV_TLSMOFFHI:
+ case BFD_RELOC_FRV_TLSMOFFLO:
+ case BFD_RELOC_FRV_GOTTLSOFF12:
+ case BFD_RELOC_FRV_GOTTLSOFFHI:
+ case BFD_RELOC_FRV_GOTTLSOFFLO:
+ case BFD_RELOC_FRV_TLSOFF:
+ case BFD_RELOC_FRV_TLSDESC_RELAX:
+ case BFD_RELOC_FRV_GETTLSOFF_RELAX:
+ case BFD_RELOC_FRV_TLSOFF_RELAX:
+ return 1;
+
+ default:
+ break;
+ }
return generic_force_reloc (fix);
}
+
+/* Apply a fixup that could be resolved within the assembler. */
+
+void
+md_apply_fix (fixS *fixP, valueT *valP, segT seg)
+{
+ if (fixP->fx_addsy == 0)
+ switch (fixP->fx_cgen.opinfo)
+ {
+ case BFD_RELOC_FRV_HI16:
+ *valP >>= 16;
+ /* Fall through. */
+ case BFD_RELOC_FRV_LO16:
+ *valP &= 0xffff;
+ break;
+
+ /* We need relocations for these, even if their symbols reduce
+ to constants. */
+ case BFD_RELOC_FRV_GPREL12:
+ case BFD_RELOC_FRV_GPRELU12:
+ case BFD_RELOC_FRV_GPREL32:
+ case BFD_RELOC_FRV_GPRELHI:
+ case BFD_RELOC_FRV_GPRELLO:
+ case BFD_RELOC_FRV_GOT12:
+ case BFD_RELOC_FRV_GOTHI:
+ case BFD_RELOC_FRV_GOTLO:
+ case BFD_RELOC_FRV_FUNCDESC_VALUE:
+ case BFD_RELOC_FRV_FUNCDESC_GOTOFF12:
+ case BFD_RELOC_FRV_FUNCDESC_GOTOFFHI:
+ case BFD_RELOC_FRV_FUNCDESC_GOTOFFLO:
+ case BFD_RELOC_FRV_GOTOFF12:
+ case BFD_RELOC_FRV_GOTOFFHI:
+ case BFD_RELOC_FRV_GOTOFFLO:
+ case BFD_RELOC_FRV_GETTLSOFF:
+ case BFD_RELOC_FRV_TLSDESC_VALUE:
+ case BFD_RELOC_FRV_GOTTLSDESC12:
+ case BFD_RELOC_FRV_GOTTLSDESCHI:
+ case BFD_RELOC_FRV_GOTTLSDESCLO:
+ case BFD_RELOC_FRV_TLSMOFF12:
+ case BFD_RELOC_FRV_TLSMOFFHI:
+ case BFD_RELOC_FRV_TLSMOFFLO:
+ case BFD_RELOC_FRV_GOTTLSOFF12:
+ case BFD_RELOC_FRV_GOTTLSOFFHI:
+ case BFD_RELOC_FRV_GOTTLSOFFLO:
+ case BFD_RELOC_FRV_TLSOFF:
+ case BFD_RELOC_FRV_TLSDESC_RELAX:
+ case BFD_RELOC_FRV_GETTLSOFF_RELAX:
+ case BFD_RELOC_FRV_TLSOFF_RELAX:
+ fixP->fx_addsy = abs_section_sym;
+ break;
+ }
+ else
+ switch (fixP->fx_cgen.opinfo)
+ {
+ case BFD_RELOC_FRV_GETTLSOFF:
+ case BFD_RELOC_FRV_TLSDESC_VALUE:
+ case BFD_RELOC_FRV_GOTTLSDESC12:
+ case BFD_RELOC_FRV_GOTTLSDESCHI:
+ case BFD_RELOC_FRV_GOTTLSDESCLO:
+ case BFD_RELOC_FRV_TLSMOFF12:
+ case BFD_RELOC_FRV_TLSMOFFHI:
+ case BFD_RELOC_FRV_TLSMOFFLO:
+ case BFD_RELOC_FRV_GOTTLSOFF12:
+ case BFD_RELOC_FRV_GOTTLSOFFHI:
+ case BFD_RELOC_FRV_GOTTLSOFFLO:
+ case BFD_RELOC_FRV_TLSOFF:
+ case BFD_RELOC_FRV_TLSDESC_RELAX:
+ case BFD_RELOC_FRV_GETTLSOFF_RELAX:
+ case BFD_RELOC_FRV_TLSOFF_RELAX:
+ /* Mark TLS symbols as such. */
+ if (S_GET_SEGMENT (fixP->fx_addsy) != absolute_section)
+ S_SET_THREAD_LOCAL (fixP->fx_addsy);
+ break;
+ }
+
+ gas_cgen_md_apply_fix (fixP, valP, seg);
+ return;
+}
+
\f
/* Write a value out to the object file, using the appropriate endianness. */
void
-frv_md_number_to_chars (buf, val, n)
- char * buf;
- valueT val;
- int n;
+frv_md_number_to_chars (char *buf, valueT val, int n)
{
number_to_chars_bigendian (buf, val, n);
}
-/* Turn a string in input_line_pointer into a floating point constant of type
- type, and store the appropriate bytes in *litP. The number of LITTLENUMS
- emitted is stored in *sizeP . An error message is returned, or NULL on OK.
-*/
-
-/* Equal to MAX_PRECISION in atof-ieee.c */
-#define MAX_LITTLENUMS 6
-
char *
-md_atof (type, litP, sizeP)
- char type;
- char * litP;
- int * sizeP;
+md_atof (int type, char *litP, int *sizeP)
{
- int i;
- int prec;
- LITTLENUM_TYPE words [MAX_LITTLENUMS];
- char * t;
-
- switch (type)
- {
- case 'f':
- case 'F':
- case 's':
- case 'S':
- prec = 2;
- break;
-
- case 'd':
- case 'D':
- case 'r':
- case 'R':
- prec = 4;
- break;
-
- /* FIXME: Some targets allow other format chars for bigger sizes here. */
-
- default:
- * 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 (i = 0; i < prec; i++)
- {
- md_number_to_chars (litP, (valueT) words[i],
- sizeof (LITTLENUM_TYPE));
- litP += sizeof (LITTLENUM_TYPE);
- }
-
- return 0;
+ return ieee_md_atof (type, litP, sizeP, TRUE);
}
bfd_boolean
-frv_fix_adjustable (fixP)
- fixS * fixP;
+frv_fix_adjustable (fixS *fixP)
{
bfd_reloc_code_real_type reloc_type;
/* Allow user to set flags bits. */
void
-frv_set_flags (arg)
- int arg ATTRIBUTE_UNUSED;
+frv_set_flags (int arg ATTRIBUTE_UNUSED)
{
flagword new_flags = get_absolute_expression ();
flagword new_mask = ~ (flagword)0;
BFD_RELOC_32 at that time. */
void
-frv_pic_ptr (nbytes)
- int nbytes;
+frv_pic_ptr (int nbytes)
{
expressionS exp;
char *p;
do
{
- expression (&exp);
+ bfd_reloc_code_real_type reloc_type = BFD_RELOC_CTOR;
+
+ if (strncasecmp (input_line_pointer, "funcdesc(", 9) == 0)
+ {
+ input_line_pointer += 9;
+ expression (&exp);
+ if (*input_line_pointer == ')')
+ input_line_pointer++;
+ else
+ as_bad (_("missing ')'"));
+ reloc_type = BFD_RELOC_FRV_FUNCDESC;
+ }
+ else if (strncasecmp (input_line_pointer, "tlsmoff(", 8) == 0)
+ {
+ input_line_pointer += 8;
+ expression (&exp);
+ if (*input_line_pointer == ')')
+ input_line_pointer++;
+ else
+ as_bad (_("missing ')'"));
+ reloc_type = BFD_RELOC_FRV_TLSMOFF;
+ }
+ else
+ expression (&exp);
p = frag_more (4);
memset (p, 0, 4);
fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &exp, 0,
- BFD_RELOC_CTOR);
+ reloc_type);
}
while (*input_line_pointer++ == ',');
not possible, issue an error. */
static void
-frv_frob_file_section (abfd, sec, ptr)
- bfd *abfd;
- asection *sec;
- PTR ptr ATTRIBUTE_UNUSED;
+frv_frob_file_section (bfd *abfd, asection *sec, void *ptr ATTRIBUTE_UNUSED)
{
segment_info_type *seginfo = seg_info (sec);
fixS *fixp;
for any relocations that pic won't support. */
void
-frv_frob_file ()
+frv_frob_file (void)
{
- bfd_map_over_sections (stdoutput, frv_frob_file_section, (PTR)0);
+ bfd_map_over_sections (stdoutput, frv_frob_file_section, (void *) 0);
}
void
-frv_frob_label (this_label)
- symbolS *this_label;
+frv_frob_label (symbolS *this_label)
{
struct vliw_insn_list *vliw_insn_list_entry;
}
fixS *
-frv_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
- fragS * frag;
- int where;
- const CGEN_INSN * insn;
- int length;
- const CGEN_OPERAND * operand;
- int opinfo;
- expressionS * exp;
+frv_cgen_record_fixup_exp (fragS *frag,
+ int where,
+ const CGEN_INSN *insn,
+ int length,
+ const CGEN_OPERAND *operand,
+ int opinfo,
+ expressionS *exp)
{
fixS * fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
operand, opinfo, exp);