/* BFD back-end for Renesas H8/300 COFF binaries.
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
Written by Steve Chamberlain, <sac@cygnus.com>.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
#include "bfd.h"
#include "sysdep.h"
funcvec_hash_newfunc
(struct bfd_hash_entry *, struct bfd_hash_table *, const char *);
-static bfd_boolean
-funcvec_hash_table_init
- (struct funcvec_hash_table *, bfd *,
- struct bfd_hash_entry *(*) (struct bfd_hash_entry *,
- struct bfd_hash_table *,
- const char *));
-
static bfd_reloc_status_type special
(bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **);
static int select_reloc
/* Bump the offset at which we store entries in the function
vector. We'd like to bump up the size of the vectors section,
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
- || bfd_get_mach (table->abfd) == bfd_mach_h8300s)
- table->offset += 4;
- else
- return NULL;
+ switch (bfd_get_mach (table->abfd))
+ {
+ case bfd_mach_h8300:
+ case bfd_mach_h8300hn:
+ case bfd_mach_h8300sn:
+ table->offset += 2;
+ break;
+ case bfd_mach_h8300h:
+ case bfd_mach_h8300s:
+ table->offset += 4;
+ break;
+ default:
+ return NULL;
+ }
/* Everything went OK. */
return (struct bfd_hash_entry *) ret;
struct bfd_hash_entry *(*newfunc)
(struct bfd_hash_entry *,
struct bfd_hash_table *,
- const char *))
+ const char *),
+ unsigned int entsize)
{
/* Initialize our local fields, then call the generic initialization
routine. */
table->offset = 0;
table->abfd = abfd;
- return (bfd_hash_table_init (&table->root, newfunc));
+ return (bfd_hash_table_init (&table->root, newfunc, entsize));
}
/* Create the derived linker hash table. We use a derived hash table
if (ret == NULL)
return NULL;
if (!_bfd_link_hash_table_init (&ret->root.root, abfd,
- _bfd_generic_link_hash_newfunc))
+ _bfd_generic_link_hash_newfunc,
+ sizeof (struct generic_link_hash_entry)))
{
free (ret);
return NULL;
the function vector's entry in the jsr instruction. */
HOWTO (R_MEM_INDIRECT, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, special, "8/indirect", FALSE, 0x000000ff, 0x000000ff, FALSE),
- /* Internal reloc for relaxing. This is created when a 16bit pc-relative
- branch is turned into an 8bit pc-relative branch. */
+ /* Internal reloc for relaxing. This is created when a 16-bit pc-relative
+ branch is turned into an 8-bit pc-relative branch. */
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),
relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
relent->addend = reloc->r_offset;
-
relent->address -= section->vma;
-#if 0
- relent->section = 0;
-#endif
}
static bfd_boolean
/* Only examine the relocs which might be relaxable. */
switch (reloc->howto->type)
{
- /* This is the 16/24 bit absolute branch which could become an 8 bit
- pc-relative branch. */
+ /* 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. */
}
break;
- /* This is the 16 bit pc-relative branch which could become an 8 bit
+ /* 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
}
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. */
+ /* 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);
}
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. */
+ /* 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 16-bit 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);
break;
}
- /* FALLTHROUGH and try to turn the 32/24 bit reloc into a 16 bit
+ /* FALLTHROUGH and try to turn the 24-/32-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. */
+ /* 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);
bfd_vma value;
bfd_vma dot;
int gap, tmp;
+ unsigned char temp_code;
switch (reloc->howto->type)
{
- /* Generic 8bit pc-relative relocation. */
+ /* Generic 8-bit pc-relative relocation. */
case R_PCRBYTE:
/* Get the address of the target of this branch. */
value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
- dot = (link_order->offset
+ dot = (input_section->output_offset
+ dst_address
+ link_order->u.indirect.section->output_section->vma);
if (gap < -128 || gap > 126)
{
if (! ((*link_info->callbacks->reloc_overflow)
- (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),
+ (link_info, NULL,
+ bfd_asymbol_name (*reloc->sym_ptr_ptr),
reloc->howto->name, reloc->addend, input_section->owner,
input_section, reloc->address)))
abort ();
/* All done. */
break;
- /* Generic 16bit pc-relative relocation. */
+ /* Generic 16-bit 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
+ dot = (input_section->output_offset
+ dst_address
+ link_order->u.indirect.section->output_section->vma + 1);
if (gap > 32766 || gap < -32768)
{
if (! ((*link_info->callbacks->reloc_overflow)
- (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),
+ (link_info, NULL,
+ bfd_asymbol_name (*reloc->sym_ptr_ptr),
reloc->howto->name, reloc->addend, input_section->owner,
input_section, reloc->address)))
abort ();
/* All done. */
break;
- /* Generic 8bit absolute relocation. */
+ /* Generic 8-bit 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);
/* All done. */
break;
- /* Various simple 16bit absolute relocations. */
+ /* Various simple 16-bit absolute relocations. */
case R_MOV16B1:
case R_JMP1:
case R_RELWORD:
src_address += 2;
break;
- /* Various simple 24/32bit absolute relocations. */
+ /* Various simple 24-/32-bit absolute relocations. */
case R_MOV24B1:
case R_MOVL1:
case R_RELLONG:
src_address += 4;
break;
- /* Another 24/32bit absolute relocation. */
+ /* Another 24-/32-bit 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);
src_address += 4;
break;
- /* A 16bit abolute relocation that was formerlly a 24/32bit
- absolute relocation. */
+ /* This is a 24-/32-bit absolute address in one of the following
+ instructions:
+
+ "band", "bclr", "biand", "bild", "bior", "bist", "bixor",
+ "bld", "bnot", "bor", "bset", "bst", "btst", "bxor", "ldc.w",
+ "stc.w" and "mov.[bwl]"
+
+ We may relax this into an 16-bit absolute address if it's in
+ the right range. */
case R_MOVL2:
value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
value = bfd_h8300_pad_address (abfd, value);
/* Sanity check. */
if (value <= 0x7fff || value >= 0xffff8000u)
{
- /* Insert the 16bit value into the proper location. */
+ /* Insert the 16-bit 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. */
+ /* Fix the opcode. For all the instructions that belong to
+ this relaxation, 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),
+ (link_info, NULL,
+ 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. */
+ /* A 16-bit 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
+ dot = (input_section->output_offset
+ dst_address
+ link_order->u.indirect.section->output_section->vma + 1);
if (gap < -128 || gap > 126)
{
if (! ((*link_info->callbacks->reloc_overflow)
- (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),
+ (link_info, NULL,
+ bfd_asymbol_name (*reloc->sym_ptr_ptr),
reloc->howto->name, reloc->addend, input_section->owner,
input_section, reloc->address)))
abort ();
bfd_put_8 (abfd, 0x55, data + dst_address - 1);
break;
case 0x5a:
- /* jmp ->bra */
+ /* jmp -> bra */
bfd_put_8 (abfd, 0x40, data + dst_address - 1);
break;
abort ();
}
- /* Write out the 8bit value. */
+ /* Write out the 8-bit value. */
bfd_put_8 (abfd, gap, data + dst_address);
dst_address += 1;
break;
- /* A 16bit pc-relative branch that is now an 8-bit pc-relative branch. */
+ /* A 16-bit pc-relative branch that is now an 8-bit pc-relative branch. */
case R_PCRWORD_B:
/* 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
+ dot = (input_section->output_offset
+ dst_address
+ link_order->u.indirect.section->output_section->vma - 1);
if (gap < -128 || gap > 126)
{
if (! ((*link_info->callbacks->reloc_overflow)
- (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),
+ (link_info, NULL,
+ bfd_asymbol_name (*reloc->sym_ptr_ptr),
reloc->howto->name, reloc->addend, input_section->owner,
input_section, reloc->address)))
abort ();
{
case 0x58:
/* bCC:16 -> bCC:8 */
- /* Get the condition code from the original insn. */
+ /* Get the second byte of the original insn, which contains
+ the condition code. */
tmp = data[dst_address - 1];
+
+ /* Compute the fisrt byte of the relaxed instruction. The
+ original sequence 0x58 0xX0 is relaxed to 0x4X, where X
+ represents the condition code. */
tmp &= 0xf0;
tmp >>= 4;
-
- /* Now or in the high nibble of the opcode. */
tmp |= 0x40;
/* Write it. */
/* Output the target. */
bfd_put_8 (abfd, gap, data + dst_address - 1);
- /* We don't advance dst_address -- the 8bit reloc is applied at
+ /* We don't advance dst_address -- the 8-bit reloc is applied at
dst_address - 1, so the next insn should begin at dst_address. */
src_address += 2;
break;
- /* Similarly for a 24bit absolute that is now 8 bits. */
+ /* Similarly for a 24-bit 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);
/* Get the address of the instruction (not the reloc). */
- dot = (link_order->offset
+ dot = (input_section->output_offset
+ dst_address
+ link_order->u.indirect.section->output_section->vma + 2);
break;
- /* A 16bit absolute mov.b that is now an 8bit absolute mov.b. */
+ /* This is a 16-bit absolute address in one of the following
+ instructions:
+
+ "band", "bclr", "biand", "bild", "bior", "bist", "bixor",
+ "bld", "bnot", "bor", "bset", "bst", "btst", "bxor", and
+ "mov.b"
+
+ We may relax this into an 8-bit absolute address if it's in
+ the right range. */
case R_MOV16B2:
value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
- /* Sanity check. */
+ /* All instructions with R_H8_DIR16B2 start with 0x6a. */
if (data[dst_address - 2] != 0x6a)
abort ();
+ temp_code = data[src_address - 1];
+
+ /* If this is a mov.b instruction, clear the lower nibble, which
+ contains the source/destination register number. */
+ if ((temp_code & 0x10) != 0x10)
+ temp_code &= 0xf0;
+
/* Fix up the opcode. */
- switch (data[src_address - 1] & 0xf0)
+ switch (temp_code)
{
case 0x00:
+ /* This is mov.b @aa:16,Rd. */
data[dst_address - 2] = (data[src_address - 1] & 0xf) | 0x20;
break;
case 0x80:
+ /* This is mov.b Rs,@aa:16. */
data[dst_address - 2] = (data[src_address - 1] & 0xf) | 0x30;
break;
+ case 0x18:
+ /* This is a bit-maniputation instruction that stores one
+ bit into memory, one of "bclr", "bist", "bnot", "bset",
+ and "bst". */
+ data[dst_address - 2] = 0x7f;
+ break;
+ case 0x10:
+ /* This is a bit-maniputation instruction that loads one bit
+ from memory, one of "band", "biand", "bild", "bior",
+ "bixor", "bld", "bor", "btst", and "bxor". */
+ data[dst_address - 2] = 0x7e;
+ break;
default:
abort ();
}
src_address += 2;
break;
- /* Similarly for a 24bit mov.b */
+ /* This is a 24-bit absolute address in one of the following
+ instructions:
+
+ "band", "bclr", "biand", "bild", "bior", "bist", "bixor",
+ "bld", "bnot", "bor", "bset", "bst", "btst", "bxor", and
+ "mov.b"
+
+ We may relax this into an 8-bit absolute address if it's in
+ the right range. */
case R_MOV24B2:
value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
- /* Sanity check. */
+ /* All instructions with R_MOV24B2 start with 0x6a. */
if (data[dst_address - 2] != 0x6a)
abort ();
+ temp_code = data[src_address - 1];
+
+ /* If this is a mov.b instruction, clear the lower nibble, which
+ contains the source/destination register number. */
+ if ((temp_code & 0x30) != 0x30)
+ temp_code &= 0xf0;
+
/* Fix up the opcode. */
- switch (data[src_address - 1] & 0xf0)
+ switch (temp_code)
{
case 0x20:
+ /* This is mov.b @aa:24/32,Rd. */
data[dst_address - 2] = (data[src_address - 1] & 0xf) | 0x20;
break;
case 0xa0:
+ /* This is mov.b Rs,@aa:24/32. */
data[dst_address - 2] = (data[src_address - 1] & 0xf) | 0x30;
break;
+ case 0x38:
+ /* This is a bit-maniputation instruction that stores one
+ bit into memory, one of "bclr", "bist", "bnot", "bset",
+ and "bst". */
+ data[dst_address - 2] = 0x7f;
+ break;
+ case 0x30:
+ /* This is a bit-maniputation instruction that loads one bit
+ from memory, one of "band", "biand", "bild", "bior",
+ "bixor", "bld", "bor", "btst", and "bxor". */
+ data[dst_address - 2] = 0x7e;
+ break;
default:
abort ();
}
/* Get the address of the target of this branch. */
value = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
- dot = (link_order->offset
+ dot = (input_section->output_offset
+ dst_address
+ link_order->u.indirect.section->output_section->vma) + 1;
if (gap < -128 || gap > 126)
{
if (! ((*link_info->callbacks->reloc_overflow)
- (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),
+ (link_info, NULL,
+ bfd_asymbol_name (*reloc->sym_ptr_ptr),
reloc->howto->name, reloc->addend, input_section->owner,
input_section, reloc->address)))
abort ();
src_address += 4;
break;
- /* An 8bit memory indirect instruction (jmp/jsr).
+ /* An 8-bit memory indirect instruction (jmp/jsr).
There's several things that need to be done to handle
this relocation.
else
{
if (! ((*link_info->callbacks->reloc_overflow)
- (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr),
+ (link_info, NULL,
+ bfd_asymbol_name (*reloc->sym_ptr_ptr),
reloc->howto->name, reloc->addend, input_section->owner,
input_section, reloc->address)))
abort ();
name = symbol->name;
if (symbol->flags & BSF_LOCAL)
{
- char *new_name = bfd_malloc ((bfd_size_type) strlen (name) + 9);
+ char *new_name = bfd_malloc ((bfd_size_type) strlen (name) + 10);
+
if (new_name == NULL)
abort ();
- strcpy (new_name, name);
- sprintf (new_name + strlen (name), "_%08x",
- (int) symbol->section);
+ sprintf (new_name, "%s_%08x", name, symbol->section->id);
name = new_name;
}
src_address++;
/* Now create an entry in the function vector itself. */
- if (bfd_get_mach (input_section->owner) == bfd_mach_h8300)
- bfd_put_16 (abfd,
- bfd_coff_reloc16_get_value (reloc,
- link_info,
- input_section),
- vectors_sec->contents + h->offset);
- 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,
- input_section),
- vectors_sec->contents + h->offset);
- else
- abort ();
+ switch (bfd_get_mach (input_section->owner))
+ {
+ case bfd_mach_h8300:
+ case bfd_mach_h8300hn:
+ case bfd_mach_h8300sn:
+ bfd_put_16 (abfd,
+ bfd_coff_reloc16_get_value (reloc,
+ link_info,
+ input_section),
+ vectors_sec->contents + h->offset);
+ break;
+ case bfd_mach_h8300h:
+ case bfd_mach_h8300s:
+ bfd_put_32 (abfd,
+ bfd_coff_reloc16_get_value (reloc,
+ link_info,
+ input_section),
+ vectors_sec->contents + h->offset);
+ break;
+ default:
+ abort ();
+ }
/* Gross. We've already written the contents of the vector section
before we get here... So we write it again with the new data. */
vectors_sec->output_section,
vectors_sec->contents,
(file_ptr) vectors_sec->output_offset,
- vectors_sec->_raw_size);
+ vectors_sec->size);
break;
}
/* And initialize the funcvec hash table. */
if (!funcvec_hash_table_init (funcvec_hash_table, abfd,
- funcvec_hash_newfunc))
+ funcvec_hash_newfunc,
+ sizeof (struct funcvec_hash_entry)))
{
bfd_release (abfd, funcvec_hash_table);
return FALSE;
{
char *new_name;
- new_name = bfd_malloc ((bfd_size_type) strlen (name) + 9);
+ new_name = bfd_malloc ((bfd_size_type) strlen (name) + 10);
if (new_name == NULL)
abort ();
- strcpy (new_name, name);
- sprintf (new_name + strlen (name), "_%08x",
- (int) symbol->section);
+ sprintf (new_name, "%s_%08x", name, symbol->section->id);
name = new_name;
}
/* Bump the size of the vectors section. Each vector
takes 2 bytes on the h8300 and 4 bytes on the h8300h. */
- if (bfd_get_mach (abfd) == bfd_mach_h8300)
- htab->vectors_sec->_raw_size += 2;
- else if (bfd_get_mach (abfd) == bfd_mach_h8300h
- || bfd_get_mach (abfd) == bfd_mach_h8300s)
- htab->vectors_sec->_raw_size += 4;
+ switch (bfd_get_mach (abfd))
+ {
+ case bfd_mach_h8300:
+ case bfd_mach_h8300hn:
+ case bfd_mach_h8300sn:
+ htab->vectors_sec->size += 2;
+ break;
+ case bfd_mach_h8300h:
+ case bfd_mach_h8300s:
+ htab->vectors_sec->size += 4;
+ break;
+ default:
+ abort ();
+ }
}
}
}
/* Now actually allocate some space for the function vector. It's
wasteful to do this more than once, but this is easier. */
sec = htab->vectors_sec;
- if (sec->_raw_size != 0)
+ if (sec->size != 0)
{
/* Free the old contents. */
if (sec->contents)
free (sec->contents);
/* Allocate new contents. */
- sec->contents = bfd_malloc (sec->_raw_size);
+ sec->contents = bfd_malloc (sec->size);
}
return TRUE;