but it's not easily available here. */
if (bfd_get_mach (table->abfd) == bfd_mach_h8300)
table->offset += 2;
- else if (bfd_get_mach (table->abfd) == bfd_mach_h8300h)
+ else if (bfd_get_mach (table->abfd) == bfd_mach_h8300h
+ || bfd_get_mach (table->abfd) == bfd_mach_h8300s)
table->offset += 4;
else
return NULL;
HOWTO (R_MOVL2, 0, 1, 16, false, 0, complain_overflow_bitfield, special, "32/24 relaxed move", false, 0x0000ffff, 0x0000ffff, false),
+ HOWTO (R_BCC_INV, 0, 0, 8, true, 0, complain_overflow_signed, special, "DISP8 inverted", false, 0x000000ff, 0x000000ff, true),
+
+ HOWTO (R_JMP_DEL, 0, 0, 8, true, 0, complain_overflow_signed, special, "Deleted jump", false, 0x000000ff, 0x000000ff, true),
};
#define SELECT_RELOC(x,howto) \
{ x.r_type = select_reloc(howto); }
-#define BADMAG(x) (H8300BADMAG(x)&& H8300HBADMAG(x))
+#define BADMAG(x) (H8300BADMAG(x) && H8300HBADMAG(x) && H8300SBADMAG(x))
#define H8300 1 /* Customize coffcode.h */
#define __A_MAGIC_SET__
case R_MOVL2:
internal->howto = howto_table + 17;
break;
+ case R_BCC_INV:
+ internal->howto = howto_table + 18;
+ break;
+ case R_JMP_DEL:
+ internal->howto = howto_table + 19;
+ break;
default:
abort ();
break;
/* relent->section = 0;*/
}
+static boolean
+h8300_symbol_address_p (abfd, input_section, address)
+ bfd *abfd;
+ asection *input_section;
+ bfd_vma address;
+{
+ asymbol **s;
+
+ s = _bfd_generic_link_get_symbols (abfd);
+ BFD_ASSERT (s != (asymbol **) NULL);
+
+ /* Search all the symbols for one in INPUT_SECTION with
+ address ADDRESS. */
+ while (*s)
+ {
+ asymbol *p = *s;
+ if (p->section == input_section
+ && (input_section->output_section->vma
+ + input_section->output_offset
+ + p->value) == address)
+ return true;
+ s++;
+ }
+ return false;
+}
+
+
/* 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
bfd_vma value;
bfd_vma dot;
bfd_vma gap;
+ static asection *last_input_section = NULL;
+ static arelent *last_reloc = NULL;
/* 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,
uncooked section. */
bfd_vma address = reloc->address - shrink;
+ if (input_section != last_input_section)
+ last_reloc = NULL;
+
/* Only examine the relocs which might be relaxable. */
switch (reloc->howto->type)
{
/* 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. */
+ closer if we do relax this branch. */
if ((int)gap >= -128 && (int)gap <= 128 )
{
+
+ /* It's possible we may be able to eliminate this branch entirely;
+ if the previous instruction is a branch around this instruction,
+ and there's no label at this instruction, then we can reverse
+ the condition on the previous branch and eliminate this jump.
+
+ original: new:
+ bCC lab1 bCC' lab2
+ jmp lab2
+ lab1: lab1:
+
+ This saves 4 bytes instead of two, and should be relatively
+ common. */
+
+ if (gap <= 126
+ && last_reloc
+ && last_reloc->howto->type == R_PCRBYTE)
+ {
+ bfd_vma last_value;
+ last_value = bfd_coff_reloc16_get_value (last_reloc, link_info,
+ input_section) + 1;
+
+ if (last_value == dot + 2
+ && last_reloc->address + 1 == reloc->address
+ && ! h8300_symbol_address_p (abfd, input_section, dot - 2))
+ {
+ reloc->howto = howto_table + 19;
+ last_reloc->howto = howto_table + 18;
+ last_reloc->sym_ptr_ptr = reloc->sym_ptr_ptr;
+ last_reloc->addend = reloc->addend;
+ shrink += 4;
+ bfd_perform_slip (abfd, 4, input_section, address);
+ break;
+ }
+ }
+
/* Change the reloc type. */
reloc->howto = reloc->howto + 1;
if ((bfd_get_mach (abfd) == bfd_mach_h8300
&& value >= 0xff00
&& value <= 0xffff)
- || (bfd_get_mach (abfd) == bfd_mach_h8300h
+ || ((bfd_get_mach (abfd) == bfd_mach_h8300h
+ || bfd_get_mach (abfd) == bfd_mach_h8300s)
&& value >= 0xffff00
&& value <= 0xffffff))
{
/* 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
+ if ((bfd_get_mach (abfd) == bfd_mach_h8300h
+ || bfd_get_mach (abfd) == bfd_mach_h8300s)
&& value >= 0xffff00
&& value <= 0xffffff)
{
break;
}
+ last_reloc = reloc;
+ last_input_section = input_section;
return shrink;
}
src_address += 4;
break;
+ case R_BCC_INV:
+ /* Get the address of the target of this branch. */
+ value = bfd_coff_reloc16_get_value(reloc, link_info, input_section);
+
+ 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 ();
+ }
+
+ /* Everything looks OK. Fix the condition in the instruction, apply
+ the relocation, and update the src/dst address appropriately. */
+
+ bfd_put_8 (abfd, bfd_get_8 (abfd, data + dst_address - 1) ^ 1,
+ data + dst_address - 1);
+ bfd_put_8 (abfd, gap, data + dst_address);
+ dst_address++;
+ src_address++;
+
+ /* All done. */
+ break;
+
+ case R_JMP_DEL:
+ src_address += 4;
+ break;
+
/* An 8bit memory indirect instruction (jmp/jsr).
There's several things that need to be done to handle
address in the function vector table. */
asymbol *symbol;
bfd_vma value;
- char *name;
+ const char *name;
struct funcvec_hash_entry *h;
asection *vectors_sec = h8300_coff_hash_table (link_info)->vectors_sec;
link_info,
input_section),
vectors_sec->contents + h->offset);
- else if (bfd_get_mach (input_section->owner) == bfd_mach_h8300h)
+ else if (bfd_get_mach (input_section->owner) == bfd_mach_h8300h
+ || bfd_get_mach (input_section->owner) == bfd_mach_h8300s)
bfd_put_32 (abfd,
bfd_coff_reloc16_get_value (reloc,
link_info,
{
arelent *reloc = relocs[i];
asymbol *symbol = *(reloc->sym_ptr_ptr);
- char *name;
+ const char *name;
/* We've got an indirect reloc. See if we need to add it
to the function vector table. At this point, we have
takes 2 bytes on the h8300 and 4 bytes on the h8300h. */
if (bfd_get_mach (abfd) == bfd_mach_h8300)
h8300_coff_hash_table (info)->vectors_sec->_raw_size += 2;
- else if (bfd_get_mach (abfd) == bfd_mach_h8300h)
+ else if (bfd_get_mach (abfd) == bfd_mach_h8300h
+ || bfd_get_mach (abfd) == bfd_mach_h8300s)
h8300_coff_hash_table (info)->vectors_sec->_raw_size += 4;
}
}