* coff-h8300.c (h8300_reloc16_estimate): Fix many minor spacing
problems. (h8300_reloc16_estimate, cases R_JMP1, R_JMP2): Adjust "dot" correctly for the two variants. Allow relaxing if the target is 128 bytes away since after relaxation it'll be 126 bytes away. (h8300_reloc16_estimate, case R_PCRWORD): Correctly adjust "dot" and "value". Allow relaxing if the target is 128 bytes away since after relaxation it'll be 126 bytes away. * reloc16.c (bfd_coff_reloc16_relax_section): Keep relaxing the given section until nothing changes. Improving corner case relaxing for jmp:16->bra:8, jmp:24->bra:8 and bCC:16->bCC:8. Re-relax a section if something changes; more relaxing opportunities may be available.
This commit is contained in:
parent
f98286385f
commit
fd7c5d73ce
1 changed files with 440 additions and 352 deletions
792
bfd/coff-h8300.c
792
bfd/coff-h8300.c
|
@ -225,17 +225,14 @@ static reloc_howto_type howto_table[] =
|
|||
HOWTO (R_PCRBYTE, 0, 0, 8, true, 0, complain_overflow_signed, special, "DISP8", false, 0x000000ff, 0x000000ff, true),
|
||||
HOWTO (R_PCRWORD, 0, 1, 16, true, 0, complain_overflow_signed, special, "DISP16", false, 0x0000ffff, 0x0000ffff, true),
|
||||
HOWTO (R_PCRLONG, 0, 2, 32, true, 0, complain_overflow_signed, special, "DISP32", false, 0xffffffff, 0xffffffff, true),
|
||||
HOWTO (R_MOVB1, 0, 1, 16, false, 0, complain_overflow_bitfield, special, "16/8", false, 0x0000ffff, 0x0000ffff, false),
|
||||
HOWTO (R_MOVB2, 0, 1, 16, false, 0, complain_overflow_bitfield, special, "8/16", false, 0x0000ffff, 0x0000ffff, false),
|
||||
HOWTO (R_MOV16B1, 0, 1, 16, false, 0, complain_overflow_bitfield, special, "relaxable mov.b:16", false, 0x0000ffff, 0x0000ffff, false),
|
||||
HOWTO (R_MOV16B2, 0, 1, 8, false, 0, complain_overflow_bitfield, special, "relaxed mov.b:16", false, 0x000000ff, 0x000000ff, false),
|
||||
HOWTO (R_JMP1, 0, 1, 16, false, 0, complain_overflow_bitfield, special, "16/pcrel", false, 0x0000ffff, 0x0000ffff, false),
|
||||
HOWTO (R_JMP2, 0, 0, 8, false, 0, complain_overflow_bitfield, special, "pcrecl/16", false, 0x000000ff, 0x000000ff, false),
|
||||
|
||||
|
||||
HOWTO (R_JMPL1, 0, 2, 32, false, 0, complain_overflow_bitfield, special, "24/pcrell", false, 0x00ffffff, 0x00ffffff, false),
|
||||
HOWTO (R_JMPL_B8, 0, 0, 8, false, 0, complain_overflow_bitfield, special, "pc8/24", false, 0x000000ff, 0x000000ff, false),
|
||||
|
||||
HOWTO (R_MOVLB1, 0, 1, 16, false, 0, complain_overflow_bitfield,special, "24/8", false, 0x0000ffff, 0x0000ffff, false),
|
||||
HOWTO (R_MOVLB2, 0, 1, 16, false, 0, complain_overflow_bitfield, special, "8/24", false, 0x0000ffff, 0x0000ffff, false),
|
||||
HOWTO (R_JMPL2, 0, 0, 8, false, 0, complain_overflow_bitfield, special, "pc8/24", false, 0x000000ff, 0x000000ff, false),
|
||||
HOWTO (R_MOV24B1, 0, 1, 32, false, 0, complain_overflow_bitfield, special, "relaxable mov.b:24", false, 0xffffffff, 0xffffffff, false),
|
||||
HOWTO (R_MOV24B2, 0, 1, 8, false, 0, complain_overflow_bitfield, special, "relaxed mov.b:24", false, 0x0000ffff, 0x0000ffff, false),
|
||||
|
||||
/* An indirect reference to a function. This causes the function's address
|
||||
to be added to the function vector in lo-mem and puts the address of
|
||||
|
@ -244,7 +241,12 @@ static reloc_howto_type howto_table[] =
|
|||
|
||||
/* Internal reloc for relaxing. This is created when a 16bit pc-relative
|
||||
branch is turned into an 8bit pc-relative branch. */
|
||||
HOWTO (R_PCRWORD_B, 0, 0, 8, true, 0, complain_overflow_bitfield, special, "pcrecl/16", false, 0x000000ff, 0x000000ff, false),
|
||||
HOWTO (R_PCRWORD_B, 0, 0, 8, true, 0, complain_overflow_bitfield, special, "relaxed bCC:16", false, 0x000000ff, 0x000000ff, false),
|
||||
|
||||
HOWTO (R_MOVL1, 0, 2, 32, false, 0, complain_overflow_bitfield,special, "32/24 relaxable move", false, 0xffffffff, 0xffffffff, false),
|
||||
|
||||
HOWTO (R_MOVL2, 0, 1, 16, false, 0, complain_overflow_bitfield, special, "32/24 relaxed move", false, 0x0000ffff, 0x0000ffff, false),
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -302,10 +304,10 @@ rtype2howto (internal, dst)
|
|||
case R_PCRLONG:
|
||||
internal->howto = howto_table + 5;
|
||||
break;
|
||||
case R_MOVB1:
|
||||
case R_MOV16B1:
|
||||
internal->howto = howto_table + 6;
|
||||
break;
|
||||
case R_MOVB2:
|
||||
case R_MOV16B2:
|
||||
internal->howto = howto_table + 7;
|
||||
break;
|
||||
case R_JMP1:
|
||||
|
@ -317,13 +319,13 @@ rtype2howto (internal, dst)
|
|||
case R_JMPL1:
|
||||
internal->howto = howto_table + 10;
|
||||
break;
|
||||
case R_JMPL_B8:
|
||||
case R_JMPL2:
|
||||
internal->howto = howto_table + 11;
|
||||
break;
|
||||
case R_MOVLB1:
|
||||
case R_MOV24B1:
|
||||
internal->howto = howto_table + 12;
|
||||
break;
|
||||
case R_MOVLB2:
|
||||
case R_MOV24B2:
|
||||
internal->howto = howto_table + 13;
|
||||
break;
|
||||
case R_MEM_INDIRECT:
|
||||
|
@ -332,6 +334,12 @@ rtype2howto (internal, dst)
|
|||
case R_PCRWORD_B:
|
||||
internal->howto = howto_table + 15;
|
||||
break;
|
||||
case R_MOVL1:
|
||||
internal->howto = howto_table + 16;
|
||||
break;
|
||||
case R_MOVL2:
|
||||
internal->howto = howto_table + 17;
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
break;
|
||||
|
@ -379,6 +387,13 @@ reloc_processing (relent, reloc, symbols, abfd, section)
|
|||
/* relent->section = 0;*/
|
||||
}
|
||||
|
||||
/* If RELOC represents a relaxable instruction/reloc, change it into
|
||||
the relaxed reloc, notify the linker that symbol addresses
|
||||
have changed (bfd_perform_slip) and return how much the current
|
||||
section has shrunk by.
|
||||
|
||||
FIXME: Much of this code has knowledge of the ordering of entries
|
||||
in the howto table. This needs to be fixed. */
|
||||
|
||||
static int
|
||||
h8300_reloc16_estimate(abfd, input_section, reloc, shrink, link_info)
|
||||
|
@ -393,142 +408,158 @@ h8300_reloc16_estimate(abfd, input_section, reloc, shrink, link_info)
|
|||
bfd_vma gap;
|
||||
|
||||
/* The address of the thing to be relocated will have moved back by
|
||||
the size of the shrink - but we don't change reloc->address here,
|
||||
since we need it to know where the relocation lives in the source
|
||||
uncooked section */
|
||||
|
||||
/* reloc->address -= shrink; conceptual */
|
||||
|
||||
the size of the shrink - but we don't change reloc->address here,
|
||||
since we need it to know where the relocation lives in the source
|
||||
uncooked section. */
|
||||
bfd_vma address = reloc->address - shrink;
|
||||
|
||||
|
||||
/* Only examine the relocs which might be relaxable. */
|
||||
switch (reloc->howto->type)
|
||||
{
|
||||
case R_MOVB2:
|
||||
case R_JMP2:
|
||||
case R_PCRWORD_B:
|
||||
shrink+=2;
|
||||
break;
|
||||
|
||||
/* Thing is a move one byte */
|
||||
case R_MOVB1:
|
||||
value = bfd_coff_reloc16_get_value(reloc, link_info, input_section);
|
||||
|
||||
if (value >= 0xff00)
|
||||
{
|
||||
|
||||
/* Change the reloc type from 16bit, possible 8 to 8bit
|
||||
possible 16 */
|
||||
reloc->howto = reloc->howto + 1;
|
||||
/* The place to relc moves back by one */
|
||||
/* This will be two bytes smaller in the long run */
|
||||
shrink +=2 ;
|
||||
bfd_perform_slip(abfd, 2, input_section, address);
|
||||
}
|
||||
|
||||
break;
|
||||
/* This is the 24 bit branch which could become an 8 bitter,
|
||||
the relocation points to the first byte of the insn, not the
|
||||
actual data */
|
||||
|
||||
case R_JMPL1:
|
||||
value = bfd_coff_reloc16_get_value(reloc, link_info, input_section);
|
||||
|
||||
dot = input_section->output_section->vma +
|
||||
input_section->output_offset + address;
|
||||
|
||||
/* See if the address we're looking at within 127 bytes of where
|
||||
we are, if so then we can use a small branch rather than the
|
||||
jump we were going to */
|
||||
|
||||
gap = value - dot ;
|
||||
|
||||
if (-120 < (long)gap && (long)gap < 120 )
|
||||
{
|
||||
|
||||
/* Change the reloc type from 24bit, possible 8 to 8bit
|
||||
possible 32 */
|
||||
reloc->howto = reloc->howto + 1;
|
||||
/* This will be two bytes smaller in the long run */
|
||||
shrink +=2 ;
|
||||
bfd_perform_slip(abfd, 2, input_section, address);
|
||||
}
|
||||
break;
|
||||
|
||||
/* This is the 16/24 bit absolute branch which could become an 8 bit
|
||||
pc-relative branch. */
|
||||
case R_JMP1:
|
||||
|
||||
case R_JMPL1:
|
||||
/* Get the address of the target of this branch. */
|
||||
value = bfd_coff_reloc16_get_value(reloc, link_info, input_section);
|
||||
|
||||
/* Get the address of the next instruction (not the reloc). */
|
||||
dot = (input_section->output_section->vma
|
||||
+ input_section->output_offset + address);
|
||||
|
||||
/* Adjust for R_JMP1 vs R_JMPL1. */
|
||||
dot += (reloc->howto->type == R_JMP1 ? 1 : 2);
|
||||
|
||||
/* Compute the distance from this insn to the branch target. */
|
||||
gap = value - dot;
|
||||
|
||||
/* If the distance is within -128..+128 inclusive, then we can relax
|
||||
this jump. +128 is valid since the target will move two bytes
|
||||
this jump. */
|
||||
if ((int)gap >= -128 && (int)gap <= 128 )
|
||||
{
|
||||
/* Change the reloc type. */
|
||||
reloc->howto = reloc->howto + 1;
|
||||
|
||||
/* This shrinks this section by two bytes. */
|
||||
shrink += 2;
|
||||
bfd_perform_slip(abfd, 2, input_section, address);
|
||||
}
|
||||
break;
|
||||
|
||||
/* This is the 16 bit pc-relative branch which could become an 8 bit
|
||||
pc-relative branch. */
|
||||
case R_PCRWORD:
|
||||
/* Get the address of the target of this branch, add one to the value
|
||||
because the addend field in PCrel jumps is off by -1. */
|
||||
value = bfd_coff_reloc16_get_value(reloc, link_info, input_section) + 1;
|
||||
|
||||
/* Get the address of the next instruction if we were to relax. */
|
||||
dot = input_section->output_section->vma +
|
||||
input_section->output_offset + address;
|
||||
|
||||
/* See if the address we're looking at within 127 bytes of where
|
||||
we are, if so then we can use a small branch rather than the
|
||||
jump we were going to */
|
||||
/* Compute the distance from this insn to the branch target. */
|
||||
gap = value - dot;
|
||||
|
||||
gap = value - (dot - shrink);
|
||||
|
||||
|
||||
if (-120 < (long)gap && (long)gap < 120 )
|
||||
/* If the distance is within -128..+128 inclusive, then we can relax
|
||||
this jump. +128 is valid since the target will move two bytes
|
||||
closer if we do relax this branch. */
|
||||
if ((int)gap >= -128 && (int)gap <= 128 )
|
||||
{
|
||||
|
||||
/* Change the reloc type from 16bit, possible 8 to 8bit
|
||||
possible 16 */
|
||||
reloc->howto = reloc->howto + 1;
|
||||
/* The place to relc moves back by one */
|
||||
|
||||
/* This will be two bytes smaller in the long run */
|
||||
shrink +=2 ;
|
||||
bfd_perform_slip(abfd, 2, input_section, address);
|
||||
}
|
||||
break;
|
||||
|
||||
case R_PCRWORD:
|
||||
|
||||
value = bfd_coff_reloc16_get_value(reloc, link_info, input_section);
|
||||
|
||||
dot = input_section->output_section->vma +
|
||||
input_section->output_offset + address - 2;
|
||||
|
||||
/* See if the address we're looking at within 127 bytes of where
|
||||
we are, if so then we can use a small branch rather than the
|
||||
jump we were going to */
|
||||
|
||||
gap = value - (dot - shrink);
|
||||
|
||||
|
||||
if (-120 < (long)gap && (long)gap < 120 )
|
||||
{
|
||||
|
||||
/* Change the reloc type from 16bit, possible 8 to 8bit
|
||||
possible 16 */
|
||||
/* Change the reloc type. */
|
||||
reloc->howto = howto_table + 15;
|
||||
/* The place to relc moves back by one */
|
||||
|
||||
/* This will be two bytes smaller in the long run */
|
||||
shrink +=2 ;
|
||||
/* This shrinks this section by two bytes. */
|
||||
shrink += 2;
|
||||
bfd_perform_slip(abfd, 2, input_section, address);
|
||||
}
|
||||
break;
|
||||
|
||||
/* This is a 16 bit absolute address in a mov.b insn, which can
|
||||
become an 8 bit absolute address if it's in the right range. */
|
||||
case R_MOV16B1:
|
||||
/* Get the address of the data referenced by this mov.b insn. */
|
||||
value = bfd_coff_reloc16_get_value(reloc, link_info, input_section);
|
||||
|
||||
/* The address is in 0xff00..0xffff inclusive on the h8300 or
|
||||
0xffff00..0xffffff inclusive on the h8300h, then we can
|
||||
relax this mov.b */
|
||||
if ((bfd_get_mach (abfd) == bfd_mach_h8300
|
||||
&& value >= 0xff00
|
||||
&& value <= 0xffff)
|
||||
|| (bfd_get_mach (abfd) == bfd_mach_h8300h
|
||||
&& value >= 0xffff00
|
||||
&& value <= 0xffffff))
|
||||
{
|
||||
/* Change the reloc type. */
|
||||
reloc->howto = reloc->howto + 1;
|
||||
|
||||
/* This shrinks this section by two bytes. */
|
||||
shrink += 2;
|
||||
bfd_perform_slip(abfd, 2, input_section, address);
|
||||
}
|
||||
break;
|
||||
|
||||
/* Similarly for a 24 bit absolute address in a mov.b. Note that
|
||||
if we can't relax this into an 8 bit absolute, we'll fall through
|
||||
and try to relax it into a 16bit absolute. */
|
||||
case R_MOV24B1:
|
||||
/* Get the address of the data referenced by this mov.b insn. */
|
||||
value = bfd_coff_reloc16_get_value(reloc, link_info, input_section);
|
||||
|
||||
/* The address is in 0xffff00..0xffffff inclusive on the h8300h,
|
||||
then we can relax this mov.b */
|
||||
if (bfd_get_mach (abfd) == bfd_mach_h8300h
|
||||
&& value >= 0xffff00
|
||||
&& value <= 0xffffff)
|
||||
{
|
||||
/* Change the reloc type. */
|
||||
reloc->howto = reloc->howto + 1;
|
||||
|
||||
/* This shrinks this section by four bytes. */
|
||||
shrink += 4;
|
||||
bfd_perform_slip(abfd, 4, input_section, address);
|
||||
|
||||
/* Done with this reloc. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* FALLTHROUGH and try to turn the 32/24 bit reloc into a 16 bit
|
||||
reloc. */
|
||||
|
||||
/* This is a 24/32 bit absolute address in a mov insn, which can
|
||||
become an 16 bit absolute address if it's in the right range. */
|
||||
case R_MOVL1:
|
||||
/* Get the address of the data referenced by this mov insn. */
|
||||
value = bfd_coff_reloc16_get_value(reloc, link_info, input_section);
|
||||
|
||||
/* If this address is in 0x0000..0x7fff inclusive or
|
||||
0xff8000..0xffffff inclusive, then it can be relaxed. */
|
||||
if (value <= 0x7fff || value >= 0xff8000)
|
||||
{
|
||||
/* Change the reloc type. */
|
||||
reloc->howto = howto_table + 17;
|
||||
|
||||
/* This shrinks this section by two bytes. */
|
||||
shrink += 2;
|
||||
bfd_perform_slip(abfd, 2, input_section, address);
|
||||
}
|
||||
break;
|
||||
|
||||
/* No other reloc types represent relaxing opportunities. */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return shrink;
|
||||
}
|
||||
|
||||
|
||||
/* First phase of a relaxing link */
|
||||
|
||||
/* Reloc types
|
||||
large small
|
||||
R_MOVB1 R_MOVB2 mov.b with 16bit or 8 bit address
|
||||
R_JMP1 R_JMP2 jmp or pcrel branch
|
||||
R_JMPL1 R_JMPL_B8 24jmp or pcrel branch
|
||||
R_MOVLB1 R_MOVLB2 24 or 8 bit reloc for mov.b
|
||||
R_PCRWORD R_PCRWORD_B 8 bit pcrel branch from 16bit pcrel
|
||||
branch.
|
||||
|
||||
*/
|
||||
/* Handle relocations for the H8/300, including relocs for relaxed
|
||||
instructions.
|
||||
|
||||
FIXME: Not all relocations check for overflow! */
|
||||
|
||||
static void
|
||||
h8300_reloc16_extra_cases (abfd, link_info, link_order, reloc, data, src_ptr,
|
||||
|
@ -544,288 +575,345 @@ h8300_reloc16_extra_cases (abfd, link_info, link_order, reloc, data, src_ptr,
|
|||
unsigned int src_address = *src_ptr;
|
||||
unsigned int dst_address = *dst_ptr;
|
||||
asection *input_section = link_order->u.indirect.section;
|
||||
bfd_vma value;
|
||||
bfd_vma dot;
|
||||
int gap,tmp;
|
||||
|
||||
switch (reloc->howto->type)
|
||||
{
|
||||
/* A 24 bit branch which could be a 8 bit pcrel, really pointing to
|
||||
the byte before the 24bit hole, so we can treat it as a 32bit pointer */
|
||||
|
||||
/* Generic 8bit pc-relative relocation. */
|
||||
case R_PCRBYTE:
|
||||
{
|
||||
bfd_vma dot = link_order->offset
|
||||
+ dst_address
|
||||
+ link_order->u.indirect.section->output_section->vma;
|
||||
int gap = (bfd_coff_reloc16_get_value (reloc, link_info, input_section)
|
||||
- dot);
|
||||
if (gap > 127 || gap < -128)
|
||||
{
|
||||
if (! ((*link_info->callbacks->reloc_overflow)
|
||||
(link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),
|
||||
reloc->howto->name, reloc->addend, input_section->owner,
|
||||
input_section, reloc->address)))
|
||||
abort ();
|
||||
}
|
||||
gap &= ~1;
|
||||
bfd_put_8 (abfd, gap, data + dst_address);
|
||||
dst_address++;
|
||||
src_address++;
|
||||
/* Get the address of the target of this branch. */
|
||||
value = bfd_coff_reloc16_get_value(reloc, link_info, input_section);
|
||||
|
||||
break;
|
||||
}
|
||||
case R_PCRWORD:
|
||||
{
|
||||
bfd_vma dot = link_order->offset
|
||||
+ dst_address
|
||||
+ link_order->u.indirect.section->output_section->vma;
|
||||
int gap = (bfd_coff_reloc16_get_value (reloc, link_info, input_section)
|
||||
- dot) - 1;
|
||||
if (gap > 32767 || gap < -32768)
|
||||
{
|
||||
if (! ((*link_info->callbacks->reloc_overflow)
|
||||
(link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),
|
||||
reloc->howto->name, reloc->addend, input_section->owner,
|
||||
input_section, reloc->address)))
|
||||
abort ();
|
||||
}
|
||||
dot = (link_order->offset
|
||||
+ dst_address
|
||||
+ link_order->u.indirect.section->output_section->vma);
|
||||
|
||||
bfd_put_16 (abfd, gap, data + dst_address);
|
||||
dst_address+=2;
|
||||
src_address+=2;
|
||||
gap = value - dot;
|
||||
|
||||
break;
|
||||
}
|
||||
/* Sanity check. */
|
||||
if (gap < -128 || gap > 126)
|
||||
{
|
||||
if (! ((*link_info->callbacks->reloc_overflow)
|
||||
(link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),
|
||||
reloc->howto->name, reloc->addend, input_section->owner,
|
||||
input_section, reloc->address)))
|
||||
abort ();
|
||||
}
|
||||
|
||||
case R_RELBYTE:
|
||||
{
|
||||
unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info,
|
||||
input_section);
|
||||
if (gap < 0xff
|
||||
|| (gap >= 0x0000ff00
|
||||
&& gap <= 0x0000ffff)
|
||||
|| ( gap >= 0x00ffff00
|
||||
&& gap <= 0x00ffffff)
|
||||
|| ( gap >= 0xffffff00
|
||||
&& gap <= 0xffffffff))
|
||||
{
|
||||
bfd_put_8 (abfd, gap, data + dst_address);
|
||||
dst_address += 1;
|
||||
src_address += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! ((*link_info->callbacks->reloc_overflow)
|
||||
(link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),
|
||||
reloc->howto->name, reloc->addend, input_section->owner,
|
||||
input_section, reloc->address)))
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
/* Everything looks OK. Apply the relocation and update the
|
||||
src/dst address appropriately. */
|
||||
|
||||
bfd_put_8 (abfd, gap, data + dst_address);
|
||||
dst_address++;
|
||||
src_address++;
|
||||
|
||||
/* All done. */
|
||||
break;
|
||||
|
||||
/* Generic 16bit pc-relative relocation. */
|
||||
case R_PCRWORD:
|
||||
/* Get the address of the target of this branch. */
|
||||
value = bfd_coff_reloc16_get_value(reloc, link_info, input_section);
|
||||
|
||||
/* Get the address of the instruction (not the reloc). */
|
||||
dot = (link_order->offset
|
||||
+ dst_address
|
||||
+ link_order->u.indirect.section->output_section->vma + 1);
|
||||
|
||||
gap = value - dot;
|
||||
|
||||
/* Sanity check. */
|
||||
if (gap > 32766 || gap < -32768)
|
||||
{
|
||||
if (! ((*link_info->callbacks->reloc_overflow)
|
||||
(link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),
|
||||
reloc->howto->name, reloc->addend, input_section->owner,
|
||||
input_section, reloc->address)))
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* Everything looks OK. Apply the relocation and update the
|
||||
src/dst address appropriately. */
|
||||
|
||||
bfd_put_16 (abfd, gap, data + dst_address);
|
||||
dst_address += 2;
|
||||
src_address += 2;
|
||||
|
||||
/* All done. */
|
||||
break;
|
||||
|
||||
/* Generic 8bit absolute relocation. */
|
||||
case R_RELBYTE:
|
||||
/* Get the address of the object referenced by this insn. */
|
||||
value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
|
||||
|
||||
/* Sanity check. */
|
||||
if (value < 0xff
|
||||
|| (value >= 0x0000ff00 && value <= 0x0000ffff)
|
||||
|| (value >= 0x00ffff00 && value <= 0x00ffffff)
|
||||
|| (value >= 0xffffff00 && value <= 0xffffffff))
|
||||
{
|
||||
/* Everything looks OK. Apply the relocation and update the
|
||||
src/dst address appropriately. */
|
||||
|
||||
bfd_put_8 (abfd, gap, data + dst_address);
|
||||
dst_address += 1;
|
||||
src_address += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! ((*link_info->callbacks->reloc_overflow)
|
||||
(link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),
|
||||
reloc->howto->name, reloc->addend, input_section->owner,
|
||||
input_section, reloc->address)))
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* All done. */
|
||||
break;
|
||||
|
||||
/* Various simple 16bit absolute relocations. */
|
||||
case R_MOV16B1:
|
||||
case R_JMP1:
|
||||
/* A relword which would have like to have been a pcrel */
|
||||
case R_MOVB1:
|
||||
/* A relword which would like to have been modified but
|
||||
didn't make it */
|
||||
case R_RELWORD:
|
||||
bfd_put_16 (abfd,
|
||||
bfd_coff_reloc16_get_value (reloc, link_info, input_section),
|
||||
data + dst_address);
|
||||
value = bfd_coff_reloc16_get_value(reloc, link_info, input_section);
|
||||
bfd_put_16 (abfd, value, data + dst_address);
|
||||
dst_address += 2;
|
||||
src_address += 2;
|
||||
break;
|
||||
|
||||
/* Various simple 24/32bit absolute relocations. */
|
||||
case R_MOV24B1:
|
||||
case R_MOVL1:
|
||||
case R_RELLONG:
|
||||
bfd_put_32 (abfd,
|
||||
bfd_coff_reloc16_get_value (reloc, link_info, input_section),
|
||||
data + dst_address);
|
||||
/* Get the address of the target of this branch. */
|
||||
value = bfd_coff_reloc16_get_value (reloc, link_info, input_section),
|
||||
bfd_put_32 (abfd, value, data + dst_address);
|
||||
dst_address += 4;
|
||||
src_address += 4;
|
||||
break;
|
||||
|
||||
case R_MOVB2:
|
||||
/* Special relaxed type, there will be a gap between where we
|
||||
get stuff from and where we put stuff to now
|
||||
|
||||
for a mov.b @aa:16 -> mov.b @aa:8
|
||||
opcode 0x6a 0x0y offset
|
||||
-> 0x2y off
|
||||
*/
|
||||
if (data[dst_address - 1] != 0x6a)
|
||||
abort ();
|
||||
switch (data[src_address] & 0xf0)
|
||||
/* Another 24/32bit absolute relocation. */
|
||||
case R_JMPL1:
|
||||
/* Get the address of the target of this branch. */
|
||||
value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
|
||||
|
||||
value = ((value & 0x00ffffff)
|
||||
| (bfd_get_32 (abfd, data + src_address) & 0xff000000));
|
||||
bfd_put_32 (abfd, value, data + dst_address);
|
||||
dst_address += 4;
|
||||
src_address += 4;
|
||||
break;
|
||||
|
||||
/* A 16bit abolute relocation that was formerlly a 24/32bit
|
||||
absolute relocation. */
|
||||
case R_MOVL2:
|
||||
value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
|
||||
|
||||
/* Sanity check. */
|
||||
if (value < 0x8000 || value > 0xff8000)
|
||||
{
|
||||
case 0x00:
|
||||
/* Src is memory */
|
||||
data[dst_address - 1] = (data[src_address] & 0xf) | 0x20;
|
||||
/* Insert the 16bit value into the proper location. */
|
||||
bfd_put_16 (abfd, value, data + dst_address);
|
||||
|
||||
/* Fix the opcode. For all the move insns, we simply
|
||||
need to turn off bit 0x20 in the previous byte. */
|
||||
data[dst_address - 1] &= ~0x20;
|
||||
dst_address += 2;
|
||||
src_address += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! ((*link_info->callbacks->reloc_overflow)
|
||||
(link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),
|
||||
reloc->howto->name, reloc->addend, input_section->owner,
|
||||
input_section, reloc->address)))
|
||||
abort ();
|
||||
}
|
||||
break;
|
||||
|
||||
/* A 16bit absolute branch that is now an 8-bit pc-relative branch. */
|
||||
case R_JMP2:
|
||||
/* Get the address of the target of this branch. */
|
||||
value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
|
||||
|
||||
/* Get the address of the next instruction. */
|
||||
dot = (link_order->offset
|
||||
+ dst_address
|
||||
+ link_order->u.indirect.section->output_section->vma + 1);
|
||||
|
||||
gap = value - dot;
|
||||
|
||||
/* Sanity check. */
|
||||
if (gap < -128 || gap > 126)
|
||||
{
|
||||
if (! ((*link_info->callbacks->reloc_overflow)
|
||||
(link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),
|
||||
reloc->howto->name, reloc->addend, input_section->owner,
|
||||
input_section, reloc->address)))
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* Now fix the instruction itself. */
|
||||
switch (data[dst_address - 1])
|
||||
{
|
||||
case 0x5e:
|
||||
/* jsr -> bsr */
|
||||
bfd_put_8 (abfd, 0x55, data + dst_address - 1);
|
||||
break;
|
||||
case 0x80:
|
||||
/* Src is reg */
|
||||
data[dst_address - 1] = (data[src_address] & 0xf) | 0x30;
|
||||
case 0x5a:
|
||||
/* jmp ->bra */
|
||||
bfd_put_8 (abfd, 0x40, data + dst_address - 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* the offset must fit ! after all, what was all the relaxing
|
||||
about ? */
|
||||
/* Write out the 8bit value. */
|
||||
bfd_put_8 (abfd, gap, data + dst_address);
|
||||
|
||||
bfd_put_8 (abfd,
|
||||
bfd_coff_reloc16_get_value (reloc, link_info, input_section),
|
||||
data + dst_address);
|
||||
|
||||
/* Note the magic - src goes up by two bytes, but dst by only
|
||||
one */
|
||||
dst_address += 1;
|
||||
src_address += 3;
|
||||
|
||||
break;
|
||||
|
||||
case R_JMP2:
|
||||
|
||||
/* Special relaxed type */
|
||||
{
|
||||
bfd_vma dot = link_order->offset
|
||||
+ dst_address
|
||||
+ link_order->u.indirect.section->output_section->vma;
|
||||
|
||||
int gap = (bfd_coff_reloc16_get_value (reloc, link_info, input_section)
|
||||
- dot - 1);
|
||||
|
||||
if ((gap & ~0xff) != 0 && ((gap & 0xff00) != 0xff00))
|
||||
abort ();
|
||||
|
||||
bfd_put_8 (abfd, gap, data + dst_address);
|
||||
|
||||
switch (data[dst_address - 1])
|
||||
{
|
||||
case 0x5e:
|
||||
/* jsr -> bsr */
|
||||
bfd_put_8 (abfd, 0x55, data + dst_address - 1);
|
||||
break;
|
||||
case 0x5a:
|
||||
/* jmp ->bra */
|
||||
bfd_put_8 (abfd, 0x40, data + dst_address - 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
dst_address++;
|
||||
src_address += 3;
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
/* A 16bit pc-relative branch that is now an 8-bit pc-relative branch. */
|
||||
case R_PCRWORD_B:
|
||||
|
||||
/* Special relaxed type */
|
||||
{
|
||||
bfd_vma dot = link_order->offset
|
||||
+ dst_address
|
||||
+ link_order->u.indirect.section->output_section->vma - 2;
|
||||
/* Get the address of the target of this branch. */
|
||||
value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
|
||||
|
||||
int gap = (bfd_coff_reloc16_get_value (reloc, link_info, input_section)
|
||||
- dot - 1);
|
||||
/* Get the address of the instruction (not the reloc). */
|
||||
dot = (link_order->offset
|
||||
+ dst_address
|
||||
+ link_order->u.indirect.section->output_section->vma - 1);
|
||||
|
||||
if ((gap & ~0xff) != 0 && ((gap & 0xff00) != 0xff00))
|
||||
abort ();
|
||||
gap = value - dot;
|
||||
|
||||
switch (data[dst_address - 2])
|
||||
{
|
||||
int tmp;
|
||||
|
||||
case 0x58:
|
||||
/* bCC:16 -> bCC:8 */
|
||||
/* Get the condition code from the original insn. */
|
||||
tmp = data[dst_address - 1];
|
||||
tmp &= 0xf0;
|
||||
tmp >>= 4;
|
||||
|
||||
/* Now or in the high nibble of the opcode. */
|
||||
tmp |= 0x40;
|
||||
|
||||
/* Write it. */
|
||||
bfd_put_8 (abfd, tmp, data + dst_address - 2);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Sanity check. */
|
||||
if (gap < -128 || gap > 126)
|
||||
{
|
||||
if (! ((*link_info->callbacks->reloc_overflow)
|
||||
(link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),
|
||||
reloc->howto->name, reloc->addend, input_section->owner,
|
||||
input_section, reloc->address)))
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Now fix the instruction. */
|
||||
switch (data[dst_address - 2])
|
||||
{
|
||||
case 0x58:
|
||||
/* bCC:16 -> bCC:8 */
|
||||
/* Get the condition code from the original insn. */
|
||||
tmp = data[dst_address - 1];
|
||||
tmp &= 0xf0;
|
||||
tmp >>= 4;
|
||||
|
||||
/* Now or in the high nibble of the opcode. */
|
||||
tmp |= 0x40;
|
||||
|
||||
/* Write it. */
|
||||
bfd_put_8 (abfd, tmp, data + dst_address - 2);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* Output the target. */
|
||||
bfd_put_8 (abfd, gap, data + dst_address - 1);
|
||||
|
||||
/* We don't advance dst_address -- the 8bit reloc is applied at
|
||||
dst_address - 1, so the next insn should begin at dst_address.
|
||||
|
||||
src_address is advanced by two (original reloc was 16bits). */
|
||||
dst_address - 1, so the next insn should begin at dst_address. */
|
||||
src_address += 2;
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case R_JMPL_B8: /* 24 bit branch which is now 8 bits */
|
||||
|
||||
/* Speciial relaxed type */
|
||||
{
|
||||
bfd_vma dot = link_order->offset
|
||||
+ dst_address
|
||||
+ link_order->u.indirect.section->output_section->vma;
|
||||
/* Similarly for a 24bit absolute that is now 8 bits. */
|
||||
case R_JMPL2:
|
||||
/* Get the address of the target of this branch. */
|
||||
value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
|
||||
|
||||
int gap = (bfd_coff_reloc16_get_value (reloc, link_info, input_section)
|
||||
- dot - 2);
|
||||
/* Get the address of the instruction (not the reloc). */
|
||||
dot = (link_order->offset
|
||||
+ dst_address
|
||||
+ link_order->u.indirect.section->output_section->vma + 2);
|
||||
|
||||
if ((gap & ~0xff) != 0 && ((gap & 0xff00) != 0xff00))
|
||||
gap = value - dot;
|
||||
|
||||
/* Fix the instruction. */
|
||||
switch (data[src_address])
|
||||
{
|
||||
case 0x5e:
|
||||
/* jsr -> bsr */
|
||||
bfd_put_8 (abfd, 0x55, data + dst_address);
|
||||
break;
|
||||
case 0x5a:
|
||||
/* jmp ->bra */
|
||||
bfd_put_8 (abfd, 0x40, data + dst_address);
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
switch (data[src_address])
|
||||
{
|
||||
case 0x5e:
|
||||
/* jsr -> bsr */
|
||||
bfd_put_8 (abfd, 0x55, data + dst_address);
|
||||
break;
|
||||
case 0x5a:
|
||||
/* jmp ->bra */
|
||||
bfd_put_8 (abfd, 0x40, data + dst_address);
|
||||
break;
|
||||
|
||||
default:
|
||||
bfd_put_8 (abfd, 0xde, data + dst_address);
|
||||
break;
|
||||
}
|
||||
|
||||
bfd_put_8 (abfd, gap, data + dst_address + 1);
|
||||
dst_address += 2;
|
||||
src_address += 4;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case R_JMPL1:
|
||||
{
|
||||
int v = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
|
||||
int o = bfd_get_32 (abfd, data + src_address);
|
||||
v = (v & 0x00ffffff) | (o & 0xff000000);
|
||||
bfd_put_32 (abfd, v, data + dst_address);
|
||||
dst_address += 4;
|
||||
src_address += 4;
|
||||
}
|
||||
bfd_put_8 (abfd, gap, data + dst_address + 1);
|
||||
dst_address += 2;
|
||||
src_address += 4;
|
||||
|
||||
break;
|
||||
|
||||
/* A 16bit absolute mov.b that is now an 8bit absolute mov.b. */
|
||||
case R_MOV16B2:
|
||||
value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
|
||||
|
||||
/* A 24 bit mov which could be an 8 bit move, really pointing to
|
||||
the byte before the 24bit hole, so we can treat it as a 32bit pointer */
|
||||
case R_MOVLB1:
|
||||
{
|
||||
int v = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
|
||||
int o = bfd_get_32 (abfd, data + dst_address);
|
||||
v = (v & 0x00ffffff) | (o & 0xff000000);
|
||||
bfd_put_32 (abfd, v, data + dst_address);
|
||||
dst_address += 4;
|
||||
src_address += 4;
|
||||
}
|
||||
/* Sanity check. */
|
||||
if (data[dst_address - 2] != 0x6a)
|
||||
abort ();
|
||||
|
||||
/* Fix up the opcode. */
|
||||
switch (data[src_address-1] & 0xf0)
|
||||
{
|
||||
case 0x00:
|
||||
data[dst_address - 2] = (data[src_address-1] & 0xf) | 0x20;
|
||||
break;
|
||||
case 0x80:
|
||||
data[dst_address - 2] = (data[src_address-1] & 0xf) | 0x30;
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
bfd_put_8 (abfd, value & 0xff, data + dst_address - 1);
|
||||
src_address += 2;
|
||||
break;
|
||||
|
||||
/* Similarly for a 24bit mov.b */
|
||||
case R_MOV24B2:
|
||||
value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
|
||||
|
||||
/* Sanity check. */
|
||||
if (data[dst_address - 2] != 0x6a)
|
||||
abort ();
|
||||
|
||||
/* Fix up the opcode. */
|
||||
switch (data[src_address-1] & 0xf0)
|
||||
{
|
||||
case 0x20:
|
||||
data[dst_address - 2] = (data[src_address-1] & 0xf) | 0x20;
|
||||
break;
|
||||
case 0xa0:
|
||||
data[dst_address - 2] = (data[src_address-1] & 0xf) | 0x30;
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
bfd_put_8 (abfd, value & 0xff, data + dst_address - 1);
|
||||
src_address += 4;
|
||||
break;
|
||||
|
||||
/* An 8bit memory indirect instruction (jmp/jsr).
|
||||
|
|
Loading…
Reference in a new issue