* config/tc-sh.h (md_cons_align): Define.

(sh_cons_align): Declare.
	* config/tc-sh.c (md_pseudo_table): Add .uaword and .ualong.
	(sh_no_align_cons): New static variable.
	(s_uacons): New static function.
	(sh_cons_align): New function.
	(sh_handle_align): Warn about misaligned data.
	* doc/c-sh.texi: Document .uaword and .ualong.
PR 12528.
This commit is contained in:
Ian Lance Taylor 1997-06-06 21:17:46 +00:00
parent aa02a0b0f2
commit 7257418129
2 changed files with 520 additions and 198 deletions

View File

@ -1,3 +1,19 @@
Fri Jun 6 17:15:55 1997 Ian Lance Taylor <ian@cygnus.com>
* config/tc-sh.h (md_cons_align): Define.
(sh_cons_align): Declare.
* config/tc-sh.c (md_pseudo_table): Add .uaword and .ualong.
(sh_no_align_cons): New static variable.
(s_uacons): New static function.
(sh_cons_align): New function.
(sh_handle_align): Warn about misaligned data.
* doc/c-sh.texi: Document .uaword and .ualong.
Thu Jun 5 15:38:17 1997 Ian Lance Taylor <ian@cygnus.com>
* macro.c (macro_expand): In MRI mode, treat single quote as a
separator character when checking for a positional argument.
Tue Jun 3 16:15:13 1997 Nick Clifton <nickc@cygnus.com>
* config/tc-arm.c (md_parse_option): Merge in changes from

View File

