Index: bfd/elf32-h8300.c |
diff --git a/bfd/elf32-h8300.c b/bfd/elf32-h8300.c |
index 388d2205c58dee7ec081f835127553e87c471ffa..822d985f6e7ccb5f63c8fff1c41189ec88718811 100644 |
--- a/bfd/elf32-h8300.c |
+++ b/bfd/elf32-h8300.c |
@@ -1,6 +1,5 @@ |
/* BFD back-end for Renesas H8/300 ELF binaries. |
- Copyright 1993, 1995, 1998, 1999, 2001, 2002, 2003, 2004, 2005, 2006, |
- 2007, 2008, 2009, 2010, 2012 Free Software Foundation, Inc. |
+ Copyright 1993-2013 Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
@@ -185,7 +184,21 @@ static reloc_howto_type h8_elf_howto_table[] = |
0, /* src_mask */ |
0xffffffff, /* dst_mask */ |
FALSE), /* pcrel_offset */ |
-#define R_H8_PCREL16_X (R_H8_DIR32A16_X + 1) |
+#define R_H8_DISP32A16_X (R_H8_DIR32A16_X + 1) |
+ HOWTO (R_H8_DISP32A16, /* type */ |
+ 0, /* rightshift */ |
+ 2, /* size (0 = byte, 1 = short, 2 = long) */ |
+ 32, /* bitsize */ |
+ FALSE, /* pc_relative */ |
+ 0, /* bitpos */ |
+ complain_overflow_dont,/* complain_on_overflow */ |
+ special, /* special_function */ |
+ "R_H8_DISP32A16", /* name */ |
+ FALSE, /* partial_inplace */ |
+ 0, /* src_mask */ |
+ 0xffffffff, /* dst_mask */ |
+ FALSE), /* pcrel_offset */ |
+#define R_H8_PCREL16_X (R_H8_DISP32A16_X + 1) |
HOWTO (R_H8_PCREL16, /* type */ |
0, /* rightshift */ |
1, /* size (0 = byte, 1 = short, 2 = long) */ |
@@ -234,6 +247,7 @@ static const struct elf_reloc_map h8_reloc_map[] = { |
{ BFD_RELOC_H8_DIR24A8, R_H8_DIR24A8_X }, |
{ BFD_RELOC_H8_DIR24R8, R_H8_DIR24R8_X }, |
{ BFD_RELOC_H8_DIR32A16, R_H8_DIR32A16_X }, |
+ { BFD_RELOC_H8_DISP32A16, R_H8_DISP32A16_X }, |
{ BFD_RELOC_16_PCREL, R_H8_PCREL16_X }, |
{ BFD_RELOC_8_PCREL, R_H8_PCREL8_X }, |
}; |
@@ -338,6 +352,7 @@ elf32_h8_final_link_relocate (unsigned long r_type, bfd *input_bfd, |
case R_H8_DIR32: |
case R_H8_DIR32A16: |
+ case R_H8_DISP32A16: |
case R_H8_DIR24A8: |
value += addend; |
bfd_put_32 (input_bfd, value, hit_data); |
@@ -453,12 +468,12 @@ elf32_h8_relocate_section (bfd *output_bfd, struct bfd_link_info *info, |
} |
else |
{ |
- bfd_boolean unresolved_reloc, warned; |
+ bfd_boolean unresolved_reloc, warned, ignored; |
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, |
r_symndx, symtab_hdr, sym_hashes, |
h, sec, relocation, |
- unresolved_reloc, warned); |
+ unresolved_reloc, warned, ignored); |
} |
if (sec != NULL && discarded_section (sec)) |
@@ -670,7 +685,9 @@ elf32_h8_merge_private_bfd_data (bfd *ibfd, bfd *obfd) |
bset:24/32 -> bset:16 2 bytes |
(also applicable to other bit manipulation instructions) |
- mov.[bwl]:24/32 -> mov.[bwl]:16 2 bytes */ |
+ mov.[bwl]:24/32 -> mov.[bwl]:16 2 bytes |
+ |
+ mov.[bwl] @(displ:24/32+ERx) -> mov.[bwl] @(displ:16+ERx) 4 bytes. */ |
static bfd_boolean |
elf32_h8_relax_section (bfd *abfd, asection *sec, |
@@ -725,13 +742,19 @@ elf32_h8_relax_section (bfd *abfd, asection *sec, |
some long jumps created by the compiler. */ |
if (irel != internal_relocs) |
last_reloc = irel - 1; |
- |
- if (ELF32_R_TYPE (irel->r_info) != R_H8_DIR24R8 |
- && ELF32_R_TYPE (irel->r_info) != R_H8_PCREL16 |
- && ELF32_R_TYPE (irel->r_info) != R_H8_DIR16A8 |
- && ELF32_R_TYPE (irel->r_info) != R_H8_DIR24A8 |
- && ELF32_R_TYPE (irel->r_info) != R_H8_DIR32A16) |
- continue; |
+ |
+ switch(ELF32_R_TYPE (irel->r_info)) |
+ { |
+ case R_H8_DIR24R8: |
+ case R_H8_PCREL16: |
+ case R_H8_DIR16A8: |
+ case R_H8_DIR24A8: |
+ case R_H8_DIR32A16: |
+ case R_H8_DISP32A16: |
+ break; |
+ default: |
+ continue; |
+ } |
/* Get the section contents if we haven't done so already. */ |
if (contents == NULL) |
@@ -807,8 +830,8 @@ elf32_h8_relax_section (bfd *abfd, asection *sec, |
the linker is run. */ |
switch (ELF32_R_TYPE (irel->r_info)) |
{ |
- /* Try to turn a 24-bit absolute branch/call into an 8-bit |
- pc-relative branch/call. */ |
+ /* Try to turn a 24-bit absolute branch/call into an 8-bit |
+ pc-relative branch/call. */ |
case R_H8_DIR24R8: |
{ |
bfd_vma value = symval + irel->r_addend; |
@@ -848,19 +871,19 @@ elf32_h8_relax_section (bfd *abfd, asection *sec, |
Only perform this optimisation for jumps (code 0x5a) not |
subroutine calls, as otherwise it could transform: |
- mov.w r0,r0 |
- beq .L1 |
- jsr @_bar |
- .L1: rts |
- _bar: rts |
+ mov.w r0,r0 |
+ beq .L1 |
+ jsr @_bar |
+ .L1: rts |
+ _bar: rts |
into: |
- mov.w r0,r0 |
- bne _bar |
- rts |
- _bar: rts |
+ mov.w r0,r0 |
+ bne _bar |
+ rts |
+ _bar: rts |
which changes the call (jsr) into a branch (bne). */ |
- if (code == 0x5a |
+ if (code == 0x5a /* jmp24. */ |
&& (int) gap <= 130 |
&& (int) gap >= -128 |
&& last_reloc |
@@ -904,7 +927,7 @@ elf32_h8_relax_section (bfd *abfd, asection *sec, |
code ^= 1; |
bfd_put_8 (abfd, |
code, |
- contents + last_reloc->r_offset - 1); |
+ contents + last_reloc->r_offset - 1); |
/* Delete four bytes of data. */ |
if (!elf32_h8_relax_delete_bytes (abfd, sec, |
@@ -918,11 +941,11 @@ elf32_h8_relax_section (bfd *abfd, asection *sec, |
} |
if (code == 0x5e) |
- /* This is jsr. */ |
- bfd_put_8 (abfd, 0x55, contents + irel->r_offset - 1); |
+ /* This is jsr24 */ |
+ bfd_put_8 (abfd, 0x55, contents + irel->r_offset - 1); /* bsr8. */ |
else if (code == 0x5a) |
- /* This is jmp. */ |
- bfd_put_8 (abfd, 0x40, contents + irel->r_offset - 1); |
+ /* This is jmp24 */ |
+ bfd_put_8 (abfd, 0x40, contents + irel->r_offset - 1); /* bra8. */ |
else |
abort (); |
@@ -942,8 +965,8 @@ elf32_h8_relax_section (bfd *abfd, asection *sec, |
break; |
} |
- /* Try to turn a 16-bit pc-relative branch into a 8-bit pc-relative |
- branch. */ |
+ /* Try to turn a 16-bit pc-relative branch into a 8-bit pc-relative |
+ branch. */ |
case R_H8_PCREL16: |
{ |
bfd_vma value = symval + irel->r_addend; |
@@ -980,18 +1003,18 @@ elf32_h8_relax_section (bfd *abfd, asection *sec, |
contains the condition code. */ |
code = bfd_get_8 (abfd, contents + irel->r_offset - 1); |
- /* Compute the fisrt byte of the relaxed |
+ /* Compute the first byte of the relaxed |
instruction. The original sequence 0x58 0xX0 |
is relaxed to 0x4X, where X represents the |
condition code. */ |
code &= 0xf0; |
code >>= 4; |
code |= 0x40; |
- bfd_put_8 (abfd, code, contents + irel->r_offset - 2); |
+ bfd_put_8 (abfd, code, contents + irel->r_offset - 2); /* bCC:8. */ |
} |
- else if (code == 0x5c) |
+ else if (code == 0x5c) /* bsr16. */ |
/* This is bsr. */ |
- bfd_put_8 (abfd, 0x55, contents + irel->r_offset - 2); |
+ bfd_put_8 (abfd, 0x55, contents + irel->r_offset - 2); /* bsr8. */ |
else |
/* Might be MOVSD. */ |
break; |
@@ -1013,15 +1036,15 @@ elf32_h8_relax_section (bfd *abfd, asection *sec, |
break; |
} |
- /* This is a 16-bit absolute address in one of the following |
- instructions: |
+ /* 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. */ |
+ We may relax this into an 8-bit absolute address if it's in |
+ the right range. */ |
case R_H8_DIR16A8: |
{ |
bfd_vma value; |
@@ -1101,15 +1124,15 @@ elf32_h8_relax_section (bfd *abfd, asection *sec, |
break; |
} |
- /* This is a 24-bit absolute address in one of the following |
- instructions: |
+ /* 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. */ |
+ We may relax this into an 8-bit absolute address if it's in |
+ the right range. */ |
case R_H8_DIR24A8: |
{ |
bfd_vma value; |
@@ -1176,7 +1199,7 @@ elf32_h8_relax_section (bfd *abfd, asection *sec, |
R_H8_DIR8); |
irel->r_offset--; |
- /* Delete two bytes of data. */ |
+ /* Delete four bytes of data. */ |
if (!elf32_h8_relax_delete_bytes (abfd, sec, |
irel->r_offset + 1, 4)) |
goto error_return; |
@@ -1193,9 +1216,9 @@ elf32_h8_relax_section (bfd *abfd, asection *sec, |
/* 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]" |
+ "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. */ |
@@ -1218,7 +1241,7 @@ elf32_h8_relax_section (bfd *abfd, asection *sec, |
if (irel->r_offset >= 4) |
{ |
- /* Check for 4-byte MOVA relaxation. */ |
+ /* Check for 4-byte MOVA relaxation (SH-specific). */ |
int second_reloc = 0; |
op_ptr = contents + irel->r_offset - 4; |
@@ -1239,7 +1262,8 @@ elf32_h8_relax_section (bfd *abfd, asection *sec, |
second_reloc = 1; |
} |
} |
- if (irel < irelend) |
+ |
+ if (irel + 1 < irelend) |
{ |
Elf_Internal_Rela *next_reloc = irel + 1; |
arelent bfd_reloc; |
@@ -1284,7 +1308,7 @@ elf32_h8_relax_section (bfd *abfd, asection *sec, |
} |
} |
- /* Now check for short version of MOVA. */ |
+ /* Now check for short version of MOVA. (SH-specific) */ |
op_ptr = contents + irel->r_offset - 2; |
op0 = bfd_get_8 (abfd, op_ptr + 0); |
op1 = bfd_get_8 (abfd, op_ptr + 1); |
@@ -1321,8 +1345,98 @@ elf32_h8_relax_section (bfd *abfd, asection *sec, |
Note that this is not required, and it may be slow. */ |
*again = TRUE; |
} |
- break; |
+ break; /* case R_H8_DIR32A16 */ |
+ } |
+ |
+ case R_H8_DISP32A16: |
+ /* mov.[bwl] @(displ:24/32+ERx) -> mov.[bwl] @(displ:16+ERx) 4 bytes |
+ It is assured that instruction uses at least 4 bytes opcode before |
+ reloc entry addressing mode "register indirect with displacement" |
+ relaxing options (all saving 4 bytes): |
+ 0x78 0sss0000 0x6A 0010dddd disp:32 mov.b @(d:32,ERs),Rd -> |
+ 0x6E 0sssdddd disp:16 mov.b @(d:16,ERs),Rd |
+ 0x78 0sss0000 0x6B 0010dddd disp:32 mov.w @(d:32,ERs),Rd -> |
+ 0x6F 0sssdddd disp:16 mov.w @(d:16,ERs),Rd |
+ 0x01 0x00 0x78 0sss0000 0x6B 00100ddd disp:32 mov.l @(d:32,ERs),ERd -> |
+ 0x01 0x00 0x6F 0sss0ddd disp:16 mov.l @(d:16,ERs),ERd |
+ |
+ 0x78 0ddd0000 0x6A 1010ssss disp:32 mov.b Rs,@(d:32,ERd) -> |
+ 0x6E 1dddssss disp:16 mov.b Rs,@(d:16,ERd) |
+ 0x78 0ddd0000 0x6B 1010ssss disp:32 mov.w Rs,@(d:32,ERd) -> |
+ 0x6F 1dddssss disp:16 mov.w Rs,@(d:16,ERd) |
+ 0x01 0x00 0x78 xddd0000 0x6B 10100sss disp:32 mov.l ERs,@(d:32,ERd) -> |
+ 0x01 0x00 0x6F 1ddd0sss disp:16 mov.l ERs,@(d:16,ERd) |
+ mov.l prefix 0x01 0x00 can be left as is and mov.l handled same |
+ as mov.w/ */ |
+ { |
+ bfd_vma value; |
+ |
+ value = bfd_h8300_pad_address (abfd, symval + irel->r_addend); |
+ if (value <= 0x7fff || value >= 0xffff8000u) |
+ { |
+ unsigned char op0, op1, op2, op3, op0n, op1n; |
+ int relax = 0; |
+ |
+ /* Note that we've changed the relocs, section contents, |
+ etc. */ |
+ elf_section_data (sec)->relocs = internal_relocs; |
+ elf_section_data (sec)->this_hdr.contents = contents; |
+ symtab_hdr->contents = (unsigned char *) isymbuf; |
+ |
+ if (irel->r_offset >= 4) |
+ { |
+ op0 = bfd_get_8 (abfd, contents + irel->r_offset - 4); |
+ op1 = bfd_get_8 (abfd, contents + irel->r_offset - 3); |
+ op2 = bfd_get_8 (abfd, contents + irel->r_offset - 2); |
+ op3 = bfd_get_8 (abfd, contents + irel->r_offset - 1); |
+ |
+ if (op0 == 0x78) |
+ { |
+ switch(op2) |
+ { |
+ case 0x6A: |
+ if ((op1 & 0x8F) == 0x00 && (op3 & 0x70) == 0x20) |
+ { |
+ /* mov.b. */ |
+ op0n = 0x6E; |
+ relax = 1; |
+ } |
+ break; |
+ case 0x6B: |
+ if ((op1 & 0x0F) == 0x00 && (op3 & 0x70) == 0x20) |
+ { |
+ /* mov.w/l. */ |
+ op0n = 0x6F; |
+ relax = 1; |
+ } |
+ break; |
+ default: |
+ break; |
+ } |
+ } |
+ } |
+ |
+ if (relax) |
+ { |
+ op1n = (op3 & 0x8F) | (op1 & 0x70); |
+ bfd_put_8 (abfd, op0n, contents + irel->r_offset - 4); |
+ bfd_put_8 (abfd, op1n, contents + irel->r_offset - 3); |
+ |
+ /* Fix the relocation's type. */ |
+ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_H8_DIR16); |
+ irel->r_offset -= 2; |
+ |
+ /* Delete four bytes of data. */ |
+ if (!elf32_h8_relax_delete_bytes (abfd, sec, irel->r_offset + 2, 4)) |
+ goto error_return; |
+ |
+ /* That will change things, so, we should relax again. |
+ Note that this is not required, and it may be slow. */ |
+ *again = TRUE; |
+ } |
+ } |
} |
+ break; |
default: |
break; |
@@ -1404,7 +1518,7 @@ elf32_h8_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, int count) |
{ |
/* Get the new reloc address. */ |
if ((irel->r_offset > addr |
- && irel->r_offset < toaddr)) |
+ && irel->r_offset <= toaddr)) |
irel->r_offset -= count; |
} |
@@ -1416,7 +1530,7 @@ elf32_h8_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, int count) |
{ |
if (isym->st_shndx == sec_shndx |
&& isym->st_value > addr |
- && isym->st_value < toaddr) |
+ && isym->st_value <= toaddr) |
isym->st_value -= count; |
} |
@@ -1428,14 +1542,13 @@ elf32_h8_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, int count) |
for (; sym_hashes < end_hashes; sym_hashes++) |
{ |
struct elf_link_hash_entry *sym_hash = *sym_hashes; |
+ |
if ((sym_hash->root.type == bfd_link_hash_defined |
|| sym_hash->root.type == bfd_link_hash_defweak) |
&& sym_hash->root.u.def.section == sec |
&& sym_hash->root.u.def.value > addr |
- && sym_hash->root.u.def.value < toaddr) |
- { |
- sym_hash->root.u.def.value -= count; |
- } |
+ && sym_hash->root.u.def.value <= toaddr) |
+ sym_hash->root.u.def.value -= count; |
} |
return TRUE; |