#include "elf/sh.h"
#endif
+#include "dwarf2dbg.h"
+struct dwarf2_line_info debug_line;
+
const char comment_chars[] = "!";
const char line_separator_chars[] = ";";
const char line_comment_chars[] = "!#";
void s_align_bytes ();
static void s_uacons PARAMS ((int));
static sh_opcode_info *find_cooked_opcode PARAMS ((char **));
-static void assemble_ppi PARAMS ((char *, sh_opcode_info *));
+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;
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},
{"uses", s_uses, 0},
{"uaword", s_uacons, 2},
{"ualong", s_uacons, 4},
+ { "file", dwarf2_directive_file, 0 },
+ { "loc", dwarf2_directive_loc, 0 },
{0, 0, 0}
};
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[*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. */
return 0;
}
-static symbolS *dot()
+static symbolS *
+dot ()
{
const char *fake;
now_seg,
(valueT) frag_now_fix (),
frag_now);
-
}
-
-static
-char *
+static char *
parse_exp (s, op)
char *s;
sh_operand_info *op;
return new;
}
-
/* The many forms of operand:
Rn Register direct
disp:12
#imm8
pr, gbr, vbr, macl, mach
-
*/
-static
-char *
+static char *
parse_at (src, op)
char *src;
sh_operand_info *op;
}
else if (mode == A_PC)
{
- /* Turn a plain @(4,pc) into @(.+4,pc) */
- if (op->immediate.X_op == O_constant) {
- op->immediate.X_add_symbol = dot();
- op->immediate.X_op = O_symbol;
- }
+ /* Turn a plain @(4,pc) into @(.+4,pc). */
+ if (op->immediate.X_op == O_constant)
+ {
+ op->immediate.X_add_symbol = dot();
+ op->immediate.X_op = O_symbol;
+ }
op->type = A_DISP_PC;
}
else
}
}
-static
-char *
+static char *
get_operands (info, args, operand)
sh_opcode_info *info;
char *args;
addressing modes, return the opcode which matches the opcodes
provided. */
-static
-sh_opcode_info *
+static sh_opcode_info *
get_specific (opcode, operands)
sh_opcode_info *opcode;
sh_operand_info *operands;
sh_opcode_info *this_try = opcode;
char *name = opcode->name;
int n = 0;
+
while (opcode->name)
{
this_try = opcode++;
opcodes with the same name. */
return 0;
}
-
+
/* Look at both operands needed by the opcodes and provided by
the user - since an arg test will often fail on the same arg
again and again, we'll try and test the last failing arg the
{
sh_operand_info *user = operands + n;
sh_arg_type arg = this_try->arg[n];
-
+
switch (arg)
{
case A_IMM:
goto fail;
break;
- case A_REG_B:
+ case A_REG_B:
if (user->type != arg)
goto fail;
reg_b = user->reg;
goto fail;
reg_m = 4;
break;
-
+
default:
printf (_("unhandled %d\n"), arg);
goto fail;
goto fail;
valid_arch &= this_try->arch;
return this_try;
- fail:;
+ fail:
+ ;
}
return 0;
return operand->X_add_number;
}
-
static void
insert (where, how, pcrel, op)
char *where;
Hence a 9 digit number should be enough to count all REPEATs. */
name = alloca (11);
sprintf (name, "_R%x", count++ & 0x3fffffff);
- end_sym = symbol_new (name, undefined_section, 0, &zero_address_frag);
+ end_sym = symbol_new (name, undefined_section, 0, &zero_address_frag);
/* Make this a local symbol. */
#ifdef OBJ_COFF
SF_SET_LOCAL (end_sym);
/* Now we know what sort of opcodes it is, let's build the bytes. */
-static void
+static unsigned int
build_Mytes (opcode, operand)
sh_opcode_info *opcode;
sh_operand_info *operand;
int index;
char nbuf[4];
char *output = frag_more (2);
+ unsigned int size = 2;
int low_byte = target_big_endian ? 1 : 0;
nbuf[0] = 0;
nbuf[1] = 0;
case REG_NM:
nbuf[index] = reg_n | (reg_m >> 2);
break;
- case REG_B:
+ case REG_B:
nbuf[index] = reg_b | 0x08;
break;
case IMM0_4BY4:
}
}
}
- if (! target_big_endian) {
- output[1] = (nbuf[0] << 4) | (nbuf[1]);
- output[0] = (nbuf[2] << 4) | (nbuf[3]);
- }
- else {
- output[0] = (nbuf[0] << 4) | (nbuf[1]);
- output[1] = (nbuf[2] << 4) | (nbuf[3]);
- }
+ if (!target_big_endian)
+ {
+ output[1] = (nbuf[0] << 4) | (nbuf[1]);
+ output[0] = (nbuf[2] << 4) | (nbuf[3]);
+ }
+ else
+ {
+ output[0] = (nbuf[0] << 4) | (nbuf[1]);
+ output[1] = (nbuf[2] << 4) | (nbuf[3]);
+ }
+ return size;
}
/* Find an opcode at the start of *STR_P in the hash table, and set
unsigned char *op_end;
char name[20];
int nlen = 0;
-
+
/* Drop leading whitespace. */
while (*str == ' ')
str++;
name[nlen] = c;
nlen++;
}
-
+
name[nlen] = 0;
*str_p = op_end;
/* Assemble a parallel processing insn. */
#define DDT_BASE 0xf000 /* Base value for double data transfer insns */
-static void
+static unsigned int
assemble_ppi (op_end, opcode)
char *op_end;
sh_opcode_info *opcode;
int field_b = 0;
char *output;
int move_code;
+ unsigned int size;
/* Some insn ignore one or more register fields, e.g. psts machl,a0.
Make sure we encode a defined insn pattern. */
{
/* Couldn't find an opcode which matched the operands. */
char *where = frag_more (2);
+ size = 2;
where[0] = 0x0;
where[1] = 0x0;
as_bad (_("invalid operands for opcode"));
- return;
+ return size;
}
-
+
if (opcode->nibbles[0] != PPI)
as_bad (_("insn can't be combined with parallel processing insn"));
unsigned long ppi_code = (movx | movy | 0xf800) << 16 | field_b;
output = frag_more (4);
+ size = 4;
if (! target_big_endian)
{
output[3] = ppi_code >> 8;
move_code |= 0xf800;
}
else
- /* Just a double data transfer. */
- output = frag_more (2);
+ {
+ /* Just a double data transfer. */
+ output = frag_more (2);
+ size = 2;
+ }
if (! target_big_endian)
{
output[1] = move_code >> 8;
output[0] = move_code >> 8;
output[1] = move_code;
}
+ return size;
}
/* This is the guts of the machine-dependent assembler. STR points to a
unsigned char *op_end;
sh_operand_info operand[3];
sh_opcode_info *opcode;
+ unsigned int size;
opcode = find_cooked_opcode (&str);
op_end = str;
if (opcode->nibbles[0] == PPI)
{
- assemble_ppi (op_end, opcode);
- return;
- }
-
- if (opcode->arg[0] == A_BDISP12
- || opcode->arg[0] == A_BDISP8)
- {
- parse_exp (op_end + 1, &operand[0]);
- build_relax (opcode, &operand[0]);
+ size = assemble_ppi (op_end, opcode);
}
else
{
- if (opcode->arg[0] == A_END)
+ if (opcode->arg[0] == A_BDISP12
+ || opcode->arg[0] == A_BDISP8)
{
- /* Ignore trailing whitespace. If there is any, it has already
- been compressed to a single space. */
- if (*op_end == ' ')
- op_end++;
+ parse_exp (op_end + 1, &operand[0]);
+ build_relax (opcode, &operand[0]);
}
else
{
- op_end = get_operands (opcode, op_end, operand);
- }
- opcode = get_specific (opcode, operand);
+ if (opcode->arg[0] == A_END)
+ {
+ /* Ignore trailing whitespace. If there is any, it has already
+ been compressed to a single space. */
+ if (*op_end == ' ')
+ op_end++;
+ }
+ else
+ {
+ op_end = get_operands (opcode, op_end, operand);
+ }
+ opcode = get_specific (opcode, operand);
- if (opcode == 0)
- {
- /* Couldn't find an opcode which matched the operands. */
- char *where = frag_more (2);
+ if (opcode == 0)
+ {
+ /* Couldn't find an opcode which matched the operands. */
+ char *where = frag_more (2);
+ size = 2;
- where[0] = 0x0;
- where[1] = 0x0;
- as_bad (_("invalid operands for opcode"));
- return;
+ where[0] = 0x0;
+ where[1] = 0x0;
+ as_bad (_("invalid operands for opcode"));
+ }
+ else
+ {
+ if (*op_end)
+ as_bad (_("excess operands: '%s'"), op_end);
+
+ size = build_Mytes (opcode, operand);
+ }
}
+ }
- if (*op_end)
- as_bad (_("excess operands: '%s'"), op_end);
+ if (debug_type == DEBUG_DWARF2)
+ {
+ bfd_vma addr;
- build_Mytes (opcode, operand);
- }
+ /* 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);
+ }
}
/* This routine is called each time a label definition is seen. It
offset = frag_now_fix ();
if (frag_now != last_label_frag
|| offset != last_label_offset)
- {
+ {
fix_new (frag_now, offset, 2, &abs_symbol, 0, 0, BFD_RELOC_SH_LABEL);
last_label_frag = frag_now;
last_label_offset = offset;
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;
}
litP += 2;
}
}
-
+
return NULL;
}
{"dsp", no_argument, NULL, OPTION_DSP},
{NULL, no_argument, NULL, 0}
};
-size_t md_longopts_size = sizeof(md_longopts);
+size_t md_longopts_size = sizeof (md_longopts);
int
md_parse_option (c, arg)
md_show_usage (stream)
FILE *stream;
{
- fprintf(stream, _("\
+ fprintf (stream, _("\
SH options:\n\
-little generate little endian code\n\
-relax alter jump instructions for long displacements\n\
symbol. When using BFD_ASSEMBLER, this is called via
bfd_map_over_sections. */
-/*ARGSUSED*/
static void
sh_count_relocs (abfd, sec, data)
bfd *abfd ATTRIBUTE_UNUSED;
/* Handle the count relocs for a particular section. When using
BFD_ASSEMBLER, this is called via bfd_map_over_sections. */
-/*ARGSUSED*/
static void
sh_frob_section (abfd, sec, ignore)
bfd *abfd ATTRIBUTE_UNUSED;
(unsigned long) fragP->fr_address);
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,
+ (unsigned long) fragP->fr_address,
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,
+ (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. */
+#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
*/
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 ] = 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 + 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 + 8] = 0x40 | JREG; /* Build jmp @JREG */
+ buffer[lowbyte + 8] = t ? 0xb : 0x2b;
- buffer[highbyte+10] = 0x20; /* build nop */
- buffer[lowbyte+10] = 0x0b;
+ buffer[highbyte + 10] = 0x20; /* build nop */
+ buffer[lowbyte + 10] = 0x0b;
/* Make reloc for the long disp. */
fix_new (fragP,
branch with delay slot. It turned:
bf.s L6 (slot mov.l r12,@(44,r0))
into:
-
+
2c: 8f 01 a0 8b bf.s 32 <_main+32> (slot bra L6)
30: 00 09 nop
32: 10 cb mov.l r12,@(44,r0)
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"),
+ as_bad (_("at 0x%lx, displacement overflows 8-bit field"),
(unsigned long) fragP->fr_address);
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,
+ (unsigned long) fragP->fr_address,
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,
+ (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. */
+#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:
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
Note that adding further restrictions may invalidate
reasonable looking assembly code, such as ``and -0x1,r0''. */
max = 0xff;
- min = - 0xff;
+ min = -0xff;
*buf++ = val;
break;
break;
case BFD_RELOC_32:
- if (! target_big_endian)
- {
- *buf++ = val >> 0;
- *buf++ = val >> 8;
- *buf++ = val >> 16;
- *buf++ = val >> 24;
- }
- else
- {
- *buf++ = val >> 24;
- *buf++ = val >> 16;
- *buf++ = val >> 8;
- *buf++ = val >> 0;
- }
+ case BFD_RELOC_32_PCREL:
+ md_number_to_chars (buf, val, 4);
break;
case BFD_RELOC_16:
- if (! target_big_endian)
- {
- *buf++ = val >> 0;
- *buf++ = val >> 8;
- }
- else
- {
- *buf++ = val >> 8;
- *buf++ = val >> 0;
- }
+ md_number_to_chars (buf, val, 2);
break;
case BFD_RELOC_SH_USES:
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 ();
}
}
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 ();
+}