/* tc-bfin.c -- Assembler for the ADI Blackfin.
- Copyright 2005
+ Copyright 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,
#include "as.h"
#include "struc-symbol.h"
-#include "obj-elf.h"
#include "bfin-defs.h"
#include "obstack.h"
#include "safe-ctype.h"
#ifdef OBJ_ELF
#include "dwarf2dbg.h"
#endif
+#include "libbfd.h"
+#include "elf/common.h"
+#include "elf/bfin.h"
extern int yyparse (void);
struct yy_buffer_state;
extern YY_BUFFER_STATE yy_scan_string (const char *yy_str);
extern void yy_delete_buffer (YY_BUFFER_STATE b);
static parse_state parse (char *line);
-static void bfin_s_bss PARAMS ((int));
-static int md_chars_to_number PARAMS ((unsigned char *, int));
/* Global variables. */
struct bfin_insn *insn;
extern struct obstack mempool;
FILE *errorf;
+/* Flags to set in the elf header */
+#define DEFAULT_FLAGS 0
+
+#ifdef OBJ_FDPIC_ELF
+# define DEFAULT_FDPIC EF_BFIN_FDPIC
+#else
+# define DEFAULT_FDPIC 0
+#endif
+
+static flagword bfin_flags = DEFAULT_FLAGS | DEFAULT_FDPIC;
+static const char *bfin_pic_flag = DEFAULT_FDPIC ? "-mfdpic" : (const char *)0;
+
/* Registers list. */
struct bfin_reg_entry
{
{0, 0}
};
+/* Blackfin specific function to handle FD-PIC pointer initializations. */
+
+static void
+bfin_pic_ptr (int nbytes)
+{
+ expressionS exp;
+ char *p;
+
+ if (nbytes != 4)
+ abort ();
+
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
+ if (is_it_end_of_statement ())
+ {
+ demand_empty_rest_of_line ();
+ return;
+ }
+
+#ifdef md_cons_align
+ md_cons_align (nbytes);
+#endif
+
+ do
+ {
+ bfd_reloc_code_real_type reloc_type = BFD_RELOC_BFIN_FUNCDESC;
+
+ 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 ')'"));
+ }
+ else
+ error ("missing funcdesc in picptr");
+
+ p = frag_more (4);
+ memset (p, 0, 4);
+ fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &exp, 0,
+ reloc_type);
+ }
+ while (*input_line_pointer++ == ',');
+
+ input_line_pointer--; /* Put terminator back into stream. */
+ demand_empty_rest_of_line ();
+}
+
+static void
+bfin_s_bss (int ignore ATTRIBUTE_UNUSED)
+{
+ register int temp;
+
+ temp = get_absolute_expression ();
+ subseg_set (bss_section, (subsegT) temp);
+ demand_empty_rest_of_line ();
+}
const pseudo_typeS md_pseudo_table[] = {
{"align", s_align_bytes, 0},
{"byte2", cons, 2},
{"byte4", cons, 4},
+ {"picptr", bfin_pic_ptr, 4},
{"code", obj_elf_section, 0},
{"db", cons, 1},
{"dd", cons, 4},
{0, 0, 0}
};
-static void
-bfin_s_bss (int ignore ATTRIBUTE_UNUSED)
-{
- register int temp;
-
- temp = get_absolute_expression ();
- subseg_set (bss_section, (subsegT) temp);
- demand_empty_rest_of_line ();
-}
-
-
/* Characters that are used to denote comments and line separators. */
const char comment_chars[] = "";
const char line_comment_chars[] = "#";
/* Define bfin-specific command-line options (there are none). */
const char *md_shortopts = "";
-struct option md_longopts[] = {
- {NULL, no_argument, NULL, 0}
+#define OPTION_FDPIC (OPTION_MD_BASE)
+#define OPTION_NOPIC (OPTION_MD_BASE + 1)
+
+struct option md_longopts[] =
+{
+ { "mfdpic", no_argument, NULL, OPTION_FDPIC },
+ { "mnopic", no_argument, NULL, OPTION_NOPIC },
+ { "mno-fdpic", no_argument, NULL, OPTION_NOPIC },
+ { NULL, no_argument, NULL, 0 },
};
+
size_t md_longopts_size = sizeof (md_longopts);
int
md_parse_option (int c ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED)
{
- return 0;
+ switch (c)
+ {
+ default:
+ return 0;
+
+ case OPTION_FDPIC:
+ bfin_flags |= EF_BFIN_FDPIC;
+ bfin_pic_flag = "-mfdpic";
+ break;
+
+ case OPTION_NOPIC:
+ bfin_flags &= ~(EF_BFIN_FDPIC);
+ bfin_pic_flag = 0;
+ break;
+ }
+
+ return 1;
}
void
void
md_begin ()
{
+ /* Set the ELF flags if desired. */
+ if (bfin_flags)
+ bfd_set_private_flags (stdoutput, bfin_flags);
+
/* Set the default machine type. */
if (!bfd_set_arch_mach (stdoutput, bfd_arch_bfin, 0))
- as_warn ("Could not set architecture and machine.");
+ as_warn (_("Could not set architecture and machine."));
/* Ensure that lines can begin with '(', for multiple
register stack pops. */
- lex_type ['('] = 3;
+ lex_type ['('] = LEX_BEGIN_NAME;
#ifdef OBJ_ELF
record_alignment (text_section, 2);
state = yyparse ();
if (state == SEMANTIC_ERROR)
{
- as_bad ("Parse failed.");
+ as_bad (_("Parse failed."));
insn = 0;
}
/* Convert from target byte order to host byte order. */
static int
-md_chars_to_number (val, n)
- unsigned char *val; /* Value in target byte order. */
- int n; /* Number of bytes in the input. */
+md_chars_to_number (char *val, int n)
{
int retval;
switch (fixP->fx_r_type)
{
case BFD_RELOC_BFIN_GOT:
+ case BFD_RELOC_BFIN_GOT17M4:
+ case BFD_RELOC_BFIN_FUNCDESC_GOT17M4:
fixP->fx_no_overflow = 1;
newval = md_chars_to_number (where, 2);
newval |= 0x0 & 0x7f;
break;
if (value < -1024 || value > 1022)
as_bad_where (fixP->fx_file, fixP->fx_line,
- "pcrel too far BFD_RELOC_BFIN_10");
+ _("pcrel too far BFD_RELOC_BFIN_10"));
/* 11 bit offset even numbered, so we remove right bit. */
value = value >> 1;
break;
if (value < -4096 || value > 4094)
- as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far BFD_RELOC_BFIN_12");
+ as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far BFD_RELOC_BFIN_12"));
/* 13 bit offset even numbered, so we remove right bit. */
value = value >> 1;
newval = md_chars_to_number (where, 2);
break;
if (value < -16777216 || value > 16777214)
- as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far BFD_RELOC_BFIN_24");
+ as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far BFD_RELOC_BFIN_24"));
/* 25 bit offset even numbered, so we remove right bit. */
value = value >> 1;
if (!value)
break;
if (value < 4 || value > 30)
- as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far BFD_RELOC_BFIN_5");
+ as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far BFD_RELOC_BFIN_5"));
value = value >> 1;
newval = md_chars_to_number (where, 1);
newval = (newval & 0xf0) | (value & 0xf);
break;
value += 2;
if (value < 4 || value > 2046)
- as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far BFD_RELOC_BFIN_11_PCREL");
+ as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far BFD_RELOC_BFIN_11_PCREL"));
/* 11 bit unsigned even, so we remove right bit. */
value = value >> 1;
newval = md_chars_to_number (where, 2);
case BFD_RELOC_8:
if (value < -0x80 || value >= 0x7f)
- as_bad_where (fixP->fx_file, fixP->fx_line, "rel too far BFD_RELOC_8");
+ as_bad_where (fixP->fx_file, fixP->fx_line, _("rel too far BFD_RELOC_8"));
md_number_to_chars (where, value, 1);
break;
case BFD_RELOC_BFIN_16_IMM:
case BFD_RELOC_16:
if (value < -0x8000 || value >= 0x7fff)
- as_bad_where (fixP->fx_file, fixP->fx_line, "rel too far BFD_RELOC_8");
+ as_bad_where (fixP->fx_file, fixP->fx_line, _("rel too far BFD_RELOC_16"));
md_number_to_chars (where, value, 2);
break;
md_number_to_chars (where, value, 2);
break;
+ case BFD_RELOC_BFIN_FUNCDESC:
case BFD_RELOC_VTABLE_INHERIT:
case BFD_RELOC_VTABLE_ENTRY:
fixP->fx_done = FALSE;
}
-/* 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 prec;
- LITTLENUM_TYPE words [MAX_LITTLENUMS];
- LITTLENUM_TYPE *wordP;
- char * t;
-
- switch (type)
- {
- case 'f':
- case 'F':
- prec = 2;
- break;
-
- case 'd':
- case 'D':
- 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);
-
- *sizeP = prec * sizeof (LITTLENUM_TYPE);
- /* This loops outputs the LITTLENUMs in REVERSE order; in accord with
- the littleendianness of the processor. */
- for (wordP = words + prec - 1; prec--;)
- {
- md_number_to_chars (litP, (valueT) (*wordP--), sizeof (LITTLENUM_TYPE));
- litP += sizeof (LITTLENUM_TYPE);
- }
-
- return 0;
+ return ieee_md_atof (type, litP, sizeP, FALSE);
}
switch (fixP->fx_r_type)
{
/* Adjust_reloc_syms doesn't know about the GOT. */
- case BFD_RELOC_BFIN_GOT :
- case BFD_RELOC_BFIN_PLTPC :
+ case BFD_RELOC_BFIN_GOT:
+ case BFD_RELOC_BFIN_GOT17M4:
+ case BFD_RELOC_BFIN_FUNCDESC_GOT17M4:
+ case BFD_RELOC_BFIN_PLTPC:
/* We need the symbol name for the VTABLE entries. */
case BFD_RELOC_VTABLE_INHERIT:
case BFD_RELOC_VTABLE_ENTRY:
char *c1, *label_name;
symbolS *line_label;
char *c = input_line_pointer;
+ int cr_num = 0;
while (ISSPACE (*c))
- c++;
-
- /* Look for LSETUP(. */
- if (!strncasecmp (input_line_pointer, "lsetup(", 7))
{
- /* Need to insert space between lsetup and paren. */
- input_line_pointer --;
- input_line_pointer[0] = 'l';
- input_line_pointer[1] = 's';
- input_line_pointer[2] = 'e';
- input_line_pointer[3] = 't';
- input_line_pointer[4] = 'u';
- input_line_pointer[5] = 'p';
- input_line_pointer[6] = ' ';
- return;
+ if (*c == '\n')
+ cr_num++;
+ c++;
}
/* Look for Loop_Begin or Loop_End statements. */
c1 = c;
while (ISALPHA (*c) || ISDIGIT (*c) || *c == '_') c++;
+ if (input_line_pointer[-1] == '\n')
+ bump_line_counters ();
+
+ while (cr_num--)
+ bump_line_counters ();
+
input_line_pointer = c;
if (maybe_end)
{
- label_name = (char *) xmalloc ((c - c1) + strlen ("__END") + 1);
+ label_name = (char *) xmalloc ((c - c1) + strlen ("__END") + 5);
label_name[0] = 0;
+ strcat (label_name, "L$L$");
strncat (label_name, c1, c-c1);
strcat (label_name, "__END");
}
else /* maybe_begin. */
{
- label_name = (char *) xmalloc ((c - c1) + strlen ("__BEGIN") + 1);
+ label_name = (char *) xmalloc ((c - c1) + strlen ("__BEGIN") + 5);
label_name[0] = 0;
+ strcat (label_name, "L$L$");
strncat (label_name, c1, c-c1);
strcat (label_name, "__BEGIN");
}
/* Loop_End follows the last instruction in the loop.
Adjust label address. */
if (maybe_end)
- line_label->sy_value.X_add_number -= last_insn_size;
-
+ ((struct local_symbol *) line_label)->lsy_value -= last_insn_size;
}
/* Special extra functions that help bfin-parse.y perform its job. */
-#include <stdio.h>
#include <assert.h>
-#include <obstack.h>
-#include <bfd.h>
-#include "bfin-defs.h"
struct obstack mempool;
}
switch (parent_reloc)
{
- /* Some reloctions will need to allocate extra words. */
+ /* Some relocations will need to allocate extra words. */
case BFD_RELOC_BFIN_16_IMM:
case BFD_RELOC_BFIN_16_LOW:
case BFD_RELOC_BFIN_16_HIGH:
break;
case BFD_RELOC_16:
case BFD_RELOC_BFIN_GOT:
+ case BFD_RELOC_BFIN_GOT17M4:
+ case BFD_RELOC_BFIN_FUNCDESC_GOT17M4:
note1 = conscode (gencode (value), NULL_CODE);
pcrel = 0;
break;
if (note1 != NULL_CODE)
note = conscode (note1, note);
}
+ else if (head->type == Expr_Node_Binop
+ && (head->value.op_value == Expr_Op_Type_Add
+ || head->value.op_value == Expr_Op_Type_Sub)
+ && head->Left_Child->type == Expr_Node_Reloc
+ && head->Right_Child->type == Expr_Node_Constant)
+ {
+ int val = head->Right_Child->value.i_value;
+ if (head->value.op_value == Expr_Op_Type_Sub)
+ val = -val;
+ note = conscode (note_reloc2 (gencode (0), head->Left_Child->value.s_value,
+ parent_reloc, val, 0),
+ NULL_CODE);
+ if (note1 != NULL_CODE)
+ note = conscode (note1, note);
+ }
else
{
/* Call the recursive function. */
note = conctcode (note1, conscode (note_reloc1 (gencode (0), op, BFD_ARELOC_BFIN_LOR, 0), NULL_CODE));
break;
default:
- fprintf (stderr, "%s:%d:Unkonwn operator found for arithmetic" " relocation", __FILE__, __LINE__);
+ fprintf (stderr, "%s:%d:Unknown operator found for arithmetic" " relocation", __FILE__, __LINE__);
}
note = conctcode (note1, conscode (note_reloc1 (gencode (0), op, BFD_ARELOC_BFIN_COMP, 0), NULL_CODE));
break;
default:
- fprintf (stderr, "%s:%d:Unkonwn operator found for arithmetic" " relocation", __FILE__, __LINE__);
+ fprintf (stderr, "%s:%d:Unknown operator found for arithmetic" " relocation", __FILE__, __LINE__);
}
break;
default:
INSTR_T
bfin_gen_ldstidxi (REG_T ptr, REG_T reg, int W, int sz, int Z, Expr_Node * poffset)
{
- int offset;
- int value = 0;
INIT (LDSTidxI);
if (!IS_PREG (*ptr) || (!IS_DREG (*reg) && !Z))
ASSIGN_R (reg);
ASSIGN (W);
ASSIGN (sz);
- switch (sz)
- {
- case 0:
- value = EXPR_VALUE (poffset) >> 2;
- break;
- case 1:
- value = EXPR_VALUE (poffset) >> 1;
- break;
- case 2:
- value = EXPR_VALUE (poffset);
- break;
- }
-
ASSIGN (Z);
- offset = (value & 0xffff);
- ASSIGN (offset);
- /* TODO : test if you need to check this here.
- The reloc case should automatically generate instruction
- if constant. */
- if(poffset->type != Expr_Node_Constant){
- /* A GOT relocation such as R0 = [P5 + symbol@GOT].
- Distinguish between R0 = [P5 + symbol@GOT] and
- P5 = [P5 + _current_shared_library_p5_offset_]. */
- if(!strcmp(poffset->value.s_value, "_current_shared_library_p5_offset_")){
- return conscode (gencode (HI (c_code.opcode)),
- Expr_Node_Gen_Reloc(poffset, BFD_RELOC_16));
+ if (poffset->type != Expr_Node_Constant)
+ {
+ /* a GOT relocation such as R0 = [P5 + symbol@GOT] */
+ /* distinguish between R0 = [P5 + symbol@GOT] and
+ P5 = [P5 + _current_shared_library_p5_offset_]
+ */
+ if (poffset->type == Expr_Node_Reloc
+ && !strcmp (poffset->value.s_value,
+ "_current_shared_library_p5_offset_"))
+ {
+ return conscode (gencode (HI (c_code.opcode)),
+ Expr_Node_Gen_Reloc(poffset, BFD_RELOC_16));
+ }
+ else if (poffset->type != Expr_Node_GOT_Reloc)
+ abort ();
+
+ return conscode (gencode (HI (c_code.opcode)),
+ Expr_Node_Gen_Reloc(poffset->Left_Child,
+ poffset->value.i_value));
}
- else
+ else
{
- return conscode (gencode (HI (c_code.opcode)),
- Expr_Node_Gen_Reloc(poffset, BFD_RELOC_BFIN_GOT));
+ int value, offset;
+ switch (sz)
+ { // load/store access size
+ case 0: // 32 bit
+ value = EXPR_VALUE (poffset) >> 2;
+ break;
+ case 1: // 16 bit
+ value = EXPR_VALUE (poffset) >> 1;
+ break;
+ case 2: // 8 bit
+ value = EXPR_VALUE (poffset);
+ break;
+ default:
+ abort ();
+ }
+
+ offset = (value & 0xffff);
+ ASSIGN (offset);
+ return GEN_OPCODE32 ();
}
- }
- else{
- return GEN_OPCODE32 ();
- }
}
Expr_Node *lbegin, *lend;
loopsym = expr->value.s_value;
- lbeginsym = (char *) xmalloc (strlen (loopsym) + strlen ("__BEGIN") + 1);
- lendsym = (char *) xmalloc (strlen (loopsym) + strlen ("__END") + 1);
+ lbeginsym = (char *) xmalloc (strlen (loopsym) + strlen ("__BEGIN") + 5);
+ lendsym = (char *) xmalloc (strlen (loopsym) + strlen ("__END") + 5);
lbeginsym[0] = 0;
lendsym[0] = 0;
+ strcat (lbeginsym, "L$L$");
strcat (lbeginsym, loopsym);
strcat (lbeginsym, "__BEGIN");
+ strcat (lendsym, "L$L$");
strcat (lendsym, loopsym);
strcat (lendsym, "__END");
lbegin = Expr_Node_Create (Expr_Node_Reloc, lbeginval, NULL, NULL);
lend = Expr_Node_Create (Expr_Node_Reloc, lendval, NULL, NULL);
+
+ symbol_remove (symbol_find (loopsym), &symbol_rootP, &symbol_lastP);
+
return bfin_gen_loopsetup(lbegin, reg, rop, lend, preg);
}
return FALSE;
}
-bfd_boolean
-bfin_name_is_register (char *name)
-{
- int i;
-
- if (*name == '[' || *name == '(')
- return TRUE;
-
- if ((name[0] == 'W' || name[0] == 'w') && name[1] == '[')
- return TRUE;
-
- if ((name[0] == 'B' || name[0] == 'b') && name[1] == '[')
- return TRUE;
-
- if (!strncasecmp (name, "saa(", 4))
- return TRUE;
-
- if (!strncasecmp (name, "lsetup(", 7))
- return TRUE;
-
- for (i=0; bfin_reg_info[i].name != 0; i++)
- {
- if (!strcasecmp (bfin_reg_info[i].name, name))
- return TRUE;
- }
- return FALSE;
-}
-
-void
-bfin_equals (Expr_Node *sym)
-{
- char *c;
-
- c = input_line_pointer;
- while (*c != '=')
- c--;
-
- input_line_pointer = c;
-
- equals ((char *) sym->value.s_value, 1);
-}
-
bfd_boolean
bfin_start_label (char *ptr)
{
if (*ptr == '(' || *ptr == '[')
return FALSE;
- if (!strncmp (ptr, "saa(", 4))
- return FALSE;
-
- if (!strncmp (ptr, "lsetup(", 7))
- return FALSE;
-
return TRUE;
}