aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2019-11-27 10:51:27 +1030
committerAlan Modra <amodra@gmail.com>2019-11-27 11:58:17 +1030
commit96e2dbda089775359b130e16a337c169d67abc6b (patch)
treebf6bd5d7b9411b4a1e58d7f232ec0ebc866348c0
parent855bae2c96421af06af9c77ed9b94b3dea5ae016 (diff)
downloadgdb-96e2dbda089775359b130e16a337c169d67abc6b.zip
gdb-96e2dbda089775359b130e16a337c169d67abc6b.tar.gz
gdb-96e2dbda089775359b130e16a337c169d67abc6b.tar.bz2
Correct R_SH_IND12W handling
Using bfd_vma for insn is to avoid having to worry about sign propagation in expressions involving insn and sym_value when bfd_vma is not the same as unsigned long. * elf32-sh.c (sh_reloc): Use a bfd_vma insn. (sh_reloc <R_SH_IND12W>): Divide calculated relocation value by two before applying to insn. Correct overflow test. * coff-sh.c (sh_reloc): Likewise.
-rw-r--r--bfd/ChangeLog7
-rw-r--r--bfd/coff-sh.c16
-rw-r--r--bfd/elf32-sh.c14
3 files changed, 20 insertions, 17 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 515a127..3ef8515 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,10 @@
+2019-11-27 Alan Modra <amodra@gmail.com>
+
+ * elf32-sh.c (sh_reloc): Use a bfd_vma insn.
+ (sh_reloc <R_SH_IND12W>): Divide calculated relocation value
+ by two before applying to insn. Correct overflow test.
+ * coff-sh.c (sh_reloc): Likewise.
+
2019-11-26 Nick Clifton <nickc@redhat.com>
* elf32-sh.c (sh_elf_reloc): Use a signed_vma when checking for a
diff --git a/bfd/coff-sh.c b/bfd/coff-sh.c
index 1077a20..e1bfaf0 100644
--- a/bfd/coff-sh.c
+++ b/bfd/coff-sh.c
@@ -567,7 +567,7 @@ sh_reloc (bfd * abfd,
bfd * output_bfd,
char ** error_message ATTRIBUTE_UNUSED)
{
- unsigned long insn;
+ bfd_vma insn;
bfd_vma sym_value;
unsigned short r_type;
bfd_vma addr = reloc_entry->address;
@@ -610,14 +610,14 @@ sh_reloc (bfd * abfd,
#endif
insn = bfd_get_32 (abfd, hit_data);
insn += sym_value + reloc_entry->addend;
- bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
+ bfd_put_32 (abfd, insn, hit_data);
break;
#ifdef COFF_WITH_PE
case R_SH_IMAGEBASE:
insn = bfd_get_32 (abfd, hit_data);
insn += sym_value + reloc_entry->addend;
insn -= pe_data (input_section->output_section->owner)->pe_opthdr.ImageBase;
- bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
+ bfd_put_32 (abfd, insn, hit_data);
break;
#endif
case R_SH_PCDISP:
@@ -627,12 +627,10 @@ sh_reloc (bfd * abfd,
+ input_section->output_offset
+ addr
+ 4);
- sym_value += (insn & 0xfff) << 1;
- if (insn & 0x800)
- sym_value -= 0x1000;
- insn = (insn & 0xf000) | (sym_value & 0xfff);
- bfd_put_16 (abfd, (bfd_vma) insn, hit_data);
- if ((bfd_signed_vma) sym_value < -0x1000 || sym_value >= 0x1000)
+ sym_value += (((insn & 0xfff) ^ 0x800) - 0x800) << 1;
+ insn = (insn & 0xf000) | ((sym_value >> 1) & 0xfff);
+ bfd_put_16 (abfd, insn, hit_data);
+ if (sym_value + 0x1000 >= 0x2000 || (sym_value & 1) != 0)
return bfd_reloc_overflow;
break;
default:
diff --git a/bfd/elf32-sh.c b/bfd/elf32-sh.c
index 863e2e1..be4256c 100644
--- a/bfd/elf32-sh.c
+++ b/bfd/elf32-sh.c
@@ -232,7 +232,7 @@ sh_elf_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol_in,
void *data, asection *input_section, bfd *output_bfd,
char **error_message ATTRIBUTE_UNUSED)
{
- unsigned long insn;
+ bfd_vma insn;
bfd_vma sym_value;
enum elf_sh_reloc_type r_type;
bfd_vma addr = reloc_entry->address;
@@ -274,7 +274,7 @@ sh_elf_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol_in,
case R_SH_DIR32:
insn = bfd_get_32 (abfd, hit_data);
insn += sym_value + reloc_entry->addend;
- bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
+ bfd_put_32 (abfd, insn, hit_data);
break;
case R_SH_IND12W:
insn = bfd_get_16 (abfd, hit_data);
@@ -283,12 +283,10 @@ sh_elf_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol_in,
+ input_section->output_offset
+ addr
+ 4);
- sym_value += (insn & 0xfff) << 1;
- if (insn & 0x800)
- sym_value -= 0x1000;
- insn = (insn & 0xf000) | (sym_value & 0xfff);
- bfd_put_16 (abfd, (bfd_vma) insn, hit_data);
- if ((bfd_signed_vma) sym_value < -0x1000 || sym_value >= 0x1000)
+ sym_value += (((insn & 0xfff) ^ 0x800) - 0x800) << 1;
+ insn = (insn & 0xf000) | ((sym_value >> 1) & 0xfff);
+ bfd_put_16 (abfd, insn, hit_data);
+ if (sym_value + 0x1000 >= 0x2000 || (sym_value & 1) != 0)
return bfd_reloc_overflow;
break;
default: