aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog6
-rw-r--r--bfd/elf32-sh.c42
2 files changed, 43 insertions, 5 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 99506d1..dc6ff2d 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,9 @@
+2001-03-12 DJ Delorie <dj@redhat.com>
+
+ * elf32-sh.c (sh_elf_relocate_section): Only relocation
+ R_SH_DIR8WP* relocs if they're against external symbols, else
+ they're just for relaxing. Validate the reloc values.
+
2001-03-12 Stefan Geuken <mail@stefan-geuken.de>
* binary.c (bfd_external_binary_architecture): Declare.
diff --git a/bfd/elf32-sh.c b/bfd/elf32-sh.c
index 0e6be9b..6d7bc2e 100644
--- a/bfd/elf32-sh.c
+++ b/bfd/elf32-sh.c
@@ -3029,14 +3029,46 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
break;
case R_SH_IND12W:
+ relocation -= 4;
+ goto final_link_relocate;
+
case R_SH_DIR8WPN:
case R_SH_DIR8WPZ:
case R_SH_DIR8WPL:
- /* These should normally be handled by the assembler, but at
- least IND12W is generated by ourselves, so we must deal
- with it. */
- relocation -= 4;
- goto final_link_relocate;
+ /* If the reloc is against the start of this section, then
+ the assembler has already taken care of it and the reloc
+ is here only to assist in relaxing. If the reloc is not
+ against the start of this section, then it's against an
+ external symbol and we must deal with it ourselves. */
+ if (input_section->output_section->vma + input_section->output_offset
+ != relocation)
+ {
+ int disp = (relocation
+ - input_section->output_section->vma
+ - input_section->output_offset
+ - rel->r_offset);
+ int mask = 0;
+ switch (r_type)
+ {
+ case R_SH_DIR8WPN:
+ case R_SH_DIR8WPZ: mask = 1; break;
+ case R_SH_DIR8WPL: mask = 3; break;
+ default: mask = 0; break;
+ }
+ if (disp & mask)
+ {
+ ((*_bfd_error_handler)
+ (_("%s: 0x%lx: fatal: unaligned branch target for relax-support relocation"),
+ bfd_get_filename (input_section->owner),
+ (unsigned long) rel->r_offset));
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ relocation -= 4;
+ goto final_link_relocate;
+ }
+ r = bfd_reloc_ok;
+ break;
default:
bfd_set_error (bfd_error_bad_value);