#endif
#include "dwarf2dbg.h"
-struct dwarf2_line_info debug_line;
const char comment_chars[] = "!";
const char line_separator_chars[] = ";";
static sh_opcode_info *find_cooked_opcode PARAMS ((char **));
static unsigned int assemble_ppi PARAMS ((char *, sh_opcode_info *));
+#ifdef OBJ_ELF
+static void sh_elf_cons PARAMS ((int));
+
+symbolS *GOT_symbol; /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
+#endif
+
int shl = 0;
static void
const pseudo_typeS md_pseudo_table[] =
{
+#ifdef OBJ_ELF
+ {"long", sh_elf_cons, 4},
+ {"int", sh_elf_cons, 4},
+ {"word", sh_elf_cons, 2},
+ {"short", sh_elf_cons, 2},
+#else
{"int", cons, 4},
{"word", cons, 2},
+#endif /* OBJ_ELF */
{"form", listing_psize, 0},
{"little", little, 0},
{"heading", listing_title, 0},
#define C(a,b) ENCODE_RELAX(a,b)
-#define JREG 14 /* Register used as a temp when relaxing */
#define ENCODE_RELAX(what,length) (((what) << 4) + (length))
#define GET_WHAT(x) ((x>>4))
static struct hash_control *opcode_hash_control; /* Opcode mnemonics */
+\f
+#ifdef OBJ_ELF
+/* Parse @got, etc. and return the desired relocation.
+ If we have additional arithmetic expression, then we fill in new_exp_p. */
+static bfd_reloc_code_real_type
+sh_elf_suffix (str_p, exp_p, new_exp_p)
+ char **str_p;
+ expressionS *exp_p, *new_exp_p;
+{
+ struct map_bfd {
+ char *string;
+ int length;
+ bfd_reloc_code_real_type reloc;
+ };
+
+ char ident[20];
+ char *str = *str_p;
+ char *str2;
+ int ch;
+ int len;
+ struct map_bfd *ptr;
+
+#define MAP(str,reloc) { str, sizeof (str)-1, reloc }
+
+ static struct map_bfd mapping[] = {
+ MAP ("got", BFD_RELOC_32_GOT_PCREL),
+ MAP ("plt", BFD_RELOC_32_PLT_PCREL),
+ MAP ("gotoff", BFD_RELOC_32_GOTOFF),
+ { (char *)0, 0, BFD_RELOC_UNUSED }
+ };
+
+ if (*str++ != '@')
+ return BFD_RELOC_UNUSED;
+
+ for (ch = *str, str2 = ident;
+ (str2 < ident + sizeof (ident) - 1
+ && (isalnum (ch) || ch == '@'));
+ ch = *++str)
+ {
+ *str2++ = (islower (ch)) ? ch : tolower (ch);
+ }
+
+ *str2 = '\0';
+ len = str2 - ident;
+
+ ch = ident[0];
+ for (ptr = &mapping[0]; ptr->length > 0; ptr++)
+ if (ch == ptr->string[0]
+ && len == ptr->length
+ && memcmp (ident, ptr->string, ptr->length) == 0)
+ {
+ /* Now check for identifier@suffix+constant */
+ if (*str == '-' || *str == '+')
+ {
+ char *orig_line = input_line_pointer;
+
+ input_line_pointer = str;
+ expression (new_exp_p);
+ if (new_exp_p->X_op == O_constant)
+ {
+ exp_p->X_add_number += new_exp_p->X_add_number;
+ str = input_line_pointer;
+ }
+ if (new_exp_p->X_op == O_subtract)
+ str = input_line_pointer;
+
+ if (&input_line_pointer != str_p)
+ input_line_pointer = orig_line;
+ }
+
+ *str_p = str;
+ return ptr->reloc;
+ }
+
+ return BFD_RELOC_UNUSED;
+}
+
+/* The regular cons() function, that reads constants, doesn't support
+ suffixes such as @GOT, @GOTOFF and @PLT, that generate
+ machine-specific relocation types. So we must define it here. */
+/* Clobbers input_line_pointer, checks end-of-line. */
+static void
+sh_elf_cons (nbytes)
+ register int nbytes; /* 1=.byte, 2=.word, 4=.long */
+{
+ expressionS exp, new_exp;
+ bfd_reloc_code_real_type reloc;
+ const char *name;
+
+ if (is_it_end_of_statement ())
+ {
+ demand_empty_rest_of_line ();
+ return;
+ }
+
+ do
+ {
+ expression (&exp);
+ new_exp.X_op = O_absent;
+ new_exp.X_add_symbol = new_exp.X_op_symbol = NULL;
+ /* If the _GLOBAL_OFFSET_TABLE_ symbol hasn't been found yet,
+ use the name of the symbol to tell whether it's the
+ _GLOBAL_OFFSET_TABLE_. If it has, comparing the symbols is
+ sufficient. */
+ if (! GOT_symbol && exp.X_add_symbol)
+ name = S_GET_NAME (exp.X_add_symbol);
+ else
+ name = NULL;
+ /* Check whether this expression involves the
+ _GLOBAL_OFFSET_TABLE_ symbol, by itself or added to a
+ difference of two other symbols. */
+ if (((GOT_symbol && GOT_symbol == exp.X_add_symbol)
+ || (! GOT_symbol && name
+ && strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0))
+ && (exp.X_op == O_symbol
+ || (exp.X_op == O_add
+ && ((symbol_get_value_expression (exp.X_op_symbol)->X_op)
+ == O_subtract))))
+ {
+ reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput,
+ BFD_RELOC_32);
+ int size = bfd_get_reloc_size (reloc_howto);
+
+ if (GOT_symbol == NULL)
+ GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
+
+ if (size > nbytes)
+ as_bad (_("%s relocations do not fit in %d bytes\n"),
+ reloc_howto->name, nbytes);
+ else
+ {
+ register char *p = frag_more ((int) nbytes);
+ int offset = nbytes - size;
+
+ fix_new_exp (frag_now, p - frag_now->fr_literal + offset,
+ size, &exp, 0, TC_RELOC_GLOBAL_OFFSET_TABLE);
+ }
+ }
+ /* Check if this symbol involves one of the magic suffixes, such
+ as @GOT, @GOTOFF or @PLT, and determine which relocation type
+ to use. */
+ else if ((exp.X_op == O_symbol || (exp.X_op == O_add && exp.X_op_symbol))
+ && *input_line_pointer == '@'
+ && ((reloc = sh_elf_suffix (&input_line_pointer, &exp, &new_exp))
+ != BFD_RELOC_UNUSED))
+ {
+ reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput,
+ reloc);
+ int size = bfd_get_reloc_size (reloc_howto);
+
+ /* Force a GOT to be generated. */
+ if (GOT_symbol == NULL)
+ GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
+
+ if (size > nbytes)
+ as_bad (_("%s relocations do not fit in %d bytes\n"),
+ reloc_howto->name, nbytes);
+ else
+ {
+ register char *p = frag_more ((int) nbytes);
+ int offset = nbytes - size;
+
+ fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size,
+ &exp, 0, reloc);
+ if (new_exp.X_op != O_absent)
+ fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size,
+ &new_exp, 0, BFD_RELOC_32);
+ }
+ }
+ else
+ emit_expr (&exp, (unsigned int) nbytes);
+ }
+ while (*input_line_pointer++ == ',');
+
+ input_line_pointer--; /* Put terminator back into stream. */
+ if (*input_line_pointer == '#' || *input_line_pointer == '!')
+ {
+ while (! is_end_of_line[(unsigned char) *input_line_pointer++]);
+ }
+ else
+ demand_empty_rest_of_line ();
+}
+#endif /* OBJ_ELF */
+
+\f
/* This function is called once, at assembler startup time. This should
set up all the tables, etc that the MD part of the assembler needs. */
int *mode;
int *reg;
{
+ char l0 = tolower (src[0]);
+ char l1 = l0 ? tolower (src[1]) : 0;
+
/* We use ! IDENT_CHAR for the next character after the register name, to
make sure that we won't accidentally recognize a symbol name such as
'sram' or sr_ram as being a reference to the register 'sr'. */
- if (src[0] == 'r')
+ if (l0 == 'r')
{
- if (src[1] == '1')
+ if (l1 == '1')
{
if (src[2] >= '0' && src[2] <= '5'
&& ! IDENT_CHAR ((unsigned char) src[3]))
return 3;
}
}
- if (src[1] >= '0' && src[1] <= '9'
+ if (l1 >= '0' && l1 <= '9'
&& ! IDENT_CHAR ((unsigned char) src[2]))
{
*mode = A_REG_N;
- *reg = (src[1] - '0');
+ *reg = (l1 - '0');
return 2;
}
- if (src[1] >= '0' && src[1] <= '7' && strncmp (&src[2], "_bank", 5) == 0
+ if (l1 >= '0' && l1 <= '7' && strncasecmp (&src[2], "_bank", 5) == 0
&& ! IDENT_CHAR ((unsigned char) src[7]))
{
*mode = A_REG_B;
- *reg = (src[1] - '0');
+ *reg = (l1 - '0');
return 7;
}
- if (src[1] == 'e' && ! IDENT_CHAR ((unsigned char) src[2]))
+ if (l1 == 'e' && ! IDENT_CHAR ((unsigned char) src[2]))
{
*mode = A_RE;
return 2;
}
- if (src[1] == 's' && ! IDENT_CHAR ((unsigned char) src[2]))
+ if (l1 == 's' && ! IDENT_CHAR ((unsigned char) src[2]))
{
*mode = A_RS;
return 2;
}
}
- if (src[0] == 'a')
+ if (l0 == 'a')
{
- if (src[1] == '0')
+ if (l1 == '0')
{
if (! IDENT_CHAR ((unsigned char) src[2]))
{
*reg = A_A0_NUM;
return 2;
}
- if (src[2] == 'g' && ! IDENT_CHAR ((unsigned char) src[3]))
+ if (tolower (src[2]) == 'g' && ! IDENT_CHAR ((unsigned char) src[3]))
{
*mode = DSP_REG_N;
*reg = A_A0G_NUM;
return 3;
}
}
- if (src[1] == '1')
+ if (l1 == '1')
{
if (! IDENT_CHAR ((unsigned char) src[2]))
{
*reg = A_A1_NUM;
return 2;
}
- if (src[2] == 'g' && ! IDENT_CHAR ((unsigned char) src[3]))
+ if (tolower (src[2]) == 'g' && ! IDENT_CHAR ((unsigned char) src[3]))
{
*mode = DSP_REG_N;
*reg = A_A1G_NUM;
}
}
- if (src[1] == 'x' && src[2] >= '0' && src[2] <= '1'
+ if (l1 == 'x' && src[2] >= '0' && src[2] <= '1'
&& ! IDENT_CHAR ((unsigned char) src[3]))
{
*mode = A_REG_N;
- *reg = 4 + (src[1] - '0');
+ *reg = 4 + (l1 - '0');
return 3;
}
- if (src[1] == 'y' && src[2] >= '0' && src[2] <= '1'
+ if (l1 == 'y' && src[2] >= '0' && src[2] <= '1'
&& ! IDENT_CHAR ((unsigned char) src[3]))
{
*mode = A_REG_N;
- *reg = 6 + (src[1] - '0');
+ *reg = 6 + (l1 - '0');
return 3;
}
- if (src[1] == 's' && src[2] >= '0' && src[2] <= '3'
+ if (l1 == 's' && src[2] >= '0' && src[2] <= '3'
&& ! IDENT_CHAR ((unsigned char) src[3]))
{
- int n = src[1] - '0';
+ int n = l1 - '0';
*mode = A_REG_N;
*reg = n | ((~n & 2) << 1);
}
}
- if (src[0] == 'i' && src[1] && ! IDENT_CHAR ((unsigned char) src[3]))
+ if (l0 == 'i' && l1 && ! IDENT_CHAR ((unsigned char) src[3]))
{
- if (src[1] == 's')
+ if (l1 == 's')
{
*mode = A_REG_N;
*reg = 8;
return 2;
}
- if (src[1] == 'x')
+ if (l1 == 'x')
{
*mode = A_REG_N;
*reg = 8;
return 2;
}
- if (src[1] == 'y')
+ if (l1 == 'y')
{
*mode = A_REG_N;
*reg = 9;
}
}
- if (src[0] == 'x' && src[1] >= '0' && src[1] <= '1'
+ if (l0 == 'x' && l1 >= '0' && l1 <= '1'
&& ! IDENT_CHAR ((unsigned char) src[2]))
{
*mode = DSP_REG_N;
- *reg = A_X0_NUM + src[1] - '0';
+ *reg = A_X0_NUM + l1 - '0';
return 2;
}
- if (src[0] == 'y' && src[1] >= '0' && src[1] <= '1'
+ if (l0 == 'y' && l1 >= '0' && l1 <= '1'
&& ! IDENT_CHAR ((unsigned char) src[2]))
{
*mode = DSP_REG_N;
- *reg = A_Y0_NUM + src[1] - '0';
+ *reg = A_Y0_NUM + l1 - '0';
return 2;
}
- if (src[0] == 'm' && src[1] >= '0' && src[1] <= '1'
+ if (l0 == 'm' && l1 >= '0' && l1 <= '1'
&& ! IDENT_CHAR ((unsigned char) src[2]))
{
*mode = DSP_REG_N;
- *reg = src[1] == '0' ? A_M0_NUM : A_M1_NUM;
+ *reg = l1 == '0' ? A_M0_NUM : A_M1_NUM;
return 2;
}
- if (src[0] == 's'
- && src[1] == 's'
- && src[2] == 'r' && ! IDENT_CHAR ((unsigned char) src[3]))
+ if (l0 == 's'
+ && l1 == 's'
+ && tolower (src[2]) == 'r' && ! IDENT_CHAR ((unsigned char) src[3]))
{
*mode = A_SSR;
return 3;
}
- if (src[0] == 's' && src[1] == 'p' && src[2] == 'c'
+ if (l0 == 's' && l1 == 'p' && tolower (src[2]) == 'c'
&& ! IDENT_CHAR ((unsigned char) src[3]))
{
*mode = A_SPC;
return 3;
}
- if (src[0] == 's' && src[1] == 'g' && src[2] == 'r'
+ if (l0 == 's' && l1 == 'g' && tolower (src[2]) == 'r'
&& ! IDENT_CHAR ((unsigned char) src[3]))
{
*mode = A_SGR;
return 3;
}
- if (src[0] == 'd' && src[1] == 's' && src[2] == 'r'
+ if (l0 == 'd' && l1 == 's' && tolower (src[2]) == 'r'
&& ! IDENT_CHAR ((unsigned char) src[3]))
{
*mode = A_DSR;
return 3;
}
- if (src[0] == 'd' && src[1] == 'b' && src[2] == 'r'
+ if (l0 == 'd' && l1 == 'b' && tolower (src[2]) == 'r'
&& ! IDENT_CHAR ((unsigned char) src[3]))
{
*mode = A_DBR;
return 3;
}
- if (src[0] == 's' && src[1] == 'r' && ! IDENT_CHAR ((unsigned char) src[2]))
+ if (l0 == 's' && l1 == 'r' && ! IDENT_CHAR ((unsigned char) src[2]))
{
*mode = A_SR;
return 2;
}
- if (src[0] == 's' && src[1] == 'p' && ! IDENT_CHAR ((unsigned char) src[2]))
+ if (l0 == 's' && l1 == 'p' && ! IDENT_CHAR ((unsigned char) src[2]))
{
*mode = A_REG_N;
*reg = 15;
return 2;
}
- if (src[0] == 'p' && src[1] == 'r' && ! IDENT_CHAR ((unsigned char) src[2]))
+ if (l0 == 'p' && l1 == 'r' && ! IDENT_CHAR ((unsigned char) src[2]))
{
*mode = A_PR;
return 2;
}
- if (src[0] == 'p' && src[1] == 'c' && ! IDENT_CHAR ((unsigned char) src[2]))
+ if (l0 == 'p' && l1 == 'c' && ! IDENT_CHAR ((unsigned char) src[2]))
{
/* Don't use A_DISP_PC here - that would accept stuff like 'mova pc,r0'
and use an uninitialized immediate. */
*mode = A_PC;
return 2;
}
- if (src[0] == 'g' && src[1] == 'b' && src[2] == 'r'
+ if (l0 == 'g' && l1 == 'b' && tolower (src[2]) == 'r'
&& ! IDENT_CHAR ((unsigned char) src[3]))
{
*mode = A_GBR;
return 3;
}
- if (src[0] == 'v' && src[1] == 'b' && src[2] == 'r'
+ if (l0 == 'v' && l1 == 'b' && tolower (src[2]) == 'r'
&& ! IDENT_CHAR ((unsigned char) src[3]))
{
*mode = A_VBR;
return 3;
}
- if (src[0] == 'm' && src[1] == 'a' && src[2] == 'c'
+ if (l0 == 'm' && l1 == 'a' && tolower (src[2]) == 'c'
&& ! IDENT_CHAR ((unsigned char) src[4]))
{
if (src[3] == 'l')
return 4;
}
}
- if (src[0] == 'm' && src[1] == 'o' && src[2] == 'd'
+ if (l0 == 'm' && l1 == 'o' && tolower (src[2]) == 'd'
&& ! IDENT_CHAR ((unsigned char) src[4]))
{
*mode = A_MOD;
return 3;
}
- if (src[0] == 'f' && src[1] == 'r')
+ if (l0 == 'f' && l1 == 'r')
{
if (src[2] == '1')
{
return 3;
}
}
- if (src[0] == 'd' && src[1] == 'r')
+ if (l0 == 'd' && l1 == 'r')
{
if (src[2] == '1')
{
return 3;
}
}
- if (src[0] == 'x' && src[1] == 'd')
+ if (l0 == 'x' && l1 == 'd')
{
if (src[2] == '1')
{
return 3;
}
}
- if (src[0] == 'f' && src[1] == 'v')
+ if (l0 == 'f' && l1 == 'v')
{
if (src[2] == '1'&& src[3] == '2' && ! IDENT_CHAR ((unsigned char) src[4]))
{
return 3;
}
}
- if (src[0] == 'f' && src[1] == 'p' && src[2] == 'u' && src[3] == 'l'
+ if (l0 == 'f' && l1 == 'p' && tolower (src[2]) == 'u'
+ && tolower (src[3]) == 'l'
&& ! IDENT_CHAR ((unsigned char) src[4]))
{
*mode = FPUL_N;
return 4;
}
- if (src[0] == 'f' && src[1] == 'p' && src[2] == 's' && src[3] == 'c'
- && src[4] == 'r' && ! IDENT_CHAR ((unsigned char) src[5]))
+ if (l0 == 'f' && l1 == 'p' && tolower (src[2]) == 's'
+ && tolower (src[3]) == 'c'
+ && tolower (src[4]) == 'r' && ! IDENT_CHAR ((unsigned char) src[5]))
{
*mode = FPSCR_N;
return 5;
}
- if (src[0] == 'x' && src[1] == 'm' && src[2] == 't' && src[3] == 'r'
- && src[4] == 'x' && ! IDENT_CHAR ((unsigned char) src[5]))
+ if (l0 == 'x' && l1 == 'm' && tolower (src[2]) == 't'
+ && tolower (src[3]) == 'r'
+ && tolower (src[4]) == 'x' && ! IDENT_CHAR ((unsigned char) src[5]))
{
*mode = XMTRX_M4;
return 5;
unsigned char *op_end;
sh_operand_info operand[3];
sh_opcode_info *opcode;
- unsigned int size;
+ unsigned int size = 0;
opcode = find_cooked_opcode (&str);
op_end = str;
}
}
}
-
- if (debug_type == DEBUG_DWARF2)
- {
- bfd_vma addr;
-
- /* First update the notion of the current source line. */
- dwarf2_where (&debug_line);
-
- /* We want the offset of the start of this instruction within the
- the current frag. may be used later */
- addr = frag_now->fr_address + frag_now_fix () - size;
-
-
- /* And record the information. */
- dwarf2_gen_line_info (addr, &debug_line);
- }
+ dwarf2_emit_insn (size);
}
/* This routine is called each time a label definition is seen. It
md_undefined_symbol (name)
char *name;
{
+#ifdef OBJ_ELF
+ /* Under ELF we need to default _GLOBAL_OFFSET_TABLE. Otherwise we
+ have no need to default values of symbols. */
+ if (strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0)
+ {
+ if (!GOT_symbol)
+ {
+ if (symbol_find (name))
+ as_bad ("GOT already in the symbol table");
+
+ GOT_symbol = symbol_new (name, undefined_section,
+ (valueT)0, & zero_address_frag);
+ }
+
+ return GOT_symbol;
+ }
+#endif /* OBJ_ELF */
+
return 0;
}
case C (UNCOND_JUMP, UNCOND32):
case C (UNCOND_JUMP, UNDEF_WORD_DISP):
if (fragP->fr_symbol == NULL)
- as_bad (_("at 0x%lx, displacement overflows 12-bit field"),
- (unsigned long) fragP->fr_address);
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("displacement overflows 12-bit field"));
else if (S_IS_DEFINED (fragP->fr_symbol))
- as_bad (_("at 0x%lx, displacement to defined symbol %s overflows 12-bit field"),
- (unsigned long) fragP->fr_address,
- S_GET_NAME (fragP->fr_symbol));
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("displacement to defined symbol %s overflows 12-bit field"),
+ S_GET_NAME (fragP->fr_symbol));
else
- as_bad (_("at 0x%lx, displacement to undefined symbol %s overflows 12-bit field"),
- (unsigned long) fragP->fr_address,
- S_GET_NAME (fragP->fr_symbol));
-
-#if 0
- /* This code works, but generates poor code and the compiler
- should never produce a sequence that requires it to be used. */
-
- /* A jump wont fit in 12 bits, make code which looks like
- bra foo
- mov.w @(0, PC), r14
- .long disp
- foo: bra @r14
- */
- int t = buffer[0] & 0x10;
-
- buffer[highbyte ] = 0xa0; /* branch over move and disp */
- buffer[lowbyte ] = 3;
- buffer[highbyte + 2] = 0xd0 | JREG; /* Build mov insn */
- buffer[lowbyte + 2] = 0x00;
-
- buffer[highbyte + 4] = 0; /* space for 32 bit jump disp */
- buffer[lowbyte + 4] = 0;
- buffer[highbyte + 6] = 0;
- buffer[lowbyte + 6] = 0;
-
- buffer[highbyte + 8] = 0x40 | JREG; /* Build jmp @JREG */
- buffer[lowbyte + 8] = t ? 0xb : 0x2b;
-
- buffer[highbyte + 10] = 0x20; /* build nop */
- buffer[lowbyte + 10] = 0x0b;
-
- /* Make reloc for the long disp. */
- fix_new (fragP,
- fragP->fr_fix + 4,
- 4,
- fragP->fr_symbol,
- fragP->fr_offset,
- 0,
- BFD_RELOC_32);
- fragP->fr_fix += UNCOND32_LENGTH;
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("displacement to undefined symbol %s overflows 12-bit field"),
+ S_GET_NAME (fragP->fr_symbol));
+ /* Stabilize this frag, so we don't trip an assert. */
+ fragP->fr_fix += fragP->fr_var;
fragP->fr_var = 0;
- donerelax = 1;
-#endif
-
break;
case C (COND_JUMP, COND12):
case C (COND_JUMP, UNDEF_WORD_DISP):
case C (COND_JUMP_DELAY, UNDEF_WORD_DISP):
if (fragP->fr_symbol == NULL)
- as_bad (_("at 0x%lx, displacement overflows 8-bit field"),
- (unsigned long) fragP->fr_address);
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("displacement overflows 8-bit field"));
else if (S_IS_DEFINED (fragP->fr_symbol))
- as_bad (_("at 0x%lx, displacement to defined symbol %s overflows 8-bit field "),
- (unsigned long) fragP->fr_address,
- S_GET_NAME (fragP->fr_symbol));
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("displacement to defined symbol %s overflows 8-bit field"),
+ S_GET_NAME (fragP->fr_symbol));
else
- as_bad (_("at 0x%lx, displacement to undefined symbol %s overflows 8-bit field "),
- (unsigned long) fragP->fr_address,
- S_GET_NAME (fragP->fr_symbol));
-
-#if 0
- /* This code works, but generates poor code, and the compiler
- should never produce a sequence that requires it to be used. */
-
- /* A bcond won't fit and it won't go into a 12 bit
- displacement either, the code sequence looks like:
- b!cond foop
- mov.w @(n, PC), r14
- jmp @r14
- nop
- .long where
- foop:
- */
-
- buffer[0] ^= 0x2; /* Toggle T/F bit */
-#define JREG 14
- buffer[1] = 5; /* branch over mov, jump, nop and ptr */
- buffer[2] = 0xd0 | JREG; /* Build mov insn */
- buffer[3] = 0x2;
- buffer[4] = 0x40 | JREG; /* Build jmp @JREG */
- buffer[5] = 0x0b;
- buffer[6] = 0x20; /* build nop */
- buffer[7] = 0x0b;
- buffer[8] = 0; /* space for 32 bit jump disp */
- buffer[9] = 0;
- buffer[10] = 0;
- buffer[11] = 0;
- buffer[12] = 0;
- buffer[13] = 0;
- /* Make reloc for the long disp */
- fix_new (fragP,
- fragP->fr_fix + 8,
- 4,
- fragP->fr_symbol,
- fragP->fr_offset,
- 0,
- BFD_RELOC_32);
- fragP->fr_fix += COND32_LENGTH;
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("displacement to undefined symbol %s overflows 8-bit field "),
+ S_GET_NAME (fragP->fr_symbol));
+ /* Stabilize this frag, so we don't trip an assert. */
+ fragP->fr_fix += fragP->fr_var;
fragP->fr_var = 0;
- donerelax = 1;
-#endif
-
break;
default:
valueT
md_section_align (seg, size)
- segT seg;
+ segT seg ATTRIBUTE_UNUSED;
valueT size;
{
#ifdef BFD_ASSEMBLER
return;
}
- p = frag_var (rs_align_code, 1, 1, (relax_substateT) 0,
+ p = frag_var (rs_align_test, 1, 1, (relax_substateT) 0,
(symbolS *) NULL, (offsetT) nalign, (char *) NULL);
record_alignment (now_seg, nalign);
sh_handle_align (frag)
fragS *frag;
{
+ int bytes = frag->fr_next->fr_address - frag->fr_address - frag->fr_fix;
+
+ if (frag->fr_type == rs_align_code)
+ {
+ static const unsigned char big_nop_pattern[] = { 0x00, 0x09 };
+ static const unsigned char little_nop_pattern[] = { 0x09, 0x00 };
+
+ char *p = frag->fr_literal + frag->fr_fix;
+
+ if (bytes & 1)
+ {
+ *p++ = 0;
+ bytes--;
+ frag->fr_fix += 1;
+ }
+
+ if (target_big_endian)
+ {
+ memcpy (p, big_nop_pattern, sizeof big_nop_pattern);
+ frag->fr_var = sizeof big_nop_pattern;
+ }
+ else
+ {
+ memcpy (p, little_nop_pattern, sizeof little_nop_pattern);
+ frag->fr_var = sizeof little_nop_pattern;
+ }
+ }
+ else if (frag->fr_type == rs_align_test)
+ {
+ if (bytes != 0)
+ as_warn_where (frag->fr_file, frag->fr_line, _("misaligned data"));
+ }
+
if (sh_relax
- && frag->fr_type == rs_align
+ && (frag->fr_type == rs_align
+ || frag->fr_type == rs_align_code)
&& frag->fr_address + frag->fr_fix > 0
&& frag->fr_offset > 1
&& now_seg != bss_section)
fix_new (frag, frag->fr_fix, 2, &abs_symbol, frag->fr_offset, 0,
BFD_RELOC_SH_ALIGN);
-
- if (frag->fr_type == rs_align_code
- && frag->fr_next->fr_address - frag->fr_address - frag->fr_fix != 0)
- as_warn_where (frag->fr_file, frag->fr_line, _("misaligned data"));
}
/* This macro decides whether a particular reloc is an entry in a
if (fixP->fx_addsy == NULL)
return 1;
+ if (fixP->fx_r_type == BFD_RELOC_SH_PCDISP8BY2
+ || fixP->fx_r_type == BFD_RELOC_SH_PCDISP12BY2
+ || fixP->fx_r_type == BFD_RELOC_SH_PCRELIMM8BY2
+ || fixP->fx_r_type == BFD_RELOC_SH_PCRELIMM8BY4
+ || fixP->fx_r_type == BFD_RELOC_8_PCREL
+ || fixP->fx_r_type == BFD_RELOC_SH_SWITCH16
+ || fixP->fx_r_type == BFD_RELOC_SH_SWITCH32)
+ return 1;
+
+ if (! TC_RELOC_RTSYM_LOC_FIXUP (fixP)
+ || fixP->fx_r_type == BFD_RELOC_32_GOTOFF
+ || fixP->fx_r_type == BFD_RELOC_RVA)
+ return 0;
+
/* We need the symbol name for the VTABLE entries */
if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
int shift;
#ifdef BFD_ASSEMBLER
+ /* A difference between two symbols, the second of which is in the
+ current section, is transformed in a PC-relative relocation to
+ the other symbol. We have to adjust the relocation type here. */
+ if (fixP->fx_pcrel)
+ {
+ switch (fixP->fx_r_type)
+ {
+ default:
+ break;
+
+ case BFD_RELOC_32:
+ fixP->fx_r_type = BFD_RELOC_32_PCREL;
+ break;
+
+ /* Currently, we only support 32-bit PCREL relocations.
+ We'd need a new reloc type to handle 16_PCREL, and
+ 8_PCREL is already taken for R_SH_SWITCH8, which
+ apparently does something completely different than what
+ we need. FIXME. */
+ case BFD_RELOC_16:
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+
+ case BFD_RELOC_8:
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ }
+
/* The function adjust_reloc_syms won't convert a reloc against a weak
symbol into a reloc against a section, but bfd_install_relocation
will screw up if the symbol is defined, so we have to adjust val here
- to avoid the screw up later. */
- if (fixP->fx_addsy != NULL
+ to avoid the screw up later.
+
+ For ordinary relocs, this does not happen for ELF, since for ELF,
+ bfd_install_relocation uses the "special function" field of the
+ howto, and does not execute the code that needs to be undone, as long
+ as the special function does not return bfd_reloc_continue.
+ It can happen for GOT- and PLT-type relocs the way they are
+ described in elf32-sh.c as they use bfd_elf_generic_reloc, but it
+ doesn't matter here since those relocs don't use VAL; see below. */
+ if (OUTPUT_FLAVOR != bfd_target_elf_flavour
+ && fixP->fx_addsy != NULL
&& S_IS_WEAK (fixP->fx_addsy))
val -= S_GET_VALUE (fixP->fx_addsy);
#endif
case BFD_RELOC_SH_PCDISP12BY2:
val /= 2;
- if (val < -0x800 || val >= 0x7ff)
+ if (val < -0x800 || val > 0x7ff)
as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far"));
buf[lowbyte] = val & 0xff;
buf[highbyte] |= (val >> 8) & 0xf;
break;
case BFD_RELOC_32:
+ case BFD_RELOC_32_PCREL:
md_number_to_chars (buf, val, 4);
break;
return;
#endif
+#ifdef OBJ_ELF
+ case BFD_RELOC_32_PLT_PCREL:
+ /* Make the jump instruction point to the address of the operand. At
+ runtime we merely add the offset to the actual PLT entry. */
+ *valp = 0xfffffffc;
+ break;
+
+ case BFD_RELOC_SH_GOTPC:
+ /* This is tough to explain. We end up with this one if we have
+ operands that look like "_GLOBAL_OFFSET_TABLE_+[.-.L284]".
+ The goal here is to obtain the absolute address of the GOT,
+ and it is strongly preferable from a performance point of
+ view to avoid using a runtime relocation for this. There are
+ cases where you have something like:
+
+ .long _GLOBAL_OFFSET_TABLE_+[.-.L66]
+
+ and here no correction would be required. Internally in the
+ assembler we treat operands of this form as not being pcrel
+ since the '.' is explicitly mentioned, and I wonder whether
+ it would simplify matters to do it this way. Who knows. In
+ earlier versions of the PIC patches, the pcrel_adjust field
+ was used to store the correction, but since the expression is
+ not pcrel, I felt it would be confusing to do it this way. */
+ *valp -= 1;
+ md_number_to_chars (buf, val, 4);
+ break;
+
+ case BFD_RELOC_32_GOT_PCREL:
+ *valp = 0; /* Fully resolved at runtime. No addend. */
+ md_number_to_chars (buf, 0, 4);
+ break;
+
+ case BFD_RELOC_32_GOTOFF:
+ break;
+#endif
+
default:
abort ();
}
#endif /* OBJ_COFF */
-/* When we align the .text section, insert the correct NOP pattern. */
-
-int
-sh_do_align (n, fill, len, max)
- int n;
- const char *fill;
- int len ATTRIBUTE_UNUSED;
- int max;
-{
- if (fill == NULL
- && subseg_text_p (now_seg)
- && n > 1)
- {
- static const unsigned char big_nop_pattern[] = { 0x00, 0x09 };
- static const unsigned char little_nop_pattern[] = { 0x09, 0x00 };
-
- /* First align to a 2 byte boundary, in case there is an odd
- .byte. */
- frag_align (1, 0, 0);
- if (target_big_endian)
- frag_align_pattern (n, big_nop_pattern, sizeof big_nop_pattern, max);
- else
- frag_align_pattern (n, little_nop_pattern, sizeof little_nop_pattern,
- max);
- return 1;
- }
-
- return 0;
-}
-
#ifndef BFD_ASSEMBLER
#ifdef OBJ_COFF
}
else if (fixp->fx_pcrel)
rel->addend = fixp->fx_addnumber;
+ else if (r_type == BFD_RELOC_32 || r_type == BFD_RELOC_32_GOTOFF)
+ rel->addend = fixp->fx_addnumber;
else
rel->addend = 0;
}
#endif /* BFD_ASSEMBLER */
-
-void
-sh_finalize ()
-{
- if (debug_type == DEBUG_DWARF2)
- dwarf2_finish ();
-}