mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-11-25 21:19:54 +00:00
* 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:
parent
aa02a0b0f2
commit
7257418129
@ -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
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user