@ -1,6 +1,5 @@
/* tc-sh.c -- Assemble code for the Hitachi Super-H
Copyright (C) 1993, 94, 95, 1996 Free Software Foundation.
Copyright (C) 1993, 94, 95, 96, 1997 Free Software Foundation.
This file is part of GAS, the GNU Assembler.
@ -37,6 +36,9 @@ const char line_comment_chars[] = "!#";
static void s_uses PARAMS ((int));
static void sh_count_relocs PARAMS ((bfd *, segT, PTR));
static void sh_frob_section PARAMS ((bfd *, segT, PTR));
/* This table describes all the machine specific pseudo-ops the assembler
has to support. The fields are:
pseudo-op name without dot
@ -46,6 +48,7 @@ static void s_uses PARAMS ((int));
void cons ();
void s_align_bytes ();
static void s_uacons PARAMS ((int));
int shl = 0;
@ -68,6 +71,8 @@ const pseudo_typeS md_pseudo_table[] =
{"page", listing_eject, 0},
{"program", s_ignore, 0},
{"uses", s_uses, 0},
{"uaword", s_uacons, 2},
{"ualong", s_uacons, 4},
{0, 0, 0}
};
@ -815,31 +820,31 @@ build_Mytes (opcode, operand)
nbuf[index] = reg_b | 0x08;
break;
case DISP_4:
insert (output + low_byte, R_SH_IMM4, 0);
insert (output + low_byte, BFD_RELOC_SH_IMM4, 0);
break;
case IMM_4BY4:
insert (output + low_byte, R_SH_IMM4BY4, 0);
insert (output + low_byte, BFD_RELOC_SH_IMM4BY4, 0);
break;
case IMM_4BY2:
insert (output + low_byte, R_SH_IMM4BY2, 0);
insert (output + low_byte, BFD_RELOC_SH_IMM4BY2, 0);
break;
case IMM_4:
insert (output + low_byte, R_SH_IMM4, 0);
insert (output + low_byte, BFD_RELOC_SH_IMM4, 0);
break;
case IMM_8BY4:
insert (output + low_byte, R_SH_IMM8BY4, 0);
insert (output + low_byte, BFD_RELOC_SH_IMM8BY4, 0);
break;
case IMM_8BY2:
insert (output + low_byte, R_SH_IMM8BY2, 0);
insert (output + low_byte, BFD_RELOC_SH_IMM8BY2, 0);
break;
case IMM_8:
insert (output + low_byte, R_SH_IMM8, 0);
insert (output + low_byte, BFD_RELOC_SH_IMM8, 0);
break;
case PCRELIMM_8BY4:
insert (output, R_SH_PCRELIMM8BY4, 1);
insert (output, BFD_RELOC_SH_PCRELIMM8BY4, 1);
break;
case PCRELIMM_8BY2:
insert (output, R_SH_PCRELIMM8BY2, 1);
insert (output, BFD_RELOC_SH_PCRELIMM8BY2, 1);
break;
default:
printf ("failed for %d\n", i);
@ -905,7 +910,8 @@ md_assemble (str)
{
/* Output a CODE reloc to tell the linker that the following
bytes are instructions, not data. */
fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0, R_SH_CODE);
fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0,
BFD_RELOC_SH_CODE);
seg_info (now_seg)->tc_segment_info_data.in_code = 1;
}
@ -940,18 +946,32 @@ md_assemble (str)
}
/* This routine is called each time a label definition is seen. It
emits a R_SH_LABEL reloc if necessary. */
emits a BFD_RELOC_SH_LABEL reloc if necessary. */
void
sh_frob_label ()
{
static fragS *last_label_frag;
static int last_label_offset;
if (sh_relax
&& seg_info (now_seg)->tc_segment_info_data.in_code)
fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0, R_SH_LABEL);
{
int offset;
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;
}
}
}
/* This routine is called when the assembler is about to output some
data. It emits a R_SH_DATA reloc if necessary. */
data. It emits a BFD_RELOC_SH_DATA reloc if necessary. */
void
sh_flush_pending_output ()
@ -959,18 +979,12 @@ sh_flush_pending_output ()
if (sh_relax
&& seg_info (now_seg)->tc_segment_info_data.in_code)
{
fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0, R_SH_DATA);
fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0,
BFD_RELOC_SH_DATA);
seg_info (now_seg)->tc_segment_info_data.in_code = 0;
}
}
void
DEFUN (tc_crawl_symbol_chain, (headers),
object_headers * headers)
{
printf ("call to tc_crawl_symbol_chain \n");
}
symbolS *
DEFUN (md_undefined_symbol, (name),
char *name)
@ -978,6 +992,15 @@ DEFUN (md_undefined_symbol, (name),
return 0;
}
#ifdef OBJ_COFF
void
DEFUN (tc_crawl_symbol_chain, (headers),
object_headers * headers)
{
printf ("call to tc_crawl_symbol_chain \n");
}
void
DEFUN (tc_headers_hook, (headers),
object_headers * headers)
@ -985,6 +1008,8 @@ DEFUN (tc_headers_hook, (headers),
printf ("call to tc_headers_hook \n");
}
#endif
/* Various routines to kill one day */
/* Equal to MAX_PRECISION in atof-ieee.c */
#define MAX_LITTLENUMS 6
@ -1068,7 +1093,7 @@ s_uses (ignore)
return;
}
fix_new_exp (frag_now, frag_now_fix (), 2, &ex, 1, R_SH_USES);
fix_new_exp (frag_now, frag_now_fix (), 2, &ex, 1, BFD_RELOC_SH_USES);
demand_empty_rest_of_line ();
}
@ -1147,47 +1172,86 @@ md_create_long_jump (ptr, from_Nddr, to_Nddr, frag, to_symbol)
as_fatal ("failed sanity check.");
}
/* This is function is called after the symbol table has been
completed, but before md_convert_frag has been called. If we have
seen any .uses pseudo-ops, they point to an instruction which loads
a register with the address of a function. We look through the
fixups to find where the function address is being loaded from. We
then generate a COUNT reloc giving the number of times that
function address is referred to. The linker uses this information
when doing relaxing, to decide when it can eliminate the stored
function address entirely. */
/* This struct is used to pass arguments to sh_count_relocs through
bfd_map_over_sections. */
void
sh_coff_frob_file ()
struct sh_count_relocs
{
int iseg;
/* Symbol we are looking for. */
symbolS *sym;
/* Count of relocs found. */
int count;
};
if (! sh_relax)
return;
/* Count the number of fixups in a section which refer to a particular
symbol. When using BFD_ASSEMBLER, this is called via
bfd_map_over_sections. */
for (iseg = SEG_E0; iseg < SEG_UNKNOWN; iseg++)
/*ARGSUSED*/
static void
sh_count_relocs (abfd, sec, data)
bfd *abfd;
segT sec;
PTR data;
{
struct sh_count_relocs *info = (struct sh_count_relocs *) data;
segment_info_type *seginfo;
symbolS *sym;
fixS *fix;
for (fix = segment_info[iseg].fix_root; fix != NULL; fix = fix->fx_next)
seginfo = seg_info (sec);
if (seginfo == NULL)
return;
sym = info->sym;
for (fix = seginfo->fix_root; fix != NULL; fix = fix->fx_next)
{
if (fix->fx_addsy == sym)
{
++info->count;
fix->fx_tcbit = 1;
}
}
}
/* 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;
segT sec;
PTR ignore;
{
segment_info_type *seginfo;
fixS *fix;
seginfo = seg_info (sec);
if (seginfo == NULL)
return;
for (fix = seginfo->fix_root; fix != NULL; fix = fix->fx_next)
{
symbolS *sym;
bfd_vma val;
fixS *fscan;
int iscan;
int count;
struct sh_count_relocs info;
if (fix->fx_r_type != R_SH_USES)
if (fix->fx_r_type != BFD_RELOC_SH_USES)
continue;
/* The R_SH_USES reloc should refer to a defined local
/* The BFD_RELOC_SH_USES reloc should refer to a defined local
symbol in the same section. */
sym = fix->fx_addsy;
if (sym == NULL
|| fix->fx_subsy != NULL
|| fix->fx_addnumber != 0
|| S_GET_SEGMENT (sym) != iseg
|| S_GET_STORAGE_CLASS (sym) == C_EXT)
|| S_GET_SEGMENT (sym) != sec
#if ! defined (BFD_ASSEMBLER) && defined (OBJ_COFF)
|| S_GET_STORAGE_CLASS (sym) == C_EXT
#endif
|| S_IS_EXTERNAL (sym))
{
as_warn_where (fix->fx_file, fix->fx_line,
".uses does not refer to a local symbol in the same section");
@ -1197,14 +1261,14 @@ sh_coff_frob_file ()
/* Look through the fixups again, this time looking for one
at the same location as sym. */
val = S_GET_VALUE (sym);
for (fscan = segment_info[iseg].fix_root;
for (fscan = seginfo->fix_root;
fscan != NULL;
fscan = fscan->fx_next)
if (val == fscan->fx_frag->fr_address + fscan->fx_where
&& fscan->fx_r_type != R_SH_ALIGN
&& fscan->fx_r_type != R_SH_CODE
&& fscan->fx_r_type != R_SH_DATA
&& fscan->fx_r_type != R_SH_LABEL)
&& fscan->fx_r_type != BFD_RELOC_SH_ALIGN
&& fscan->fx_r_type != BFD_RELOC_SH_CODE
&& fscan->fx_r_type != BFD_RELOC_SH_DATA
&& fscan->fx_r_type != BFD_RELOC_SH_LABEL)
break;
if (fscan == NULL)
{
@ -1225,8 +1289,11 @@ sh_coff_frob_file ()
if (sym == NULL
|| fscan->fx_subsy != NULL
|| fscan->fx_addnumber != 0
|| S_GET_SEGMENT (sym) != iseg
|| S_GET_STORAGE_CLASS (sym) == C_EXT)
|| S_GET_SEGMENT (sym) != sec
#if ! defined (BFD_ASSEMBLER) && defined (OBJ_COFF)
|| S_GET_STORAGE_CLASS (sym) == C_EXT
#endif
|| S_IS_EXTERNAL (sym))
{
as_warn_where (fix->fx_file, fix->fx_line,
".uses target does not refer to a local symbol in the same section");
@ -1235,32 +1302,57 @@ sh_coff_frob_file ()
/* Now we look through all the fixups of all the sections,
counting the number of times we find a reference to sym. */
count = 0;
for (iscan = SEG_E0; iscan < SEG_UNKNOWN; iscan++)
info.sym = sym;
info.count = 0;
#ifdef BFD_ASSEMBLER
bfd_map_over_sections (stdoutput, sh_count_relocs, (PTR) &info);
#else
{
for (fscan = segment_info[iscan].fix_root;
fscan != NULL;
fscan = fscan->fx_next)
{
if (fscan->fx_addsy == sym)
{
++count;
fscan->fx_tcbit = 1;
}
}
}
int iscan;
if (count < 1)
for (iscan = SEG_E0; iscan < SEG_UNKNOWN; iscan++)
sh_count_relocs ((bfd *) NULL, iscan, (PTR) &info);
}
#endif
if (info.count < 1)
abort ();
/* Generate a R_SH_COUNT fixup at the location of sym. We
have already adjusted the value of sym to include the
/* Generate a BFD_RELOC_SH_COUNT fixup at the location of sym.
We have already adjusted the value of sym to include the
fragment address, so we undo that adjustment here. */
subseg_change (iseg, 0);
subseg_change (sec, 0);
fix_new (sym->sy_frag, S_GET_VALUE (sym) - sym->sy_frag->fr_address,
4, &abs_symbol, count, 0, R_SH_COUNT);
4, &abs_symbol, info.count, 0, BFD_RELOC_SH_COUNT);
}
}
/* This function is called after the symbol table has been completed,
but before the relocs or section contents have been written out.
If we have seen any .uses pseudo-ops, they point to an instruction
which loads a register with the address of a function. We look
through the fixups to find where the function address is being
loaded from. We then generate a COUNT reloc giving the number of
times that function address is referred to. The linker uses this
information when doing relaxing, to decide when it can eliminate
the stored function address entirely. */
void
sh_frob_file ()
{
if (! sh_relax)
return;
#ifdef BFD_ASSEMBLER
bfd_map_over_sections (stdoutput, sh_frob_section, (PTR) NULL);
#else
{
int iseg;
for (iseg = SEG_E0; iseg < SEG_UNKNOWN; iseg++)
sh_frob_section ((bfd *) NULL, iseg, (PTR) NULL);
}
#endif
}
/* Called after relaxing. Set the correct sizes of the fragments, and
@ -1268,7 +1360,11 @@ sh_coff_frob_file ()
void
md_convert_frag (headers, seg, fragP)
#ifdef BFD_ASSEMBLER
bfd *headers;
#else
object_headers *headers;
#endif
segT seg;
fragS *fragP;
{
@ -1279,7 +1375,7 @@ md_convert_frag (headers, seg, fragP)
case C (COND_JUMP, COND8):
subseg_change (seg, 0);
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
1, R_SH_PCDISP8BY2);
1, BFD_RELOC_SH_PCDISP8BY2);
fragP->fr_fix += 2;
fragP->fr_var = 0;
break;
@ -1287,7 +1383,7 @@ md_convert_frag (headers, seg, fragP)
case C (UNCOND_JUMP, UNCOND12):
subseg_change (seg, 0);
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
1, R_SH_PCDISP);
1, BFD_RELOC_SH_PCDISP12BY2);
fragP->fr_fix += 2;
fragP->fr_var = 0;
break;
@ -1337,7 +1433,7 @@ md_convert_frag (headers, seg, fragP)
fragP->fr_symbol,
fragP->fr_offset,
0,
R_SH_IMM32);
BFD_RELOC_32);
fragP->fr_fix += UNCOND32_LENGTH;
fragP->fr_var = 0;
donerelax = 1;
@ -1359,15 +1455,19 @@ md_convert_frag (headers, seg, fragP)
/* Build a relocation to six bytes farther on. */
subseg_change (seg, 0);
fix_new (fragP, fragP->fr_fix, 2,
segment_info[seg].dot,
#ifdef BFD_ASSEMBLER
section_symbol (seg),
#else
seg_info (seg)->dot,
#endif
fragP->fr_address + fragP->fr_fix + 6,
1, R_SH_PCDISP8BY2);
1, BFD_RELOC_SH_PCDISP8BY2);
/* Set up a jump instruction. */
buffer[highbyte + 2] = 0xa0;
buffer[lowbyte + 2] = 0;
fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol,
fragP->fr_offset, 1, R_SH_PCDISP);
fragP->fr_offset, 1, BFD_RELOC_SH_PCDISP12BY2);
/* Fill in a NOP instruction. */
buffer[highbyte + 4] = 0x0;
@ -1425,7 +1525,7 @@ md_convert_frag (headers, seg, fragP)
fragP->fr_symbol,
fragP->fr_offset,
0,
R_SH_IMM32);
BFD_RELOC_32);
fragP->fr_fix += COND32_LENGTH;
fragP->fr_var = 0;
donerelax = 1;
@ -1438,10 +1538,11 @@ md_convert_frag (headers, seg, fragP)
}
if (donerelax && !sh_relax)
as_warn ("Offset doesn't fit at 0x%lx, trying to get to %s+0x%lx",
(unsigned long) fragP->fr_address,
fragP->fr_symbol ? S_GET_NAME(fragP->fr_symbol): "",
(unsigned long) fragP->fr_offset);
as_warn_where (fragP->fr_file, fragP->fr_line,
"overflow in branch to %s; converted into longer instruction sequence",
(fragP->fr_symbol != NULL
? S_GET_NAME (fragP->fr_symbol)
: ""));
}
valueT
@ -1449,13 +1550,83 @@ DEFUN (md_section_align, (seg, size),
segT seg AND
valueT size)
{
#ifdef BFD_ASSEMBLER
#ifdef OBJ_ELF
return size;
#else /* ! OBJ_ELF */
return ((size + (1 << bfd_get_section_alignment (stdoutput, seg)) - 1)
& (-1 << bfd_get_section_alignment (stdoutput, seg)));
#endif /* ! OBJ_ELF */
#else /* ! BFD_ASSEMBLER */
return ((size + (1 << section_alignment[(int) seg]) - 1)
& (-1 << section_alignment[(int) seg]));
#endif /* ! BFD_ASSEMBLER */
}
/* This static variable is set by s_uacons to tell sh_cons_align that
the expession does not need to be aligned. */
static int sh_no_align_cons = 0;
/* This handles the unaligned space allocation pseudo-ops, such as
.uaword. .uaword is just like .word, but the value does not need
to be aligned. */
static void
s_uacons (bytes)
int bytes;
{
/* Tell sh_cons_align not to align this value. */
sh_no_align_cons = 1;
cons (bytes);
}
/* If a .word, et. al., pseud-op is seen, warn if the value is not
aligned correctly. Note that this can cause warnings to be issued
when assembling initialized structured which were declared with the
packed attribute. FIXME: Perhaps we should require an option to
enable this warning? */
void
sh_cons_align (nbytes)
int nbytes;
{
int nalign;
char *p;
if (sh_no_align_cons)
{
/* This is an unaligned pseudo-op. */
sh_no_align_cons = 0;
return;
}
nalign = 0;
while ((nbytes & 1) == 0)
{
++nalign;
nbytes >>= 1;
}
if (nalign == 0)
return;
if (now_seg == absolute_section)
{
if ((abs_section_offset & ((1 << nalign) - 1)) != 0)
as_warn ("misaligned data");
return;
}
p = frag_var (rs_align_code, 1, 1, (relax_substateT) 0,
(symbolS *) NULL, (offsetT) nalign, (char *) NULL);
record_alignment (now_seg, nalign);
}
/* When relaxing, we need to output a reloc for any .align directive
that requests alignment to a four byte boundary or larger. */
that requests alignment to a four byte boundary or larger. This is
also where we check for misaligned data. */
void
sh_handle_align (frag)
@ -1467,7 +1638,11 @@ sh_handle_align (frag)
&& frag->fr_offset > 1
&& now_seg != bss_section)
fix_new (frag, frag->fr_fix, 2, &abs_symbol, frag->fr_offset, 0,
R_SH_ALIGN);
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
@ -1475,16 +1650,23 @@ sh_handle_align (frag)
to know about all such entries so that it can adjust them if
necessary. */
#ifdef BFD_ASSEMBLER
#define SWITCH_TABLE_CONS(fix) (0)
#else
#define SWITCH_TABLE_CONS(fix) \
((fix)->fx_r_type == 0 \
&& ((fix)->fx_size == 2 \
|| (fix)->fx_size == 4))
#endif
#define SWITCH_TABLE(fix) \
((fix)->fx_addsy != NULL \
&& (fix)->fx_subsy != NULL \
&& S_GET_SEGMENT ((fix)->fx_addsy) == text_section \
&& S_GET_SEGMENT ((fix)->fx_subsy) == text_section \
&& ((fix)->fx_r_type == R_SH_IMM32 \
|| (fix)->fx_r_type == R_SH_IMM16 \
|| ((fix)->fx_r_type == 0 \
&& ((fix)->fx_size == 2 \
|| (fix)->fx_size == 4))))
&& ((fix)->fx_r_type == BFD_RELOC_32 \
|| (fix)->fx_r_type == BFD_RELOC_16 \
|| SWITCH_TABLE_CONS (fix)))
/* See whether we need to force a relocation into the output file.
This is used to force out switch and PC relative relocations when
@ -1499,63 +1681,76 @@ sh_force_relocation (fix)
return (fix->fx_pcrel
|| SWITCH_TABLE (fix)
|| fix->fx_r_type == R_SH_COUNT
|| fix->fx_r_type == R_SH_ALIGN
|| fix->fx_r_type == R_SH_CODE
|| fix->fx_r_type == R_SH_DATA
|| fix->fx_r_type == R_SH_LABEL);
|| fix->fx_r_type == BFD_RELOC_SH_COUNT
|| fix->fx_r_type == BFD_RELOC_SH_ALIGN
|| fix->fx_r_type == BFD_RELOC_SH_CODE
|| fix->fx_r_type == BFD_RELOC_SH_DATA
|| fix->fx_r_type == BFD_RELOC_SH_LABEL);
}
/* Apply a fixup to the object file. */
#ifdef BFD_ASSEMBLER
int
md_apply_fix (fixP, valp)
fixS *fixP;
valueT *valp;
#else
void
md_apply_fix (fixP, val)
fixS *fixP;
long val;
#endif
{
char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
int lowbyte = target_big_endian ? 1 : 0;
int highbyte = target_big_endian ? 0 : 1;
#ifdef BFD_ASSEMBLER
long val = *valp;
#endif
#ifndef BFD_ASSEMBLER
if (fixP->fx_r_type == 0)
{
if (fixP->fx_size == 2)
fixP->fx_r_type = R_SH_IMM16;
fixP->fx_r_type = BFD_RELOC_16;
else if (fixP->fx_size == 4)
fixP->fx_r_type = R_SH_IMM32;
fixP->fx_r_type = BFD_RELOC_32;
else if (fixP->fx_size == 1)
fixP->fx_r_type = R_SH_IMM8;
fixP->fx_r_type = BFD_RELOC_SH_IMM8;
else
abort ();
}
#endif
switch (fixP->fx_r_type)
{
case R_SH_IMM4:
case BFD_RELOC_SH_IMM4:
*buf = (*buf & 0xf0) | (val & 0xf);
break;
case R_SH_IMM4BY2:
case BFD_RELOC_SH_IMM4BY2:
*buf = (*buf & 0xf0) | ((val >> 1) & 0xf);
break;
case R_SH_IMM4BY4:
case BFD_RELOC_SH_IMM4BY4:
*buf = (*buf & 0xf0) | ((val >> 2) & 0xf);
break;
case R_SH_IMM8BY2:
case BFD_RELOC_SH_IMM8BY2:
*buf = val >> 1;
break;
case R_SH_IMM8BY4:
case BFD_RELOC_SH_IMM8BY4:
*buf = val >> 2;
break;
case R_SH_IMM8:
case BFD_RELOC_8:
case BFD_RELOC_SH_IMM8:
*buf++ = val;
break;
case R_SH_PCRELIMM8BY4:
case BFD_RELOC_SH_PCRELIMM8BY4:
/* The lower two bits of the PC are cleared before the
displacement is added in. We can assume that the destination
is on a 4 byte bounday. If this instruction is also on a 4
@ -1575,21 +1770,21 @@ md_apply_fix (fixP, val)
buf[lowbyte] = val;
break;
case R_SH_PCRELIMM8BY2:
case BFD_RELOC_SH_PCRELIMM8BY2:
val /= 2;
if (val & ~0xff)
as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far");
buf[lowbyte] = val;
break;
case R_SH_PCDISP8BY2:
case BFD_RELOC_SH_PCDISP8BY2:
val /= 2;
if (val < -0x80 || val > 0x7f)
as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far");
buf[lowbyte] = val;
break;
case R_SH_PCDISP:
case BFD_RELOC_SH_PCDISP12BY2:
val /= 2;
if (val < -0x800 || val >= 0x7ff)
as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far");
@ -1597,7 +1792,7 @@ md_apply_fix (fixP, val)
buf[highbyte] |= (val >> 8) & 0xf;
break;
case R_SH_IMM32:
case BFD_RELOC_32:
if (! target_big_endian)
{
*buf++ = val >> 0;
@ -1614,7 +1809,7 @@ md_apply_fix (fixP, val)
}
break;
case R_SH_IMM16:
case BFD_RELOC_16:
if (! target_big_endian)
{
*buf++ = val >> 0;
@ -1627,22 +1822,26 @@ md_apply_fix (fixP, val)
}
break;
case R_SH_USES:
case BFD_RELOC_SH_USES:
/* Pass the value into sh_coff_reloc_mangle. */
fixP->fx_addnumber = val;
break;
case R_SH_COUNT:
case R_SH_ALIGN:
case R_SH_CODE:
case R_SH_DATA:
case R_SH_LABEL:
case BFD_RELOC_SH_COUNT:
case BFD_RELOC_SH_ALIGN:
case BFD_RELOC_SH_CODE:
case BFD_RELOC_SH_DATA:
case BFD_RELOC_SH_LABEL:
/* Nothing to do here. */
break;
default:
abort ();
}
#ifdef BFD_ASSEMBLER
return 0;
#endif
}
int md_long_jump_size;
@ -1729,6 +1928,8 @@ md_pcrel_from (fixP)
return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address + 2;
}
#ifdef OBJ_COFF
int
tc_coff_sizemachdep (frag)
fragS *frag;
@ -1736,20 +1937,24 @@ tc_coff_sizemachdep (frag)
return md_relax_table[frag->fr_subtype].rlx_length;
}
#endif /* OBJ_COFF */
/* When we align the .text section, insert the correct NOP pattern. */
int
sh_do_align (n, fill, len)
sh_do_align (n, fill, len, max)
int n;
const char *fill;
int len;
int max;
{
if ((fill == NULL || (*fill == 0 && len == 1))
&& (now_seg == text_section
if (fill == NULL
#ifdef BFD_ASSEMBLER
|| (now_seg->flags & SEC_CODE) != 0
&& (now_seg->flags & SEC_CODE) != 0
#else
&& now_seg != data_section
&& now_seg != bss_section
#endif
|| strcmp (obj_segment_name (now_seg), ".init") == 0)
&& n > 1)
{
static const unsigned char big_nop_pattern[] = { 0x00, 0x09 };
@ -1757,19 +1962,55 @@ sh_do_align (n, fill, len)
/* First align to a 2 byte boundary, in case there is an odd
.byte. */
frag_align (1, 0);
frag_align (1, 0, 0);
if (target_big_endian)
frag_align_pattern (n, big_nop_pattern, sizeof big_nop_pattern);
frag_align_pattern (n, big_nop_pattern, sizeof big_nop_pattern, max);
else
frag_align_pattern (n, little_nop_pattern, sizeof little_nop_pattern);
frag_align_pattern (n, little_nop_pattern, sizeof little_nop_pattern,
max);
return 1;
}
return 0;
}
#ifndef BFD_ASSEMBLER
#ifdef OBJ_COFF
/* Map BFD relocs to SH COFF relocs. */
struct reloc_map
{
bfd_reloc_code_real_type bfd_reloc;
int sh_reloc;
};
static const struct reloc_map coff_reloc_map[] =
{
{ BFD_RELOC_32, R_SH_IMM32 },
{ BFD_RELOC_16, R_SH_IMM16 },
{ BFD_RELOC_8, R_SH_IMM8 },
{ BFD_RELOC_SH_PCDISP8BY2, R_SH_PCDISP8BY2 },
{ BFD_RELOC_SH_PCDISP12BY2, R_SH_PCDISP },
{ BFD_RELOC_SH_IMM4, R_SH_IMM4 },
{ BFD_RELOC_SH_IMM4BY2, R_SH_IMM4BY2 },
{ BFD_RELOC_SH_IMM4BY4, R_SH_IMM4BY4 },
{ BFD_RELOC_SH_IMM8, R_SH_IMM8 },
{ BFD_RELOC_SH_IMM8BY2, R_SH_IMM8BY2 },
{ BFD_RELOC_SH_IMM8BY4, R_SH_IMM8BY4 },
{ BFD_RELOC_SH_PCRELIMM8BY2, R_SH_PCRELIMM8BY2 },
{ BFD_RELOC_SH_PCRELIMM8BY4, R_SH_PCRELIMM8BY4 },
{ BFD_RELOC_SH_SWITCH16, R_SH_SWITCH16 },
{ BFD_RELOC_SH_SWITCH32, R_SH_SWITCH32 },
{ BFD_RELOC_SH_USES, R_SH_USES },
{ BFD_RELOC_SH_COUNT, R_SH_COUNT },
{ BFD_RELOC_SH_ALIGN, R_SH_ALIGN },
{ BFD_RELOC_SH_CODE, R_SH_CODE },
{ BFD_RELOC_SH_DATA, R_SH_DATA },
{ BFD_RELOC_SH_LABEL, R_SH_LABEL },
{ BFD_RELOC_UNUSED, 0 }
};
/* Adjust a reloc for the SH. This is similar to the generic code,
but does some minor tweaking. */
@ -1787,16 +2028,25 @@ sh_coff_reloc_mangle (seg, fix, intr, paddr)
if (! SWITCH_TABLE (fix))
{
intr->r_type = fix->fx_r_type;
const struct reloc_map *rm;
for (rm = coff_reloc_map; rm->bfd_reloc != BFD_RELOC_UNUSED; rm++)
if (rm->bfd_reloc == (bfd_reloc_code_real_type) fix->fx_r_type)
break;
if (rm->bfd_reloc == BFD_RELOC_UNUSED)
as_bad_where (fix->fx_file, fix->fx_line,
"Can not represent %s relocation in this object file format",
bfd_get_reloc_code_name (fix->fx_r_type));
intr->r_type = rm->sh_reloc;
intr->r_offset = 0;
}
else
{
know (sh_relax);
if (fix->fx_r_type == R_SH_IMM16)
if (fix->fx_r_type == BFD_RELOC_16)
intr->r_type = R_SH_SWITCH16;
else if (fix->fx_r_type == R_SH_IMM32)
else if (fix->fx_r_type == BFD_RELOC_32)
intr->r_type = R_SH_SWITCH32;
else
abort ();
@ -1813,11 +2063,11 @@ sh_coff_reloc_mangle (seg, fix, intr, paddr)
{
switch (fix->fx_r_type)
{
case R_SH_PCRELIMM8BY2:
case R_SH_PCRELIMM8BY4:
case R_SH_PCDISP8BY2:
case R_SH_PCDISP:
case R_SH_USES:
case BFD_RELOC_SH_PCRELIMM8BY2:
case BFD_RELOC_SH_PCRELIMM8BY4:
case BFD_RELOC_SH_PCDISP8BY2:
case BFD_RELOC_SH_PCDISP12BY2:
case BFD_RELOC_SH_USES:
symbol_ptr = seg->dot;
break;
default:
@ -1825,14 +2075,14 @@ sh_coff_reloc_mangle (seg, fix, intr, paddr)
}
}
if (fix->fx_r_type == R_SH_USES)
if (fix->fx_r_type == BFD_RELOC_SH_USES)
{
/* We can't store the offset in the object file, since this
reloc does not take up any space, so we store it in r_offset.
The fx_addnumber field was set in md_apply_fix. */
intr->r_offset = fix->fx_addnumber;
}
else if (fix->fx_r_type == R_SH_COUNT)
else if (fix->fx_r_type == BFD_RELOC_SH_COUNT)
{
/* We can't store the count in the object file, since this reloc
does not take up any space, so we store it in r_offset. The
@ -1842,16 +2092,16 @@ sh_coff_reloc_mangle (seg, fix, intr, paddr)
/* This reloc is always absolute. */
symbol_ptr = NULL;
}
else if (fix->fx_r_type == R_SH_ALIGN)
else if (fix->fx_r_type == BFD_RELOC_SH_ALIGN)
{
/* Store the alignment in the r_offset field. */
intr->r_offset = fix->fx_offset;
/* This reloc is always absolute. */
symbol_ptr = NULL;
}
else if (fix->fx_r_type == R_SH_CODE
|| fix->fx_r_type == R_SH_DATA
|| fix->fx_r_type == R_SH_LABEL)
else if (fix->fx_r_type == BFD_RELOC_SH_CODE
|| fix->fx_r_type == BFD_RELOC_SH_DATA
|| fix->fx_r_type == BFD_RELOC_SH_LABEL)
{
/* These relocs are always absolute. */
symbol_ptr = NULL;
@ -1870,4 +2120,60 @@ sh_coff_reloc_mangle (seg, fix, intr, paddr)
intr->r_symndx = -1;
}
#endif
#endif /* OBJ_COFF */
#endif /* ! BFD_ASSEMBLER */
#ifdef BFD_ASSEMBLER
/* Create a reloc. */
arelent *
tc_gen_reloc (section, fixp)
asection *section;
fixS *fixp;
{
arelent *rel;
bfd_reloc_code_real_type r_type;
rel = (arelent *) xmalloc (sizeof (arelent));
rel->sym_ptr_ptr = &fixp->fx_addsy->bsym;
rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
r_type = fixp->fx_r_type;
if (SWITCH_TABLE (fixp))
{
rel->addend = rel->address - S_GET_VALUE (fixp->fx_subsy);
if (r_type == BFD_RELOC_16)
r_type = BFD_RELOC_SH_SWITCH16;
else if (r_type == BFD_RELOC_32)
r_type = BFD_RELOC_SH_SWITCH32;
else
abort ();
}
else if (r_type == BFD_RELOC_SH_USES)
rel->addend = fixp->fx_addnumber;
else if (r_type == BFD_RELOC_SH_COUNT)
rel->addend = fixp->fx_offset;
else if (r_type == BFD_RELOC_SH_ALIGN)
rel->addend = fixp->fx_offset;
else if (fixp->fx_pcrel)
rel->addend = fixp->fx_addnumber;
else
rel->addend = 0;
rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
if (rel->howto == NULL)
{
as_bad_where (fixp->fx_file, fixp->fx_line,
"Cannot represent relocation type %s",
bfd_get_reloc_code_name (r_type));
/* Set howto to a garbage value so that we can keep going. */
rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
assert (rel->howto != NULL);
}
return rel;
}
#endif /* BFD_ASSEMBLER */